v150 · Web Cryptography
ML-KEM key exchange
A key-encapsulation mechanism lets two parties agree on a shared secret without ever sending it. Alice publishes an ML-KEM public key. Bob encapsulateBits()s to it — producing a ciphertext he sends back plus a secret he keeps. Alice decapsulateBits()s the ciphertext with her private key and recovers the same secret. Run it below with the real browser implementation.
Launch Chrome 150+ with
--enable-blink-features=WebCryptoPQC, or enable
chrome://flags/#enable-experimental-web-platform-features and relaunch.
Origin-trial token: WebCryptoAdditionalAlgorithms202606. The buttons below call the
real crypto.subtle methods and will report exactly what the browser returns.
① Alice — generateKey()
Public key · exported as raw-public, sent to Bob
Private key — stays on this page; Alice keeps it secret
② Bob — encapsulateBits(alg, alicePublicKey)
Ciphertext · sent back to Alice
Bob's shared secret
③ Alice — decapsulateBits(alg, alicePrivateKey, ciphertext)
Alice's recovered secret
Secrets agree? not run
// Alice generates an ML-KEM keypair
const alice = await crypto.subtle.generateKey(
{ name: "ML-KEM-768" }, true, ["encapsulateBits", "decapsulateBits"]);
// Bob encapsulates to Alice's public key
const { ciphertext, sharedKey: bobSecret } =
await crypto.subtle.encapsulateBits("ML-KEM-768", alice.publicKey);
// Alice decapsulates the ciphertext with her private key
const aliceSecret =
await crypto.subtle.decapsulateBits("ML-KEM-768", alice.privateKey, ciphertext);
// bobSecret and aliceSecret are byte-identical — the shared key
see also
- Hybrid session key —
encapsulateKey()derives an AES-GCM key directly - ML-DSA signatures — the post-quantum signature companion
- Capability matrix — which algorithms this browser actually supports
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗