Two people
Last updated
A private conversation is an MLS group with two principals and no parent. The workspace owner cannot read it, and neither can an administrator, a bot or the relay. For the same reason, nobody can restore it.
Key packages
Protocol version 2 adds frame tag 22. A device publishes MLS key packages so somebody can add it to a conversation without both being online together. It fetches a peer's packages to add that peer.
Key packages are cleartext by construction. A key package bootstraps encryption, so no earlier key exists to seal it under. The relay also has to index them by device key to serve a fetch at all.
An envelope's kind lives inside the ciphertext, so the relay could not perform that lookup on an envelope. Key packages therefore travel on the wire, where the relay can see them, and must not be mistaken for content.
| Form | Direction | Meaning |
|---|---|---|
| publish | client to relay | Store these against the authenticated device key |
| published | relay to client | The shelf's depth afterwards |
| fetch | client to relay | Hand me at most count packages for this device |
| bundles | relay to client | The packages, now removed from the shelf |
| none | relay to client | The shelf is empty, which is no error |
A fetch consumes what it hands out, in the statement that selects it. Serving one package twice would hand two different conversations the same joiner leaf key. The query itself enforces one-time delivery.
An empty shelf is a valid answer. A correct client waits for the peer to top up and does not retry. A retry loop against an empty shelf is what drains one.
| Limit | Value | Why |
|---|---|---|
| outstanding packages per device | 100 | A package over the cap is refused and nothing is evicted, because a silent discard produces an unaddable member with no error anywhere |
| packages per fetch | 8 | A higher count would allow enumeration |
| KEYS frames per connection per minute | 30 | A roster prefetch is a startup burst |
The welcome carries no group id
Kind 0x0022 dm.welcome is an ordinary envelope in the workspace root group, since the two devices share no other group yet. It carries a blinded tag, BLAKE3 over a domain label and the target key package reference, and the MLS Welcome itself.
It omits the conversation's group id, which the joiner reads from inside the Welcome. Naming the group id would tell every member of the root group which pair opened a conversation and when. The design withholds that metadata.
A client ignores a tag that matches nothing. Asking about it would mean asking the room who the message was for.
Group policy
| Property | Value |
|---|---|
| principals | two, and any number of their devices |
| agents | not admitted |
| admission | explicit, so there is no self-join |
| groupinfo.publish | never, so no external commit even holding the root key |
| history.publish | never, so a later-added device reads from that point on only |
| parent | none, so the root key grants nothing and an administrator cannot read it |
| recovery.wrap | never published |
Because of the last row, losing every device on both sides loses the conversation permanently. A per-pair recovery principal was considered and rejected outright. It would be an escrow key, and any escrow key that exists can be compelled.
Both sides derive the same group from the sorted pair of handles. Two people who open a conversation at the same moment converge on one, with no coordination and no round trip. Device keys play no part, so a person's second laptop joins their existing conversation.
What stays visible
The relay learns that a group with two devices exists and when it is written to. Other members of the workspace learn from the root log that some welcome was published, though not by whom, to whom, or about what. The roster tells everybody who is in the workspace, as it did before.
The relay also learns that one device fetched another's key packages. A partial mitigation applies. A client prefetches the whole roster on first use, so the request does not time-correlate with the intent to talk to a particular person.
The relay still learns that a device intends to be able to talk to its colleagues, which it could have guessed.
Nobody learns who is talking to whom, or about what.