Post-quantum Double Ratchet + X3DH
ML-KEM-768 ML-DSA-65 AES-256-GCM FIPS 203/204 in-browser · no server github ↗
Ready — establish a session or run the auto demo

X3DH + Double Ratchet demo. Both sides generate fresh ML-KEM-768 + ML-DSA-65 keypairs in your browser. X3DH derives a shared root key — no secret is transmitted. A session PIN (SHA-256 of both exchange keys) lets both parties verify they're talking to the right identity before trusting. Then watch the KEM ratchet advance with each reply.

Establish session via X3DH
Alice → "Hello Bob, testing pqc-ratchet"
Alice → "Second message, same ratchet epoch"
Bob → "Hi Alice! (new KEM epoch — ratchet advances)"
Bob → "Second reply, epoch continues"
Alice → "Back to Alice — another new epoch"
Bob → "Final message — epoch 3"
Alice Initiator
Session PIN
·
SHA-256(IK_A ‖ IK_B)[0..3] ✓ matches Bob
DSA pub Exchange Root key Chain Ratchet pub
received messages appear here
Bob Responder
Session PIN
·
SHA-256(IK_A ‖ IK_B)[0..3] ✓ matches Alice
DSA pub Exchange Root key Chain Ratchet pub
received messages appear here
Protocol Wire Log 0 events click any entry to expand wire bytes
Establish a session to see the protocol wire log
How it works in code full program for both sides · ~50 lines total · active block highlights as demo runs
Alice initiator — sends the PreKeyMessage

        
Bob responder — receives and replies

        
🟢 Bob — Incoming Session Request
Alice wants to establish a secure session with you. Verify the identity fingerprint matches what Alice sees before approving.
Identity Fingerprint · SHA-256(Alice‖Bob exchange keys)[0..3]
Both sides computed this from your exchange public keys.
A man-in-the-middle would produce a different value.
Why does this matter? This fingerprint proves Alice's public key binding is genuine. In production you'd verify this over a separate channel (voice call, in-person, QR scan) before clicking Approve. This demo simulates that trust decision.