diff options
Diffstat (limited to 'docs/meshbay-draft-v6.md')
| -rw-r--r-- | docs/meshbay-draft-v6.md | 52 |
1 files changed, 34 insertions, 18 deletions
diff --git a/docs/meshbay-draft-v6.md b/docs/meshbay-draft-v6.md index 28aea0c..eb7e56d 100644 --- a/docs/meshbay-draft-v6.md +++ b/docs/meshbay-draft-v6.md @@ -555,29 +555,45 @@ v5 §9's list stands, with these movements: |---|---|---| | C4 | Remote keypair bundles | **Partially closed.** Gone for native devices; open for browser-using accounts until the signed `device_policy {allow_bundle: false}` opt-out ships | | T3 | Hub serves the SPA | **Accepted permanently** for browser users. Removed for native clients, whose value depends on 18.7 | -| — | Chat encryption (Sender Keys) | Phase 15, unchanged. Pairwise to identity keys, never GEK-derived — and **now to devices**, which multiplies the recipients per person | +| — | Chat encryption | **Built 2026-09-07, and not as Sender Keys** — see `docs/chat-sender-keys.md`. The row that stood here ("pairwise to identity keys, never GEK-derived") was reversed on 2026-09-03 and then overtaken entirely. Per group, off by default, MNP 1.2 | | — | Delegation | Designed, deferred, unchanged | | — | Hub identity pinning | New. `GET /v1/hub/pubkey` exists and nothing pins it; bounded, because a substituted hub can neither read content nor ship the code to a native client | -**Phase 15 has been re-read against device linking (2026-08-17) and was wrong as written.** -The correction is recorded in `devel-phases-next.md` §15.0b; the load-bearing part: +**Phase 15 was re-read twice and abandoned as written.** The first correction +(2026-08-17, `devel-phases-next.md` §15.0b) said a sender key must be per device, never +per person, because a shared chain advanced by two devices produces key and nonce reuse — +`first-review.md` C1, one level down. That is still true, and it is why the design that +was built has no shared mutable sending state at all. -- **A sender key is per device, never per person.** A shared per-person chain advanced by - two devices produces key and nonce reuse — which is exactly why `first-review.md` C1 - rejected a shared Double Ratchet for groups. The same mistake, one level down. -- `senderkeys.py` already fails this silently: `GroupSenderKeyStore.add_sender` does - `self._states[dist.sender_id] = ...`, so a second device under the same `sender_id` - **overwrites the first and drops its chain**. `sender_id` must become a device - identifier. -- **Revoking a device must rotate**, like revoking a member. -- **A newly linked device cannot read history** until every sender redistributes, unless - the linking device hands over its own state sealed to the new device's key. -- **Sender attribution stays node-trusted.** A sender key proves a *device*; the mapping - from device to account comes from the node's roster. Encrypted chat does not make - senders cryptographically authenticated to each other, and the docs must not imply it. +The second correction (2026-09-07) ended the protocol choice. **`docs/chat-sender-keys.md` +is the specification; this records only what changed.** Once distribution is under the +group key *and* the node serves history to devices that were not present, the node must +retain each chain's earliest key — and a chain key at iteration *i* yields every message +key from *i* on by pure HKDF. Forward secrecy is therefore zero either way, so the ratchet +bought no confidentiality over one AEAD while adding stateful client code with silent +failure modes. Three were reproduced in that document; the worst is that under group-key +distribution **any member could sign as any other**, because `add_sender` accepts any +distribution and the signing key inside one is bound to nothing. -Ordering consequence: **device linking (Stage C) lands before Phase 15**, or Phase 15 is -built against an identity model that is about to change underneath it. +What was built instead: one key per group, per epoch, per **device**, derived by name from +an epoch key the node generates and delivers wrapped under the group key. A new epoch +opens whenever the set of devices that may read future messages shrinks; old epochs are +kept and still delivered, so the history stays readable to everyone who could already read +it — and rotating the group key becomes a re-wrap rather than the destruction of the whole +archive, which is what a group-key-derived archive key would have caused on the first +`member unpin`. Messages are signed over the ciphertext with the device key the node +pinned. + +Two properties of the old plan survive unchanged: + +- **Revoking a device opens a new epoch**, exactly as revoking a member does. +- **Sender attribution is device-rooted, and the device-to-account mapping comes from the + node's roster.** Encryption does not by itself make senders cryptographically + authenticated to each other; the *signature* does, and only as far as the reader's + roster is honest. The docs must not imply more. + +Ordering consequence, unchanged and now satisfied: **device linking (Stage C) lands +first**, or this is built against an identity model about to change underneath it. --- |