Walkthrough: Alice & Bob
The runnable version of this walkthrough lives in src/demo.rs as the
demo_e2e_full_session test. Run it with output:
cargo test -p two-mls-pq demo_ -- --nocapture
# real ML-KEM-768:
cargo test -p two-mls-pq --features cryptokit demo_ -- --nocapture
The narrative, step by step:
- Identities — Alice and Bob each build a
TwoMlsPqPrincipalfor theirClientId(opaque identity bytes); the MLS signing key is generated internally. - Key packages — each generates a
CombinerKeyPackage(classical + ML-KEM-768 halves, sameClientId). - Parsing — the peer’s halves parse to
MlsKeyPackages; the classical suite is0x0003, the PQ suite0xFDEA; the twoClientIds must match. - Establishment —
initiate(…)+set_initial_app_payload→ envelope →open_initial→receive→APQWelcome_B→process_incoming(standalone, or as the staple on Bob’s first frame — welcome re-deliveries are idempotent). Both sides are now established with the PSK chain bound. - Routine round — Alice
prepare_to_encrypt(None)+encrypt. The frame is the[staple][proposal][app]triple: her latest send-group commit (or her welcome, until the first commit) plus anUpd(Alice)proposal for Bob to approve; Bob decrypts, skipping any staple he has already applied. - Full commit — Bob proposes; Alice
queue_proposalthen commits on her next send, advancing the epoch and refreshing the PSK. - Continued messaging — bidirectional traffic continues post-refresh.
- Rotation — Alice
prepare_to_encrypt(Some(new_id))(lazy: the successor’s keys are minted and authorized on the fly — no separate stage call); Bob observesCommitResult.new_sender. Her PQ leaves catch up automatically: the session opens an A.5 re-key on her next send once the rotation leaves the send-PQ leaf lagging (no host call — see Session Lifecycle).
For the full flow detail — the PQ side-band rounds, routing, and rotation — see the Session Lifecycle chapter, and the Wire Format chapter for the frame tags each step emits.