Disclosure: Some links on this site are affiliate links. If you purchase through them, we earn a small commission at no extra cost to you. Learn more

Hybrid TLS: Merging Classic and Post-Quantum Security

TL;DR

The industry is not replacing classical key exchange with post-quantum key exchange — it is running both in every handshake. X25519MLKEM768, now the default in major browsers, combines a classical X25519 (Curve25519) Diffie-Hellman exchange with an ML-KEM-768 encapsulation, concatenates both resulting secrets, and feeds the concatenation into TLS 1.3's existing HKDF key schedule as a single shared secret: ss=ssX25519ssML-KEMss = ss_{X25519} \,\|\, ss_{\text{ML-KEM}}. The security argument is a disjunction, not a sum: the combined key remains secure if either component's hardness assumption holds, which is precisely why lattice-based ML-KEM is wrapped around X25519 rather than deployed alone — ML-KEM has had a few years of public cryptanalysis against ECC's multi-decade track record, and hybridization means a structural break in the new math degrades the connection back to classical security instead of to no security at all. Negotiation reuses TLS 1.3's existing key_share mechanism — no new handshake flow, no certificate changes — which is what makes this deployable today rather than after a full protocol revision.

Why Hybrid, Not PQC-Only

ML-KEM's Module-LWE hardness assumption has been public since 2016 and standardized since 2024. X25519's discrete-log-based hardness assumption has been public since 1976 and has survived roughly five decades of cryptanalysis, including the entire post-quantum research program searching for classical weaknesses. Deploying ML-KEM alone means every TLS connection's confidentiality rests on an assumption with a short public track record; deploying X25519 alone means every connection remains exposed to Shor's algorithm once a cryptographically relevant quantum computer exists.

Hybridization removes the need to choose. Define the combined secret as the concatenation of both component secrets, fed through the key derivation function already used in TLS 1.3's handshake:

Equation
ss=HKDF-Extract(0, ssX25519ssML-KEM)ss = \text{HKDF-Extract}\big(0,\ ss_{X25519} \,\|\, ss_{\text{ML-KEM}}\big)

An attacker who wants to recover the resulting handshake secret must solve both the X25519 discrete logarithm problem and invert ML-KEM's encapsulation — breaking only one component leaves the other's secret still mixed unrecoverably into ssss via the KDF. This holds even if the two schemes fail for entirely different reasons: a classical cryptanalytic break of Module-LWE and a future quantum break of elliptic-curve discrete log are both survivable by the same hybrid handshake, because neither failure alone determines ssss. Reverting to classical-only security on an ML-KEM break, rather than to no security at all, is the entire point of wrapping the new algorithm in the old one instead of the reverse.

What X25519MLKEM768 Actually Sends

The name is literal: it concatenates a classical group (X25519) with a post-quantum KEM parameter set (ML-KEM-768), and TLS negotiates it as a single named group in the supported_groups and key_share extensions — the same extensions TLS 1.3 already uses for plain X25519 or secp256r1. No new extension type, no new handshake message, no new round trip.

A client offering this group generates two independent ephemeral key pairs and sends both public values concatenated as one key_share entry: an X25519 public key and an ML-KEM-768 encapsulation key. A server that selects this group performs both operations independently — an X25519 Diffie-Hellman computation against the client's X25519 share, and an ML-KEM encapsulation against the client's ML-KEM encapsulation key — and returns its own X25519 public key concatenated with the ML-KEM ciphertext in its own key_share. Both sides now hold ssX25519ss_{X25519} and ssML-KEMss_{\text{ML-KEM}} independently, concatenate them in the fixed order the specification defines, and hand the result to the same HKDF-based key schedule TLS 1.3 already runs for a non-hybrid handshake. Every downstream step — Handshake Secret, Master Secret, traffic key derivation — is unchanged.

Negotiating It in Practice

  1. Client advertises multiple groups. A ClientHello lists X25519MLKEM768 alongside plain X25519 (and often secp256r1) in supported_groups, ordered by preference, so the handshake still completes against servers that don't support the hybrid group.
  2. Client sends key shares optimistically. To avoid an extra round trip, clients typically generate and send key_share entries for their top one or two preferred groups upfront, rather than waiting to be asked — a server requesting an unsent group triggers a HelloRetryRequest, adding a round trip only on that fallback path.
  3. Server selects and responds. A server configured to prefer X25519MLKEM768 performs both component operations against the client's hybrid key_share and returns its own combined share in the ServerHello. A server that doesn't recognize the hybrid group simply falls through to the next group the client offered.
  4. No certificate changes required. The hybrid mechanism operates entirely on the ephemeral key exchange. Certificate signatures remain classical (RSA or ECDSA) or migrate to ML-DSA independently, on its own deployment timeline — the two migrations (key exchange, signatures) are decoupled.
  5. Server-side requirements. This needs a TLS stack built against a library version that implements ML-KEM and the hybrid group (OpenSSL 3.5+, BoringSSL, or equivalent), with the group explicitly enabled and prioritized in the server's group/curve configuration — the exact directive name is stack-specific, but the pattern is the same as any other curve preference list: place X25519MLKEM768 ahead of X25519 so capable clients get the hybrid exchange while older clients still negotiate successfully.

Chrome and other major browsers already offer X25519MLKEM768 by default as of 2024–2025, so a server that enables it sees a meaningful fraction of real handshakes upgrade to hybrid key exchange without any client-side change required from end users.

PQC-Ready Providers

Provider comparisons and deployment guides for enabling X25519MLKEM768 on your own stack are in progress — check back soon.