Pixieby Sociofabric

Sealed Sender: Hiding Who Is Talking

The relay has a job that sounds self-contradictory: it must confirm that a message comes from a real, non-banned user, and it must do that without ever learning which user.

Content encryption (the previous article) hides what is said. This article hides who said it, from the one party in the best position to build a social graph out of that fact: the server in the middle.


1. The leak that survives encryption

Go back to the strawman inbox, the naive mailbox table from the series opener, one row per message. Even with a perfectly encrypted body, the row the relay handles looks like (from: Alice, to: Bob, …). That from: Alice is the whole ballgame. It lets the relay log "Alice talks to Bob at 9pm, to Carol at midnight, to a crisis-hotline number on Tuesday," a portrait assembled entirely from envelopes it was never supposed to open, because it never had to: the sender wrote their own name on the outside.

The obvious fix is to not write the name on the outside. But then two problems appear that the naive design was quietly solving for free:

Signal named and solved the first half of this in 2018 with sealed sender, and our design follows that shape, with the authorization half handled by a separate anonymous token we will get to in Anonymous Admission.


2. Put the identity inside the seal

The core move is almost too simple: the sender's identity goes inside the encrypted payload, not on the envelope. Alice's public key and account handle are sealed in the blob that only Bob can open. The relay routes by the outside and never sees a from at all.

And the outside is less than it sounds.

The to field is not "Bob." It is a rotating per-pair, per-device address that both ends derive from the channel key they already share and the current hour.

No public key, phone number or account handle appears on the wire. The value names a slot to drop bytes into for the next hour and nothing else, and next hour it is a different value.

ALICE SEALS RELAY ROUTES BLIND BOB OPENS ALICE RELAY BOB TO:8F3C… FROM: ALICE FROM: ALICE NAME SEALED INSIDE SEES: ONE ROTATING ADDRESS — NO FROM SEAL OPENS: ALICE THE NAME RIDES INSIDE THE SEAL — THE RELAY ROUTES BLIND

But that immediately raises Bob's problem. If anyone can seal a blob to Bob claiming to be Alice, how does Bob know it is really Alice and not an impostor? In the old design the relay vouched for the sender; now the relay is blindfolded. The authenticity has to travel inside the seal too.

So Alice includes, inside the payload, a sender certificate: a short document that says "the holder of this public key is a registered, non-banned user," signed by a service Bob trusts. Bob opens the seal, reads the certificate, checks the signature, and only then believes the message. The relay never participates in that check: it happens end to end, between Alice's claim and Bob's verification, through a server that saw only ciphertext.


3. The sender certificate, concretely

The certificate is minted by credential-svc (a registration/identity service, separate from the relay) when Alice proves she is a logged-in, in-good-standing user. It binds her sending public key to that blessing and carries an expiry. One choice is deliberate and worth spelling out:

Think of the cert_id (the short, opaque ticket number that rides on the outside of the envelope) as a numbered coat-check ticket. It proves you checked in with the front desk, and the bouncer can cross it against a short list of tickets that have been cancelled. But the number, by itself, is not your name.


4. What the relay sees, precisely

When Alice sends, the outer envelope the relay handles carries only:

From that, the relay learns almost exactly one sentence: "some real, non-banned user (ticket cert_id) paid one token to send some class of message to this address at roughly this time." No account, no public key, no name. The identity is inside the seal, verified only by Bob.

ALICE PACKS RELAY CHECKS BOB VERIFIES ALICE RELAY BOB SEALED CERT BODY SENDER KEY EXPIRY ED25519 SIG ML-DSA-65 SIG CERT_ID #7 VISIBLE HERE CERT_ID #7 REVOCATION LIST NOT REVOKED ✓ NO CERT BODY · NO NAME OPENED CERT ED25519 ML-DSA-65 IDENTITY ACCEPTED THE TICKET RIDES OUTSIDE · THE HYBRID CERTIFICATE STAYS INSIDE THE RELAY CHECKS A TICKET · ONLY BOB VERIFIES THE PERSON

"Almost", because the token carries one more field the relay reads in the clear: a key_id naming which live issuing key minted it. Under honest operation that reveals about two bits of information: there are only a couple of live keys at a time, so learning which one says very little. But the issuer chooses the value, which makes it exactly the sort of field that could be turned into a per-user tag. It is not left to good intentions; The Admission Token §5 is entirely about the checks that keep it meaningless.


5. The signature that became a MAC

There is one subtlety that connects this article to the last of the series' narrative pieces, Deniability, and it is worth flagging now because it changes what "the certificate proves."

You might expect Alice to also sign each individual message with her key, so Bob knows this specific message (not just the certificate) came from her. Early designs did exactly that. We removed it, on purpose. A per-message signature is transferable proof: it lets Bob (or anyone who later sees the transcript, the saved record of the conversation) prove to a third party that Alice wrote those exact words. That is a courtroom exhibit, and it is the opposite of the deniability a private conversation should have.

So the inner per-message authenticator is not a signature but a MAC: a message authentication code, a short tag computed under a key that both Alice and Bob share for their conversation.

It convinces Bob the message is authentic, because only someone with the shared key could have made it and Bob did not. But it proves nothing to anyone else, because Bob could have produced the very same tag himself.

ALICE BOB JUDGE SAME CHANNEL KEY MESSAGE + MAC AUTHENTIC TO BOB BOB COULD MAKE THE SAME TAG THIRD-PARTY LINE ? NO ATTRIBUTION AUTHENTIC TO ITS RECIPIENT · DENIABLE TO EVERYONE ELSE

6. The honest residual

Sealed sender hides who. It does not, by itself, hide sameness, and it is worth being precise about which design that sentence indicts.

The cert_id on the envelope is stable for the life of a certificate. That is deliberately load-bearing: it is how revocation and abuse-metering work without an identity. But if a user carried one certificate, a relay watching the traffic could cluster by it: every message bearing ticket #7 is "the same pseudonymous user," and over a day that pseudonym's whole social pattern, who they message and when and how much, resolves into one shape. Unlabelled, but a shape.

That is the leak the design as described so far would create, and it is the reason the shipped certificate is not one per user. A pseudonym is a weaker leak than a name, but it is still a leak, and closing it is a real piece of engineering on its own. That engineering is the next article: Sender Unlinkability.


References & further reading

← The End-to-End Layer: What the Relay Can Never SeeSender Unlinkability: The Pseudonym Problem →