Protocol Simulations / MLS Group Messaging
What you will do: Run the MLS primitives with real keys — ML-DSA-65 credential signing, ML-KEM-768 TreeKEM updates, AES-128-GCM messages — and watch the ratchet tree change as members join.
Worked example: Alice and Bob start the group; add a third member and see which nodes on the direct path have to re-key.
Runtime and privacy: The cryptographic exercise runs in this browser. Review the site privacy terms before entering sensitive material; use synthetic inputs for learning and evaluation.
Browse all Crypto Lab tools · Learn with MLS — Group Messaging
For your role
- Developer / Engineer
- Run the three live primitives, the ML-DSA-65 credential signing, the ML-KEM-768 HPKE TreeKEM update and the AES-128-GCM message encryption, then Add a member to the ratchet tree: the nodes on the direct path that must re-key are the ones your client would update.
- Security Architect
- Use Add, Remove and Update on the TreeKEM ratchet tree to see how group size changes the number of re-keyed nodes; the How openmls_pqctoday_crypto wires OpenMLS to the HSM section shows where signature keys can be kept in custody.
- Researcher / Academic
- Enable HSM mode so the three primitives route through softhsmv3 (C_SignMessage, C_EncapsulateKey, C_EncryptInit) and compare the key material with the software path; the Authoritative references list the RFCs the invariants come from.
Live MLS crypto primitives
Three in-browser operations that underpin every MLS session. Run each step to see real key material and verify the cryptographic invariants. Enable HSM mode below to route all steps through softhsmv3 (PKCS#11 v3.2) — C_SignMessage, C_EncapsulateKey, and C_EncryptInit. All crypto executes client-side — no server contact.
Live HSM Mode Active
SoftHSM3 · PKCS#11 v3.2 · Rust · session open
Credential signing key — ML-DSA-65
Each MLS leaf node carries an identity credential. The leaf_node is signed with ML-DSA-65 before being committed to the tree.
TreeKEM node update — ML-KEM-768 HPKE
When a member commits, they HPKE-encapsulate a fresh path_secret for every ancestor node. Receivers recover the shared secret via decapsulation. Wrong keys get a distinct implicit-rejection value (RFC 9180 §6.1).
Application message encryption — AES-128-GCM
MLS derives a content key and nonce from the epoch key schedule (RFC 9420 §5.2). Messages are AES-GCM authenticated — the epoch number, group ID, and content type are bound as Additional Data.
TreeKEM ratchet tree
Watch which nodes get re-keyed on every Commit. Highlighted nodes are the committer's direct path — the only nodes touched by an O(log N) update.
How openmls_pqctoday_crypto wires OpenMLS to the HSM
OpenMLS expects a single OpenMlsProvider trait combining crypto, randomness, and storage. Our provider routes each crypto trait method through PKCS#11 v3.2 against softhsmv3. The table below reflects the v0.2 implementation (Phase 1 + Phase 2 of the provider roadmap).
What this table describes: the real openmls_pqctoday_crypto Rust crate, which runs server-side. The workshop in this module is a JavaScript reimplementation of the same PKCS#11 calls against the same softhsmv3 engine — the crypto is genuinely HSM-backed either way, but the steps you run here are not literally this crate executing.
| OpenMLS operation | PKCS#11 mechanism | HSM-resident | Notes |
|---|---|---|---|
| hash | CKM_SHA256 / SHA384 / SHA512 | yes | C_DigestInit + C_Digest |
| hmac | CKM_SHA256_HMAC | yes | Session-only generic-secret key, destroyed after each MAC |
| hkdf_extract / hkdf_expand | CKM_*_HMAC (RFC 5869 over HSM HMAC) | yes | Every HMAC round executes in the token |
| aead_encrypt / aead_decrypt | CKM_AES_GCM | yes | Session-only AES key for each operation |
| signature_key_gen | CKM_EC_EDWARDS_KEY_PAIR_GEN / CKM_EC_KEY_PAIR_GEN | yes | Token object with CKA_SENSITIVE=TRUE, CKA_EXTRACTABLE=FALSE |
| sign / verify_signature | CKM_EDDSA / CKM_ECDSA_SHA* | yes | Provider returns an opaque HsmKeyHandle, not key material |
| HPKE (DhKem25519 + SHA-256 + AES-128-GCM) | CKM_ECDH1_DERIVE + CKM_SHA256_HMAC + CKM_AES_GCM | yes | RFC 9180 reimplementation over PKCS#11 primitives |
| HPKE (other suites) | hpke-rs-rust-crypto (fallback) | Phase 2.1 | Phase 2.1 — generalise PKCS#11 path to P-256/P-384/P-521/ChaCha20 |
Signature key custody
When OpenMLS calls signature_key_gen(), our provider runs C_GenerateKeyPair with CKA_SENSITIVE=TRUE and CKA_EXTRACTABLE=FALSE. What we return to OpenMLS as the "private key" is an opaque, versioned handle blob.
HsmKeyHandle wire format ┌────────┬─────────┬──────────┬──────────────┬────────────┐ │ "PQTH" │ ver (1) │ sig sch. │ cka_id_len │ cka_id │ │ 4 B │ 1 B │ 2 B │ 2 B │ N bytes │ └────────┴─────────┴──────────┴──────────────┴────────────┘
On every sign() call, the provider decodes the handle, looks up the token object via C_FindObjects{ CKA_CLASS=PRIVATE_KEY, CKA_ID=… }, and runs C_SignInit + C_Sign inside the HSM. Real key bytes never exist in process memory.
Authoritative references
The library entries that anchor this module's claims:
- • RFC 9420
- • RFC 9180
- • draft-ietf-mls-pq-ciphersuites-06
- • draft-ietf-mls-combiner-02
- • draft-ietf-mls-extensions-09
Try it
Add a third member to the group. Which nodes re-key?
Next step
Turn it into a plan: Hybrid Transition PlannerThis tool practises the MLS — Group Messaging module, phase 5 (Pilots & Migration); Hybrid Transition Planner produces a deliverable of that phase.
Related content
Next in Protocol Simulations