up:: 00 Field Guide Map

Implement Post-Quantum Cryptography

Implementing post-quantum cryptography means replacing the quantum-vulnerable public-key algorithms in your systems (RSA and elliptic-curve key exchange and signatures) with the NIST standards (ML-KEM, ML-DSA, SLH-DSA), almost always through a hybrid step, without a big-bang rewrite.

This is the build reference: how the mechanism actually works, the exact algorithms and their sizes, the libraries that already ship them, where the code changes, what it costs, and the footguns that page you at 2am. It assumes you’re fluent in TLS, keys, certificates, and your own stack, and it teaches the cryptographic depth on top of that. By the end you’ll know what to deploy, exactly where it goes, in what order, and what breaks if you skip a step, enough to run the whole rollout yourself. Every term links to its own note, so you can hover to preview or open it in a tab.

The one principle that orders everything below: key exchange is urgent, and signatures can wait. Recorded traffic is exposed retroactively the day a capable quantum computer exists, so hybrid key exchange is the work you ship now, and its tooling is mature. Signatures only fail in real time once the machine is here, and the ecosystem they depend on (CAs, trust stores, HSMs) is years behind, so you migrate signing and PKI on a deliberate, slower track. Hold that split in your head and the rest of this page falls into order.

The 60-second brief

  1. Key exchange is the urgent half. A quantum computer threatens recorded traffic retroactively (Harvest Now, Decrypt Later), so hybrid key exchange is the do-it-now work. Its support is mature.
  2. Signatures and PKI are the slower track. They only fail once a quantum computer actually exists, and the ecosystem around them (CAs, trust stores, HSMs) is years behind, so keep classical authentication for now and migrate signing deliberately.
  3. For TLS, this is mostly a toolchain upgrade. OpenSSL 3.5 and Go 1.24 negotiate the hybrid group X25519MLKEM768 out of the box. A lot of your surface migrates when you bump a dependency.
  4. The cost is bytes on the wire rather than CPU. ML-KEM is often faster than the ECDH it replaces. The pain is packet sizes and the handshake, so that’s what you instrument.
  5. Put the algorithm behind an interface. Build for crypto-agility now, because there will be a next algorithm (FN-DSA, HQC), and you don’t want to run this project twice.

The build, end to end

Here’s the whole implementation as a sequence, so every detailed section below has a place to land. Steps 1 through 4 are the urgent track you can run this quarter; steps 5 and 6 are the deliberate follow-on that depends on an ecosystem still catching up.

StepWhat you doWhat you getCovered below in
1. Locate itInventory every place you terminate TLS or verify a signatureA CBOMFind all the crypto in your codebase
2. Choose the algorithmsPick ML-KEM, ML-DSA, or SLH-DSA by job and sizeTarget algorithms per surfaceWhich algorithm for what
3. Ship hybrid key exchangeEnable X25519MLKEM768, endpoint by endpointHarvesting exposure closedHybrid, Libraries, By surface
4. Validate and measureConfirm the negotiated group; instrument the handshakeProof it’s live, plus your own numbersTesting, Cost
5. Migrate signing and PKIMove CA keys and signing to ML-DSA or SLH-DSA, on the slow trackPost-quantum authentication where it’s readyBy surface, Not ready yet
6. Bake in agilityPut the algorithm behind an interfaceThe next swap is config, not a rebuildMake crypto swappable

If you’re deploying TLS this quarter, steps 1 through 4 are your whole job, and most of step 3 is a toolchain upgrade. The rest of the page is each of these in the depth you need to run it.

What actually breaks, and what replaces it?

The split is clean, and the reason for it is worth holding in your head, because it tells you what to touch and what to leave alone.

Shor’s algorithm efficiently solves integer factorization and the discrete logarithm on a quantum computer. Every mainstream public-key algorithm rests on one of those two problems being hard, so all of them fall: RSA (factoring), Diffie-Hellman and ECDH (discrete log), ECDSA and Ed25519 (elliptic-curve discrete log). Grover’s algorithm only gives a square-root speedup on unstructured search, which halves the effective security of symmetric primitives, so you absorb it by doubling key size rather than replacing the algorithm.

CryptographyAttackVerdictReplace with
RSA key transport, Diffie-Hellman, ECDH, X25519Shor’sBrokenML-KEM
RSA signatures, ECDSA, Ed25519Shor’sBrokenML-DSA or SLH-DSA
AES-128Grover’sWeakenedAES-256
AES-256, SHA-256, SHA-3Grover’sSafeKeep

The practical consequence: the work concentrates entirely on key establishment and signatures. Your bulk data encryption is fine as long as it’s AES-256, and your hashes are fine at SHA-256 and above. The full mechanism is in quantum-vulnerable algorithms.

Source: NIST IR 8547.

Which post-quantum algorithm do I use for what?

NIST finalized the first three standards on August 13, 2024. Each does one job, and the deciding factor between them is almost always size rather than speed.

ML-KEM (FIPS 203) is the key-encapsulation mechanism. It’s what you use to agree on a shared secret over an open channel, replacing ECDH and RSA key transport. Lattice-based (Module-LWE). NIST’s default parameter set is ML-KEM-768.

Parameter setNIST categoryEncapsulation keyCiphertextShared secret
ML-KEM-5121800 B768 B32 B
ML-KEM-768 (default)31,184 B1,088 B32 B
ML-KEM-102451,568 B1,568 B32 B

ML-DSA (FIPS 204) is the general-purpose signature, replacing ECDSA and most RSA signing. Also lattice-based (Module-LWE and Module-SIS). Start at ML-DSA-65 for category-3 unless you have a reason not to.

Parameter setNIST categoryPublic keySignature
ML-DSA-4421,312 B2,420 B
ML-DSA-65 (common start)31,952 B3,309 B
ML-DSA-8752,592 B4,627 B

SLH-DSA (FIPS 205) is the conservative signature, and it rests only on hash-function security, with no lattice assumption. Reserve it for long-lived, low-volume signing (firmware, roots of trust, code signing) where you want a hedge against a lattice break and can absorb a large signature. It’s stateless, unlike the older LMS and XMSS. Twelve parameter sets exist, trading signature size against signing speed (s for small, f for fast); signatures range from 7,856 bytes to 49,856 bytes, and public keys stay tiny at 32 to 64 bytes.

FN-DSA (FIPS 206) is FALCON-derived and gives smaller signatures than ML-DSA, but it wasn’t finalized in the November 2024 draft, so it’s a design-for, not a deploy-today.

Sources: NIST FIPS 203, FIPS 204, FIPS 205, August 2024.

What is hybrid key exchange, and why is it the default?

Hybrid means running a classical algorithm and a post-quantum one together in the same handshake, and deriving the session key from both. The most common construction is X25519MLKEM768: do an ordinary X25519 exchange, do an ML-KEM-768 encapsulation, concatenate the two shared secrets, and feed the result through the KDF. The property that matters is that the session is secure as long as either half holds. A break in ML-KEM leaves you with X25519’s classical security, and a quantum computer that breaks X25519 leaves you with ML-KEM.

That’s why it’s the default rather than pure ML-KEM. It hedges against a discovered weakness in the new lattice schemes while still closing the harvesting exposure, and it keeps you interoperable with peers mid-migration. The one deployment trap: a hybrid ClientHello carries an ML-KEM key that’s over a kilobyte, which can push the ClientHello past a single network packet, and old middleboxes or load balancers that assume a small ClientHello can silently drop or mangle it. Roll out endpoint by endpoint, because a protocol is only as quantum-safe as its weakest deployed endpoint. Full detail is in hybrid cryptography and the protocols.

Which libraries ship post-quantum crypto today?

As of 2026, native support is broad, and for TLS a large part of your migration is a toolchain upgrade rather than new code. Find your stack:

Your stackLibraryPost-quantum status
C, server TLSOpenSSL 3.5 (Apr 2025)Native ML-KEM, ML-DSA, SLH-DSA; hybrid X25519MLKEM768. The FIPS-validated module is still pre-PQC (see the caveat below)
C, embeddedwolfSSLML-KEM and ML-DSA (all parameter sets), hybrid TLS 1.3, works with curl; FIPS 140-3 with PQC in progress
C, AWS ecosystemAWS-LC and s2n-tlsML-KEM; AWS-LC FIPS 3.0 was the first library to include ML-KEM in a FIPS 140-3 validation; s2n enables X25519MLKEM768 and SecP256r1MLKEM768
C++Botan 3.xNative ML-KEM, ML-DSA, SLH-DSA, plus FrodoKEM and Classic McEliece
Go, standard librarycrypto/mlkem (Go 1.24)ML-KEM-768 and ML-KEM-1024; X25519MLKEM768 wired into crypto/tls by default
Go, extendedCloudflare CIRCLML-KEM (FIPS 203) and Dilithium variants; a cfgo fork for experimenting with PQC certificates
Java, JDKJDK 24 (JEP 496, JEP 497)ML-KEM and ML-DSA in java.security; TLS/JSSE integration is still in progress
Java, providerBouncyCastleML-KEM, ML-DSA, SLH-DSA through JCA/JSSE; the fullest path before JDK 24
Rustrustls with aws-lc-rsX25519MLKEM768 via the prefer-post-quantum feature; the rustls-post-quantum crate
Any language, referenceliboqs (OQS)Every NIST PQC algorithm plus research candidates; Python, Go, Rust, and Java bindings; the oqs-provider for OpenSSL. A reference implementation, not a FIPS-certified module
SSHOpenSSH 9.9 through 10.4mlkem768x25519-sha256, the default key exchange since 10.0 (Apr 2025); 10.1 warns on classical-only key exchange; 10.4 (Jul 2026) added an experimental post-quantum signature, mldsa44-ed25519, so SSH authentication is starting to move too

Two common stacks aren’t there yet: mbedTLS has PQC on its roadmap but not in a released version, and pyca/cryptography (Python) is tracking ML-KEM, ML-DSA, and SLH-DSA support. On the client side, Chrome (131, Nov 2024) and Firefox (135, Feb 2025) already negotiate the hybrid group, so a server on OpenSSL 3.5 or later gets post-quantum key exchange with real browsers today.

Open-source availability and FIPS-validated availability are two different dates

An algorithm shipping in a library is not the same as that algorithm being in the library’s validated module. OpenSSL 3.5 has native ML-KEM, but the CMVP-validated FIPS 140-3 OpenSSL module is still 3.1.2, which predates PQC; the PQC-bearing 3.5.4 was submitted for FIPS 140-3 validation in October 2025 and is pending, and NIST’s validation process typically runs 12 to 18 months. If you answer to a regulator, your gate is the validated-module date, not the release date. AWS-LC and wolfSSL are the ones to watch, because they’re pushing PQC through FIPS 140-3 validation first.

The two paths you’ll actually take most often. In Go 1.24, crypto/tls negotiates X25519MLKEM768 automatically, so a standard server gets hybrid key exchange from the toolchain upgrade alone, and you reach for the KEM directly only when you need it:

// Go 1.24+: crypto/tls negotiates X25519MLKEM768 automatically.
srv := &http.Server{Addr: ":443", TLSConfig: &tls.Config{ /* your certs */ }}
 
// Using the KEM directly:
import "crypto/mlkem"
dk, _ := mlkem.GenerateKey768()          // decapsulation (private) key
ek := dk.EncapsulationKey()              // give this to the peer
secret, ciphertext := ek.Encapsulate()   // peer side: shared secret + ciphertext
secret2, _ := dk.Decapsulate(ciphertext) // your side: same shared secret

With OpenSSL 3.5, you can confirm a server negotiates the hybrid group without writing any code:

openssl s_client -groups X25519MLKEM768 -connect example.com:443

Exact signatures live in each project’s docs. The point is that for the urgent track, key exchange, you’re mostly enabling something your updated toolchain already implements.

Sources: OpenSSL 3.5 release; Go crypto/mlkem; JDK JEP 496 (ML-KEM); JDK JEP 497 (ML-DSA); OpenSSH post-quantum; wolfSSL post-quantum; AWS-LC FIPS 3.0 with ML-KEM; Botan; Cloudflare CIRCL; rustls-post-quantum; liboqs / Open Quantum Safe; Survey of PQC support in libraries, arXiv:2508.16078.

Where does the code actually change, surface by surface?

“Migrate” means something different for each surface, and the effort is rarely in the cryptography itself.

SurfaceWhat changesThe catch
TLS (web, APIs)Enable hybrid key exchange; often just a toolchain bumpThe oversized ClientHello tripping old middleboxes; roll out per endpoint
PKI and certificatesMigrate the CA’s own signing key to ML-DSA; plan trust-store distributionReissuing leaf certs without migrating the CA key changes nothing
Code and firmware signingML-DSA, or SLH-DSA for long-lived rootsAlready-signed artifacts keep verifying; plan re-signing and timestamping
SSHHybrid key exchange in recent OpenSSH; upgrade and set the KexAlgorithmsOld clients and jump hosts negotiate down
IPsec / VPNHybrid key exchange on the tunnel; often vendor firmwareFixed-firmware gear may need replacement, not config
Identity (JWT, SAML)Migrate token-signing keys to ML-DSAUsually a different team than PKI; easy to miss in the inventory
Data at restKeep AES-256; re-wrap keys that are protected by RSA or ECDHThe key-wrapping path is the exposure, not the bulk cipher

The consistent pattern: key establishment is the fast, urgent, mostly-mature track, and signing is the slow track gated by the wider ecosystem.

How much does post-quantum crypto actually cost?

Here are real measurements, so you can calibrate expectations before you benchmark your own system. Treat each as one architecture’s numbers, not a universal benchmark, because connection-reuse ratio and hardware dominate the result.

  • TLS handshake, server-class. A 2026 banking proof-of-concept measuring hybrid ML-KEM-512 at the TLS termination layer (Apache plus a Java API gateway, 100 concurrent clients) reported roughly a 23% increase in handshake time, about 1.3% on end-to-end request latency, and zero errors across all runs. Where connection reuse dominates, the handshake costs more and the overall request barely notices. Source: Balaji et al., “Operationalising Post-Quantum TLS,” arXiv:2605.17955 (2026).

  • Constrained devices. On an ESP32 running DTLS 1.3, certificate verification with ML-DSA-44 was roughly 12 times faster than ECDSA (about 16.5 ms versus 194 ms), yet ML-DSA-44 was the dominant memory cost, adding several kilobytes of code and about 28 kB of peak heap over the ECDSA build. On small devices the binding constraint is heap footprint rather than speed. Source: Blanco-Romero et al., arXiv:2603.10274 (2026), Tables 1 and 5.

  • Signature-heavy TLS. A measured SLH-DSA TLS certificate chain ran roughly 32.1 KB at the leaf, against about 16.6 KB for ML-DSA and 1.0 KB for classical ECDSA. That size pushed the handshake across a transport boundary and added a full extra round trip to time-to-first-byte, where ML-DSA stayed inside one flight. Source: Chou, M. and Cao, P. (2026), arXiv:2604.24869, Tables IV and VI.

The through-line is that compute is rarely the problem, and bytes on the wire are. Instrument handshake latency, handshake-failure rate, and the tail, not average CPU.

What are the footguns?

The traps that don’t show up until production or an audit:

  1. Reissuing leaf certificates without migrating the CA key. The vulnerability is the CA’s own signing key. New leaf certs under a quantum-vulnerable CA change nothing about your real exposure.
  2. Bumping RSA to 4096 bits. Larger RSA buys almost nothing against Shor’s algorithm, which scales with the structure of the problem rather than the key size. It’s a false fix.
  3. Certificate pinning a classical cert. Pinning locks you to a still-vulnerable certificate and makes the eventual migration harder.
  4. Stateful hash-based signatures (LMS and XMSS). They only stay secure if you manage signing state correctly and sign in hardware. Reuse a one-time key by mishandling state and the scheme breaks catastrophically. This is exactly why SLH-DSA exists as the stateless option.
  5. ML-DSA implementation details. The signing seed is as sensitive as the private key, the implementation can’t use floating point, and rejection sampling is a side-channel surface. Use a validated library rather than rolling your own.
  6. SLH-DSA’s message ceiling. Its security holds as long as a key pair signs at most 2⁶⁴ messages. For firmware or root keys that sign rarely, that’s unreachable, but know the bound exists before you point it at a high-volume workload.
  7. The weakest endpoint. One un-migrated load balancer, legacy VPN gateway, or old client renegotiates you back to classical and silently reopens the harvesting door. Migration status is a property of the whole path, not the server you configured.
  8. Post-quantum authentication at scale. Full PQ authentication isn’t realistically deployable everywhere yet, given cert-chain sizes and CA and verifier support. Keep classical signatures for authentication for now, and spend your urgency on hybrid key exchange.

Source: ML-DSA implementation cautions from NIST FIPS 204, August 2024; stateful-scheme requirements from NIST SP 800-208, October 2020.

How do I make my crypto swappable?

You will migrate cryptography again, so the highest-leverage thing you build now is the ability to change the algorithm without changing the system. That’s crypto-agility, and it comes in four practical patterns:

  1. An abstraction layer. Put algorithm choice behind an interface, so calling code names the operation (encapsulate, sign) and never the primitive.
  2. Crypto as a service. Route key operations through a KMS or HSM, so the algorithm lives in one managed place instead of scattered through the codebase.
  3. A provider or plugin architecture. Use the pluggable crypto layer your platform already has: JCA/JSSE providers on the JVM, PKCS#11, or OpenSSL providers, so a swap is a configuration change.
  4. Protocol negotiation. Let TLS, IPsec, and SSH negotiate the algorithm at connection time, which is what makes the hybrid rollout incremental in the first place.

There’s a deeper distinction worth internalizing: algorithm agility (swap the primitive) is what most vendors mean, but architectural agility (change the trust model, key distribution, or lifecycle) is the harder and more durable version. Design for the first at minimum.

Source: Bertino et al., “Quantum-Resistant Networks,” arXiv:2605.04129 (2026), §10.2.

How do I find all the crypto in my codebase?

You can’t migrate what you haven’t located, and cryptography hides in more places than a grep for “RSA” will find. Build a CBOM from a developer’s seat using four combined methods, because no single one sees the whole estate:

  1. Static analysis. Scan code and binaries for crypto library calls, hardcoded parameters, and key-management patterns that never appear in a live handshake.
  2. Configuration extraction. Parse server, application, and infrastructure-as-code configs for the algorithm and parameter choices as actually configured. For TLS especially, source from config files, not handshake observation alone, because a scan sees only what a server negotiates when probed, not what it still permits.
  3. Active scanning. Use sslyze, testssl.sh, and certificate enumeration to catch what’s live.
  4. Dependency inventory. Your crypto often lives in libraries you pulled in; a scanned handshake won’t tell you a pinned old version is the real problem.

Record each finding with its data class and control boundary, because those two fields are what let you rank it later. Full method is in CBOM.

Source: Balaji et al., arXiv:2605.17955 (2026).

How do I test that I actually migrated?

Verification is its own step, because “the library supports it” is not “my endpoint negotiates it.”

  1. Confirm the negotiated group, not the available one. Capture a real handshake and check that the session actually used X25519MLKEM768, for example with openssl s_client -groups X25519MLKEM768 or a packet capture, rather than trusting that the option was compiled in.
  2. Inspect the certificate chain. Export the leaf and intermediates and check the signature algorithm, so you know whether you migrated the CA key or only the leaf.
  3. Check validation status if you answer to a regulator. Confirm the module is CAVP-tested and FIPS 140-3 validated for the new algorithms, not merely present in the library. Presence is not validation.
  4. Watch the handshake-failure rate on rollout. The oversized-ClientHello failures show up as connection errors from specific network paths, so instrument failures by endpoint and roll back per endpoint using the hybrid fallback.

What’s not ready to ship yet?

Intellectual honesty is part of getting this right, so here’s what to design for rather than deploy:

  • FN-DSA (FIPS 206). The smaller-signature FALCON-derived option wasn’t finalized in the November 2024 draft. Track it; don’t build on it yet.
  • HQC. NIST selected it on March 11, 2025 as a code-based backup KEM on different math from ML-KEM, with a final standard expected around 2027. It’s a design-for-a-backup, not a deploy-today.
  • Fleet-wide post-quantum authentication. Cert-chain sizes and uneven CA and verifier support mean full PQ auth isn’t realistic everywhere yet. Hybrid key exchange is the track that’s ready.

Source: NIST, “NIST Selects HQC as Fifth Algorithm for Post-Quantum Encryption”, March 11, 2025.

Questions developers ask

Do I have to rewrite my application? No. Keep the algorithm behind a provider or config, and for TLS the hybrid group is negotiated by an updated toolchain, so most of the urgent track is an upgrade rather than a rewrite.

What do I migrate first? Hybrid key exchange, because of harvesting. Signatures and PKI are a deliberate later track.

Will this slow my system down? Mostly on the handshake. Expect a modest handshake increase and a much smaller end-to-end effect where connections are reused, but measure your own, because the numbers are architecture-dependent.

Which library should I use? Native support if your stack has it: OpenSSL 3.5 and Go 1.24 speak the hybrid group already, and BouncyCastle covers the JVM. Reach for liboqs only when yours doesn’t yet.

Is ML-KEM slower than ECDH? Usually the opposite. ML-KEM’s compute is fast; the cost you plan around is the larger key and ciphertext on the wire.

Is post-quantum authentication ready to ship? Not at scale. Keep classical signatures for authentication for now, and ship hybrid key exchange today.

What actually breaks in production? The oversized hybrid ClientHello tripping old middleboxes and load balancers. Roll out endpoint by endpoint and watch the handshake-failure rate.

Quick reference: the vocabulary

  • ML-KEM (FIPS 203): the key-encapsulation standard. Replaces ECDH and RSA key transport.
  • ML-DSA (FIPS 204): the general-purpose signature. Replaces ECDSA and RSA signing.
  • SLH-DSA (FIPS 205): the conservative, hash-based signature for long-lived keys.
  • Hybrid: classical and post-quantum together; secure if either half holds. X25519MLKEM768 is the common construction.
  • HNDL: why key exchange is the urgent track.
  • Crypto-agility: building so the next algorithm swap is a config change.
  • CBOM: the inventory of every algorithm, key, and cert in your systems.
  • FIPS 140-3 / CAVP: the validation status that tells you a module is certified rather than merely present.

That’s the whole build: what breaks, what replaces it, where the code changes, what it costs, and what will page you. It’s enough to run the rollout yourself.

When the program around it needs an owner, the budget, the vendor timelines, the board, the migration sequence across the whole estate, that’s a different job from the code. It’s mapped in the executive owner’s playbook; hand that to whoever owns your migration. And when your org wants it architected and run against your real systems, there’s an alignment briefing for that.

Last verified 2026-07-09 · Maintained by Addie LaMarr, LaMarr Labs.