up:: In the Protocols MOC
TLS 1.3 Hybrid Key Exchange
TLS 1.3 hybrid key exchange is a way of establishing the TLS session key by running a classical elliptic-curve key agreement and a post-quantum ML-KEM key encapsulation together inside a single handshake, then combining both shared secrets so the session is secure as long as either algorithm remains unbroken. It shows up on the wire as a named group like X25519MLKEM768 in the same negotiation slot TLS already used to pick a classical curve, which is what let browsers, servers, and CDNs turn it on without inventing a new protocol. It is the most widely deployed piece of post-quantum cryptography running on the real internet today, and it exists to close the harvest-now-decrypt-later window on live traffic right now.
The short version:
- Hybrid key exchange pairs a classical curve (usually X25519) with post-quantum ML-KEM-768 in one TLS 1.3 handshake, and folds both shared secrets into the key schedule so the connection breaks only if both halves fail at once.
- It rides the existing machinery. The hybrid combination is just a new named group in the
supported_groupsandkey_shareextensions, negotiated exactly like a classical curve, so a peer that doesn’t support it falls back cleanly. - The dominant group is
X25519MLKEM768, codepoint0x11EC(decimal 4588), the one browsers and CDNs ship by default. Two P-curve variants exist for stacks that need them,SecP256r1MLKEM768(0x11EB) andSecP384r1MLKEM1024(0x11ED). - The one real deployment trap is size. The ML-KEM key pushes the ClientHello over a kilobyte, past the single-packet boundary decades of middleboxes silently assumed, and some of that old gear drops the larger handshake even though both endpoints support it.
- It’s live now. OpenSSL 3.5, Go 1.24, recent OpenSSH, Chrome, and Firefox all negotiate it, so a modern server plus a modern browser get post-quantum key exchange today, and you confirm it on the wire, not from a config file.
Think of a TLS handshake as the first envelope in a negotiation, where the client mails a sealed proposal listing the lock designs it’s willing to use. For twenty years that envelope stayed thin enough to slip through every mail slot on the route. Hybrid stuffs a second, much bulkier lock design into the same envelope, and now it’s too fat for some of the older slots, so a sorting machine somewhere between sender and recipient jams on it even though the two parties at the ends are perfectly happy with the new lock. That’s the whole story of TLS hybrid key exchange. The cryptography is the easy part, and the size is the fight.
What is TLS 1.3 hybrid key exchange?
TLS 1.3 hybrid key exchange is a concrete instance of the general hybrid pattern, specialized to the way TLS 1.3 sets up a session. It combines two key-establishment mechanisms from different families, an elliptic-curve Diffie-Hellman exchange whose security a quantum computer running Shor’s algorithm would break, and the lattice-based ML-KEM key-encapsulation mechanism that’s built to resist that attack. Both run in the same handshake, and their two shared secrets are concatenated and fed into the standard TLS 1.3 key schedule in place of the single classical secret the protocol used before.
The design goal is stated plainly in the IETF’s hybrid-design document, that a hybrid mechanism “facilitate[s] the establishment of a shared secret which remains secure as long as one of the component key exchange mechanisms remains unbroken.”
Source: Stebila, Fluhrer, Gueron, “Hybrid key exchange in TLS 1.3,” IETF, draft-ietf-tls-hybrid-design.
The precise construction that almost everyone deploys is standardized in a companion draft, draft-ietf-tls-ecdhe-mlkem, which defines the specific ECDHE-plus-ML-KEM named groups, their wire encoding, and how the secrets combine. That document reached “Approved” state in the IETF process in 2026, and its groups are already carrying real traffic. The rest of this note walks through what it specifies.
Source: Kwiatkowski, Kampanakis, Westerbaan, Stebila, “Post-quantum hybrid ECDHE-MLKEM Key Agreement for TLSv1.3,” IETF, draft-ietf-tls-ecdhe-mlkem.
Where does cryptography live in the TLS 1.3 handshake?
TLS 1.3 negotiates its key exchange through two extensions in the opening messages, and hybrid slots into both without changing their shape. Understanding those two extensions is what makes the rest of the mechanism legible.
supported_groupsis the client’s menu. In the ClientHello, the client lists every key-exchange group it’s willing to use, in preference order, from classical curves likesecp256r1andx25519to hybrid groups likeX25519MLKEM768. This is defined in RFC 8446 §4.2.7.key_sharecarries the actual public values. Rather than wait a round trip, the client optimistically includes the ephemeral public key material for one or more of those groups directly in the ClientHello, so the server can complete the exchange in a single flight. This is RFC 8446 §4.2.8.- The server picks one group that appears on both sides and returns its own
key_sharefor that group in the ServerHello. If the client offered a group the server likes but didn’t include a matchingkey_share, the server can send a HelloRetryRequest asking the client to resend with that group’s share, which costs an extra round trip. This is RFC 8446 §4.1.4.
Source: Rescorla, “The Transport Layer Security (TLS) Protocol Version 1.3,” IETF, RFC 8446 (supported_groups §4.2.7, key_share §4.2.8, HelloRetryRequest §4.1.4).
The important consequence is that a hybrid group is a first-class citizen of this exact negotiation. It’s not a new protocol version, not a new extension, and not a new handshake shape. It’s one more entry on the supported_groups menu with a matching key_share, which is precisely why deploying it is a configuration change on machinery TLS already had rather than a rewrite.
How does the hybrid group build the key_share?
The hybrid key_share is a straight concatenation of a classical share and an ML-KEM value, and the order of the two pieces is fixed per group by the specification. Walking X25519MLKEM768 end to end shows the whole mechanism.
- Client sends its share. The client generates an X25519 ephemeral key pair and an ML-KEM-768 encapsulation key, and places both in one
key_shareentry. ForX25519MLKEM768the ML-KEM encapsulation key comes first, then the X25519 public key, totaling 1216 bytes (1184 for ML-KEM, 32 for X25519). - Server encapsulates and replies. The server runs ML-KEM encapsulation against the client’s encapsulation key, producing a ciphertext and the post-quantum shared secret, and generates its own X25519 ephemeral key. Its
key_sharereply is the ML-KEM ciphertext followed by its X25519 public key, totaling 1120 bytes (1088 for the ciphertext, 32 for X25519). - Both sides compute two secrets. Each party independently derives the X25519 Diffie-Hellman result and the ML-KEM shared secret. The client decapsulates the ciphertext with its ML-KEM private key to recover the post-quantum secret.
- The secrets are concatenated and fed to the key schedule. For
X25519MLKEM768the combined value is the ML-KEM shared secret followed by the X25519 shared secret, and per the hybrid-design draft “the two shared secrets are concatenated together and used as the shared secret in the existing TLS 1.3 key schedule.” Every downstream handshake and traffic key comes from both halves at once.
Source: draft-ietf-tls-ecdhe-mlkem, §3; draft-ietf-tls-hybrid-design.
There’s a nuance worth carrying, because it trips people reading a packet capture. The ordering isn’t uniform across the three groups. For X25519MLKEM768 the ML-KEM piece leads in both the wire share and the combined secret. For the two P-curve groups the ECDHE piece leads instead. The specification is explicit that for SecP256r1MLKEM768 “the client’s key_exchange value is the concatenation of the secp256r1 ephemeral share and ML-KEM-768 encapsulation key,” and that its combined secret “is the concatenation of the ECDHE and ML-KEM shared secret.” So the layout depends on which group you negotiated, and a parser that hardcodes one order will misread the other.
Source: draft-ietf-tls-ecdhe-mlkem, §3.
| Group | Client key_share (in order) | Server key_share (in order) | Combined secret order |
|---|---|---|---|
X25519MLKEM768 | ML-KEM-768 encap key (1184 B), then X25519 (32 B) = 1216 B | ML-KEM-768 ciphertext (1088 B), then X25519 (32 B) = 1120 B | ML-KEM secret, then X25519 secret |
SecP256r1MLKEM768 | secp256r1 (65 B), then ML-KEM-768 encap key (1184 B) = 1249 B | secp256r1 (65 B), then ML-KEM-768 ciphertext (1088 B) = 1153 B | ECDHE secret, then ML-KEM secret |
SecP384r1MLKEM1024 | secp384r1 (97 B), then ML-KEM-1024 encap key (1568 B) = 1665 B | secp384r1 (97 B), then ML-KEM-1024 ciphertext (1568 B) = 1665 B | ECDHE secret, then ML-KEM secret |
Source: draft-ietf-tls-ecdhe-mlkem, §3 (sizes and ordering quoted verbatim from the draft).
What are the named hybrid groups and their codepoints?
The specification defines three hybrid groups, each pairing an elliptic curve with the ML-KEM parameter set at a matching security level, and each with an assigned TLS supported_groups codepoint. The codepoint is what actually travels in the handshake, so knowing the number lets you read a raw capture.
| Group | Codepoint | Classical part | Post-quantum part | Recommended |
|---|---|---|---|---|
X25519MLKEM768 | 0x11EC (4588) | X25519 | ML-KEM-768 | Yes |
SecP256r1MLKEM768 | 0x11EB (4587) | secp256r1 (NIST P-256) | ML-KEM-768 | No |
SecP384r1MLKEM1024 | 0x11ED (4589) | secp384r1 (NIST P-384) | ML-KEM-1024 | No |
Source: draft-ietf-tls-ecdhe-mlkem, §3, and the IANA TLS Supported Groups registry (X25519MLKEM768 marked Recommended Y, the two P-curve groups Recommended N).
The practical guidance is simple. X25519MLKEM768 is the one the draft calls “the most practical choice for a single post-quantum/traditional hybrid combiner in TLS 1.3,” and it’s the one shipped on by default across browsers and CDNs, so it’s what you’ll see in nearly all real traffic. The P-curve variants exist for organizations whose policy or hardware standardizes on the NIST curves, most often because they’re bound by a profile like CNSA 2.0 that specifies P-384 and ML-KEM-1024, in which case SecP384r1MLKEM1024 is the matching group. If you have no such constraint, X25519MLKEM768 is the default.
Why does the ClientHello size cause problems?
The trap is that the ML-KEM key inflates the ClientHello past a boundary the internet quietly hardened around, and it’s the most common way a hybrid rollout fails in production. A classical X25519 key_share is 32 bytes. A X25519MLKEM768 share is 1216 bytes, and that extra kilobyte lands in the very first message the client sends. For most of TLS’s history the ClientHello fit inside a single network packet, and a long tail of middleboxes, load balancers, and inspection appliances was built assuming it always would. Push the ClientHello past that boundary and it splits across two packets, and some of that older equipment mishandles or simply drops a ClientHello it can’t buffer.
This is protocol ossification. The ecosystem calcified around an assumption that held for years, and the assumption stopped being true. Cloudflare, testing hybrid at internet scale, found sharp cliffs where connections failed once the handshake grew past specific sizes, evidence that particular middleboxes can’t process handshakes beyond a fixed length and start dropping them. The failure isn’t in the cryptography and isn’t in the two endpoints that both support hybrid. It’s a third box on the path that neither endpoint controls.
Source: Cloudflare, “Defending against future threats: Cloudflare goes post-quantum”.
The standards left an escape hatch built from the negotiation itself. A client can advertise a hybrid group in supported_groups while sending only a small classical key_share, and if the server wants hybrid it responds with a HelloRetryRequest asking the client to resend with the full hybrid share on a second round trip. That trades one extra round trip for surviving the middleboxes, and it’s a workaround for a compatibility problem that classical-only key exchange never had. The load-bearing lesson, and the rule that governs all applied PQC, is that a protocol is only as quantum-safe as its weakest deployed endpoint on the path. Two perfectly configured hybrid endpoints still fail if a legacy device between them refuses the larger handshake.
Which libraries and browsers negotiate it today?
Hybrid TLS key exchange moved from paper to production fast, and as of 2026 both ends of a real connection can speak it out of the box. The pairing shipped almost everywhere is X25519MLKEM768.
| Where | What ships it | Status |
|---|---|---|
| Server TLS, C | OpenSSL 3.5 (April 2025) | Native ML-KEM and X25519MLKEM768 hybrid group; the FIPS-validated module still lags the release |
| Server TLS, Go | Go 1.24 crypto/tls | Negotiates X25519MLKEM768 automatically; crypto/mlkem exposes the KEM directly |
| Remote access | OpenSSH 9.9 and 10.0 | mlkem768x25519-sha256, the default key exchange since OpenSSH 10.0 (April 2025) |
| Browser (Chromium) | Chrome and Edge | Ship X25519MLKEM768 on by default; switched from the pre-standard Kyber draft group in late 2024 |
| Browser | Firefox | Added mlkem768x25519 post-quantum key exchange, reaching HTTP/3 in Firefox 135 (February 2025) |
Sources: OpenSSL 3.5 release; Go crypto/mlkem; OpenSSH, “Post-Quantum Cryptography”; Google Security Blog, “A new path for Kyber on the web” (September 2024, Chrome moving to the standardized group); Mozilla Firefox 135 release notes (mlkem768x25519 for HTTP/3, February 2025).
There’s a caveat that matters if you answer to a regulator. An algorithm shipping in a library is not the same as that algorithm being inside the library’s validated cryptographic module. OpenSSL 3.5 has native ML-KEM, but the CMVP-validated FIPS 140-3 OpenSSL module predates PQC, so for a compliance gate the validated-module date is what counts, not the release date. The urgent, deployable half of the migration is still key exchange, because the tooling is here even where the certification paperwork is catching up.
How do you enable and verify it?
Enabling hybrid key exchange is mostly a toolchain question, and verifying it is a wire question, because “the library supports it” is not the same claim as “this endpoint actually negotiated it.” Both checks are concrete.
- On Go 1.24, a standard TLS server negotiates
X25519MLKEM768automatically once you’re on the toolchain, with no code change to the server, so much of the surface migrates on the dependency bump alone. You reach forcrypto/mlkemdirectly only when you need the KEM outside TLS. - On OpenSSL 3.5, you can confirm a server negotiates the hybrid group from the command line without writing any code:
openssl s_client -groups X25519MLKEM768 -connect example.com:443
- On the wire, a packet capture of the handshake is the ground truth. The ClientHello’s
supported_groupslists the hybrid codepoint, and the ServerHello’s selected group and the kilobyte-scalekey_sharevalues confirm hybrid was genuinely chosen rather than merely offered. ForX25519MLKEM768the selected-group value is0x11EC. - Watch the handshake-failure rate as you roll out, because the oversized-ClientHello failures surface as connection errors from specific network paths rather than as a clean error, and they’re the tell that a middlebox on some route can’t carry the larger handshake.
Source: Go crypto/mlkem; OpenSSL 3.5 release.
The reason verification is its own step is that hybrid can silently not happen. If either side doesn’t support the group, or a middlebox drops the larger handshake, the negotiation falls back to a classical group and the connection still succeeds, just without post-quantum protection. Confirming the negotiated group on real traffic is what separates a deployment that closed the HNDL window from one that only looks like it did.
What does hybrid key exchange not protect?
Hybrid key exchange secures the confidentiality of the session, and it deliberately does nothing for authentication, which is a separate plane running on a separate timeline. The server still proves its identity with a certificate signed by a classical ECDSA or RSA algorithm, and a quantum computer breaks those signatures too. So a connection can use X25519MLKEM768 for its keys while presenting a fully classical certificate, and that’s the normal state of a 2026 deployment.
The distinction is HNDL versus Non-HNDL exposure. Key exchange is the HNDL-urgent half, because recorded traffic is decryptable retroactively the day a capable quantum computer exists, so closing it now protects data captured today. Certificate signatures are Non-HNDL, because a forged signature only helps an attacker in real time once the machine is here, and the ecosystem they depend on (certificate authorities, trust stores, hardware security modules) is years behind.
That’s why hybrid key exchange ships first and post-quantum authentication with ML-DSA and composite certificates follows on a deliberately slower track. A CBOM has to inventory the two planes separately, or it will call a key-exchange-migrated server “done” while its identity is still classically forgeable.
Common misconceptions
- “Enabling hybrid means my TLS is post-quantum.” It means the confidentiality plane is. The certificate that authenticates the server is still signed with classical ECDSA or RSA, so the identity remains quantum-forgeable until PKI migrates. Confidentiality and authentication move on separate schedules.
- “If both my client and server support hybrid, I’m done.” A middlebox, load balancer, or inspection appliance on the path that neither endpoint controls can drop the oversized ClientHello. Endpoint support is necessary and not sufficient. The whole path has to tolerate the larger handshake.
- “The performance cost is the ML-KEM math.” ML-KEM computation is fast, often faster than the ECDH it joins. The cost you plan around is bytes on the wire, the extra kilobyte in the first message and the occasional extra round trip from a HelloRetryRequest, not CPU time.
- “
X25519Kyber768Draft00andX25519MLKEM768are the same thing.” They’re the pre-standard and standardized versions, built on Kyber and finalized ML-KEM respectively, and they carry different codepoints. Early Chrome and Firefox shipped the draft group in 2023, then the ecosystem moved toX25519MLKEM768after FIPS 203. Only the standardized group should be deployed now. - “Turning on the group guarantees it’s used.” If a peer or a middlebox can’t carry it, the handshake falls back to a classical group and still succeeds, so a connection can look healthy while quietly using classical-only key exchange. You confirm the negotiated group on the wire, not from the fact that the option was enabled.
- “Hybrid is the permanent design.” The classical half is the exact thing a quantum computer breaks, so it’s carried as a hedge during the transition and is meant to retire before Q-Day, leaving standalone ML-KEM. A hybrid that never sheds its classical component is running dead weight and hiding an unfinished migration.
Questions people ask
Which hybrid group will I actually see in TLS traffic? X25519MLKEM768, codepoint 0x11EC (decimal 4588). It combines X25519 with ML-KEM-768, it’s the group the draft marks Recommended, and it’s shipped on by default in Chrome, Edge, and Firefox, so it dominates real captures. The SecP256r1MLKEM768 and SecP384r1MLKEM1024 variants only appear on stacks standardized to the NIST P-curves.
Do I have to rewrite my application to enable it? No. For TLS it’s overwhelmingly a toolchain upgrade. Go 1.24 negotiates X25519MLKEM768 automatically, and OpenSSL 3.5 supports it through configuration, so a large part of your surface migrates when you bump the dependency rather than change application code.
How much bigger is the handshake, exactly? A classical X25519 key_share is 32 bytes. A X25519MLKEM768 client share is 1216 bytes and the server share is 1120 bytes, driven by the ML-KEM-768 encapsulation key at 1184 bytes and ciphertext at 1088 bytes. That roughly-one-kilobyte jump in the first message is the entire source of the middlebox compatibility problem.
Why does the ordering of the two parts differ between groups? The specification fixes a per-group layout. For X25519MLKEM768 the ML-KEM part leads in both the wire share and the combined secret, while for the two P-curve groups the ECDHE part leads. It’s a spec convention, not a security difference, but a packet parser that assumes one order will misread the other.
Is it backward compatible with peers that don’t support it? Yes. It’s negotiated as an ordinary named group, so a peer that doesn’t list the hybrid group in supported_groups transparently falls back to a classical group with no handshake failure. Compatibility is preserved at the negotiation layer, which is exactly why the rollout can go endpoint by endpoint.
Does it protect data I already sent? No. Encryption protects sessions going forward, so any session that used classical-only key exchange before you enabled hybrid stays exposed to a future quantum computer. That’s the harvest-now-decrypt-later problem, and it’s the argument for enabling hybrid on long-lived confidential traffic as early as possible.
Is going straight to standalone ML-KEM an option instead of hybrid? It’s allowed and, for some profiles, preferred. Hybrid is the commercial default because it hedges against an undiscovered flaw in the young lattice scheme while still closing the harvesting window, whereas CNSA 2.0 permits standalone post-quantum key establishment for national security systems. The tradeoff is a young-algorithm hedge against a smaller, simpler handshake.
When does the classical half come out? Once a cryptographically relevant quantum computer exists, the classical component adds nothing against that adversary and is pure overhead, so the migration’s endpoint is retiring it and running ML-KEM alone. Planning that retirement is part of doing hybrid correctly, because a hybrid with no exit plan quietly becomes permanent technical debt.
Go deeper
The registry-and-history detail behind the named groups, the IANA codepoints, and how the ecosystem moved from the pre-standard Kyber draft group to X25519MLKEM768, lives in X25519MLKEM768 and the TLS hybrid named groups. The hub that maps this into every other protocol is In the Protocols MOC.
Everything here is the map, given freely. When your team needs its own TLS termination points, endpoints, and certificate chains assessed for a safe hybrid rollout and a real retirement plan, that’s what an alignment briefing is for.
Last verified 2026-07-09 · Maintained by Addie LaMarr, LaMarr Labs.