Skip to content

Security considerations

SSP/1’s trust boundary runs around the mesh. Inside it: nodes admitted by the trust authority. Outside it: every other authority, every relay and mailbox operator, every hosting provider, and all shared infrastructure.

The boundary is enforced cryptographically rather than administratively. A node is inside because it holds an identity key the mesh has admitted, not because it sits on a particular network or is named in a configuration file.

There is no privilege gradient inside the boundary. A node authorized to write a table may write anything to it. Per-event signatures make authorship attributable, not constrained.

Position Obtains Does not obtain
Mailbox / relay operator Payload sizes, timing, site_id correspondence graph Payload plaintext; ability to forge events or membership
Network observer Whatever the binding leaks Event contents, if the binding provides confidentiality
Removed node Everything it held before removal Future events, future group secrets
Out-of-scope node Nothing for tables outside its scope Data its policy denies
Compromised authorized node Everything within its scope, and the ability to author events attributed to itself The ability to author events attributed to another node
Stolen locked node Ciphertext at rest and a protected key store Key material, where custody is hardware-backed
Stolen unlocked node Everything that node held

Event authorship is verifiable. Every event is a COSE_Sign1 message signed under the authoring node’s root identity key, with the verifier’s own mesh_id supplied as external AAD. A node cannot author an event attributed to another node, and an event captured from one mesh fails verification in every other.

Convergence is deterministic. The materialized state is a pure function of the delivered event set, so no delivery order produces a divergent replica. This is a correctness property with a security consequence: an attacker who controls delivery ordering cannot induce two honest nodes to disagree.

Scope is enforced by the holder. Policy is a sender-side decision that never appears on the wire, so a receiver cannot widen its own feed by misrepresenting its policy.

Clock abuse is bounded. The skew bound stops a node with a hostile clock winning every future comparison indefinitely.

Admission requires a human. Both direct pairing and vouched joining require an affirmative human confirmation, defaulting to deny.

Enumerated in limitations. In brief: no retroactive revocation, no permanent erasure, no revocation announcement, no metadata protection at this layer, no intra-mesh privilege separation, and no specified trust resumption after first pairing.

Purpose Primitive
Durable record container COSE_Sign1 ([RFC 9052], [RFC 9053]), EdDSA suite only
Identity, event, vouch, role and binding signatures Ed25519 ([RFC 8032])
Pairing key agreement X25519 ([RFC 7748])
Key derivation HKDF-SHA256 ([RFC 5869])
All hashing: identifiers, commitments, event ids, chain links BLAKE3
Canonical encoding Deterministic CBOR ([RFC 8949] section 4.2.1)

Two narrowings are intentional rather than accidental. There is exactly one hash family: every identifier, commitment, chain link and event id is BLAKE3 over exact bytes, the same convention as SOP/1 — the family maintains no second hash namespace. And SSP/1 defines no encryption primitive at all, because it seals nothing: confidentiality is the binding’s responsibility. SHA-256 survives only inside HKDF-SHA256, where it is the PRF, not a content address.

An implementation MUST NOT back up identity key material to a location outside the trust boundary. Where a platform performs automatic cloud backup, key stores MUST be excluded, and the exclusion MUST survive file replacement.

Restoring application files alone MUST NOT recreate usable identity authority. If it does, a copied backup is a cloned node, and every guarantee on this page follows the key rather than the node.

SSP/1’s posture is that a peer must not be able to stop replication with other peers.

Concretely: out-of-scope events are dropped rather than raised; events with unresolvable row keys are dropped and the watermark advances; a malformed body rejects that exchange only; and the apply loop MUST NOT raise on peer-supplied input.

This is why the error posture distinguishes hold from drop. Every hold is a place a hostile peer could stall progress, so holds are restricted to conditions that resolve without that peer’s cooperation.