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.

The KEYS forms
FormDirectionMeaning
publishclient to relayStore these against the authenticated device key
publishedrelay to clientThe shelf's depth afterwards
fetchclient to relayHand me at most count packages for this device
bundlesrelay to clientThe packages, now removed from the shelf
nonerelay to clientThe 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.

What bounds the shelf
LimitValueWhy
outstanding packages per device100A package over the cap is refused and nothing is evicted, because a silent discard produces an unaddable member with no error anywhere
packages per fetch8A higher count would allow enumeration
KEYS frames per connection per minute30A 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

What a direct group is
PropertyValue
principalstwo, and any number of their devices
agentsnot admitted
admissionexplicit, so there is no self-join
groupinfo.publishnever, so no external commit even holding the root key
history.publishnever, so a later-added device reads from that point on only
parentnone, so the root key grants nothing and an administrator cannot read it
recovery.wrapnever 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.