Guide 11 of 11

Sealed sender

How a relay delivers a message without seeing which account sent it.

DChat GuidesReading time 3 minAll guides

Sealed sender hides who sent a message from the relay that delivers it. The relay still knows who the message is for, but not which account it came from.

A relay is a server that passes your message along. Even when it cannot read the message, an ordinary relay still sees who sent it, who it is for, when, and how large it is. Sealed sender removes the first of those: the relay delivers your message without seeing which account it came from.

DChat uses multi-recipient sealed sender: one seal covers all of the recipient's devices. Our implementation is written to the published design and its output is checked byte for byte against the reference implementation.

How the seal hides the sender

Before a message leaves your device, your app puts it in a sealed envelope addressed to the recipient's devices. The envelope is locked with keys that only those devices hold, and your name goes inside it: your DID, which of your devices sent it, and the proof that it really came from you. The relay holds the envelope and sees only the outside. Your recipient opens it, finds who wrote it, and checks the proof before anything is shown.

A fresh random value is used for every envelope, so two messages from you share nothing a relay could match up. Because one message can go to several of the recipient's devices, the envelope carries one small slot per device, in random order, with no device names on it. Each device simply tries the slots until one opens.

Delivery keys and proofs

If a relay cannot see who sent a message, how does it keep strangers from flooding someone? With a delivery proof. Every account has a delivery key, derived from its account key and published on the chain. Whenever you send a sealed message, your own account's key travels inside the seal, so the people you write to, your contacts and the members of your groups, hold it. They need no extra step.

When a contact sends you a sealed message, they sign a short proof with your delivery key. The relay checks the proof against your public record and accepts the message. The proof says "this came from one of this person's peers", never which one. If you block someone, your delivery key moves to a new version and your remaining contacts receive it with their next message.

A channel with no login

Sealed messages are submitted on a separate connection that carries no account sign-in, no account name and no signature. Your app keeps that connection apart from the one it uses for everything else and renews it regularly. The relay accepts a sealed message only if it names no sender, passes the proof check, and has a recent timestamp.

Padding and rounded timestamps

Sealed messages are padded before they are sealed, to 512 bytes, 1 KiB, 2 KiB or 4 KiB, and in steps of 4 KiB beyond that. A short "ok" and a longer sentence look the same size to the relay. The kind of content and the expiry time of a disappearing message are hidden inside the seal, and the message time is rounded down to the minute.

What the relay still needs

A relay has to know who to deliver to, so the recipient is visible. It also sees when a sealed message arrives, to the minute, and its rounded size. What it no longer sees is which account sent it. The message itself, the media and the call audio stay end to end encrypted as before.

  • The seal hides your account from the relay that delivers the message.
  • Delivery proofs keep strangers out without naming you.
  • Padding and rounded times keep sizes and clocks coarse.
  • The recipient stays visible, because delivery needs it.

Related: Spec section 13, sealed sender · How a message travels · Your devices