From Kyber to ML-KEM
ML-KEM — Module-Lattice-Based Key-Encapsulation Mechanism — is the algorithm NIST standardised as FIPS 203 in August 2024. It began life as CRYSTALS-Kyber, the winner of NIST's post-quantum competition, so you will see both names used; ML-KEM is the standardised form. Its security rests on the Module Learning-With-Errors problem: recovering secrets from lattice equations that have had small random noise mixed in, a problem with no known efficient solution on classical or quantum computers.
A KEM is not Diffie–Hellman
Classical TLS key exchange uses Diffie–Hellman: both sides contribute a public value, and each combines the other's with its own secret to reach the same shared key. A KEM (key encapsulation mechanism) is shaped differently:
- One side generates a keypair and sends the public key.
- The other side encapsulates: it produces a random shared secret and a ciphertext that only the keypair owner can open, and sends the ciphertext back.
- The keypair owner decapsulates the ciphertext and recovers the same shared secret.
Conveniently, that request/response shape maps exactly onto the TLS 1.3 handshake: the client's key share carries an ML-KEM public key in its ClientHello, and the server's key share carries the ciphertext in its ServerHello. No extra round trips.
Why hybrid: X25519MLKEM768
ML-KEM is young by cryptographic standards, so nobody deploys it alone. The group browsers and servers actually negotiate, X25519MLKEM768, runs classical X25519 and ML-KEM-768 in the same handshake and feeds both results into the key schedule. An attacker must break both algorithms to recover the session key: if lattice cryptanalysis improves, X25519 still stands; if a quantum computer arrives, ML-KEM still stands. Hybrid key exchange is the belt-and-braces that made early deployment safe — Google shipped it to Chrome by default in April 2024, and it now carries a third or more of TLS 1.3 handshakes worldwide.
What it costs
- Client key share: 1,216 bytes (a 1,184-byte ML-KEM-768 public key + 32 bytes of X25519) — versus 32 bytes for X25519 alone. The ClientHello typically spills into a second packet.
- Server key share: 1,120 bytes (a 1,088-byte ciphertext + 32 bytes).
- Compute: ML-KEM is fast — key generation, encapsulation and decapsulation are all comparable to or cheaper than X25519. The real-world handshake overhead is dominated by the extra bytes, and measures in single-digit milliseconds on typical connections.
Two siblings exist in the standard: ML-KEM-512 (lighter, NIST security category 1) and ML-KEM-1024 (heavier, category 5). TLS settled on the middle option, ML-KEM-768 (category 3), for the default hybrid; a SecP256r1MLKEM768 variant pairs it with P-256 where NIST-curve compliance is required, and SecP384r1MLKEM1024 serves CNSA 2.0-style high-assurance profiles.
How negotiation works — and fails
Post-quantum groups ride TLS 1.3's existing supported_groups mechanism: the client lists what it can do, the server picks. A server that has never heard of X25519MLKEM768 simply selects a classical group and the connection proceeds — no breakage, but no quantum protection either. That silent fallback is exactly why testing matters: your users' browsers have been offering post-quantum key exchange on every connection for a long time now; whether they get it is entirely down to your server. There is no PQC in TLS 1.2 — the migration requires TLS 1.3, full stop.
Further reading
- FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard
- RFC 9180: Hybrid Public Key Encryption (KEM background)
- draft-ietf-tls-ecdhe-mlkem: Post-quantum hybrid key exchange in TLS 1.3
See which of these groups your server negotiates — each one tested with its own pinned handshake — with the post-quantum TLS test.