Federation
Federation moves CryptidEnvelope values between servers unchanged. A receiving server learns exactly what a local server learns: a routing string and an opaque blob.
It authenticates servers, never users. PrivacyPass tokens are server-local and MUST NOT cross this boundary - a token minted by one server is meaningless to another, and forwarding one would tie a user’s action to a specific remote request.
RelayEnvelopes
Section titled “RelayEnvelopes”- Input:
RelayTransaction { origin_server, transaction_id, envelopes } - Output:
RelayReceipt { accepted } - Auth: Origin signature
- Idempotent: By
transaction_id - Errors:
ORIGIN_SIGNATURE_INVALID,TRANSACTION_MISMATCH,VERSION_UNSUPPORTED,FEATURE_UNSUPPORTED,ORIGIN_BLOCKED,CERT_FINGERPRINT_MISMATCH
Requirements
Section titled “Requirements”- Receiving servers MUST verify
X-Origin-Signatureagainst the peer’sserver_signing_keyfrom discovery, before queueing anything - Receiving servers MUST verify the TLS certificate against the peer’s
certificate_fingerprint origin_serverMUST match theX-Origin-Serverheadertransaction_idMUST match the URL path- Receiving servers MUST treat a repeated
transaction_idas idempotent - Receiving servers MUST NOT infer any user-level authorization from a valid server signature
- An envelope MUST be delivered only to the exact address it names
The Signature
Section titled “The Signature”Covers the canonical request defined in Wire Format
"cryptid-federation-v1" || method || path || origin_server || transaction_id || bodyEach component length-prefixed, body the exact transmitted bytes. The leading domain separator stops a signature produced in one context verifying in another.
Timestamps
Section titled “Timestamps”The payload’s timestamp is when the origin accepted the envelope. The receiving server assigns its own received_at on queueing and uses that for retention and ordering.
- Receiving servers MUST assign
received_atthemselves - Receiving servers MUST NOT use the origin’s
timestampto compute expiry
A peer that could set expiry could keep an envelope alive indefinitely, or expire it on arrival. The origin’s timestamp is advisory.
HTTP Binding
Section titled “HTTP Binding”PUT /federation/v1/deliver/{transaction_id}X-Origin-Server: server1.comX-Origin-Signature: <ed25519 over the canonical request>Content-Type: application/jsonBatching
Section titled “Batching”Envelopes for different recipients SHOULD NOT share a transaction.
- Server SHOULD dispatch envelopes for distinct recipients in separate transactions
- Servers MAY batch retries of the same envelope
- Servers SHOULD introduce jitter between transactions from a single fan-out
What Does Not Cross
Section titled “What Does Not Cross”| Never Crosses | Why |
|---|---|
| PrivacyPass Tokens | server-local; forwarding one would link a user action to a remote request |
| Mailbox ownership sessions | scoped to one mailbox at one server |
| Any sender identity | the outer layer is HPKE Base mode - no sender key participates at all |
| Device records | announcement state never leaves its home server |
There is no sender_address and no sender_signature. An ephemeral key is generated per envelope and discarded. Sender identity lives in the MLS credential, inside the MLS ciphertext, inside the HPKE-sealed blob - two decryptions below anything either server can reach.
Defederation
Section titled “Defederation”A server MAY refuse a peer entirely, returning ORIGIN_BLOCKED.
- Blocked origins MUST be refused before signature verification, to avoid spending work on them
- Servers SHOULD aggregate abuse per origin rather than per envelope
Blocking a peer also blocks KeyPackage fetches routed through it and any Welcome bound for its users, so it ends group formation with that server, not just message delivery.