X3DH and Double Ratchet
Buzzio 1-to-1 sessions use a Signal-style bootstrap (X3DH) followed by a Double Ratchet for ongoing messages.
X3DH bootstrap
Purpose
Establish a shared secret between Alice and Bob when they may be offline, using published prekey material — without Buzzio learning the secret.
Sketch (4-DH style)
The client performs multiple ECDH combinations over secp256k1 identity and ephemeral/prekey material, concatenates the DH outputs, and runs HKDF with info label X3DH to produce keying material for ratchet initialization.
Receiver-side calculation mirrors the same DH set from Bob’s perspective (calculateX3DHSecret / calculateX3DHSecretReceiver in CryptoEngine).
Prekeys
- Signed prekeys and batches of one-time prekeys are published so initiators can complete X3DH asynchronously.
- Consumed one-time prekeys are rotated/replenished by the client prekey service.
Output
- Legacy/v1 paths may use 64-byte HKDF output split into root + chain material.
- v2-style paths derive a 32-byte SK for Double Ratchet init via HKDF as implemented.
Exact byte layouts are defined in client code; public docs describe intent, not a formal RFC fork.
Double Ratchet
Purpose
Evolve message keys so that:
- Each message tends to use a fresh message key
- Compromise of current keys has limited ability to decrypt past traffic (forward secrecy goal)
- DH ratchet steps rekey root/chain state over time
Init
- Alice (sender after X3DH):
RatchetInitAlice-style initialization from shared secret - Bob (receiver):
RatchetInitBob-style bootstrap when the first prekey message arrives
Per-message encryption
Message keys feed AES-GCM encryption of the inner payload. Associated metadata needed for ratchet advancement (counters, DH public values as required by the implementation) travels with the ciphertext in the inner envelope.
Isolation
CPU-heavy ratchet/crypto work may run off the UI isolate to keep chat responsive.
Security properties in product language
| Property | User-facing meaning |
|---|---|
| E2EE | Only participant devices derive message keys |
| Forward secrecy goal | Stealing today’s keys should not unlock yesterday’s sealed messages |
| No operator transcript | Buzzio never holds the ratchet secrets |
Failure and recovery
- Corrupted or out-of-order envelopes fail AEAD / ratchet decrypt and are not silently accepted as plaintext.
- New device with Buzzio ID + mnemonic restores identity keys; it does not automatically reconstruct peer session history without backup/export the user unlocks.
- Session reset / re-init flows exist when ratchet state cannot continue (implementation-defined UX).