<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Parag Mali - tag: ml-kem</title><description>Posts tagged ml-kem.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 19 Jul 2026 05:08:42 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/ml-kem/rss.xml" rel="self" type="application/rss+xml"/><item><title>How ML-KEM Breaks in Real Life: The Machine Leaked While the Math Held</title><link>https://paragmali.com/blog/how-ml-kem-breaks-in-real-life-the-machine-leaked-while-the-/</link><guid isPermaLink="true">https://paragmali.com/blog/how-ml-kem-breaks-in-real-life-the-machine-leaked-while-the-/</guid><description>ML-KEM shipped with a machine-checked security proof, yet its reference code leaked secret keys through a division instruction. Why every break missed the math.</description><pubDate>Sat, 18 Jul 2026 00:00:00 GMT</pubDate><content:encoded>
ML-KEM (FIPS 203) is the first standardized post-quantum KEM, and as of publication its Module-LWE mathematics is unbroken -- the IND-CCA2 security of its Fujisaki-Okamoto construction is even machine-checked [@fvk], and the two headline quantum &quot;breaks&quot; both failed to withstand expert scrutiny -- Chen withdrew his own claim, and Luo&apos;s was refuted by named experts [@chen2024][@postquantum-luo]. Yet every real attack on it has recovered secret keys anyway: KyberSlash through a variable-time division instruction disclosed in December 2023 [@kyber-commit][@kyberslash-paper], Clangover through a compiler that reintroduced a secret branch [@clangover], and fault attacks like Carry Your Fault straight through the masking meant to stop them [@carry-fault]. The through-line is a law two decades old, first seen when AES was attacked at the implementation and never at the cipher [@bernstein2005]: a security proof constrains values, not execution, so the attacker&apos;s frontier moves outward -- instruction, compiler, construction, countermeasure -- and never has to reach the lattice. This article catalogs each documented break from its primary source and shows you how to choose an ML-KEM implementation that does not leak.
&lt;h2&gt;1. A fortress breached at the doorknob&lt;/h2&gt;
&lt;p&gt;On 13 August 2024, the U.S. National Institute of Standards and Technology published FIPS 203 and gave the world its first standardized post-quantum key-encapsulation mechanism: ML-KEM [@fips203]. It arrived with something almost no cipher in history has had at birth -- a machine-checked mathematical proof that the construction is secure [@fvk]. Eight months earlier, on 1 December 2023, the maintainers of its reference code had quietly committed a patch to stop that same code from handing an attacker the full secret key [@kyber-commit]. Not through any weakness in the lattice mathematics. Through a single division instruction.&lt;/p&gt;
&lt;p&gt;The proof was about the numbers. The attack was about the machine. This article is about the gap between them.&lt;/p&gt;

A KEM is a three-algorithm protocol -- key generation, encapsulation, and decapsulation -- for agreeing on a shared secret over an insecure channel. Encapsulation takes a public key and outputs a ciphertext plus a shared secret; decapsulation takes the ciphertext and the private key and recovers the same shared secret. ML-KEM is the KEM standardized in FIPS 203, derived from CRYSTALS-Kyber, and its security rests on the Module Learning With Errors problem [@fips203].
&lt;p&gt;Here is the thesis this article defends: as of publication, every documented attack on ML-KEM is an implementation attack. Not one has touched the Module-LWE mathematics. The keys have been recovered through a division instruction, a compiler optimization, and a fault injected into a countermeasure -- never through the lattice. This is exactly the class of attack that its structural-mathematics sibling, &quot;How ML-KEM and ML-DSA Would Break,&quot; deliberately sets aside to ask how the primitive itself might one day fall. That article studies the door; this one shows you that so far, every intruder has come through the doorknob.&lt;/p&gt;

There is no documented in-the-wild exploitation of a production ML-KEM deployment as of publication. The &quot;breaks&quot; cataloged here are of three honest kinds: vulnerable code shipping in the reference implementation and downstream libraries; CVE-class advisories such as RUSTSEC-2023-0079 [@rustsec]; and researcher proof-of-concept key recovery on real hardware [@kyberslash-paper]. That is stronger for the thesis, not weaker. The implementation layer broke first, at deployment scale, before the primitive had finished rolling out -- which is precisely what the pattern predicts.
&lt;p&gt;And it has finished rolling out into places that matter. Google&apos;s BoringSSL and the Go standard library&apos;s constant-time &lt;code&gt;crypto/mlkem&lt;/code&gt; both ship ML-KEM today [@kyberslash-site][@go-mlkem], as do &lt;code&gt;filippo.io/mlkem768&lt;/code&gt; and the vectorized AVX2 reference paths [@kyberslash-site]. The common deployment shape is a hybrid key exchange, &lt;code&gt;X25519MLKEM768&lt;/code&gt;, that stays secure if either half holds [@tls-hybrid] -- a hedge, as we will see, against both a future math break and a present implementation bug. When we say the reference code was leaking keys, we mean the code from which production ML-KEM was built.&lt;/p&gt;
&lt;p&gt;The proof was real. So where did the key go? To answer that we have to be precise about what the proof actually promises -- and what it does not.&lt;/p&gt;
&lt;h2&gt;2. The contract: what ML-KEM actually promises&lt;/h2&gt;
&lt;p&gt;A security proof is a legal contract, and like every contract it binds only what it names. Read ML-KEM&apos;s proof carefully and you find it makes a precise, narrow promise about what an adversary can learn from a public key and a set of ciphertexts. It says nothing at all about how many clock cycles decapsulation takes, what assembly the compiler emits, how the power rail fluctuates, or what happens when a cosmic ray flips a carry bit. Those are not loopholes in the contract. They are simply not in it.&lt;/p&gt;
&lt;p&gt;ML-KEM began life as CRYSTALS-Kyber, presented at IEEE EuroS&amp;amp;P in 2018 as &quot;a CCA-secure module-lattice-based KEM&quot; [@kyber2018]. Six years of analysis and a NIST competition later, it became FIPS 203 with only modest changes [@fips203]. Its security rests on one hard problem.&lt;/p&gt;

Module-LWE hides a short secret vector inside a system of noisy linear equations over a polynomial ring modulo a public prime $q = 3329$. Given many pairs $(\mathbf{a}, \mathbf{a}\cdot\mathbf{s} + e)$ with small error $e$, recovering the secret $\mathbf{s}$ is believed hard for both classical and quantum computers. ML-KEM uses a module of rank 2, 3, or 4 to produce its three security levels; the internals of why the problem is hard belong to the companion article on how the lattice itself might fall [@kyber2018][@fips203].
&lt;p&gt;The module rank is the only structural dial, and it defines the three parameter sets.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter set&lt;/th&gt;
&lt;th&gt;Module rank&lt;/th&gt;
&lt;th&gt;FIPS 203 security category&lt;/th&gt;
&lt;th&gt;Typical role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ML-KEM-512&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Category 1&lt;/td&gt;
&lt;td&gt;Lightweight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML-KEM-768&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Category 3&lt;/td&gt;
&lt;td&gt;Default / recommended&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML-KEM-1024&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Category 5&lt;/td&gt;
&lt;td&gt;High assurance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The modulus $q = 3329$ is a public constant baked into the standard.Everyone knows the divisor. What is secret is the numerator the divisor acts on -- the coefficients of the decrypted polynomial. That asymmetry, a public modulus dividing a secret operand, is the entire seed of the first break in the catalog. That distinction between the public and the secret operand is worth holding onto; it returns with a vengeance in Section 4.&lt;/p&gt;
&lt;p&gt;Now picture the whole story as a set of concentric layers around that untouched mathematics.&lt;/p&gt;

flowchart LR
    M[&quot;Layer 0: Module-LWE mathematics (unbroken)&quot;]
    I[&quot;Layer 1: the instruction (KyberSlash)&quot;]
    C[&quot;Layer 2: the compiler (Clangover)&quot;]
    F[&quot;Layer 3: the construction (FO plaintext-checking oracle)&quot;]
    K[&quot;Layer 4: the countermeasures (Carry Your Fault)&quot;]
    M --&amp;gt; I --&amp;gt; C --&amp;gt; F --&amp;gt; K
&lt;p&gt;Why does an active adversary matter here? Because a KEM that only resisted passive eavesdroppers -- the property called &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-/&quot; rel=&quot;noopener&quot;&gt;IND-CPA&lt;/a&gt; -- would be useless for a reused key. Real deployments reuse a decapsulation key across many sessions, and an attacker who can submit chosen or malformed ciphertexts and watch the results needs a stronger guarantee.&lt;/p&gt;

IND-CCA2 is the gold-standard secrecy notion for a KEM: even an adversary who can submit ciphertexts of its choosing and observe how the system responds cannot distinguish the real shared secret from random. It is exactly the notion you need when one long-lived private key decapsulates attacker-supplied ciphertexts, which is how KEMs are used in practice [@fips203].
&lt;p&gt;Kyber reaches IND-CCA2 from a weaker IND-CPA core using a classic construction.&lt;/p&gt;

The FO transform, introduced in 1999 [@fo1999] and given its modern implicit-rejection analysis in 2017 [@hhk2017], upgrades a passively secure encryption scheme to an actively secure KEM. On decapsulation, it decrypts the ciphertext to a candidate message, then re-encrypts that message and checks whether the result matches the ciphertext it received. A genuine ciphertext re-encrypts to itself; a tampered one does not.
&lt;p&gt;What happens on a mismatch is the hinge of the entire article.&lt;/p&gt;

When re-encryption does not match, ML-KEM does not return an error. It returns a pseudorandom shared secret $\bar{K} = J(z, c)$, derived by hashing a secret rejection seed $z$ together with the ciphertext $c$. To the caller, a rejected ciphertext is indistinguishable from an accepted one -- there is no decapsulation-failure signal to query. By construction, the FO transform gives an attacker no caller-visible oracle [@fips203].

flowchart TD
    A[&quot;Ciphertext c arrives at decapsulation&quot;]
    B[&quot;Decrypt c to a candidate message&quot;]
    C[&quot;Re-encrypt the candidate to c-prime&quot;]
    D{&quot;Re-encryption matches?&quot;}
    E[&quot;Return the true shared secret K&quot;]
    F[&quot;Return pseudorandom K-bar equals J of z and c&quot;]
    A --&amp;gt; B --&amp;gt; C --&amp;gt; D
    D --&amp;gt;|yes| E
    D --&amp;gt;|no| F
&lt;p&gt;That construction is not just believed secure; in 2024 a team machine-checked the IND-CCA2 security and correctness of Kyber in EasyCrypt, tying the proof to a real implementation [@fvk]. So the baseline is as strong as cryptography gets: the mathematics is unbroken, and the reduction from it to the KEM has been verified by a computer.&lt;/p&gt;

A security proof is a contract about values; a side channel is a breach in execution.
&lt;p&gt;And there is the first shift in understanding. The proof constrains what an adversary learns from the specified inputs and outputs -- the values. It is silent on cycles, on emitted assembly, on power traces, on a flipped carry bit -- the execution. The key can walk out through the machine while the proof stays perfectly true. The contract is airtight about values. But the contract is run by a machine, and the machine is where this story happens. Before we watch it leak, one piece of history tells us it was always going to.&lt;/p&gt;
&lt;h2&gt;3. The precedent: AES was attacked at the implementation, never at the cipher&lt;/h2&gt;
&lt;p&gt;In April 2005, a widely used, carefully written AES implementation was handing out its key. Not to a cryptanalyst who had found a weakness in the cipher, but to a stopwatch. Daniel J. Bernstein showed that the time AES took to encrypt depended on its secret key, because the standard software used secret-indexed table lookups whose cache behavior varied with the data [@bernstein2005]. The cipher was fine. The code was leaking. The same researcher would, eighteen years later, be among the first to flag the division timing in Kyber [@kyberslash-site].&lt;/p&gt;

A side-channel attack recovers secrets not from the mathematical output of an algorithm but from physical or behavioral byproducts of running it: elapsed time, cache state, power consumption, electromagnetic emissions, or the effect of induced faults. The algorithm can be perfectly secure on paper and still leak through the machine executing it.
&lt;p&gt;A year later, Osvik, Shamir, and Tromer turned Bernstein&apos;s observation into a general methodology, naming the Prime and Probe and Evict and Time techniques that let one process read another&apos;s cache footprint and recover an AES key from a few thousand encryptions [@ost2006]. &lt;a href=&quot;https://paragmali.com/blog/how-aes-breaks-in-real-life-the-attacks-that-never-touched-t/&quot; rel=&quot;noopener&quot;&gt;Cache-timing attacks&lt;/a&gt; became a standard tool, and &quot;How AES Breaks in Real Life,&quot; the earlier article in this series, is largely their story.&lt;/p&gt;
&lt;p&gt;Now the counterweight, and it is the whole point. In all the years since, the AES &lt;em&gt;mathematics&lt;/em&gt; has barely moved. The best known single-key attack on the full cipher is the 2011 &lt;a href=&quot;https://paragmali.com/blog/the-fortress-and-the-afterthought-how-aes-would-break-at-its/&quot; rel=&quot;noopener&quot;&gt;biclique cryptanalysis&lt;/a&gt;, which recovers an AES-128 key in about ${2}^{126.1}$ operations rather than the ${2}^{128}$ of brute force [@biclique2011]. That is a speedup of less than a factor of four against a number with thirty-nine digits -- a result its own authors framed as not threatening the practical use of AES.&lt;/p&gt;
&lt;p&gt;Two decades of the world&apos;s best cryptanalysts, and the cipher&apos;s security margin shrank by two bits, while its implementations leaked keys to a stopwatch in an afternoon.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A strong new primitive is attacked at the implementation first, and often only ever there. The mathematics is the hardest thing to break and the last thing to fall; the code around it is where the keys actually walk out. AES lived this for twenty years. ML-KEM, as of publication, is living it from the moment it was born.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If that law holds, ML-KEM&apos;s first breaks should be implementation breaks -- and the theory behind them should already exist. It does. Years before FIPS 203, researchers had worked out exactly how to attack a CCA-secure lattice KEM through its physics. In 2019, Ravi and colleagues demonstrated generic side-channel key recovery against CCA-secure lattice-based PKE and KEMs, exploiting the decryption-failure structure of these schemes [@ravi2019]. In 2021, Ueno and colleagues published &quot;Curse of Re-encryption,&quot; showing that the FO re-encryption step itself is a generic power and electromagnetic oracle across post-quantum KEMs [@ueno2021].Bernstein bookends both halves of this series: the 2005 cache-timing attack that defined how AES breaks, and the 2023 division-timing flag that opened how ML-KEM breaks. The same person, the same lesson, eighteen years apart.&lt;/p&gt;
&lt;p&gt;So the blueprint for breaking ML-KEM&apos;s implementation was drawn before the standard was finished. If the pattern holds, the first real breaks should show up early, maybe before the ink on the standard is dry. They did. Here is the catalog.&lt;/p&gt;
&lt;h2&gt;4. The catalog: the frontier moves outward&lt;/h2&gt;
&lt;p&gt;Here is the pattern to watch as we walk the documented breaks: each one lands one layer further from the mathematics than the last. The first is a single machine instruction. The second is the compiler. The third is the construction that proves the whole scheme secure. The fourth is the countermeasure built to stop the third. Not one of them reaches the lattice.&lt;/p&gt;

timeline
    title The frontier moves outward, December 2023 to 2025
    2023 : KyberSlash1 patched on 1 December, commit dda29cc : Bernstein flags it possibly exploitable on 15 December : KyberSlash2 disclosed on 30 December
    2024 : Clangover compiler-introduced branch : Carry Your Fault on masked Kyber : FIPS 203 standardized on 13 August
    2025 : KyberSlash paper at IACR TCHES, a CHES best paper
&lt;p&gt;The whole break surface fits in one table, and every number in it comes from a primary source.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Attack&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Measured result&lt;/th&gt;
&lt;th&gt;Defense&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1. Instruction&lt;/td&gt;
&lt;td&gt;KyberSlash&lt;/td&gt;
&lt;td&gt;Secret numerator divided by the public modulus compiles to a variable-time &lt;code&gt;DIV&lt;/code&gt; [@kyberslash-site]&lt;/td&gt;
&lt;td&gt;Full keys in minutes for KyberSlash2, a few hours for KyberSlash1 -- both on the Cortex-M4 and Raspberry Pi 2 (Cortex-A7) [@kyberslash-paper]&lt;/td&gt;
&lt;td&gt;Reciprocal multiplication; never-divided and AVX2 paths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Compiler&lt;/td&gt;
&lt;td&gt;Clangover&lt;/td&gt;
&lt;td&gt;Clang re-emits a secret-dependent branch from constant-time source [@clangover]&lt;/td&gt;
&lt;td&gt;ML-KEM-512 key in 5-10 minutes on an i7-13700H [@clangover]&lt;/td&gt;
&lt;td&gt;Verify the binary; verified assembly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Construction&lt;/td&gt;
&lt;td&gt;Plaintext-checking oracle&lt;/td&gt;
&lt;td&gt;Any physical pass/fail leak in FO re-encrypt-and-compare [@ravi2019][@ueno2021]&lt;/td&gt;
&lt;td&gt;Generic key recovery against a reused key&lt;/td&gt;
&lt;td&gt;Constant-time plus masked comparison&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Countermeasure&lt;/td&gt;
&lt;td&gt;Carry Your Fault&lt;/td&gt;
&lt;td&gt;Fault in the A2B carry chain that masking itself added [@carry-fault]&lt;/td&gt;
&lt;td&gt;Keys from arbitrary-order masked Kyber via EM fault on an STM32 [@carry-fault]&lt;/td&gt;
&lt;td&gt;Fault detection and redundancy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Layer 1 -- the instruction: KyberSlash&lt;/h3&gt;
&lt;p&gt;Start with one line of reference C. In &lt;code&gt;poly_tomsg&lt;/code&gt;, the routine that turns a decrypted polynomial back into message bits, the code computes &lt;code&gt;t = (((t &amp;lt;&amp;lt; 1) + KYBER_Q/2)/KYBER_Q) &amp;amp; 1;&lt;/code&gt; [@kyberslash-site]. It divides a &lt;em&gt;secret&lt;/em&gt; numerator &lt;code&gt;t&lt;/code&gt; by the &lt;em&gt;public&lt;/em&gt; modulus &lt;code&gt;KYBER_Q&lt;/code&gt;, which is 3329. On paper that is one arithmetic operation. On silicon it is a catastrophe.&lt;/p&gt;

Code is constant-time, or data-oblivious, when its execution -- the instructions retired, the memory addresses touched, and the total cycle count -- does not depend on any secret value. No secret-dependent branches, no secret-indexed memory, no variable-latency instructions on secret operands. It is the baseline defense against timing side channels, and it is a property of the running binary, not of good intentions.
&lt;p&gt;The trouble is that on many processors, integer division is not constant-time. On many CPU, compiler, and flag combinations, &lt;code&gt;/KYBER_Q&lt;/code&gt; compiles to a hardware &lt;code&gt;DIV&lt;/code&gt; whose cycle count depends on the numerator: on an AMD Zen 2 core the division slows by a cycle once the numerator reaches 8192; on the SiFive U74 RISC-V core the timing shifts at 2048, 4096, and 8192; &lt;code&gt;gcc -Os&lt;/code&gt; emits a &lt;code&gt;DIV&lt;/code&gt; where &lt;code&gt;gcc -O3&lt;/code&gt; emits a constant-time multiplication; and on a Raspberry Pi 2, &lt;code&gt;gcc -Os&lt;/code&gt; -- whose default ABI does not guarantee a hardware divide -- emits a call to a branchy software-division routine instead [@kyberslash-site]. Any one of these makes decapsulation time depend on the secret.&lt;/p&gt;

KYBER_Q is a public integer 3329, but t is secret ... the time taken by division depends on the inputs.
&lt;p&gt;That quote is from the KyberSlash FAQ [@kyberslash-site], and it is the entire attack in one sentence. There was, it turns out, a second copy of the same bug: KyberSlash2 is the identical secret-dependent division in &lt;code&gt;poly_compress&lt;/code&gt; and &lt;code&gt;polyvec_compress&lt;/code&gt;, the compression functions called from &lt;code&gt;indcpa_enc&lt;/code&gt; [@kyberslash-site]. Because decapsulation &lt;em&gt;also&lt;/em&gt; runs encryption during FO re-encryption, both the decryption and the re-encryption paths leak [@pqcforum-kyberslash2]. The measured consequence, from the KyberSlash paper, is blunt: Kyber secret keys are &quot;reliably recovered within minutes for KyberSlash2 and a few hours for KyberSlash1&quot; on an Arm Cortex-M4 and a Raspberry Pi 2 with an Arm Cortex-A7 [@kyberslash-paper].&lt;/p&gt;

flowchart TD
    A[&quot;Secret numerator t from the decrypted polynomial&quot;]
    B[&quot;Public modulus KYBER_Q, the constant 3329&quot;]
    C[&quot;Source computes t divided by KYBER_Q&quot;]
    D[&quot;Compiler emits a hardware DIV on many targets&quot;]
    E[&quot;DIV latency depends on the operand&quot;]
    F[&quot;Decapsulation time leaks bits of the secret&quot;]
    G[&quot;Plaintext-checking oracle, then full key recovery&quot;]
    A --&amp;gt; C
    B --&amp;gt; C
    C --&amp;gt; D --&amp;gt; E --&amp;gt; F --&amp;gt; G
&lt;p&gt;The timeline matters, because it is the proof of the thesis. The reference implementation was patched in &lt;code&gt;pq-crystals/kyber&lt;/code&gt; commit dda29cc on 1 December 2023, with the message &quot;Updated poly_tomsg to prevent a compiler from using DIV,&quot; crediting Cryspen&apos;s Goutam Tamvada, Karthikeyan Bhargavan, and Franziskus Kiefer [@kyber-commit].The leak was found not by an attacker but by a formal-verification team. Cryspen&apos;s engineers noticed the division while building a machine-checked Rust implementation of Kyber [@cryspen]. The people proving the code correct were the ones who saw it leak. Bernstein announced it publicly as a &quot;possibly exploitable&quot; issue on 15 December 2023 [@pqcforum-bernstein]; Ravi and Kannwischer disclosed the compression-function copy, KyberSlash2, on 30 December 2023 [@pqcforum-kyberslash2]. This is eight months &lt;em&gt;before&lt;/em&gt; FIPS 203 existed. The standard had a machine-checked proof and a leaking reference implementation at the same time.KyberSlash carries a CVE-class advisory but no NVD number. The record is RUSTSEC-2023-0079 against the &lt;code&gt;pqc_kyber&lt;/code&gt; crate, rated CVSS 7.4 HIGH, with no patched versions released upstream [@rustsec].&lt;/p&gt;
&lt;p&gt;You can see why the fix looks trivial: never divide by a public constant on a secret. Multiply by its reciprocal instead. The two compute the same value, but only one is data-oblivious.&lt;/p&gt;
&lt;p&gt;{`
const q = 3329;&lt;/p&gt;
&lt;p&gt;// Illustrative model of hardware DIV latency: on several real cores the
// cycle count creeps up as the (secret) dividend grows. Not a measurement.
function divCycles(secretNumerator) {
  return secretNumerator &amp;gt;= 8192 ? 18 : 17;
}&lt;/p&gt;
&lt;p&gt;// Reciprocal multiplication: multiply by a precomputed constant, then
// shift. One fixed cost, whatever the operand.
function reciprocalCycles(_secretNumerator) {
  return 3;
}&lt;/p&gt;
&lt;p&gt;// Both routines decode the same message bit; only the timing differs.
function decodeBit(t) {
  return (((t &amp;lt;&amp;lt; 1) + (q &amp;gt;&amp;gt; 1)) / q) &amp;amp; 1;
}&lt;/p&gt;
&lt;p&gt;const secrets = [1200, 6000, 9000, 15000];
const divCosts = secrets.map(divCycles);
const mulCosts = secrets.map(reciprocalCycles);&lt;/p&gt;
&lt;p&gt;console.log(&quot;secret numerators :&quot;, secrets.join(&quot;, &quot;));
console.log(&quot;DIV cycle model   :&quot;, divCosts.join(&quot;, &quot;), &quot; (varies with the secret)&quot;);
console.log(&quot;reciprocal model  :&quot;, mulCosts.join(&quot;, &quot;), &quot;    (constant)&quot;);
console.log(&quot;decoded bits match:&quot;, secrets.map(decodeBit).join(&quot;, &quot;));
`}&lt;/p&gt;
&lt;p&gt;The obvious fix, then, is to delete the division and write constant-time source. So people did. It was not enough.&lt;/p&gt;
&lt;h3&gt;Layer 2 -- the compiler: Clangover&lt;/h3&gt;
&lt;p&gt;You wrote constant-time C. The compiler disagreed. This is the uncomfortable discovery behind Clangover, published by Antoon Purnal in 2024 [@clangover]. The reference implementation&apos;s &lt;code&gt;poly_frommsg&lt;/code&gt; routine, which expands each message bit into a polynomial coefficient, was written to be branch-free by construction: no &lt;code&gt;if&lt;/code&gt; on a secret, just arithmetic and masks. Inspect the C and it is constant-time.&lt;/p&gt;
&lt;p&gt;Then compile it. Clang versions 15 through 18, under optimization levels &lt;code&gt;-Os&lt;/code&gt;, &lt;code&gt;-O1&lt;/code&gt;, and &lt;code&gt;-O2&lt;/code&gt; or &lt;code&gt;-O3&lt;/code&gt; with &lt;code&gt;-fno-vectorize&lt;/code&gt;, recognize the branch-free idiom and &quot;optimize&quot; it back into a &lt;em&gt;secret-dependent conditional branch&lt;/em&gt; in the emitted x86 assembly [@clangover]. The compiler, trying to be helpful, reintroduced exactly the leak the programmer had carefully removed. End-to-end decapsulation-timing measurements then recover the full ML-KEM-512 secret key in 5 to 10 minutes on an Intel Core i7-13700H compiled with Clang 16.0.6 [@clangover].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Constant-time source is not constant-time binary. A proof about C, or even a careful reading of C, does not bind the machine code an optimizing compiler emits. The property you need holds of the instructions that actually run, and the compiler stands between you and them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The reference maintainers already knew the compiler was an adversary, even if the full extent was not yet clear. Recall the wording of the KyberSlash patch: not &quot;fix a bug&quot; but &quot;prevent a compiler from using DIV&quot; [@kyber-commit].The commit message names the real opponent. The source did not contain a division instruction; it contained a division operator that the maintainers had to actively stop the compiler from turning into a &lt;code&gt;DIV&lt;/code&gt;. The adversary was the toolchain, not the algorithm. Clangover is the general form of that fear: the toolchain can undo any source-level constant-time property you think you have.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Every defense so far lived in the source language. KyberSlash was patched in source; the branch-free &lt;code&gt;poly_frommsg&lt;/code&gt; was written in source. Clangover shows the guarantee you actually need lives one level down, in the binary -- and nothing about writing careful C forces the binary to inherit the property. This is the coverage gap that Section 6&apos;s strongest defenses exist to close.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One detail in the Clangover repository ties this layer to the next. Purnal describes his attack, in his own words, as &quot;a plaintext-checking oracle attack a la Ravi et al. and Ueno et al.&quot; [@clangover] -- and so does the KyberSlash lineage. Both breaks call themselves the same thing, which is no coincidence: it is the tell that they are two instantiations of a single, deeper surface. Time to see it.&lt;/p&gt;
&lt;h3&gt;Layer 3 -- the construction: the plaintext-checking oracle&lt;/h3&gt;
&lt;p&gt;The armor is the wound. The re-encrypt-and-compare step that &lt;em&gt;proves&lt;/em&gt; ML-KEM secure against active attackers is the exact code that every documented break pries open. To see why, you have to understand what the attacks are actually querying.&lt;/p&gt;

A plaintext-checking oracle answers one question about a decapsulation: did this ciphertext decrypt to a particular message, or not? Lattice KEMs have a small, secret-dependent decryption-failure event, so an attacker who crafts ciphertexts near that boundary and learns pass-or-fail for each one can, over many queries against a reused key, solve for the secret. The oracle need not be a protocol feature; any physical leak that separates the two cases will serve [@ravi2019][@ueno2021].
&lt;p&gt;This is the surface Ravi and colleagues formalized in 2019, showing generic PC-oracle key recovery against CCA-secure lattice KEMs, and that Ueno and colleagues generalized in 2021 to the FO re-encryption step as a power and electromagnetic oracle across post-quantum schemes [@ravi2019][@ueno2021]. Both predate FIPS 203.&lt;/p&gt;
&lt;p&gt;And now the earlier layers snap into focus: KyberSlash is this oracle instantiated at the &lt;em&gt;instruction&lt;/em&gt; (division timing separates pass from fail), and Clangover is the same oracle instantiated at the &lt;em&gt;compiler&lt;/em&gt; (a reintroduced branch separates pass from fail). Purnal names the lineage outright [@clangover].&lt;/p&gt;

flowchart TD
    A[&quot;Attacker crafts a ciphertext near a decryption-failure boundary&quot;]
    B[&quot;Victim decapsulates with the reused secret key&quot;]
    C[&quot;Re-encrypt-and-compare runs on secret-derived data&quot;]
    D{&quot;Side channel reveals pass or fail?&quot;}
    E[&quot;Record one bit about the secret key&quot;]
    F[&quot;Update the secret-key estimate&quot;]
    G[&quot;Full secret key recovered&quot;]
    A --&amp;gt; B --&amp;gt; C --&amp;gt; D
    D --&amp;gt;|leak observed| E --&amp;gt; F
    F --&amp;gt;|repeat with a new ciphertext| A
    F --&amp;gt;|enough bits gathered| G
&lt;p&gt;Here is the point that has to be stated precisely, because it is the most common misreading of ML-KEM.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Implicit rejection means a re-encryption mismatch returns a pseudorandom shared secret, not an error [@fips203]. There is no caller-visible reject to query, so the FO transform hands an attacker no oracle by construction. Every real oracle in this article is a side-channel leak in the re-encryption and comparison -- timing, power, electromagnetic, or fault -- never a signal the protocol emits.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the FO transform&apos;s mathematics never failed. It is machine-checked [@fvk]. What &quot;failed&quot; is subtler and more interesting: the construction that earns the security proof is precisely the construction that forces secret-dependent computation to run at decapsulation time. The proof guarantees the &lt;em&gt;values&lt;/em&gt; leak nothing. It cannot guarantee the &lt;em&gt;execution&lt;/em&gt; leaks nothing, because guaranteeing that was never the mathematician&apos;s job -- it is the implementer&apos;s. The armor and the wound are the same lines of code.&lt;/p&gt;
&lt;p&gt;If timing and compiler leaks feed this oracle, the natural next move is to attack a different channel entirely: mask the implementation so that power and electromagnetic measurements reveal nothing either. That worked. Until the defense became the surface.&lt;/p&gt;
&lt;h3&gt;Layer 4 -- the countermeasure: masking, and Carry Your Fault&lt;/h3&gt;
&lt;p&gt;The last layer out is the defense itself. If timing and compiler channels can be closed, the remaining physical threat is an attacker with an oscilloscope or an electromagnetic probe against a device in hand. The standard answer is masking.&lt;/p&gt;

Masking splits every secret into $t+1$ random shares whose combination recovers the secret, so that any $t$ probes of the circuit are statistically independent of it -- the guarantee of the Ishai-Sahai-Wagner probing model. Linear operations stay cheap per share; the expensive part in Kyber is the nonlinear Arithmetic-to-Boolean (A2B) conversion needed because the scheme mixes arithmetic modulo $q$ with bitwise operations. Masking is the primary defense against power and electromagnetic analysis [@masking-kyber].
&lt;p&gt;Masking is not busywork or redundancy.Constant-time execution closes the timing channel; masking closes the power and electromagnetic channel. They defend different physics, so a device facing a physical adversary needs both. Neither subsumes the other [@masking-kyber]. First- and higher-order masked implementations of Kyber are a mature line of work [@masking-kyber]. And this is where the frontier does something remarkable: it marches one layer further and turns the countermeasure into the target.&lt;/p&gt;

A fault-injection attack deliberately corrupts a computation -- with a voltage or clock glitch, a laser, or an electromagnetic pulse -- and infers secrets from how the wrong result differs from the right one. It is a different threat from passive measurement: the attacker actively perturbs the device rather than only observing it [@carry-fault].
&lt;p&gt;Carry Your Fault, published by Kundu and colleagues in 2024, does exactly this [@carry-fault]. The A2B conversion that masking requires is built on an adder with a carry chain. Inject a fault into that carry chain -- the very component added to &lt;em&gt;enable&lt;/em&gt; masking -- and its data-dependent propagation leaks information about the secret. Using belief propagation over the faulted values, the attack recovers keys from Kyber masked to &lt;em&gt;arbitrary order&lt;/em&gt;, validated with electromagnetic fault injection on an STM32 microcontroller [@carry-fault]. Read that again: no masking order defeats it, because the attack feeds on a structure that higher-order masking only makes larger.&lt;/p&gt;
&lt;p&gt;It is not an isolated result. Deep-learning side-channel analysis has defeated a masked &lt;em&gt;hardware&lt;/em&gt; implementation of Kyber [@ji-dubrova], and the surveys of the field confirm that the entire documented corpus of attacks on these schemes is implementation-class -- &lt;a href=&quot;https://paragmali.com/blog/correct-constant-time-and-still-owned-a-field-guide-to-side-/&quot; rel=&quot;noopener&quot;&gt;side channel and fault&lt;/a&gt;, not lattice [@sca-survey].&lt;/p&gt;
&lt;p&gt;So count the layers. The instruction leaked (Layer 1). The compiler leaked (Layer 2). The construction defined the surface (Layer 3). The countermeasure for that surface became the surface (Layer 4). Four layers out from the lattice, and the mathematics has not moved a single bit. That is not luck. It is the shape of the problem -- and the shape points straight at the fix.&lt;/p&gt;
&lt;h2&gt;5. The breakthrough: constant-time or it is not secure&lt;/h2&gt;
&lt;p&gt;Step back and the four layers share one address. Every break lives in the gap between what the specification promises about values and what the machine does during execution. The response to that, the actual breakthrough, is not a new theorem. It is a change in what counts as &quot;done.&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The armor that proves CCA security is exactly the code that leaks. So side-channel resistance cannot be an afterthought bolted onto a correct implementation -- it is a property the implementation must be built and verified to have, at the level of the binary that ships. Constant-time or it is not secure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For decades, constant-time execution was treated as a performance-adjacent nicety, a thing careful cryptographers did by hand and hoped the compiler respected. The ML-KEM breaks retire that attitude. The discipline has three prongs: treat data-obliviousness as a hard security requirement; move the guarantee into formally verified implementations; and build tooling that &lt;em&gt;checks&lt;/em&gt; the property instead of trusting it.&lt;/p&gt;
&lt;p&gt;That last prong is where the KyberSlash authors made their most durable contribution. Ordinary constant-time checkers had a blind spot. The lineage runs from Adam Langley&apos;s ctgrind in 2010 [@ctgrind], which repurposed Valgrind&apos;s uninitialized-memory tracking to flag secret-dependent branches, through TIMECOP&apos;s automated sweep of the SUPERCOP benchmark suite [@timecop], to dudect&apos;s black-box statistical timing test [@dudect] and the ct-verif formal verifier [@ctverif].&lt;/p&gt;
&lt;p&gt;But as the TIMECOP authors themselves note, Valgrind &quot;cannot spot cases where variable-time code is caused by variable-time CPU instructions&quot; [@timecop] -- which is precisely what a &lt;code&gt;DIV&lt;/code&gt; is. So the KyberSlash team patched Valgrind to flag variable-time &lt;em&gt;instructions&lt;/em&gt; operating on secret data, and ran it across more than 1000 implementations in SUPERCOP [@kyberslash-paper]. The tool now catches the exact class of bug that produced it.&lt;/p&gt;
&lt;p&gt;Why was the burden on implementers in the first place? Because the standard never claimed otherwise. As Cryspen puts it plainly:&lt;/p&gt;

The goal of the NIST specification is clarity and succinctness, not performance or even security concerns like side-channel resistance. -- Cryspen
&lt;p&gt;Side-channel resistance is the implementer&apos;s responsibility [@cryspen]. The breakthrough is not pretending otherwise -- it is making that responsibility mechanically checkable, so a leak is caught in continuous integration instead of in a paper two years later. And checking is something you can do yourself. The dudect method needs no source access at all: measure two populations of decapsulation timings, one for a fixed input and one for random inputs, and apply Welch&apos;s t-test. A large t-statistic means the timing depends on the data.&lt;/p&gt;
&lt;p&gt;{`
// dudect-style leak test: compare two timing populations with Welch&apos;s t.
// The dudect threshold: |t| above 10 is strong evidence of a timing leak.
// A deterministic generator keeps the demo reproducible.
let seed = 424242;
function rand() {
  seed = (1103515245 * seed + 12345) &amp;amp; 0x7fffffff;
  return seed / 0x7fffffff;
}&lt;/p&gt;
&lt;p&gt;function welchT(a, b) {
  const mean = xs =&amp;gt; xs.reduce((s, x) =&amp;gt; s + x, 0) / xs.length;
  const vary = (xs, m) =&amp;gt; xs.reduce((s, x) =&amp;gt; s + (x - m) * (x - m), 0) / (xs.length - 1);
  const ma = mean(a), mb = mean(b);
  const va = vary(a, ma), vb = vary(b, mb);
  return (ma - mb) / Math.sqrt(va / a.length + vb / b.length);
}&lt;/p&gt;
&lt;p&gt;function measure(n, leaks) {
  const fixedClass = [], randomClass = [];
  for (let i = 0; i &amp;lt; n; i++) {
    const noise = rand() * 2;
    // A leaking build spends extra cycles on the fixed-input class.
    fixedClass.push(100 + noise + (leaks ? 6 : 0));
    randomClass.push(100 + rand() * 2);
  }
  return welchT(fixedClass, randomClass);
}&lt;/p&gt;
&lt;p&gt;console.log(&quot;leaking build     t =&quot;, measure(4000, true).toFixed(1), &quot; -&amp;gt; leak, |t| well above 10&quot;);
console.log(&quot;constant-time build t =&quot;, measure(4000, false).toFixed(1), &quot; -&amp;gt; no leak&quot;);
`}&lt;/p&gt;
&lt;p&gt;Discipline is a goal; a shipped binary is a fact. So how do you actually build an ML-KEM that does not leak, today?&lt;/p&gt;
&lt;h2&gt;6. State of the art: how a correct ML-KEM is built today&lt;/h2&gt;
&lt;p&gt;Here is the good news the catalog has earned: every one of those breaks has a known, shipping answer, and not one of the answers required touching the mathematics. The state of the art is not a single silver bullet. It is a stack of defensive layers, and it is useful to read them from nearest the math outward.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Division-free constant-time source.&lt;/strong&gt; The innermost fix is the one KyberSlash demanded: never divide by a public constant on a secret operand. Replace &lt;code&gt;/KYBER_Q&lt;/code&gt; with a fixed-point reciprocal multiplication -- multiply by a precomputed $\lceil 2^k / q \rceil$ and shift right by $k$ -- which is constant-cycle and frequently &lt;em&gt;faster&lt;/em&gt; than the &lt;code&gt;DIV&lt;/code&gt; it replaces. Replace secret-dependent branches with bit-masks and conditional moves. This is now the default in maintained libraries: the Go standard library&apos;s &lt;code&gt;crypto/mlkem&lt;/code&gt; [@go-mlkem], Google&apos;s BoringSSL, &lt;code&gt;filippo.io/mlkem768&lt;/code&gt;, and the PQClean AVX2 paths all ship division-free constant-time ML-KEM [@kyberslash-site].The vectorized AVX2 and NEON code paths never issued a scalar &lt;code&gt;DIV&lt;/code&gt; on secret data in the first place, so a KyberSlash-immune implementation existed in parallel the entire time [@kyberslash-site]. The bug was in the portable reference, not in the fast paths people actually deployed on servers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Formally verified implementations.&lt;/strong&gt; Constant-time source is necessary but, as Clangover proved, not sufficient. The stronger layer moves the guarantee into the binary. There are two mature routes. The first is verified assembly: the formosa-crypto libjade project, built with Jasmin and EasyCrypt, ships assembly &quot;connected through computer-verified proofs to a cryptographic security notion,&quot; including constant-time proven of the emitted code itself [@libjade]. That closes the exact gap Clangover opened -- there is no optimizing compiler left to betray you -- though its latest release supports only the AMD64 architecture [@libjade].&lt;/p&gt;
&lt;p&gt;The second route is verified Rust: Cryspen&apos;s libcrux uses the hax toolchain and F* to machine-check correctness, memory safety, and source-level secret-independence, reusing verified code from HACL* [@libcrux][@haclstar].&lt;/p&gt;
&lt;p&gt;There is an important honesty in the libcrux documentation, and it is on-thesis. The repository states that &quot;executables compiled from the code in this repository are not verified to be side-channel resistant, although we try to enforce that the source code is secret-independent&quot; [@libcrux]. In other words, libcrux verifies the source, not yet the binary, and it is still pre-release.The verified-Rust effort that produced libcrux is the same effort that surfaced KyberSlash [@cryspen]. The tooling built to prove the code correct is what found the leak first -- the strongest possible argument for verification as a discipline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hardware timing guarantees.&lt;/strong&gt; As a backstop beneath the software, modern processors offer modes that guarantee operand-independent timing for a listed subset of instructions: Arm&apos;s Data-Independent Timing (DIT) register [@arm-dit] and Intel&apos;s Data Operand Independent Timing Mode (DOITM) [@intel-doitm]. These push part of the constant-time burden from the programmer to the silicon.Both are opt-in: the operating system or program must set the register or mode before the guarantee applies, and only the listed instructions are covered. Section 7 returns to their limits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Binary verification tooling.&lt;/strong&gt; Wrapping the whole stack is the checking discipline from Section 5: dudect for black-box statistical timing tests [@dudect], TIMECOP for automated SUPERCOP-wide sweeps [@timecop], ct-verif for formal constant-time verification [@ctverif], and the KyberSlash Valgrind patch for variable-time instructions on secret data [@kyberslash-paper]. Run them against the artifact you ship.&lt;/p&gt;

flowchart TD
    M[&quot;Unbroken Module-LWE mathematics&quot;]
    subgraph timing[&quot;Closes the timing channel&quot;]
        T1[&quot;Division-free constant-time source&quot;]
        T2[&quot;Verified assembly, proven at the binary&quot;]
        T3[&quot;Hardware DIT and DOITM backstop&quot;]
    end
    subgraph power[&quot;Closes the power and EM channel&quot;]
        P1[&quot;Masking with t+1 shares&quot;]
    end
    subgraph fault[&quot;Closes the fault channel&quot;]
        FA[&quot;Redundancy and fault detection&quot;]
    end
    M --&amp;gt; timing
    M --&amp;gt; power
    M --&amp;gt; fault
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Verify the binary you ship, not the source you wrote. KyberSlash lived in a source-level division operator; Clangover lived in compiler output that no source review would catch. Every layer here is ultimately about making a guarantee that holds of the instructions that actually execute [@kyberslash-paper].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Notice what is absent from the entire stack: any change to Module-LWE, any new hardness assumption, any adjustment to the parameter sets. The mathematics was never the problem, so it is not part of the fix. But these layers are not free, and they do not all defend the same thing. Choosing among them is its own problem.&lt;/p&gt;
&lt;h2&gt;7. Competing approaches: what each defense actually buys&lt;/h2&gt;
&lt;p&gt;There is no single winner here, and pretending otherwise is how deployments end up with the wrong protection. Each layer answers a different threat model at a different cost with a different strength of guarantee. Lay them side by side and no column is all-yes.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Defense&lt;/th&gt;
&lt;th&gt;Channel closed&lt;/th&gt;
&lt;th&gt;Guarantee&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Platform scope&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Constant-time source&lt;/td&gt;
&lt;td&gt;Timing&lt;/td&gt;
&lt;td&gt;Self-asserted, source only&lt;/td&gt;
&lt;td&gt;Near zero&lt;/td&gt;
&lt;td&gt;Portable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verified assembly (libjade) [@libjade]&lt;/td&gt;
&lt;td&gt;Timing&lt;/td&gt;
&lt;td&gt;Proven at the binary&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;AMD64 only in latest release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verified Rust (libcrux) [@libcrux]&lt;/td&gt;
&lt;td&gt;Timing (source)&lt;/td&gt;
&lt;td&gt;Machine-checked source, binary not yet claimed&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Portable, pre-release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Masking [@masking-kyber]&lt;/td&gt;
&lt;td&gt;Power and EM&lt;/td&gt;
&lt;td&gt;Probing model of order $t$&lt;/td&gt;
&lt;td&gt;Quadratic, $O(t^2)$&lt;/td&gt;
&lt;td&gt;Portable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fault countermeasures [@carry-fault]&lt;/td&gt;
&lt;td&gt;Fault&lt;/td&gt;
&lt;td&gt;Detection and redundancy&lt;/td&gt;
&lt;td&gt;Roughly 2x or more&lt;/td&gt;
&lt;td&gt;Portable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware DIT / DOITM [@arm-dit][@intel-doitm]&lt;/td&gt;
&lt;td&gt;Timing&lt;/td&gt;
&lt;td&gt;Operand-independent for listed instructions&lt;/td&gt;
&lt;td&gt;Near zero&lt;/td&gt;
&lt;td&gt;Specific microarchitectures&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Read across the rows and the trade-offs are stark. Constant-time source costs almost nothing but certifies nothing about the binary -- Clangover is the proof. Verified assembly gives the strongest timing guarantee anyone can offer, proven of the shipped code, but libjade&apos;s latest release is AMD64-only [@libjade], and most ML-KEM in the world runs on Arm phones and microcontrollers. Verified Rust is maintainable and machine-checks correctness and safety, but its authors do not yet claim binary-level constant-time [@libcrux].&lt;/p&gt;
&lt;p&gt;The physical-defense rows trade differently. Masking is the &lt;em&gt;only&lt;/em&gt; layer that stops power and electromagnetic differential analysis, but it costs quadratically in the protection order [@masking-kyber] and, as Carry Your Fault showed, does not stop faults at any order [@carry-fault]. Fault countermeasures add redundancy and roughly double the work. Hardware DIT and DOITM are nearly free but cover only listed instructions on specific microarchitectures [@arm-dit][@intel-doitm].&lt;/p&gt;
&lt;p&gt;Which explains why different deployments make opposite choices, and are both right to.&lt;/p&gt;

A server or browser attacker cannot put an oscilloscope on your power rail or fire an electromagnetic pulse at your CPU. For that threat model the whole risk is timing, so a division-free constant-time implementation plus binary scanning is sufficient, and general-purpose stacks like the Go standard library and BoringSSL skip masking entirely [@kyberslash-site]. A smartcard, hardware security module, or embedded device sitting in an adversary&apos;s hand faces power, electromagnetic, and fault attacks directly, so it must add masking and fault countermeasures on top [@masking-kyber][@carry-fault]. Same primitive, same proof, opposite implementations -- because the threat models are opposite.
&lt;p&gt;The deepest tension in the table is between the two things you most want. Formal verification gives the strongest guarantee but is platform-scoped: the proof for x86-64 says nothing about the Arm build. Masking is essential against physical adversaries but is expensive and, alone, incomplete. No single implementation today is verified-constant-time at the binary, masked to high order, fault-resistant, and portable all at once. You assemble the stack from partial guarantees.&lt;/p&gt;
&lt;p&gt;Stack them all and you still hit walls -- and some of those walls are provable. So the honest next question is: what can side channels &lt;em&gt;not&lt;/em&gt; let you close?&lt;/p&gt;
&lt;h2&gt;8. Theoretical limits: what side channels can and cannot close&lt;/h2&gt;
&lt;p&gt;The limits in this story are strikingly asymmetric, and not one of them is a limit on the lattice.&lt;/p&gt;
&lt;p&gt;Timing is the easy one. Secret-independent execution is achievable at essentially zero asymptotic cost, because ML-KEM&apos;s compression divide was never necessary in the first place -- reciprocal multiplication is just as fast and constant-cycle. The &quot;lower bound&quot; on timing safety is therefore not a performance penalty but a matter of discipline plus verification. You can close the timing channel provably and for free.&lt;/p&gt;
&lt;p&gt;Masking is where the hard floors appear. Resisting an adversary who can probe $t$ intermediate values requires at least $t+1$ shares -- the Ishai-Sahai-Wagner probing-model bound -- and Kyber&apos;s nonlinear steps, the Arithmetic-to-Boolean conversions, scale as $\Theta(t^2)$ [@masking-kyber]. High-order masking is genuinely expensive, and no clever engineering buys it cheaply. Then comes the sharpest result of all, the one with the flavor of an impossibility theorem.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Carry Your Fault recovers keys from Kyber masked to arbitrary order [@carry-fault]. There is no protection order you can reach that also buys fault safety, because the attack feeds on the carry chain that masking itself introduces. Masking and fault resistance do not compose for free -- you must add fault countermeasures as a separate layer, and no amount of the first substitutes for the second.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Step back and the shape of the remaining danger becomes clear, and it is not what people expect.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The gap is coverage, not lattice hardness -- and the mathematics was never the problem. The unsolved risks are all gaps in what a guarantee covers: source versus binary (Clangover [@clangover]), platform versus platform (libjade proves AMD64, not your Arm build [@libjade]; DIT and DOITM cover only listed instructions), and channel versus channel (timing is not power is not fault). None of these gaps touches Module-LWE.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That last clause deserves the honesty the series is built on. The series thesis is that the mathematics &lt;em&gt;almost never&lt;/em&gt; causes the break, and &quot;almost never&quot; is doing real work: in other episodes, deployment defects were sometimes structural in a deeper way. For ML-KEM, as of publication, the lattice has simply not been reached -- and the two times anyone reached for it are themselves the strongest evidence.&lt;/p&gt;

In April 2024, Yilei Chen circulated a claimed polynomial-time quantum algorithm for lattice problems. Within days, informal peer review found a flaw: Hongxun Wu and, independently, Thomas Vidick identified a bug in Step 9, and Chen updated the paper to state that the claim does not hold [@chen2024][@quantuminsider]. The author withdrew it himself. In May 2026, Ming-Xing Luo posted a preprint claiming a polynomial-time quantum attack on Module-LWE and ML-KEM [@luo2026]. It has not been peer-reviewed and the author has not withdrawn it -- but named experts identified fatal flaws: Daniel Apon showed the attack&apos;s output is provably independent of the secret key, and Thomas Espitau found its central reduction dimensionally wrong and a supporting result fabricated [@postquantum-luo]. It is a reach that did not land -- and a weaker one than Chen&apos;s, because Chen retracted while Luo&apos;s claim has simply been refuted. ML-KEM is not considered broken.
&lt;p&gt;The genuine lattice question -- whether Module-LWE itself has an efficient attack -- is the subject of the companion article, &quot;How ML-KEM and ML-DSA Would Break: Module-LWE, Lattice Reduction, and the Correlated-Failure Problem.&quot; As of publication it remains open, and open is not the same as broken.&lt;/p&gt;
&lt;p&gt;So the frontier is parked at the countermeasure layer. Not because the mathematics is the next thing to fall, but because closing the last coverage gaps -- binary, platform, channel -- is genuinely unsolved. That is exactly where the research is.&lt;/p&gt;
&lt;h2&gt;9. Open problems: where the frontier is now&lt;/h2&gt;
&lt;p&gt;The unsolved problems in ML-KEM security are, almost without exception, engineering problems. That is itself the thesis, restated as a research agenda.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One artifact, all three guarantees.&lt;/strong&gt; The clearest open problem is a single machine-checked implementation that is provably constant-time &lt;em&gt;and&lt;/em&gt; masked &lt;em&gt;and&lt;/em&gt; fault-resistant, portably, at production scale. Today you assemble those from different tools -- a verified-assembly timing proof here, a masked gadget there, a fault countermeasure bolted on -- and trust that the composition holds. Carry Your Fault is the standing warning that it may not: the pieces can each be correct and still leak at their seams [@carry-fault].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The compiler as an unquantified adversary.&lt;/strong&gt; Clangover is a specific bug in specific Clang versions, but the phenomenon is general [@clangover]. There is no widely deployed guarantee that an optimizing compiler &lt;em&gt;preserves&lt;/em&gt; a source-level constant-time property through arbitrary transformations. &quot;Constant-time preservation&quot; as a compiler discipline is an active research direction, not a solved feature you can switch on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Portable verification.&lt;/strong&gt; The strongest proofs are architecture-bound. Verified assembly covers AMD64; hardware timing modes cover listed instructions on particular cores. Yet the most-deployed ML-KEM in the world runs on Arm phones and Cortex-M microcontrollers -- exactly the targets KyberSlash and Carry Your Fault attacked on real silicon [@carry-fault]. Closing the platform gap between where the proofs are and where the code runs is unsolved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hardware accelerators.&lt;/strong&gt; As ML-KEM moves into dedicated hardware, the side-channel surface moves with it. A masked &lt;em&gt;hardware&lt;/em&gt; implementation of Kyber has already fallen to deep-learning side-channel analysis [@ji-dubrova], and the surveys treat hardware side channels as an open, active area rather than a closed one [@sca-survey].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Migration and &lt;a href=&quot;https://paragmali.com/blog/q-day-has-not-happened-the-incident-already-has-harvest-now-/&quot; rel=&quot;noopener&quot;&gt;captured traffic&lt;/a&gt;.&lt;/strong&gt; The most realistic exposure needs no wild exploit at all.&lt;/p&gt;

An adversary records encrypted traffic today and stores it, betting on decrypting it in the future once cryptanalysis or a quantum computer catches up. Because captured ciphertext cannot be un-sent, any recording made now is a standing liability -- which is the entire motivation for migrating to post-quantum key exchange before a break exists [@cryspen].

Here is the sharp version of why implementation leaks matter even with the mathematics intact. Traffic protected by a hybrid ML-KEM handshake is being recorded now. If the implementation carrying that handshake leaks the key through a side channel, the recorded session is exposed -- no future quantum computer required. A live timing or fault leak in a deployed TLS or SSH path is the realistic threat, and it sits entirely in execution, not in the lattice [@cryspen].
&lt;p&gt;&lt;strong&gt;The lattice itself.&lt;/strong&gt; The one open problem that &lt;em&gt;is&lt;/em&gt; mathematical -- whether Module-LWE has an efficient attack -- is deliberately not this article&apos;s.That question is the whole subject of the companion piece, &quot;How ML-KEM and ML-DSA Would Break,&quot; which takes on how it breaks now, in the implementation, versus how it would break later, in the mathematics. As of publication it is open, and it is handed to the sibling.&lt;/p&gt;
&lt;p&gt;Research aside, you have to ship something on Monday. Here is the decision that survives all of the above.&lt;/p&gt;
&lt;h2&gt;10. What to actually do&lt;/h2&gt;
&lt;p&gt;The one sentence: pick an ML-KEM implementation that never divided on a secret or is formally verified, and verify the binary you actually ship. Everything else is refinement by threat model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;General-purpose software, no local physical adversary.&lt;/strong&gt; If you run on servers, browsers, or backends, an attacker cannot probe your power rail, so timing is your whole threat. Use a division-free constant-time implementation from a maintained source -- the Go standard library&apos;s &lt;code&gt;crypto/mlkem&lt;/code&gt; [@go-mlkem], Google&apos;s BoringSSL, &lt;code&gt;filippo.io/mlkem768&lt;/code&gt;, or an AVX2/NEON path [@kyberslash-site] -- and scan the binary with a patched Valgrind or TIMECOP [@timecop] and dudect [@dudect] in continuous integration. You do not need masking or fault countermeasures for this threat model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maximum timing assurance on x86-64.&lt;/strong&gt; If you want the strongest guarantee available, use verified assembly: libjade&apos;s constant-time property is proven of the emitted code, which is the only thing that closes the Clangover gap outright [@libjade]. Remember its latest release is AMD64-only.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maintainable high-assurance Rust.&lt;/strong&gt; libcrux gives machine-checked correctness and source-level secret-independence [@libcrux], with the caveat that it is pre-release and does not yet claim binary-level constant-time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Embedded, smartcard, or HSM with a physical adversary.&lt;/strong&gt; Stack the layers: division-free constant-time &lt;em&gt;and&lt;/em&gt; masking (sized to your threat, remembering the quadratic cost) &lt;em&gt;and&lt;/em&gt; fault detection (because arbitrary-order masking still falls to Carry Your Fault [@carry-fault]) &lt;em&gt;and&lt;/em&gt; hardware DIT or DOITM where available.&lt;/p&gt;
&lt;p&gt;The library map, at a glance:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Known-good&lt;/td&gt;
&lt;td&gt;Go &lt;code&gt;crypto/mlkem&lt;/code&gt; [@go-mlkem]&lt;/td&gt;
&lt;td&gt;Constant-time, upstreamed from &lt;code&gt;filippo.io/mlkem768&lt;/code&gt;, never divided&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Known-good&lt;/td&gt;
&lt;td&gt;BoringSSL, &lt;code&gt;filippo.io/mlkem768&lt;/code&gt;, PQClean AVX2 [@kyberslash-site]&lt;/td&gt;
&lt;td&gt;Never issued a secret-operand &lt;code&gt;DIV&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Known-good&lt;/td&gt;
&lt;td&gt;formosa-crypto libjade [@libjade]&lt;/td&gt;
&lt;td&gt;Verified-assembly constant-time on AMD64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Known-good, pre-release&lt;/td&gt;
&lt;td&gt;libcrux [@libcrux]&lt;/td&gt;
&lt;td&gt;Verified Rust, source secret-independent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patched reference&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pq-crystals/kyber&lt;/code&gt; portable C [@kyber-commit]&lt;/td&gt;
&lt;td&gt;Fixed December 2023; downstream forks may still lag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Known-bad&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pqc_kyber&lt;/code&gt; Rust crate [@rustsec]&lt;/td&gt;
&lt;td&gt;RUSTSEC-2023-0079, no patched versions; migrate off it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Rust &lt;code&gt;pqc_kyber&lt;/code&gt; crate carries RUSTSEC-2023-0079 for KyberSlash, rated CVSS 7.4 HIGH, and upstream released no patched versions [@rustsec]. It remains installable today. If it is anywhere in your dependency tree, migrate to the &lt;code&gt;ml-kem&lt;/code&gt; crate or the maintained &lt;code&gt;safe_pqc_kyber&lt;/code&gt; fork [@rustsec]. A deprecated-but-still-live dependency is the whole series thesis in miniature: the mathematics is fine, and the artifact you pulled from the registry is not.&lt;/p&gt;
&lt;/blockquote&gt;

Run `cargo audit` in your project: it flags RUSTSEC-2023-0079 when `pqc_kyber` appears anywhere in the graph [@rustsec]. To find what pulls it in, run `cargo tree -i pqc_kyber`, then swap in the `ml-kem` crate or the `safe_pqc_kyber` fork and re-run the audit until it comes back clean.
&lt;p&gt;Every pitfall in this article maps to a named incident and a concrete fix.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pitfall&lt;/th&gt;
&lt;th&gt;Incident it recreates&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Dividing a secret by &lt;code&gt;q&lt;/code&gt; in compression or decode&lt;/td&gt;
&lt;td&gt;KyberSlash [@kyberslash-paper]&lt;/td&gt;
&lt;td&gt;Reciprocal multiply; use a never-divided or AVX2 path; scan with patched Valgrind&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trusting constant-time C through the compiler&lt;/td&gt;
&lt;td&gt;Clangover [@clangover]&lt;/td&gt;
&lt;td&gt;Verify the binary; prefer verified assembly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Masking without fault countermeasures&lt;/td&gt;
&lt;td&gt;Carry Your Fault [@carry-fault]&lt;/td&gt;
&lt;td&gt;Add fault detection and redundancy as a separate layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Depending on an unpatched crate&lt;/td&gt;
&lt;td&gt;RUSTSEC-2023-0079 [@rustsec]&lt;/td&gt;
&lt;td&gt;Migrate to &lt;code&gt;ml-kem&lt;/code&gt; or &lt;code&gt;safe_pqc_kyber&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Finally, deploy hybrid.The hybrid group &lt;code&gt;X25519MLKEM768&lt;/code&gt; runs a classical elliptic-curve exchange and ML-KEM together. By construction the session stays secure as long as either component does [@tls-hybrid], so it hedges a future lattice break and a present implementation bug in the other component at the same time. A hybrid handshake is the one move that protects you against both the break that has not happened to the math and the break that already happened to the code.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Ship a division-free or formally verified ML-KEM, verify the binary you actually deploy, add masking and fault countermeasures only when a physical adversary can touch the device, and deploy hybrid so you stay secure if either half holds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Do that and you have closed every gap anyone has actually walked through. The questions that remain are the ones readers always ask.&lt;/p&gt;
&lt;h2&gt;11. Frequently asked questions&lt;/h2&gt;
&lt;p&gt;A few misconceptions come up every time this material is discussed. Here they are, answered against the primary sources.&lt;/p&gt;


No. As of publication its Module-LWE mathematics is intact and its IND-CCA2 security has been machine-checked [@fips203][@fvk]. Every documented break is an implementation or side-channel attack against specific code -- a division instruction, a compiler optimization, a fault in a countermeasure -- not a weakness in the primitive itself.


No. Two prominent claims reached for the lattice mathematics and both failed review. Yilei Chen&apos;s 2024 quantum algorithm was withdrawn after Hongxun Wu and Thomas Vidick found a bug in Step 9 [@chen2024]. A 2026 preprint by Ming-Xing Luo was refuted by named experts, who showed the attack&apos;s output is provably independent of the secret key [@luo2026][@postquantum-luo]. No quantum machine has broken ML-KEM, and none is known to exist that could.


It has a CVE-class advisory but no NVD number. The record is RUSTSEC-2023-0079 against the `pqc_kyber` crate, rated CVSS 7.4 HIGH [@rustsec]. The disclosure and reference patches were December 2023 [@kyber-commit], and the full paper appeared at IACR TCHES in 2025 [@kyberslash-paper].


Not by construction. A re-encryption mismatch returns a pseudorandom shared secret, not an error, so there is no caller-visible rejection to query [@fips203]. The oracle in every real attack is a side-channel leak in the re-encryption and comparison -- timing, power, electromagnetic, or fault -- never a signal the protocol emits.


There is no documented in-the-wild exploitation of a production ML-KEM deployment as of publication. The breaks are vulnerable code shipping in libraries, CVE-class advisories, and researcher proof-of-concept key recovery on real hardware [@kyberslash-paper].


No. Masking stops power and electromagnetic analysis but not faults: Carry Your Fault recovers keys from masking of arbitrary order [@carry-fault], and masked hardware has fallen to deep-learning side-channel analysis. A device facing a physical adversary needs constant-time execution and masking and fault countermeasures together.


Yes, with care. Pick an implementation that never divided on a secret or is formally verified, verify the binary you ship, add masking and fault countermeasures only for physical-adversary threat models, and deploy a hybrid group such as `X25519MLKEM768` so you stay secure if either half holds [@tls-hybrid].

&lt;p&gt;Count the layers one last time. The instruction leaked; the compiler leaked; the construction defined the surface; the countermeasure became the surface. Four steps outward from the lattice, and the Module-LWE mathematics never moved -- its security proof machine-checked, its two attempted quantum breaks both failed under expert scrutiny (Chen withdrew his claim; Luo&apos;s was refuted by named experts) [@fvk][@chen2024][@postquantum-luo]. The mathematics almost never caused the break. The deployment did: the reference division, the compiler&apos;s optimization, the unpatched crate, the fault through the mask. The frontier is still marching outward, and the day it finally reaches the lattice is the subject of the companion article, &quot;How ML-KEM and ML-DSA Would Break.&quot; Until then, the same law that spared the AES cipher for two decades while its implementations leaked keys to a stopwatch now governs the first post-quantum KEM.&lt;/p&gt;

The machine leaked while the math held. That is not a footnote to ML-KEM&apos;s security -- as of publication, it is the entire story of how it breaks.
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;how-ml-kem-breaks-in-real-life&quot; keyTerms={[
  { term: &quot;Key Encapsulation Mechanism (KEM)&quot;, definition: &quot;A protocol for agreeing on a shared secret; ML-KEM is the FIPS 203 standard.&quot; },
  { term: &quot;Module-LWE&quot;, definition: &quot;The lattice problem ML-KEM&apos;s security rests on; unbroken as of publication.&quot; },
  { term: &quot;Fujisaki-Okamoto transform&quot;, definition: &quot;The re-encrypt-and-compare construction that makes ML-KEM CCA-secure.&quot; },
  { term: &quot;Implicit rejection&quot;, definition: &quot;On a re-encryption mismatch, decapsulation returns a pseudorandom secret, not an error.&quot; },
  { term: &quot;KyberSlash&quot;, definition: &quot;A December 2023 secret-dependent division-timing leak in reference Kyber code.&quot; },
  { term: &quot;Clangover&quot;, definition: &quot;A compiler-introduced secret branch that defeats source-level constant-time code.&quot; },
  { term: &quot;Plaintext-checking oracle&quot;, definition: &quot;A pass-or-fail side-channel leak that reconstructs a reused secret key.&quot; },
  { term: &quot;Constant-time execution&quot;, definition: &quot;Behavior independent of secret data; a property of the shipped binary, not the source.&quot; },
  { term: &quot;Masking&quot;, definition: &quot;Splitting secrets into t+1 shares to resist power and electromagnetic analysis.&quot; },
  { term: &quot;Carry Your Fault&quot;, definition: &quot;A fault on the A2B carry chain that defeats masking of arbitrary order.&quot; }
]} questions={[
  { q: &quot;Why does a machine-checked security proof not prevent key recovery?&quot;, a: &quot;The proof constrains values, not execution; keys leak through timing, compiler output, power, or faults.&quot; },
  { q: &quot;What single surface underlies KyberSlash, Clangover, and the PC-oracle attacks?&quot;, a: &quot;The Fujisaki-Okamoto re-encrypt-and-compare step, which must run on secret-derived data.&quot; },
  { q: &quot;Does masking alone protect an embedded device?&quot;, a: &quot;No; it stops power and EM analysis but not faults, so fault countermeasures are also required.&quot; },
  { q: &quot;What deployment hedges both a math break and an implementation bug?&quot;, a: &quot;A hybrid handshake such as X25519MLKEM768, which stays secure if either component holds.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>post-quantum-cryptography</category><category>ml-kem</category><category>kyber</category><category>side-channel-attacks</category><category>constant-time</category><category>kyberslash</category><category>fujisaki-okamoto</category><category>implementation-security</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Q-Day Has Not Happened. The Incident Already Has: Harvest Now, Decrypt Later</title><link>https://paragmali.com/blog/q-day-has-not-happened-the-incident-already-has-harvest-now-/</link><guid isPermaLink="true">https://paragmali.com/blog/q-day-has-not-happened-the-incident-already-has-harvest-now-/</guid><description>No quantum computer can break RSA in 2026, yet long-lived secrets encrypted today may already be lost. Harvest now, decrypt later is a deployment failure.</description><pubDate>Sat, 18 Jul 2026 00:00:00 GMT</pubDate><content:encoded>
No quantum computer can break RSA or ECC in 2026 -- and yet a long-lived secret you encrypt today may already be lost. The reason is **harvest now, decrypt later**: an adversary who records your encrypted traffic now has done the decisive, irreversible part, and a future quantum computer only finishes the job [@apple-pq3]. That makes the casualty a *deployment* choice -- protecting must-outlive-Q-Day data with a deprecated-but-still-live algorithm -- not a math break that has happened, and the fix (hybrid X25519 + ML-KEM key establishment) is executable today [@ietf-mlkem]. You cannot un-capture ciphertext, so the only defense is to change the deployment before the recording is made.
&lt;h2&gt;1. Q-Day Has Not Happened. The Incident Already Has&lt;/h2&gt;
&lt;p&gt;In 2026, no quantum computer on Earth can factor a 2048-bit RSA key. Not one. The cryptographers who design these systems will tell you so plainly, and they are right: RSA-2048 is unbroken, and the machine that would break it does not exist -- the most recent published analysis still describes hardware that has not been built [@gidney-2025]. And yet a secret you encrypt this morning, if it must stay secret for a decade, may already be lost.&lt;/p&gt;
&lt;p&gt;That is not a contradiction. It is the whole story.&lt;/p&gt;
&lt;p&gt;The adversary&apos;s decisive act is not decryption. It is capture. Someone who records your encrypted traffic today -- the key-exchange handshake and the ciphertext that follows -- has already done the irreversible part. The decryption can wait for a machine that arrives in five years, or fifteen, or thirty. This is the attack the security community calls &lt;strong&gt;harvest now, decrypt later&lt;/strong&gt;, and the United States government now states its rationale in an executive order, warning of &quot;adversaries collecting United States information now, and decrypting it later once large-scale quantum computers are operational&quot; [@eo-14412]. Apple&apos;s engineers put the mechanics even more plainly.&lt;/p&gt;

Attackers &quot;can collect large amounts of today&apos;s encrypted data and file it all away for future reference ... retain it until they acquire a quantum computer that can decrypt it in the future, an attack scenario known as Harvest Now, Decrypt Later.&quot; -- Apple Security Engineering and Architecture [@apple-pq3]

An attack in which an adversary records encrypted traffic today -- the key-establishment handshake plus the ciphertext -- and stores it indefinitely, planning to decrypt it once a capable quantum computer exists. The decisive act is the capture, not the decryption, so the loss is decided at the moment of recording [@apple-pq3].

A quantum computer large enough and error-corrected enough to run Shor&apos;s algorithm against deployed public-key sizes such as RSA-2048 or Curve25519. No CRQC exists in 2026; the published figures for the qubits one would require are estimates on hardware that has not been built [@gidney-2025].

flowchart LR
    A[Today: adversary records handshake and ciphertext] --&amp;gt; B[Indefinite storage]
    B --&amp;gt; C[Q-Day: a CRQC runs Shor&apos;s algorithm]
    C --&amp;gt; D[Ciphertext decrypted]
    A -. the decisive, irreversible act .-&amp;gt; D
&lt;p&gt;So the clock that matters is not &quot;when does Q-Day arrive?&quot; but &quot;how long must this secret survive, and was it captured before I protected it?&quot; The cryptographer Michele Mosca turned that question into an inequality years ago, and we will spend a whole section on it, because it is the spine of everything here: if the lifetime of your secret plus the time you need to migrate exceeds the time until a capable quantum computer exists, you are already exposed [@mosca-2018].&lt;/p&gt;
&lt;p&gt;This is why this article belongs in a series about how cryptography breaks in real life -- and why it is the strangest entry in it. Every other casualty here is a break you can point to after the fact: a reused nonce, a padding oracle, a downgrade. This one is different in time. The mathematical weapon does not exist yet, and still the loss is being booked. That is the reconciliation this whole piece defends: the break is not a mathematical event that has happened. It is a &lt;strong&gt;deployment choice&lt;/strong&gt; -- protecting data that must outlive Q-Day with a quantum-vulnerable, deprecated-but-still-live algorithm while someone records the ciphertext. The math finishes the job later. The deployment decides the outcome now.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The loss is booked at capture time. Because an adversary who records your ciphertext today has already done the irreversible part, the casualty is decided by the deployment you shipped -- a quantum-vulnerable algorithm protecting data that must outlive Q-Day -- not by a mathematical break that has occurred.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One boundary before we begin. This is a story about &lt;strong&gt;confidentiality&lt;/strong&gt;: recorded ciphertext, decrypted after capture. It is not the story of quantum forgery of digital signatures, which is a different problem on a different clock, and which we will keep scrupulously separate throughout. The mechanism of the eventual break -- how one machine running Shor&apos;s algorithm flattens RSA, Diffie-Hellman, and ECC at once -- is the subject of this article&apos;s structural sibling, &quot;&lt;a href=&quot;https://paragmali.com/blog/how-q-day-breaks-everything-shors-algorithm-and-the-simultan/&quot; rel=&quot;noopener&quot;&gt;How Q-Day Breaks Everything: Shor&apos;s Algorithm and the Simultaneous Fall of RSA, Diffie-Hellman, and ECC&lt;/a&gt;.&quot; Here we need only its conclusion.&lt;/p&gt;
&lt;p&gt;If the loss is booked the moment the ciphertext is captured, then the only question that matters is what you were doing at capture time. To answer it, we have to see that this idea is older than quantum computing.&lt;/p&gt;
&lt;h2&gt;2. &quot;Store Now, Decrypt Later&quot; Is Older Than Quantum&lt;/h2&gt;
&lt;p&gt;Long before anyone wired a lattice into TLS, intelligence agencies were already doing the first half of harvest now, decrypt later -- the harvesting. The behavior the quantum threat depends on is not speculative; it is documented, and it predates the quantum motive by years.&lt;/p&gt;
&lt;p&gt;In March 2012, James Bamford reported in &lt;em&gt;Wired&lt;/em&gt; that the National Security Agency was building a data center in Bluffdale, Utah -- roughly one million square feet built to intercept and store communications at a scale discussed in exabytes and beyond [@bamford]. The next year, the documents Edward Snowden supplied to journalists revealed Bullrun, a program to defeat and circumvent internet encryption alongside bulk interception and indefinite retention [@bullrun]. The through-line of both is the same: collect broadly, store indefinitely, and revisit the ciphertext later as your ability to read it improves.&lt;/p&gt;

The length of time a piece of data must remain secret to avoid harm. A session cookie has a confidentiality lifetime of minutes; a diplomatic cable, an intelligence source&apos;s identity, or a person&apos;s genome may need to stay secret for decades. It is the single most load-bearing quantity in the harvest-now-decrypt-later argument, because it decides whether a future decryption still matters.
&lt;p&gt;Quantum computing did not invent this behavior. What it changed is the horizon. It introduced a specific future event -- a machine that can run Shor&apos;s algorithm -- that would retroactively unlock everything already collected under a quantum-vulnerable algorithm.&lt;/p&gt;
&lt;p&gt;In 2015, and again in a 2018 journal version, Michele Mosca gave that horizon a decision rule. If $X$ is how long your data must stay secret, $Y$ how long your migration takes, and $Z$ the time until a capable quantum computer exists, then whenever $X + Y &amp;gt; Z$ you are already too late for that data [@mosca-2015]. He stated the corollary this article turns on in the same breath: &quot;for systems that aim to provide long-term confidentiality, this migration should happen even sooner&quot; [@mosca-2015]. The formal statement followed in &lt;em&gt;IEEE Security &amp;amp; Privacy&lt;/em&gt; [@mosca-2018].&lt;/p&gt;
&lt;p&gt;Here is where honesty matters more than rhetoric. It is tempting to collapse all of this into one dramatic claim -- &quot;adversaries are harvesting your traffic right now for quantum decryption&quot; -- that the public evidence does not support at that strength. The responsible version is layered.&lt;/p&gt;

flowchart TD
    A[Documented threat model: NSA, CISA, NIST, EO 14412] --&amp;gt; D[HNDL risk to long-lived data]
    B[Documented general collect-and-store precedent: Utah Data Center 2012, Bullrun 2013] --&amp;gt; D
    C[Rational-actor inference for the specifically quantum motive: no public smoking gun] --&amp;gt; D

The &quot;adversary is recording now&quot; premise is three separate claims, and they do not carry equal weight.&lt;p&gt;&lt;strong&gt;(a) A documented threat model.&lt;/strong&gt; The agencies that set cryptographic policy -- NSA, CISA, and NIST jointly, and now an executive order -- name harvest now, decrypt later explicitly and build the entire migration around it [@cisa-qr] [@eo-14412] [@nsa-press].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(b) A documented general precedent.&lt;/strong&gt; Bulk interception and indefinite retention of encrypted traffic are established, documented practices, independent of quantum computing [@bamford] [@bullrun].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(c) A rational-actor inference.&lt;/strong&gt; That some adversary is &lt;em&gt;specifically&lt;/em&gt; recording ciphertext today &lt;em&gt;in order to&lt;/em&gt; await a quantum computer is a reasonable inference from (a) and (b) -- it is exactly what a well-resourced intelligence agency would do -- but it remains an inference. There is no public smoking gun: no attributed, confirmed nation-state quantum-harvest program on the record. The argument does not need one. It needs only that the behavior is cheap, documented in general form, and officially treated as the reason to migrate.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Recent events keep the general precedent current without proving the quantum-specific one. The Salt Typhoon campaign, detailed in a 2025 joint advisory, compromised the lawful-intercept infrastructure of U.S. telecommunications carriers [@cisa-salt].Salt Typhoon is espionage against wiretap systems -- interception of communications for conventional intelligence. It is not a quantum-harvest operation, and nothing in the advisory characterizes it as one. It belongs here only as evidence that broad, nation-state interception is ongoing.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Every claim in this article about &quot;harvesting now&quot; means the documented threat model, plus the documented general precedent, plus a rational-actor inference. It never means a proven, attributed, ongoing quantum-harvest operation, because none is public. The strength of the argument does not depend on one existing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mosca turned &quot;someday&quot; into an inequality you can run against your own data. But to run it, you first have to know exactly what a future quantum computer can and cannot touch -- because it is far less, and far more specific, than the word &quot;encryption&quot; suggests.&lt;/p&gt;
&lt;h2&gt;3. Why the Whole Public-Key Stack Is on the Clock -- and Symmetric Mostly Is Not&lt;/h2&gt;
&lt;p&gt;A single machine running Shor&apos;s algorithm would break RSA, finite-field Diffie-Hellman, DSA, and elliptic-curve cryptography -- all of them, together. The same machine would barely inconvenience AES-256. To see why the harvest targets one and not the other, and why that distinction is the difference between a five-minute fix and a decade-long migration, you have to separate two kinds of quantum speedup.&lt;/p&gt;

A quantum algorithm, published by Peter Shor in 1994, that factors integers and computes discrete logarithms in polynomial time [@shor-1994]. Because RSA rests on the hardness of factoring, and Diffie-Hellman and ECC rest on the hardness of discrete logarithms, one sufficiently large quantum computer running Shor breaks all of them at once. The full mechanism -- reducing both problems to quantum period-finding -- is developed in this article&apos;s structural sibling; here we use only the result [@shor-1997].
&lt;p&gt;The reason RSA, DH, DSA, and ECC fall as a group is that they are variations on the same mathematical trick: a one-way function built from a hidden period or a hidden subgroup. Shor&apos;s algorithm is, at its core, a period-finder. Break that abstraction once and every primitive built on it goes down with it -- which is why &quot;quantum-safe&quot; cannot mean &quot;a bigger RSA key.&quot; A 4096-bit RSA modulus falls to the same algorithm as a 2048-bit one; only the running time changes, and not by enough to matter [@shor-1997].&lt;/p&gt;
&lt;p&gt;Symmetric cryptography is a different story, and the difference is a theorem, not an accident. Against a symmetric cipher or a hash, the best known quantum attack is Grover&apos;s algorithm, which delivers only a quadratic speedup -- it effectively halves the security level. A 256-bit key offers roughly 128 bits of security against a quantum search, which is still far out of reach.Grover&apos;s quadratic speedup is neutralized by doubling the key or lengthening the digest, and symmetric crypto scales cheaply: doubling the key size typically costs far less than half again the performance [@cf-pq2024]. This is why AES-256 and SHA-384/512 need no replacement [@cnsa-2]. That is exactly why the NSA&apos;s post-quantum suite keeps AES-256 and SHA-384/512 unchanged while replacing every public-key algorithm [@cnsa-2], and why NIST pins its post-quantum security categories to symmetric strengths Grover cannot reach [@cf-pq2024].&lt;/p&gt;
&lt;p&gt;So the casualty is specific. It is not &quot;encryption&quot; in general. It is &lt;strong&gt;public-key key establishment&lt;/strong&gt;: the handshake step where two parties agree on the symmetric key that will actually encrypt the data.&lt;/p&gt;

The step in a secure protocol where two parties agree on a fresh shared secret -- the symmetric session key -- that encrypts the rest of the conversation. In TLS this is the key-exchange portion of the handshake. It travels in the clear, which is exactly why an adversary can record it, and it is the specific thing harvest now, decrypt later targets.
&lt;p&gt;Why key establishment and not the bulk-encrypted payload directly? Because the payload is protected by a symmetric key that Grover cannot recover -- but that key was itself agreed using a public-key exchange that Shor can break. Record the handshake and the ciphertext together, wait for a CRQC, run Shor against the recorded public values, recover the session key, and the whole conversation decrypts. The symmetric layer never had to fall; the key that unlocks it was handed over in a form the future machine can read.The same RSA or ECC key pair can serve key establishment (confidentiality) or signatures (authenticity). Only the confidentiality use is harvestable in advance. Signatures are a separate casualty, on a separate clock.&lt;/p&gt;
&lt;p&gt;This sets the contract for the rest of the article, and it is a contract with two clocks.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;strong&gt;Confidentiality (harvest now, decrypt later).&lt;/strong&gt; An adversary records ciphertext today and decrypts it after a future CRQC exists. The decisive act is now; the fix is post-quantum key establishment, deployable today. &lt;strong&gt;Authenticity (signature forgery).&lt;/strong&gt; An adversary forges a signature. This requires a quantum computer &lt;em&gt;at the moment of the attack&lt;/em&gt; -- you cannot forge tomorrow&apos;s signature by recording today&apos;s traffic. It is a real problem, but a later one, on a different clock. The two never share a single verdict.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The confidentiality casualty, then, is narrow and precise: public-key key establishment, recorded today, decrypted after Q-Day. The next question is what defenders did once they understood that -- and it turns out they have been racing this particular recording for the better part of a decade.&lt;/p&gt;
&lt;h2&gt;4. The Defense, Generation by Generation, Racing the Harvest&lt;/h2&gt;
&lt;p&gt;Here the usual shape of a &quot;how it breaks&quot; story inverts. There is no lineage of attacks to catalog, because the attack is future and singular -- one machine, not yet built. What has a lineage is the &lt;em&gt;defense&lt;/em&gt;. And the first entry in that lineage is not a defense at all. It is the status quo, and its weakness is this article&apos;s entire thesis.&lt;/p&gt;
&lt;h3&gt;Generation 0: the harvestable baseline&lt;/h3&gt;
&lt;p&gt;Classical public-key key establishment -- RSA key transport, and in modern TLS 1.3 the elliptic-curve exchange X25519 -- is where the loss is booked. Two parties derive a shared secret from public values whose security rests on factoring or the discrete logarithm; the handshake, including those public values, crosses the wire in the clear.&lt;/p&gt;
&lt;p&gt;Modern TLS already improved on the worst version of this. Ephemeral elliptic-curve Diffie-Hellman gives &lt;a href=&quot;https://paragmali.com/blog/nobody-broke-the-discrete-log-a-field-guide-to-diffie-hellma/&quot; rel=&quot;noopener&quot;&gt;forward secrecy&lt;/a&gt;.&lt;/p&gt;

A property of ephemeral key exchange: because each session&apos;s secret is generated fresh and never transmitted, compromising a server&apos;s long-term private key later does not decrypt past recorded sessions. It defends against a future *key* compromise -- but not against a future break of the underlying *math*.
&lt;p&gt;That last distinction is the whole game. Forward secrecy assumes the discrete-logarithm problem stays hard; Shor voids that assumption. As Cloudflare put it, encrypted traffic &quot;can be harvested today, and decrypted with a quantum computer in the future&quot; -- and against that recording, even forward secrecy does not help [@cf-pq2024]. An adversary who records the X25519 handshake plus the ciphertext has everything needed to recover the session key once a CRQC exists: Mosca&apos;s inequality booking a loss the moment $X + Y &amp;gt; Z$ [@mosca-2018]. Gen 0 is not broken today -- RSA-2048 is unbroken in 2026 -- but protecting must-outlive-Q-Day data with it while the recording runs is the deployment choice that decides the casualty.&lt;/p&gt;
&lt;p&gt;If the loss is booked at capture time, the defense cannot wait for Q-Day. It has to put a quantum-resistant secret into the handshake &lt;em&gt;before&lt;/em&gt; the recording is made.&lt;/p&gt;
&lt;h3&gt;Generation 1: the first hybrids&lt;/h3&gt;
&lt;p&gt;In 2016, Google ran the first real experiment: CECPQ1, a combination of X25519 with NewHope, a lattice key exchange, deployed live in Chrome and TLS by Matt Braithwaite and Adam Langley [@google-cecpq1] [@newhope].CECPQ stands for Combined Elliptic-Curve and Post-Quantum. The design principle is right there in the name: run both, and be no worse off than before even if the post-quantum half turns out to be worthless. Two years later came CECPQ2, pairing X25519 with an NTRU-based lattice scheme, HRSS [@langley-cecpq2].&lt;/p&gt;
&lt;p&gt;The idea both shared is the one the entire lineage inherits: run a classical and a post-quantum exchange side by side and combine both secrets, so the session is no worse than before even if the post-quantum part is later found useless. Langley&apos;s rationale for shipping years ahead of any standard was itself a harvest-now-decrypt-later argument, and he drew the confidentiality-versus-authenticity line this article insists on, noting that the work &quot;only addresses confidentiality, not authenticity,&quot; and that &quot;confidentiality is more pressing since it can be broken retrospectively&quot; [@langley-cecpq2].&lt;/p&gt;
&lt;p&gt;NewHope, CECPQ1&apos;s post-quantum half, was only CPA-secure -- a weaker guarantee than usual. That was acceptable in TLS precisely because confidentiality keys there are ephemeral, used once and discarded [@newhope].&lt;/p&gt;
&lt;p&gt;These were experiments, built to be thrown away. They used pre-standard primitives chosen before NIST had settled the field -- &quot;destined to be replaced,&quot; in Langley&apos;s words [@langley-cecpq2]. What they proved is that a hybrid can ride real TLS at scale, surfacing the practical problems (larger handshakes, middlebox tolerance) that would dominate deployment. The field now needed a single, vetted primitive to put inside the hybrid.&lt;/p&gt;
&lt;h3&gt;Generation 2: the standardized primitive&lt;/h3&gt;
&lt;p&gt;On 13 August 2024, NIST published FIPS 203, standardizing &lt;a href=&quot;https://paragmali.com/blog/one-event-three-assumptions-five-answers-a-field-guide-to-th/&quot; rel=&quot;noopener&quot;&gt;ML-KEM&lt;/a&gt; -- the primitive every later deployment instantiates [@fips-203].&lt;/p&gt;

The Module-Lattice-Based Key-Encapsulation Mechanism, standardized as NIST FIPS 203 on 13 August 2024, based on the Module Learning-With-Errors problem. It comes in three parameter sets -- ML-KEM-512, ML-KEM-768, and ML-KEM-1024 -- and it is a key-encapsulation mechanism, explicitly not a Diffie-Hellman-style non-interactive key agreement [@fips-203].
&lt;p&gt;&quot;ML-KEM is the new name for Kyber&quot; [@cf-pq2024]. The scheme was called CRYSTALS-Kyber during the NIST competition; in a 2026 voice the standardized name is ML-KEM, and that is the name used throughout here.&lt;/p&gt;
&lt;p&gt;The structural point that shapes everything downstream: ML-KEM is a KEM, not a NIKE. Rather than two parties deriving a key from public values with no message in between (which is what Diffie-Hellman does), one party encapsulates a fresh secret to the other&apos;s public key and sends back a ciphertext. That single fact is why the deployed answer is a hybrid &lt;em&gt;handshake&lt;/em&gt; and not a drop-in &quot;post-quantum Diffie-Hellman.&quot; But a primitive sitting in a PDF protects no packet, and ML-KEM deployed alone is a single-primitive bet on a young standard -- a bet the next section shows can go badly. The prudent way to ship it is inside a hybrid.&lt;/p&gt;
&lt;h3&gt;Generation 3: protocol integration&lt;/h3&gt;
&lt;p&gt;This is where the standard becomes protection booked at capture time. For TLS 1.3, the IETF defined the hybrid group X25519MLKEM768: a client share of 1216 bytes -- a 1184-byte ML-KEM-768 encapsulation key concatenated with a 32-byte X25519 share -- combined into a 64-byte shared secret, at codepoint 0x11EC [@ietf-mlkem].&lt;/p&gt;
&lt;p&gt;Secure messaging moved even earlier. Signal shipped PQXDH, &quot;an upgrade to the X3DH specification,&quot; to all users on 19 September 2023 -- the first at-scale messenger to put post-quantum protection into initial key establishment [@signal-pqxdh]. Apple followed on 21 February 2024 with iMessage PQ3 [@apple-pq3]. And remote administration was not far behind: OpenSSH 9.9, released 2024-09-19, made the hybrid mlkem768x25519-sha256 exchange available by default [@openssh-99].&lt;/p&gt;
&lt;p&gt;Every one of these derives the session key from both an X25519 secret and an ML-KEM secret, so it stays secure if either component holds. Each session negotiated this way is one the harvest can no longer bank on. What integration did not yet deliver was ubiquity: in 2024 these were defaults on some clients and servers, not all, and the surfaces most likely to hold long-lived secrets lagged furthest behind.&lt;/p&gt;
&lt;h3&gt;Generation 4: scale&lt;/h3&gt;
&lt;p&gt;Then the defaults arrived. OpenSSL 3.5, released 8 April 2025, changed its default TLS groups to include and prefer hybrid post-quantum KEM groups [@openssl-35]. With Chrome and Firefox defaulting to the hybrid on the client side and Cloudflare terminating it at the edge, adoption climbed from &quot;nearly two percent&quot; of Cloudflare&apos;s TLS 1.3 connections in early 2024, toward double-digit adoption by the end of that year [@cf-pq2024], to a majority of human web traffic by late 2025 [@cf-pq2025]. The exact figure, around 52 percent, is best read as a dated snapshot from live telemetry rather than a steady state [@cf-radar] [@heise] [@postquantum-com].&lt;/p&gt;

flowchart LR
    G0[Gen 0: classical-only X25519 and RSA, harvestable] --&amp;gt; G1[Gen 1: hybrid experiments CECPQ1 2016, CECPQ2 2018]
    G1 --&amp;gt; G2[Gen 2: standardized primitive ML-KEM / FIPS 203, 2024]
    G2 --&amp;gt; G3[Gen 3: protocol integration PQXDH, PQ3, OpenSSH 9.9, X25519MLKEM768]
    G3 --&amp;gt; G4[Gen 4: hybrid default across a majority of web traffic, 2025]
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Generation&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Key idea&lt;/th&gt;
&lt;th&gt;Representative&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Gen 0 -- harvestable baseline&lt;/td&gt;
&lt;td&gt;1990s-present&lt;/td&gt;
&lt;td&gt;Classical-only key establishment; forward secrecy only&lt;/td&gt;
&lt;td&gt;RSA key transport, X25519 ECDHE&lt;/td&gt;
&lt;td&gt;Still-live baseline [@cf-pq2024]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gen 1 -- first hybrids&lt;/td&gt;
&lt;td&gt;2016, 2018&lt;/td&gt;
&lt;td&gt;Classical + pre-standard PQ, safe if either half holds&lt;/td&gt;
&lt;td&gt;CECPQ1, CECPQ2&lt;/td&gt;
&lt;td&gt;Historical [@langley-cecpq2]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gen 2 -- the primitive&lt;/td&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;A single vetted, standardized KEM (not a NIKE)&lt;/td&gt;
&lt;td&gt;ML-KEM / FIPS 203&lt;/td&gt;
&lt;td&gt;Active component [@fips-203]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gen 3 -- integration&lt;/td&gt;
&lt;td&gt;2023-2024&lt;/td&gt;
&lt;td&gt;Wire the KEM into real handshakes as a hybrid&lt;/td&gt;
&lt;td&gt;X25519MLKEM768, PQXDH, PQ3, OpenSSH 9.9&lt;/td&gt;
&lt;td&gt;Active [@ietf-mlkem] [@signal-pqxdh] [@apple-pq3] [@openssh-99]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gen 4 -- scale&lt;/td&gt;
&lt;td&gt;2025&lt;/td&gt;
&lt;td&gt;Hybrid on by default at internet scale&lt;/td&gt;
&lt;td&gt;OpenSSL 3.5; majority of web traffic&lt;/td&gt;
&lt;td&gt;Active frontier [@openssl-35] [@cf-pq2025]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Each generation closed one gap the last had left open: no vetted primitive, then no deployment, then no ubiquity. None closed the one gap that no later fix can close -- the ciphertext an adversary already captured. And one question still hangs over the whole catalog: why wrap a standardized post-quantum algorithm in a hybrid at all? Why not simply ship the newest, strongest post-quantum scheme on its own? A dead end from 2022 answers that better than any argument.&lt;/p&gt;
&lt;h2&gt;5. The Ten-Minute Break That Vindicated Hybrids&lt;/h2&gt;
&lt;p&gt;In July 2022, a post-quantum key-encapsulation mechanism named SIKE was broken. Not weakened -- broken, completely, its private key recovered from public data. The remarkable part was how. SIKE was not a fringe proposal; it was a NIST Round-4 candidate, a scheme that had survived years of public analysis in the world&apos;s most scrutinized cryptography competition. And it fell not to a quantum computer but to a mathematician with a laptop.&lt;/p&gt;

The attack &quot;breaks SIKEp434, which aims at security level 1, in about ten minutes on a single core.&quot; -- Wouter Castryck and Thomas Decru [@sike-break]
&lt;p&gt;Castryck and Decru found that the extra data SIKE&apos;s underlying protocol exchanged -- torsion-point images -- leaked enough structure to recover the secret key in heuristic polynomial time. Their implementation broke the security-level-1 parameter set in about ten minutes on one CPU core [@sike-break]. No error correction, no millions of qubits. Just mathematics that had been missed.&lt;/p&gt;
&lt;p&gt;Now hold that against the problem this article has been building toward. You are deploying cryptography to protect data whose confidentiality must outlast a recording you cannot see and cannot un-make. If you bet everything on a single post-quantum scheme, and that scheme turns out to have a SIKE-shaped flaw discovered five years from now, every session you protected with it becomes retroactively readable -- and the ciphertext is already in someone&apos;s archive. Against a recording you cannot un-make, a single-primitive bet on a young standard is the one bet you cannot afford.&lt;/p&gt;
&lt;p&gt;That is the whole argument for hybrids, and it fits in a sentence.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Migration is a race against a recording you cannot see. Because you can never un-capture ciphertext, the only defense is to change the deployment &lt;em&gt;before&lt;/em&gt; capture -- and the only change safe against both a future quantum computer and an undiscovered flaw in young post-quantum math is a hybrid that survives if &lt;em&gt;either&lt;/em&gt; component holds.&lt;/p&gt;
&lt;/blockquote&gt;

Deriving one session key from two independent key exchanges -- a classical one such as X25519 and a post-quantum one such as ML-KEM-768 -- combined through a key-derivation function so the result stays secure as long as at least one of the two remains unbroken. It is a deliberate hedge in both directions: against a future quantum break of the classical half, and against an undiscovered flaw in the young post-quantum half.
&lt;p&gt;Here is the part that turns the argument from plausible to proven. When Google and Cloudflare trialed the isogeny family, they did it as a hybrid too -- CECPQ2b, X25519 combined with SIKE. So when SIKE collapsed in 2022, the question was not academic: what happened to the sessions that had negotiated the SIKE hybrid? The answer is that they were fine. Every X25519 plus SIKE session stayed confidential, because X25519 held when SIKE fell. The &quot;safe if either half holds&quot; design did exactly its job -- in the field, against a real and total break of one half.&lt;/p&gt;

SIKE is a dead end, not a step in the defense lineage -- but it is the load-bearing dead end, because it is the empirical proof of the hybrid thesis. A NIST Round-4 candidate KEM fell to a laptop in minutes, and the deployments that had wrapped it in a hybrid lost nothing, because their classical half was untouched. This is the concrete answer to the tempting question &quot;why not just ship the newest pure post-quantum algorithm?&quot; Because young primitives can die suddenly, without warning, from a piece of mathematics nobody had noticed -- and when the thing you are protecting is a recording that cannot be un-made, you diversify the bet. The isogeny *idea* is not entirely dead, but SIKE as a key-establishment path is finished, and it took CECPQ2b with it [@sike-break].
&lt;p&gt;The design principle is now settled, and the deployment is largely built. So what does correct, quantum-safe confidentiality actually look like on the wire in 2026?&lt;/p&gt;
&lt;h2&gt;6. What Quantum-Safe Confidentiality Looks Like in 2026&lt;/h2&gt;
&lt;p&gt;By 2026 the state of the art has converged on a single shape: a standardized post-quantum KEM (ML-KEM), wrapped in a hybrid with a classical elliptic-curve exchange, wired into the real key-establishment step of TLS, SSH, and secure messaging, and turned on by default. Everything deployed today is a variation on that one sentence.&lt;/p&gt;
&lt;p&gt;Start with the flagship. The TLS 1.3 hybrid group X25519MLKEM768 sends a client share of 1216 bytes -- the 1184-byte ML-KEM-768 encapsulation key followed by the 32-byte X25519 share -- and receives a 1120-byte server share, a 1088-byte ML-KEM ciphertext plus the server&apos;s 32-byte X25519 share, from which both sides derive a 64-byte combined secret. Its IANA codepoint is 0x11EC [@ietf-mlkem].The group name lists its components in the reverse of their wire order: the client share carries the 1184-byte ML-KEM-768 key first, then the 32-byte X25519 share, yet the name puts X25519 first, &quot;for historical reasons&quot; [@ietf-mlkem]. Naming is hard, even in cryptography.&lt;/p&gt;

A three-algorithm scheme -- key generation, encapsulation, and decapsulation -- in which one party encapsulates a fresh random secret to the other&apos;s public key and transmits the resulting ciphertext, and the key holder decapsulates it to recover the same secret. This is structurally unlike a non-interactive key agreement (a NIKE) such as Diffie-Hellman, where both sides derive the key from public values with no ciphertext exchanged. ML-KEM is a KEM, which is why the post-quantum answer is a hybrid handshake and not a &quot;post-quantum Diffie-Hellman&quot; [@fips-203].

sequenceDiagram
    participant C as Client
    participant S as Server
    C-&amp;gt;&amp;gt;S: X25519 share and ML-KEM-768 encapsulation key (1216-byte client share)
    S-&amp;gt;&amp;gt;C: X25519 share and ML-KEM-768 ciphertext (1120-byte server share)
    Note over C,S: Each side computes an X25519 secret AND an ML-KEM secret
    Note over C,S: A KDF combines both into the session key, safe if either half holds
&lt;p&gt;The same hybrid shape shows up everywhere else. OpenSSH exposes it as mlkem768x25519-sha256, available by default since 9.9 [@openssh-99]. Signal&apos;s PQXDH puts a lattice KEM alongside the classical exchange in initial key establishment; Apple&apos;s PQ3 does the same and extends post-quantum protection to ongoing rekeying as well [@signal-pqxdh] [@apple-pq3]. Apple ranks these on a coarse scale of its own -- Signal&apos;s initial-key-establishment protection at &quot;Level 2,&quot; PQ3&apos;s establishment-plus-rekey at &quot;Level 3&quot; -- though those levels are Apple&apos;s own taxonomy, not an industry standard [@apple-pq3].&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Layer protected&lt;/th&gt;
&lt;th&gt;Break requires&lt;/th&gt;
&lt;th&gt;Extra wire cost&lt;/th&gt;
&lt;th&gt;Default on?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;X25519MLKEM768 (TLS)&lt;/td&gt;
&lt;td&gt;TLS key establishment&lt;/td&gt;
&lt;td&gt;X25519 &lt;em&gt;and&lt;/em&gt; ML-KEM-768&lt;/td&gt;
&lt;td&gt;~1.2 KB client share&lt;/td&gt;
&lt;td&gt;Yes: browsers, OpenSSL 3.5 [@openssl-35]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlkem768x25519-sha256 (SSH)&lt;/td&gt;
&lt;td&gt;SSH key establishment&lt;/td&gt;
&lt;td&gt;X25519 &lt;em&gt;and&lt;/em&gt; ML-KEM-768&lt;/td&gt;
&lt;td&gt;~1.2 KB&lt;/td&gt;
&lt;td&gt;Yes: OpenSSH 9.9 and later [@openssh-99]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PQXDH (Signal, &quot;Level 2&quot;)&lt;/td&gt;
&lt;td&gt;Messaging initial key est.&lt;/td&gt;
&lt;td&gt;X25519 &lt;em&gt;and&lt;/em&gt; lattice KEM&lt;/td&gt;
&lt;td&gt;~1 KB per establishment&lt;/td&gt;
&lt;td&gt;Yes: all users [@signal-pqxdh]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PQ3 (Apple, &quot;Level 3&quot;)&lt;/td&gt;
&lt;td&gt;Messaging key est. and rekey&lt;/td&gt;
&lt;td&gt;ECC &lt;em&gt;and&lt;/em&gt; lattice KEM&lt;/td&gt;
&lt;td&gt;~1 KB per est. and rekey&lt;/td&gt;
&lt;td&gt;Yes: iOS 17.4 and later [@apple-pq3]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pure ML-KEM-1024 (CNSA 2.0)&lt;/td&gt;
&lt;td&gt;Key establishment&lt;/td&gt;
&lt;td&gt;ML-KEM-1024 alone&lt;/td&gt;
&lt;td&gt;~1.5 KB, no ECC&lt;/td&gt;
&lt;td&gt;Federal direction [@cnsa-2]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Classical X25519 (baseline)&lt;/td&gt;
&lt;td&gt;Key establishment&lt;/td&gt;
&lt;td&gt;X25519 alone, so a CRQC&lt;/td&gt;
&lt;td&gt;none (32-byte baseline)&lt;/td&gt;
&lt;td&gt;Yes: legacy [@cf-pq2024]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Notice what the KEM structure forces. Because ML-KEM encapsulates a secret and returns a ciphertext, rather than agreeing a key from two public values the way Diffie-Hellman does, the deployed construction is a hybrid &lt;em&gt;handshake&lt;/em&gt;, not a &quot;post-quantum Diffie-Hellman&quot; [@fips-203]. That is the single most common misconception about post-quantum key exchange, and the shape of the wire is why it is wrong.&lt;/p&gt;

A key-agreement scheme in which two parties compute a shared secret purely from each other&apos;s published public values, with no ciphertext or extra protocol message passing between them -- which is exactly what classical Diffie-Hellman is. A KEM is not a NIKE: it requires one side to encapsulate a secret and send a ciphertext back. That structural gap is why a genuine &quot;post-quantum Diffie-Hellman&quot; would need a post-quantum NIKE, and why the absence of one forces the deployed answer into a hybrid handshake instead [@fips-203].

If a true post-quantum Diffie-Hellman existed -- a non-interactive key exchange as clean as the classical one -- it would be the perfect drop-in, and none of the hybrid-handshake plumbing would be necessary. One candidate does exist in the literature: CSIDH, an isogeny-based group action its authors proposed as &quot;suitable for non-interactive key exchange in a post-quantum setting,&quot; with public keys of only 64 bytes [@csidh]. But its concrete quantum security is disputed -- Peikert&apos;s C-sieve cryptanalysis &quot;strongly invalidates its claimed NIST level 1 quantum security&quot; for the CSIDH-512 parameters [@peikert-csieve] -- and it belongs to the same isogeny family whose SIKE cousin fell classically in ten minutes. The information-theoretic alternatives, the one-time pad and quantum key distribution, do not scale to open-internet key establishment. So a standardized KEM wrapped in a hybrid, switched on before capture, is not a compromise forced by expedience. It is the realizable ideal: the best construction actually available, given that the cleaner primitive is either undeployable or untrusted.
&lt;p&gt;The cost of all this is worth stating precisely, because it lands where people do not expect. Lattice operations are cheap; the CPU overhead of an ML-KEM key generation, encapsulation, and decapsulation is negligible. The cost is bytes.&lt;/p&gt;
&lt;p&gt;{`
const X25519_SHARE = 32;    // classical elliptic-curve share
const MLKEM768_EK  = 1184;  // ML-KEM-768 encapsulation key (FIPS 203)
const hybridShare  = MLKEM768_EK + X25519_SHARE; // 1216 bytes, codepoint 0x11EC&lt;/p&gt;
&lt;p&gt;console.log(&apos;Classical X25519 client share :&apos;, X25519_SHARE, &apos;bytes&apos;);
console.log(&apos;Hybrid X25519MLKEM768 share   :&apos;, hybridShare, &apos;bytes&apos;);
console.log(&apos;Extra on the wire             : ~&apos; + ((hybridShare - X25519_SHARE) / 1024).toFixed(2) + &apos; KB&apos;);
// ~1.2 KB extra is why a post-quantum ClientHello can span more than one TCP segment (tldr.fail).
// CPU cost is negligible: lattice KEM operations are cheap.
`}&lt;/p&gt;
&lt;p&gt;About 1.2 kilobytes of extra ClientHello: that is the price of quantum-safe confidentiality on the wire, and it is why the hard problems in this migration are network problems -- does the larger handshake fit through every middlebox? -- rather than compute problems.&lt;/p&gt;
&lt;p&gt;Now the honest part, the part a launch post tends to skip.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Turning on X25519MLKEM768 protects &lt;em&gt;new&lt;/em&gt; key establishment. It does nothing for four things: ciphertext an adversary already captured (irreversible); digital signatures and the Web PKI (a different threat model, on a different clock); data encrypted at rest under a quantum-vulnerable scheme; and the long tail of non-browser protocols that have not enabled a hybrid group. A &quot;majority of web traffic&quot; statistic is a browser statistic.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That last point deserves weight before we move on. The adoption curve is real, but it measures browser-terminated TLS. It says nothing about the VPN concentrator, the mail server, the database connection, or the backup pipeline -- and those are exactly the surfaces most likely to be carrying secrets with long confidentiality lifetimes.&lt;/p&gt;
&lt;p&gt;This shape -- ML-KEM in a hybrid, on by default -- is the consensus of browsers, Signal, Apple, OpenSSH, and the CDNs. But it is not the consensus of everyone. The U.S. government is quietly betting on a different design, and the disagreement is real.&lt;/p&gt;
&lt;h2&gt;7. The Migration&apos;s Open Fault Lines&lt;/h2&gt;
&lt;p&gt;The commercial internet ships hybrids. The NSA does not want to. Its Commercial National Security Algorithm Suite 2.0 leans toward pure ML-KEM-1024, with no classical curve alongside it [@cnsa-2]. This is not a mistake to correct in either direction. It is a real disagreement between reasonable parties, worth understanding rather than resolving.&lt;/p&gt;
&lt;h3&gt;Hybrid versus pure&lt;/h3&gt;
&lt;p&gt;The case for the hybrid is the one this article has already earned: provably secure if either component holds, and vindicated in the field when SIKE fell. The formal guarantee is not a slogan. For the exact pairing of X25519 with ML-KEM-768, the X-Wing construction proves the combined KEM is secure as long as either component is -- classically if X25519 holds, post-quantum if ML-KEM-768 holds [@xwing]. To recover a hybrid session key, an adversary must break both the elliptic-curve discrete logarithm (which needs a quantum computer) and Module-LWE (which needs a cryptanalytic break) -- strictly harder than breaking either one alone.&lt;/p&gt;
&lt;p&gt;There is a deeper reason the hybrid is more than belt-and-suspenders, and it is epistemic rather than mechanical. ML-KEM&apos;s security rests on the presumed hardness of a lattice problem -- and &quot;presumed&quot; is the load-bearing word.&lt;/p&gt;

The lattice problem underneath ML-KEM: recovering a secret from many linear equations over a polynomial module that have been deliberately perturbed with small random errors. FIPS 203 claims only that ML-KEM &quot;is believed to be secure, even against adversaries who possess a quantum computer&quot; -- there is no proof that Module-LWE is hard for a classical or a quantum machine, any more than there is a proof that integer factoring or the discrete logarithm is hard [@fips-203].
&lt;p&gt;This is the honest core of the hybrid argument. The security of RSA, of elliptic curves, and of ML-KEM alike rests on unproven conjectures -- problems the world has failed to solve, not problems anyone has shown are unsolvable. A hybrid does not escape that condition; it diversifies the wager across two independent unproven conjectures, so that a break of either one alone is survivable. It buys resilience, not a proof. Nothing deployed at internet scale offers a proof.&lt;/p&gt;
&lt;p&gt;The case for pure ML-KEM-1024 is not irrational either. A vetted standard at its highest parameter set, the argument goes, should stand on its own; a hybrid adds a second code path, a combiner to get right, and larger messages, and complexity is itself attack surface. The preference is old and consistent: at CRYPTO 2018 the NSA already stated its intent to publish pure post-quantum standards &quot;not combined with an elliptic-curve operation as a safeguard,&quot; as Langley recorded at the time [@langley-cecpq2].&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Hybrid (X25519 + ML-KEM-768)&lt;/th&gt;
&lt;th&gt;Pure ML-KEM-1024&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;If ML-KEM is later broken&lt;/td&gt;
&lt;td&gt;Still safe -- X25519 holds&lt;/td&gt;
&lt;td&gt;Broken: single-primitive bet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;If X25519 is later broken (CRQC)&lt;/td&gt;
&lt;td&gt;Still safe -- ML-KEM holds&lt;/td&gt;
&lt;td&gt;Safe: ML-KEM is designed for this&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Formal guarantee&lt;/td&gt;
&lt;td&gt;Secure if &lt;em&gt;either&lt;/em&gt; component is secure (X-Wing) [@xwing]&lt;/td&gt;
&lt;td&gt;Rests entirely on Module-LWE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Empirical precedent&lt;/td&gt;
&lt;td&gt;SIKE hybrid survived the 2022 break [@sike-break]&lt;/td&gt;
&lt;td&gt;A pure SIKE deployment would have been harvestable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Two code paths plus a combiner&lt;/td&gt;
&lt;td&gt;One primitive, one path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who ships it&lt;/td&gt;
&lt;td&gt;IETF, browsers, OpenSSL, OpenSSH, Signal, Apple&lt;/td&gt;
&lt;td&gt;NSA CNSA 2.0 for national-security systems [@cnsa-2]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The honest verdict is that this is unresolved. For migration &lt;em&gt;today&lt;/em&gt;, against a recording you cannot un-make, the hybrid is the defensible default: it costs one extra primitive and about 1.2 kilobytes to convert &quot;we bet everything on a five-year-old lattice assumption&quot; into &quot;we lose only if both a classical curve and a lattice scheme fall.&quot; But the pure-PQC position -- that ML-KEM-1024 will hold, and that simplicity is a security property -- is a coherent bet on a leaner steady state. The SIKE episode is a live counterexample to single-primitive confidence during migration, not a proof that pure PQC is wrong forever.&lt;/p&gt;
&lt;p&gt;It is worth remembering why the field landed on lattices at all, because that too was a measured choice rather than a foregone one.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric (production TLS experiment, 2019)&lt;/th&gt;
&lt;th&gt;HRSS lattice (CECPQ2)&lt;/th&gt;
&lt;th&gt;SIKE isogeny (CECPQ2b)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Public-key size&lt;/td&gt;
&lt;td&gt;~1100 bytes&lt;/td&gt;
&lt;td&gt;~330 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relative compute cost&lt;/td&gt;
&lt;td&gt;Low (orders of magnitude faster)&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical client&lt;/td&gt;
&lt;td&gt;Matches or beats the isogeny scheme&lt;/td&gt;
&lt;td&gt;Slower for most clients&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where the isogeny scheme wins&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;Only the slowest tail of clients&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Before ML-KEM was the standard, Cloudflare and Google ran a production experiment pitting a lattice hybrid against the tiny-keyed isogeny hybrid, whose public keys were roughly 330 bytes against the lattice scheme&apos;s ~1100 [@cf-towards]. Nick Sullivan framed it as an ostrich against a turkey: the lattice scheme big but fast, the isogeny scheme small but slow. The ostrich won -- the lattice hybrid matched or beat the isogeny one for the overwhelming majority of clients, and the small keys did not offset the computational cost [@cf-experiment]. The later SIKE break removed isogeny KEMs from contention on security too. Both results point at the same 2026 answer: a lattice KEM, in a hybrid.&lt;/p&gt;
&lt;h3&gt;Two migrations, two clocks&lt;/h3&gt;
&lt;p&gt;The second fault line is not really a contest, and treating it as one is a category error the whole article has worked to prevent. Key-establishment migration closes the harvest-now-decrypt-later window and can be deployed today. Signature migration answers a different threat model -- forgery by a quantum adversary at attack time -- and is years behind, entangled with the certificate infrastructure and slowed by larger, heavier post-quantum signatures. The standardized signature primitives already exist, ML-DSA and SLH-DSA [@fips-204] [@fips-205], with more arriving through NIST&apos;s signatures onramp [@pqc-dig-sig], but deployment across the Web PKI has barely begun.&lt;/p&gt;
&lt;p&gt;Federal policy keeps the two explicitly separate, and always in the same order.&lt;/p&gt;

Three dated policies shape the U.S. migration, and they keep the two clocks apart. CNSA 2.0 sets the direction for national-security systems toward pure ML-KEM-1024 [@cnsa-2]. Executive Order 14412 sets federal deadlines: post-quantum key establishment by 31 December 2030, digital signatures by 31 December 2031 [@eo-14412]. And NIST IR 8547 -- still an initial public draft, so its dates may shift -- would deprecate quantum-vulnerable public-key algorithms after 2030 and disallow them after 2035 [@ir-8547]. Key establishment always leads signatures, because the confidentiality clock is the urgent one.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Neither debate here has a settled answer. Hybrid-versus-pure is a genuine trade-off between diversifying a bet and minimizing complexity. Key-establishment-versus-signature migration is not a contest at all -- they are different problems on different clocks. Anyone who tells you one option simply wins is smoothing over a real disagreement.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Both debates, though, quietly assume you at least know &lt;em&gt;when&lt;/em&gt; you must be finished. But the deadline term in Mosca&apos;s inequality -- the time until Q-Day -- is the one number nobody can honestly give you.&lt;/p&gt;
&lt;h2&gt;8. Mosca&apos;s Inequality, and What It Can and Cannot Promise&lt;/h2&gt;
&lt;p&gt;The load-bearing &quot;bound&quot; in this field is a strange one. It is not a complexity bound on an algorithm, nor a lower bound on an adversary&apos;s work. It is a decision rule about a race between clocks, and it is the tool that turns a fuzzy future into a concrete, present-tense choice you can make one dataset at a time.&lt;/p&gt;

Michele Mosca&apos;s decision rule for quantum risk. Let $X$ be the number of years your data must remain secret, $Y$ the number of years your migration to quantum-safe cryptography will take, and $Z$ the number of years until a cryptographically-relevant quantum computer exists. If $X + Y &amp;gt; Z$, your data is already exposed: it will still demand secrecy at a time when the machine that breaks it exists [@mosca-2018].
&lt;p&gt;Read it slowly, because the ordering of the terms is the whole insight. $Y$ and $Z$ are the usual suspects -- how long migration takes, how long until the machine. But $X$, the secrecy lifetime, is what makes the loss present-tense. The adversary&apos;s decisive act, capturing the ciphertext, happens now. So for a given dataset you are not really racing $Z$; you are racing $Z$ minus however long the recording has already been running, against $Y$. If your data must stay secret for thirty years, you do not have &quot;until Q-Day&quot; to migrate. You had until the moment someone started recording [@mosca-2015].&lt;/p&gt;

flowchart TD
    A[X: required secrecy lifetime] --&amp;gt; D{&quot;X + Y &amp;gt; Z ?&quot;}
    B[Y: time to migrate] --&amp;gt; D
    C[Z: time to a CRQC, uncertain but tightening] --&amp;gt; D
    D --&amp;gt;|Yes| E[Already exposed: migrate this data class first]
    D --&amp;gt;|No| F[Lower priority, re-check as Z tightens]
&lt;p&gt;The practical payoff is that you can run this yourself, today, against your own data. The numbers below are illustrative -- pick your own $Z$ and re-run -- but the structure is exactly Mosca&apos;s.&lt;/p&gt;
&lt;p&gt;{`
// X = required secrecy lifetime (years); Y = migration time (years);
// Z = years until a cryptographically-relevant quantum computer (UNCERTAIN).
const mosca = (X, Y, Z) =&amp;gt; (X + Y) &amp;gt; Z;&lt;/p&gt;
&lt;p&gt;const Z = 12; // a deliberately uncertain estimate -- change it and re-run
const data = [
  { name: &apos;Genomic records&apos;,   X: 50,  Y: 3 },
  { name: &apos;State secrets&apos;,     X: 30,  Y: 3 },
  { name: &apos;Long-term IP&apos;,      X: 20,  Y: 3 },
  { name: &apos;Session cookie&apos;,    X: 0.1, Y: 3 },
];&lt;/p&gt;
&lt;p&gt;for (const d of data) {
  const exposed = mosca(d.X, d.Y, Z);
  console.log(d.name.padEnd(18) + (exposed ? &apos;ALREADY EXPOSED -- migrate first&apos; : &apos;lower priority&apos;));
}
`}&lt;/p&gt;
&lt;p&gt;Change $Z$ to anything you like. The genome stays exposed under almost every value you would plausibly choose; the session cookie almost never does. That is the inequality doing its real work -- not predicting Q-Day, but sorting your data by whether the decision has already been lost.&lt;/p&gt;
&lt;p&gt;Now the limits, stated as plainly as the thesis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No cryptographically-relevant quantum computer exists in 2026.&lt;/strong&gt; RSA-2048 is unbroken. Every qubit figure in circulation is an estimate of what an unbuilt machine would require, and those estimates are falling. In 2019, Gidney and Ekera estimated that factoring RSA-2048 would take on the order of twenty million noisy qubits over about eight hours [@gidney-ekera-2019]. In 2025, Gidney revised the figure to fewer than one million noisy qubits in under a week [@gidney-2025]. That is a roughly twentyfold drop in six years -- and still not a demonstration. The honest description of the timeline is uncertain but tightening.Mosca himself once put &quot;a 1/2 chance of breaking RSA-2048 by 2031&quot; -- but that is his estimate, not a consensus, and this article endorses no Q-Day date [@mosca-2015].&lt;/p&gt;
&lt;p&gt;This uncertainty is exactly why some cryptographers who once shrugged at the quantum threat no longer do. The falling estimates do not name a date; they make the risk action-forcing without one.&lt;/p&gt;

&quot;I need you to recognize how immediately dispositive that is.&quot; -- Filippo Valsorda, on why an uncertain timeline is still action-forcing [@valsorda]
&lt;p&gt;There is a common objection worth meeting head-on: most TLS traffic is short-lived, so who cares if it is harvested? The objection is correct, and it does not weaken the thesis -- it sharpens it. Because ephemeral session traffic has almost no value years from now, the genuine harvest-now-decrypt-later risk concentrates precisely on the data with long confidentiality lifetimes: state secrets, health and genomic records, source identities, long-term intellectual property. The short-lived-traffic point does not universalize the casualty; it focuses it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;All of this rests on conjectural hardness.&lt;/strong&gt; No one has proved that a quantum computer -- or even a classical one -- cannot break ML-KEM, RSA, or elliptic curves. Their security rests on the presumed hardness of Module-LWE, factoring, and the discrete logarithm; FIPS 203 itself claims only that ML-KEM &quot;is believed to be secure&quot; [@fips-203]. A hybrid does not dissolve that uncertainty. It spreads the wager across two independent unproven conjectures, so a break of one alone is survivable, but it proves nothing -- which is why this migration is risk management performed before capture, not a certificate of safety [@xwing].&lt;/p&gt;
&lt;p&gt;And then the one limit no engineering reverses.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Harvested ciphertext is the one loss no future fix reverses. Migration can protect every session from this moment forward, but it cannot reach back and protect a recording already sitting in an archive. For data whose secrecy must span the gap, the decision was made at capture -- which is why the deployment choice, not the future math, is where the casualty is booked.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The inequality tells you how to decide under uncertainty. But it silently assumes one thing: that you can still migrate before capture. For a great deal of data already on the wire, that assumption is false. Which raises the question the deployment curve tends to obscure: where does the harvest still win?&lt;/p&gt;
&lt;h2&gt;9. Where the Harvest Still Wins&lt;/h2&gt;
&lt;p&gt;A majority of web traffic riding hybrid key agreement is a real milestone, and also a misleading one, because &quot;majority of web traffic&quot; is not &quot;done.&quot; Six frontiers remain, and the first is permanent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ciphertext already captured.&lt;/strong&gt; This is the irreversible frontier. Any long-lived secret already sent under classical-only key establishment and recorded by an adversary is beyond rescue; no hybrid, no key rotation, no future standard can reach into an archive and un-capture it. The only levers left are operational -- re-key and re-encrypt long-lived secrets under a hybrid now, so you stop adding to the harvested set, and rotate credentials that may already be exposed. You can stop the set from growing. You cannot make it smaller.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The long tail of unmigrated surfaces.&lt;/strong&gt; Browser TLS is migrating fast; almost nothing else is. VPNs, email transport over SMTP and IMAP, database connections, internal service meshes, backups, machine-to-machine APIs, and the vast installed base of IoT devices still negotiate classical-only key establishment in 2026. These surfaces are not a random sample -- they disproportionately carry exactly the long-confidentiality-lifetime data where the sharpened risk concentrates.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The adoption number that gets quoted -- a majority of human web traffic -- is a browser number. The mail server holding a decade of correspondence, the database of health records, the backup vault, and the site-to-site VPN carrying internal traffic are usually still classical-only. The surfaces least migrated are the ones whose secrets have the longest lifetimes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;The bug that makes turning it on look like breaking the internet.&lt;/strong&gt; There is a mundane, maddening obstacle to flipping the switch.&lt;/p&gt;

A post-quantum ClientHello is about 1.2 kilobytes larger than a classical one, which pushes it past a single packet. A single call to TCP `read()` may then return only part of the ClientHello. Servers and middleboxes that quietly assumed a one-packet ClientHello -- calling `read()` exactly once, or refusing a split message -- reject the connection outright instead of falling back to a classical handshake. Enabling post-quantum key exchange can therefore look, from the outside, like it &quot;breaks the internet,&quot; when it merely exposes a pre-existing bug in how those servers read from a socket. The failure is documented and named at tldr.fail, which also makes the boundary point this article keeps insisting on: the store-then-decrypt threat does not apply to authentication, because connections are authenticated in real time, so signatures are not harvestable the way key establishment is [@tldrfail].
&lt;p&gt;&lt;strong&gt;Timeline uncertainty.&lt;/strong&gt; Z is unknowable from public information. The estimates fall, but they describe unbuilt hardware, and no one can honestly hand you a date. Over-confidence in a late Z under-protects long-lived data; a false &quot;imminent&quot; claim wastes scarce migration effort. The discipline is to treat Z as uncertain but tightening, and decide by data lifetime rather than prediction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Crypto-agility and inventory.&lt;/strong&gt; Most organizations cannot say, with confidence, where and which cryptography they run. You cannot prioritize -- or even find -- the long-lived-secret surfaces that harvest now, decrypt later targets, if they are invisible to you.The blunt version: you cannot rotate what you cannot see. An un-inventoried quantum-vulnerable endpoint protecting decade-lifetime data is a silent casualty. Building and maintaining that inventory is the subject of this article&apos;s crypto-agility and cryptographic-bill-of-materials sibling. The official guidance already centers this: the joint CISA, NSA, and NIST quantum-readiness factsheet urges a cryptographic inventory that prioritizes long-term-confidentiality data [@cisa-qr], and NIST IR 8547 sets the deprecation clock that inventory has to race [@ir-8547].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The signature and PKI migration.&lt;/strong&gt; Authentication is also quantum-vulnerable, but -- and this is the boundary the whole article has policed -- it is not the harvest-now-decrypt-later problem. Forging a signature needs a quantum computer at attack time, so it cannot be harvested in advance. Its migration is the separate, later track the fault-lines section already mapped. It is important, it is on a separate clock, and it is not the confidentiality remedy.&lt;/p&gt;
&lt;p&gt;None of this is hopeless. Most of it is a to-do list. So here is the to-do list, in priority order.&lt;/p&gt;
&lt;h2&gt;10. What to Do Before Q-Day, Prioritized by Data Lifetime&lt;/h2&gt;
&lt;p&gt;You cannot un-capture the past. But you can stop feeding the harvest today, and the order in which you do it is not arbitrary -- it is set by the confidentiality lifetime of each data class. Run Mosca&apos;s inequality in your head as you read: the longer the secrecy lifetime, the more urgent the migration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Inventory the longest-lived secrets first.&lt;/strong&gt; Before turning any knob, find the data whose secrecy must span decades: genomic and health records, state secrets, source identities, long-validity keys, long-term intellectual property. For each class, the secrecy lifetime alone may already exceed any plausible time-to-Q-Day, which puts it at the front of the queue. You cannot protect what you have not located.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data class&lt;/th&gt;
&lt;th&gt;Typical secrecy lifetime&lt;/th&gt;
&lt;th&gt;Priority&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Genomic and health records&lt;/td&gt;
&lt;td&gt;Decades&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;Hybrid now; re-encrypt stored data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State secrets, source identities&lt;/td&gt;
&lt;td&gt;25+ years&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;Hybrid now; audit what may already be captured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long-term IP, legal, financial&lt;/td&gt;
&lt;td&gt;10-20 years&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Hybrid on all TLS and SSH termination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Business correspondence, email&lt;/td&gt;
&lt;td&gt;Years&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Post-quantum-capable transport and messaging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session tokens, ephemeral traffic&lt;/td&gt;
&lt;td&gt;Minutes to hours&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Migrate with the default; no rush&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;2. Turn on hybrid key establishment wherever you terminate TLS or SSH.&lt;/strong&gt; This is the single most effective action, and modern tooling makes it nearly free: OpenSSL 3.5 ships the hybrid group as a default, and OpenSSH 9.9 and later offer mlkem768x25519-sha256 by default [@openssl-35] [@openssh-99]. It is downgrade-safe -- a peer that does not support the group simply negotiates a classical one -- so enabling it is never worse than the status quo.&lt;/p&gt;

On a recent OpenSSH build, list the key-exchange algorithms and look for the hybrid:&lt;p&gt;&lt;code&gt;ssh -Q kex | grep mlkem&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;mlkem768x25519-sha256&lt;/code&gt; appears, your client can already negotiate post-quantum key exchange (OpenSSH 9.9 and later). For TLS, a current OpenSSL can attempt the hybrid group directly:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;openssl s_client -groups X25519MLKEM768 -connect example.com:443&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A completed handshake means both ends agreed on the hybrid group.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Prefer post-quantum-capable messaging&lt;/strong&gt; for confidential conversations. Signal&apos;s PQXDH protects initial key establishment for all users; Apple&apos;s PQ3 adds ongoing rekeying on top of it [@signal-pqxdh] [@apple-pq3]. Messaging is a canonical long-lived-secret surface, and both are already deployed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Do not wait for pure post-quantum cryptography.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; During migration, the hybrid is the move to make now. It is provably secure if either component holds [@xwing], it was vindicated when SIKE fell, and it is downgrade-safe: against a peer that does not support it, TLS simply negotiates a classical group, so a hybrid is never worse than what you already run. Pure ML-KEM is a defensible steady-state target, not a reason to delay hybrid deployment today.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;5. Treat signatures and PKI as a separate, later track.&lt;/strong&gt; Migrating your key exchange does not touch quantum forgery of signatures, and it does not need to -- that is a different threat model on a different clock. Track it separately, and do not let a signature-migration timeline slow your confidentiality migration, or the reverse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Expect the large-ClientHello bug, and test before flag-day.&lt;/strong&gt; When you enable the hybrid, some servers or middleboxes may reject the larger handshake because of the one-&lt;code&gt;read()&lt;/code&gt; bug rather than fall back gracefully [@tldrfail]. Test your endpoints, fix the socket handling, and rely on browser-side ClientHello splitting where you can.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; You cannot un-capture the past, but you can stop feeding the harvest today. Every session you move to a hybrid before it is recorded is one loss that never gets booked. That is the entire discipline: change the deployment before capture, prioritized by how long each secret must live.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is the whole discipline: decide by lifetime, deploy the hybrid before capture, and keep the two clocks separate. What is left are the questions people ask next -- and most of them are misconceptions worth correcting precisely.&lt;/p&gt;
&lt;h2&gt;11. Misconceptions, Precisely Corrected&lt;/h2&gt;


No. No cryptographically-relevant quantum computer exists in 2026, and RSA-2048 is unbroken [@gidney-2025]. The risk is not present-day decryption; it is present-day *capture*. An adversary who records your ciphertext today can decrypt it only once such a machine exists, which is exactly why the loss is decided at capture time rather than at decryption time [@mosca-2018].


The threat model is documented -- NSA, CISA, NIST, and an executive order all name it explicitly [@cisa-qr] [@eo-14412] -- and the general practice of bulk interception and indefinite retention is documented independently of quantum computing [@bamford] [@bullrun]. What is *not* publicly established is a specific, attributed, ongoing nation-state program that harvests ciphertext in order to await a quantum computer. That is a rational-actor inference, not a public smoking gun, and the case for migrating does not depend on one existing.


Yes -- and that sharpens the argument rather than weakening it. Because ephemeral session traffic has little value years from now, the genuine harvest-now-decrypt-later risk concentrates on data with long confidentiality lifetimes: state secrets, health and genomic records, source identities, long-term intellectual property. The nuance focuses the casualty; it does not dissolve it.


No. Key-establishment migration closes the confidentiality (harvest-now-decrypt-later) window. Signature forgery is a different threat model that needs a quantum computer at attack time, so it cannot be harvested in advance; its migration runs on a separate, later clock [@eo-14412]. The two never share a single verdict.


Yes. ML-KEM is the standardized name for the scheme formerly called CRYSTALS-Kyber, published as NIST FIPS 203 [@fips-203]. &quot;ML-KEM is the new name for Kyber&quot; [@cf-pq2024]; in a 2026 voice, use ML-KEM. The internals of the primitive -- Module-LWE, lattice sampling, decapsulation -- are the subject of this article&apos;s post-quantum-toolkit sibling.


No. ML-KEM is a key-encapsulation mechanism, not a non-interactive key agreement; one side encapsulates a secret and sends a ciphertext, rather than both sides deriving a key from public values the way Diffie-Hellman does [@fips-203]. The deployed answer is therefore a hybrid *handshake*, not a drop-in &quot;post-quantum Diffie-Hellman.&quot;


During migration, prefer a hybrid. It is provably secure if either component holds [@xwing], and the SIKE break is the empirical proof: a NIST Round-4 candidate KEM fell classically in about ten minutes, and every deployment that had wrapped it in a hybrid stayed safe [@sike-break]. Pure ML-KEM-1024 is a defensible steady-state target -- the direction of U.S. national-security systems [@cnsa-2] -- but not a reason to delay hybrid deployment today.

&lt;p&gt;The paradox we opened with dissolves once you see where the casualty is booked. No quantum computer can factor RSA-2048 in 2026, and yet the loss is real, present, and ongoing -- because the adversary&apos;s decisive act is capture, not decryption. Every long-lived secret sent today under a quantum-vulnerable algorithm, while a recording runs, is a casualty already entered in the ledger: collected now, read later, and past the reach of any future fix the moment it is stored.&lt;/p&gt;
&lt;p&gt;That is the reconciliation with this series&apos; running thesis, and it holds without an exception. The primitive&apos;s mathematics did not cause this break -- RSA-2048 is unbroken, and no cryptographically-relevant quantum computer exists. The deployment did: continuing to protect must-outlive-Q-Day data with a deprecated-but-still-live quantum-vulnerable algorithm while someone records the ciphertext. The remedy is a deployment change you can make today -- hybrid X25519 plus ML-KEM key establishment -- and its urgency is set entirely by how long your data must stay secret.&lt;/p&gt;
&lt;p&gt;So the only question that ever mattered is the one we started with: what were you doing at capture time? If the answer is &quot;shipping a hybrid before the recording was made,&quot; the loss was never booked. If it was &quot;waiting for Q-Day,&quot; you were already too late. The mechanism that finishes the job -- one machine running Shor&apos;s algorithm against RSA, Diffie-Hellman, and ECC at once -- is the subject of the sibling article &quot;How Q-Day Breaks Everything: Shor&apos;s Algorithm and the Simultaneous Fall of RSA, Diffie-Hellman, and ECC.&quot; Knowing where your own quantum-vulnerable cryptography lives, so you can change it before capture, is the subject of the &lt;a href=&quot;https://paragmali.com/blog/you-cannot-rotate-what-you-cannot-see-crypto-agility-and-the/&quot; rel=&quot;noopener&quot;&gt;crypto-agility and cryptographic-bill-of-materials sibling&lt;/a&gt;. Both matter. Neither un-captures a recording. Only the deployment you ship before capture ever could.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;how-q-day-is-already-breaking-things&quot; keyTerms={[
  { term: &quot;Harvest Now, Decrypt Later (HNDL)&quot;, definition: &quot;Recording encrypted traffic today to decrypt after a future quantum computer exists; the loss is decided at capture time.&quot; },
  { term: &quot;CRQC&quot;, definition: &quot;A cryptographically-relevant quantum computer, large and error-corrected enough to run Shor&apos;s algorithm against deployed key sizes. None exists in 2026.&quot; },
  { term: &quot;Mosca&apos;s inequality&quot;, definition: &quot;If secrecy lifetime X plus migration time Y exceeds time-to-CRQC Z, the data is already exposed.&quot; },
  { term: &quot;ML-KEM (FIPS 203)&quot;, definition: &quot;The standardized Module-Lattice key-encapsulation mechanism; a KEM, not a Diffie-Hellman-style NIKE.&quot; },
  { term: &quot;Hybrid key establishment&quot;, definition: &quot;Combining a classical X25519 secret and a post-quantum ML-KEM secret so the session is safe if either half holds.&quot; },
  { term: &quot;Key establishment vs signatures&quot;, definition: &quot;Confidentiality is harvestable now; signature forgery needs a quantum computer at attack time. Different threat models, different clocks.&quot; }
]} questions={[
  { q: &quot;Why is the loss booked at capture time rather than at decryption time?&quot;, a: &quot;An adversary who records the handshake and ciphertext today has done the irreversible part. Only the decryption waits for a future machine, and migration cannot un-capture what is already stored.&quot; },
  { q: &quot;Why deploy a hybrid rather than pure ML-KEM during migration?&quot;, a: &quot;A hybrid stays secure if either component holds. SIKE, a NIST Round-4 candidate, was broken classically in about ten minutes, and every hybrid deployment survived because its classical half held.&quot; },
  { q: &quot;Why does the short-lived-traffic objection sharpen rather than weaken the thesis?&quot;, a: &quot;Ephemeral traffic has little future value, so the genuine risk concentrates on long-confidentiality-lifetime data such as state secrets and genomic records.&quot; },
  { q: &quot;Why is migrating TLS key exchange not enough to stop quantum forgery of signatures?&quot;, a: &quot;Signature forgery needs a quantum computer at attack time, a different threat model on a separate clock. It cannot be harvested in advance and is not the confidentiality remedy.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>post-quantum-cryptography</category><category>harvest-now-decrypt-later</category><category>ml-kem</category><category>tls</category><category>key-establishment</category><category>quantum-computing</category><category>cryptography</category><category>mosca-inequality</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Two Standards, One Lattice: How ML-KEM and ML-DSA Would Break</title><link>https://paragmali.com/blog/two-standards-one-lattice-how-ml-kem-and-ml-dsa-would-break/</link><guid isPermaLink="true">https://paragmali.com/blog/two-standards-one-lattice-how-ml-kem-and-ml-dsa-would-break/</guid><description>ML-KEM and ML-DSA rest on one hard problem, Module-LWE, measured by one ruler. Here is how that ruler would slip -- and why one slip debits both standards.</description><pubDate>Sat, 18 Jul 2026 00:00:00 GMT</pubDate><content:encoded>
**ML-KEM and ML-DSA are not two security stories -- they are one.** Both rest on a single hard problem, Module-LWE, whose strength is not proven but *measured*, by one number: the BKZ block size that lattice reduction must reach. The realistic &quot;break&quot; is not a sudden collapse but that ruler slipping a few bits at a time as reduction improves -- and because both standards read the same ruler, one advance debits both at once (correlated failure). The wildcards are a still-hypothetical &quot;Shor for lattices&quot; (the closest attempt was retracted within days) and a structural attack on the cyclotomic ring, the one risk the ruler cannot price.
&lt;h2&gt;1. We Escaped Shor by Making One Bet&lt;/h2&gt;
&lt;p&gt;We escaped Shor by making a single bet. RSA and elliptic curves fell to a quantum algorithm that hunts for hidden periodic structure, and lattice problems replaced them precisely because they seem to offer no such structure to hunt. In August 2024 the US National Institute of Standards and Technology (NIST) finished the job, publishing ML-KEM as FIPS 203 for key establishment [@fips-203] and ML-DSA as FIPS 204 for signatures [@fips-204]. The celebrations were real. But they skipped an uncomfortable question: if a quantum computer cannot break the replacements the way it broke the originals, how &lt;em&gt;would&lt;/em&gt; they break?&lt;/p&gt;
&lt;p&gt;The honest answer is: not with a bang. ML-KEM and ML-DSA are two products of one assumption, the Module Learning-With-Errors problem, and the strength of that assumption is not proven. It is &lt;em&gt;measured&lt;/em&gt; -- read off a single ruler that lattice cryptographers argue about openly. The likely failure is not a dramatic event but that ruler slipping, a few bits at a time, as attacks improve. And because both standards are pinned to the same ruler, one slip debits both at once.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Two standards, one lattice, one ruler. ML-KEM and ML-DSA do not have two security stories; they have one -- Module-LWE -- read off a single ruler, the core-SVP block size that lattice reduction must reach. The realistic break is that ruler slipping a few bits at a time, and because both standards read the same ruler, one slip debits both at once. A &lt;em&gt;sudden&lt;/em&gt; break would have to come from the one thing the ruler does not price: the algebra of the cyclotomic ring.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That lens sorts the whole threat surface into three routes, in descending order of likelihood. First and most probable is &lt;strong&gt;erosion&lt;/strong&gt;: lattice reduction gets a little better, the ruler reads a few bits lower, and the published margins thin. This has already happened once in miniature, and it is the route this article says you should expect.&lt;/p&gt;
&lt;p&gt;The second is &lt;strong&gt;the quantum route&lt;/strong&gt; everyone fears -- a &quot;Shor for lattices&quot; that would collapse the margin all at once. It has been claimed exactly once, and retracted within days. The third is the &lt;strong&gt;wildcard&lt;/strong&gt;: a structural attack on the extra algebra of the cyclotomic ring, the one surface the ruler does not even try to price. Low probability, high impact, genuinely contested.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is a structural-cryptanalysis piece. It asks by what &lt;em&gt;mathematical&lt;/em&gt; route ML-KEM and ML-DSA would fail: attacks on the algorithms&apos; own hardness assumptions. It deliberately excludes implementation attacks -- timing leaks such as KyberSlash, fault and power analysis, random-number-generator failures, and protocol misuse. Those are real and they matter, but they break a particular &lt;em&gt;program&lt;/em&gt;, not the &lt;em&gt;mathematics&lt;/em&gt;. They belong to the empirical sibling, &quot;How ML-KEM Breaks in Real Life.&quot; One boundary case is worth stating up front: quantum algorithms that attack the math (Shor) are in scope, and we will spend a section explaining precisely why Shor gets no purchase here.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To see how the ruler slips, we first have to see where the hardness came from -- and why &quot;noisy linear algebra&quot; survived the very tools that killed RSA.&lt;/p&gt;
&lt;h2&gt;2. Where the Hardness Comes From&lt;/h2&gt;
&lt;p&gt;In 1996, at IBM&apos;s Almaden Research Center, Miklos Ajtai proved something that sounds too good to be true: certain &lt;em&gt;random&lt;/em&gt; lattice problems are as hard as the &lt;em&gt;worst&lt;/em&gt; case of a related problem [@ajtai-1996]. For a cryptographer, that is the dream.&lt;/p&gt;
&lt;p&gt;Normally, a randomly generated key gives no guarantee you did not pick an easy instance. Ajtai&apos;s worst-case-to-average-case reduction says these lattice problems are different: a random instance is not a roll of the dice -- it inherits the difficulty of the hardest instance that exists. Build your keys on that, and breaking your &lt;em&gt;average&lt;/em&gt; key would mean breaking the &lt;em&gt;worst-case&lt;/em&gt; problem everyone believes is hard.&lt;/p&gt;

The set of all integer combinations of a fixed set of basis vectors -- a regular, infinite grid of points in $n$-dimensional space. The same lattice has infinitely many bases. The hard problems live in the gap between a &quot;good&quot; basis (short, nearly perpendicular vectors) and a &quot;bad&quot; one (long, skewed vectors) that generate the identical grid.
&lt;p&gt;The grid has a catch that makes it useful. Given a &quot;bad&quot; basis, simple questions become brutal.&lt;/p&gt;

Given a basis for a lattice, find the shortest non-zero vector in it. In high dimension, with a bad basis, no efficient algorithm is known -- and the best ones we have get exponentially slower as the dimension grows. Cryptographic hardness is quoted relative to how hard SVP is in the relevant dimension.
&lt;p&gt;Ajtai&apos;s foundation was beautiful. The cryptosystems built directly on it were not. The first generation broke almost as fast as it was proposed. The Ajtai-Dwork scheme was provably hard but shipped megabyte-sized keys, and Nguyen and Stern broke it at its proposed parameters in 1998 [@nguyen-stern-1998]. The Goldreich-Goldwasser-Halevi scheme followed the tempting &quot;publish a bad basis, decrypt with a secret good basis&quot; template. Phong Nguyen broke it in 1999 by noticing that its special error distribution leaked a congruence, recovering plaintext outright at four of the five proposed dimensions and most of it at the fifth [@nguyen-ggh-1999].&lt;/p&gt;
&lt;p&gt;The lesson was expensive and permanent: hiding a good basis is not enough, because the structure you use to decrypt is structure an attacker can find. The hardness was real; the packaging was hopeless.&lt;/p&gt;
&lt;p&gt;The fix arrived in 2005, and it changed the shape of the field. Oded Regev introduced Learning With Errors.&lt;/p&gt;

Recover a secret vector $\mathbf{s}$ from many noisy linear samples $(\mathbf{a}_i,\; \langle \mathbf{a}_i, \mathbf{s}\rangle + e_i \bmod q)$, where each $\mathbf{a}_i$ is public and random and each $e_i$ is a small secret error. Without the errors this is a linear system you solve by Gaussian elimination. With them, it is believed hard. LWE is &quot;linear algebra where every equation is slightly, deliberately wrong.&quot;
&lt;p&gt;Regev&apos;s construction did two things at once. It made the noise &lt;em&gt;intrinsic&lt;/em&gt; -- the hardness no longer depended on hiding a clever basis, but came from the errors themselves -- and it came with a quantum worst-case-to-average-case reduction connecting a random LWE key to the worst case of standard lattice problems [@regev-lwe-2005]. That word &quot;quantum&quot; is deliberate: Regev&apos;s reduction was tuned for a post-quantum world from the start.&lt;/p&gt;
&lt;p&gt;It also points at the deeper reason lattices replaced RSA and elliptic curves. &lt;a href=&quot;https://paragmali.com/blog/how-q-day-breaks-everything-shors-algorithm-and-the-simultan/&quot; rel=&quot;noopener&quot;&gt;Shor&apos;s algorithm&lt;/a&gt; breaks RSA and Diffie-Hellman because those problems hide a &lt;em&gt;periodic&lt;/em&gt; structure that a quantum Fourier transform can extract. LWE exposes no such period.This is the one-line reason lattices were chosen for the post-quantum standards: a period-finding or hidden-subgroup quantum algorithm has nothing to grab onto in the geometry of short vectors. Section 7 makes this precise. The very feature that makes LWE resist Shor is that its hardness is geometric, not arithmetic.&lt;/p&gt;
&lt;p&gt;You can feel why the noise is load-bearing with a tiny numerical example.&lt;/p&gt;
&lt;p&gt;{`
// A toy LWE instance mod q. Recover the secret s from samples (a, b).
const q = 97;
const s = [42, 15, 8];                 // the secret we must recover
const dot = (a, b) =&amp;gt; a.reduce((t, x, i) =&amp;gt; t + x * b[i], 0);
const A = [[12, 5, 33],[7, 88, 1],[54, 2, 19]];  // 3 public random rows&lt;/p&gt;
&lt;p&gt;// Case 1: no noise. b = A s mod q. Gaussian elimination recovers s exactly.
const clean = A.map(a =&amp;gt; ((dot(a, s) % q) + q) % q);
console.log(&quot;clean samples b =&quot;, clean);
// With 3 equations and 3 unknowns and NO error, solving is instant and exact.&lt;/p&gt;
&lt;p&gt;// Case 2: add a small error e in {-1,0,1} to each equation.
const e = [1, -1, 1];
const noisy = A.map((a, i) =&amp;gt; ((((dot(a, s) + e[i]) % q) + q) % q));
console.log(&quot;noisy samples b =&quot;, noisy);
// Now the linear system is INCONSISTENT with the true s: every naive solve
// that assumes e = 0 returns a different, wrong vector. The attacker must
// search over which tiny error vector was added -- and in real dimensions
// (n = 256 and up) that search is the hard lattice problem itself.
console.log(&quot;difference caused by e =&quot;, noisy.map((b, i) =&amp;gt; b - clean[i]));
`}&lt;/p&gt;
&lt;p&gt;Three equations in three unknowns is trivial. The standards use dimensions in the hundreds, and the error turns &quot;solve the system&quot; into &quot;find a suspiciously short vector in a lattice built from the system&quot; -- which is SVP wearing a disguise. That disguise is the entire security story. The rest of this article is about how sharp the disguise really is.&lt;/p&gt;
&lt;p&gt;LWE did not appear from nowhere; it was the turning point of a forty-year accretion, and seeing that lineage explains why the eventual break is an endpoint, not a surprise.&lt;/p&gt;

flowchart LR
    A[&quot;LLL basis reduction, 1982&quot;] --&amp;gt; B[&quot;Ajtai worst-case hardness, 1996&quot;]
    B --&amp;gt; C[&quot;Regev LWE, 2005&quot;]
    C --&amp;gt; D[&quot;Ring-LWE, 2010&quot;]
    D --&amp;gt; E[&quot;Module-LWE, 2015&quot;]
    E --&amp;gt; F[&quot;Kyber and Dilithium, 2017-2018&quot;]
    F --&amp;gt; G[&quot;FIPS 203 and FIPS 204, 2024&quot;]
&lt;p&gt;The oldest box on that diagram, the LLL algorithm of 1982, is not a footnote [@lll-1982]. It is the ancestor of every attack in this article: the first efficient method to take a bad basis and grind it into a better one. LWE was hard and clean, but its keys were quadratic in the security parameter -- far too heavy to ship in a TLS handshake. The fix was to add structure. And structure, it turns out, is exactly where the danger lives.&lt;/p&gt;
&lt;h2&gt;3. Building the Spine: From LWE to Module-LWE&lt;/h2&gt;
&lt;p&gt;The efficiency move came in 2010, and it came with a bill the field is still arguing about. Vadim Lyubashevsky, Chris Peikert, and Oded Regev introduced Ring-LWE, which shrinks LWE&apos;s quadratic keys to quasi-linear by pouring all the algebra into a single polynomial ring [@ring-lwe-lpr-2010]. Instead of storing a full random matrix $\mathbf{A}$, you store one polynomial and let the ring&apos;s multiplication &lt;em&gt;generate&lt;/em&gt; the matrix. Multiplication becomes a number-theoretic transform, the same fast-Fourier trick that makes the schemes practical on a phone. Keys drop from megabytes to kilobytes. Without this step there is no shippable post-quantum handshake.&lt;/p&gt;
&lt;p&gt;But look at what changed. In plain LWE the matrix $\mathbf{A}$ is fully random -- every entry independent. In Ring-LWE that matrix is &lt;em&gt;generated by one polynomial&lt;/em&gt;, so its entries are locked together in a rigid, algebraic way. That relatedness is exactly what makes the scheme fast. It is also what has divided lattice cryptography ever since: does the ring structure only buy speed, or does it also buy the attacker a shortcut?&lt;/p&gt;
&lt;p&gt;Daniel Bernstein and the NTRU Prime team have argued for years that the extra structure is an under-appreciated risk, and they built their alternative to avoid the most structured ring choices [@bernstein-kyber512-2023]. The design teams and NIST bet the other way. Section 8 weighs that dispute; for now, note only that it is real and unresolved.&lt;/p&gt;
&lt;p&gt;The standards did not take either extreme. They took the middle, on purpose.&lt;/p&gt;

LWE instantiated over a rank-$k$ module of a polynomial ring: instead of one big structured polynomial (Ring-LWE) or a fully random matrix (plain LWE), you use a small matrix *of* ring elements at module rank $k$ (square $k \times k$ for ML-KEM; rectangular $k \times l$ -- such as $6 \times 5$ or $8 \times 7$ -- for ML-DSA). It is the deliberate middle ground -- most of Ring-LWE&apos;s speed, but the single-ring symmetry diluted across $k$ components. This is the shared spine of both FIPS standards.
&lt;p&gt;Damien Stehle and Adeline Langlois gave this middle ground its worst-case-to-average-case reduction in 2015, proving that module lattices inherit the same style of hardness guarantee Ajtai and Regev had established for their settings [@langlois-stehle-2015]. That reduction is what lets the designers treat Module-LWE as a trustworthy foundation rather than an ad-hoc compromise. The rank $k$ becomes a dial: turn it up and you dilute the ring structure toward plain LWE (safer, heavier); turn it down toward $k=1$ and you recover Ring-LWE (faster, more structured). The hedge is built into the assumption itself.&lt;/p&gt;

The Short Integer Solution problem over modules: find a short, non-zero combination of given ring vectors that sums to zero. It is a &quot;find a short collision&quot; problem, dual in flavor to Module-LWE&apos;s &quot;recover a short secret.&quot; ML-DSA depends on Module-SIS for unforgeability; ML-KEM does not carry this assumption at all.
&lt;p&gt;Module-SIS is the second load-bearing assumption, and it matters for the asymmetry at the heart of this article: it is carried by the signature and not by the key-encapsulation mechanism. Both schemes then live in the same specific algebraic home.&lt;/p&gt;

The ring $\mathbb{Z}_q[X]/(X^{256}+1)$ that both standards build on: polynomials of degree below 256, with coefficients modulo $q$, reduced whenever the degree reaches 256 by the rule $X^{256} = -1$. Because $256$ is a power of two, this is a &quot;power-of-two cyclotomic&quot; ring -- the most efficient choice, and the one whose extra algebra is the wildcard&apos;s attack surface.

flowchart LR
    A[&quot;Plain LWE: fully random matrix, no ring structure, safest, keys too heavy to ship&quot;] --&amp;gt; B[&quot;Module-LWE: small matrix of ring elements, structure diluted across rank k, the tuned middle&quot;]
    B --&amp;gt; C[&quot;Ring-LWE: one polynomial generates everything, fastest, most structured&quot;]
&lt;p&gt;The through-line from 1998 is worth naming, because the worry is as old as the efficiency trick.NTRU, published in 1998 by Hoffstein, Pipher, and Silverman, was the original &quot;put the lattice in a polynomial ring to make it fast&quot; cryptosystem [@ntru-1998]. It is simultaneously the ancestor of every ring-based scheme here and the origin of the recurring worry that ring structure buys the attacker something. Its descendants include the Falcon signature, whose different spine we meet in Section 4. The field has known since NTRU that ring structure is a bargain with two sides. Module-LWE is the current answer to &quot;how much structure dare we cash in?&quot;&lt;/p&gt;
&lt;p&gt;Module-LWE is the single object both FIPS standards are built on: same ring, same core problem, two products. Which raises the question that defines this whole article. If they share one foundation, do they share one failure?&lt;/p&gt;
&lt;h2&gt;4. Two Standards, One Assumption&lt;/h2&gt;
&lt;p&gt;Lay the two standards side by side and they resolve into one. ML-KEM, the key-encapsulation mechanism in FIPS 203, rests on Module-LWE alone, over the ring $\mathbb{Z}_q[X]/(X^{256}+1)$ with modulus $q = 3329$, and offers three parameter sets at module ranks 2, 3, and 4 [@fips-203]. ML-DSA, the signature in FIPS 204, rests on Module-LWE &lt;em&gt;and&lt;/em&gt; Module-SIS, over the &lt;em&gt;same&lt;/em&gt; ring but with a &lt;em&gt;different&lt;/em&gt;, much larger modulus $q = 8380417$, and signs using Fiat-Shamir with aborts [@fips-204]. Same spine, different parameters.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;ML-KEM (FIPS 203)&lt;/th&gt;
&lt;th&gt;ML-DSA (FIPS 204)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Purpose&lt;/td&gt;
&lt;td&gt;Key encapsulation&lt;/td&gt;
&lt;td&gt;Digital signatures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core hardness&lt;/td&gt;
&lt;td&gt;Module-LWE&lt;/td&gt;
&lt;td&gt;Module-LWE + Module-SIS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ring&lt;/td&gt;
&lt;td&gt;$\mathbb{Z}_q[X]/(X^{256}+1)$&lt;/td&gt;
&lt;td&gt;$\mathbb{Z}_q[X]/(X^{256}+1)$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modulus $q$&lt;/td&gt;
&lt;td&gt;3329&lt;/td&gt;
&lt;td&gt;8380417&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Module ranks&lt;/td&gt;
&lt;td&gt;2 / 3 / 4 (square $k \times k$)&lt;/td&gt;
&lt;td&gt;grows with level (rectangular $k \times l$)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing structure&lt;/td&gt;
&lt;td&gt;not applicable&lt;/td&gt;
&lt;td&gt;Fiat-Shamir with aborts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extra structural route&lt;/td&gt;
&lt;td&gt;decryption failure&lt;/td&gt;
&lt;td&gt;SelfTargetMSIS forgery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A Module-LWE break yields&lt;/td&gt;
&lt;td&gt;the decryption key&lt;/td&gt;
&lt;td&gt;the signing key (universal forgery)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The table&apos;s most important row is the third from the bottom, and it hides in plain sight. Both public keys &lt;em&gt;are&lt;/em&gt;, essentially, the same object: a Module-LWE sample $\mathbf{t} = \mathbf{A}\mathbf{s} + \mathbf{e}$, a structured matrix times a short secret plus a small error. For ML-KEM the public key is literally such a sample, and recovering $\mathbf{s}$ &lt;em&gt;is&lt;/em&gt; recovering the decryption key.&lt;/p&gt;
&lt;p&gt;For ML-DSA the public key is the same shape, and recovering the short secret &lt;em&gt;is&lt;/em&gt; recovering the signing key -- which lets an attacker forge any signature at will. In both cases the attack is one thing: solve search-Module-LWE, find the short secret hiding in the sample. This is the mechanism the whole article turns on.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Correlated failure. Because each public key is a Module-LWE sample read off the same ruler, a single advance in lattice reduction against Module-LWE debits &lt;em&gt;both&lt;/em&gt; standards at once -- the key-encapsulation mechanism and the signature together. It is not two independent bets. It is one bet, made twice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The correlation is real, but it is &lt;em&gt;one-directional&lt;/em&gt;, and precision here matters. A Module-LWE or lattice-reduction advance hits both schemes. But each scheme also carries one extra structural route the other does not share. ML-DSA has a second forgery path through its extra assumption; ML-KEM has a second path through decryption failures. Neither of those extra routes touches the other scheme, and because the two standards use different moduli, ranks, and noise, the &lt;em&gt;same&lt;/em&gt; reduction advance erodes them by &lt;em&gt;different&lt;/em&gt; amounts. &quot;Correlated&quot; does not mean &quot;identical.&quot;&lt;/p&gt;

flowchart TD
    A[&quot;Module-LWE hardness, the shared spine&quot;] --&amp;gt; B[&quot;ML-KEM public key, a Module-LWE sample&quot;]
    A --&amp;gt; C[&quot;ML-DSA public key, a Module-LWE sample&quot;]
    R[&quot;A lattice-reduction advance&quot;] --&amp;gt; A
    B --&amp;gt; D[&quot;Recover the ML-KEM decryption key&quot;]
    C --&amp;gt; E[&quot;Recover the ML-DSA signing key, universal forgery&quot;]
    C --&amp;gt; F[&quot;Extra ML-DSA route: SelfTargetMSIS forgery&quot;]
    B --&amp;gt; G[&quot;Extra ML-KEM route: decryption-failure attack&quot;]
&lt;p&gt;To see why ML-DSA&apos;s forgery route is separate, you need its signing template.&lt;/p&gt;

ML-DSA&apos;s signature method. It builds a signature the Fiat-Shamir way -- commit, hash the message to derive a challenge, respond -- but then *rejection-samples*: any candidate signature whose distribution would leak information about the secret key is thrown away (&quot;abort&quot;) and the signer retries. The published signatures are therefore distributed independently of the signing key, so the only structural way to forge is to solve the underlying short-vector problem directly.
&lt;p&gt;Vadim Lyubashevsky introduced the &quot;with aborts&quot; idea in 2009 [@lyubashevsky-fswa-2009] and made it a trapdoor-free lattice signature in 2012 [@lyubashevsky-sigs-2012]; ML-DSA is its standardized descendant [@dilithium-2018] [@pq-crystals-dilithium]. The rejection step is why forging ML-DSA reduces to a specific hard problem, called SelfTargetMSIS, rather than to &quot;study enough signatures until the key leaks.&quot; That closed door matters, because it was wide open in an earlier generation.&lt;/p&gt;

The post-quantum standards include a second lattice signature, FN-DSA (Falcon), and it is built on a completely different spine: not Fiat-Shamir with aborts, but the GPV &quot;hash-and-sign&quot; framework over NTRU lattices, using fast-Fourier Gaussian sampling [@falcon-spec] [@gpv-2008]. The contrast is instructive. The naive version of hash-and-sign -- signing by rounding with a secret basis, as in NTRUSign -- leaks that basis a little with every signature, and Nguyen and Regev showed in 2006 that collecting enough transcripts recovers the key outright [@nguyen-regev-2006]. The perturbation countermeasures meant to plug the leak were themselves broken in 2012 [@ducas-nguyen-2012]. Falcon survives because GPV sampling is *provably* independent of the basis. ML-DSA reaches the same &quot;signatures reveal nothing about the key&quot; guarantee by a different road -- rejection sampling instead of Gaussian sampling. Two lattice signatures, two spines, two distinct break surfaces: a reminder that &quot;lattice-based&quot; is not one thing.
&lt;p&gt;Correlated failure only bites if the shared foundation can actually be eroded. So how does anyone measure how close an attack is to succeeding? The answer is a single number -- and it is emphatically not a proof.&lt;/p&gt;
&lt;h2&gt;5. The Ruler: How the Margin Is Measured&lt;/h2&gt;
&lt;p&gt;Here is the uncomfortable truth behind every &quot;128-bit security&quot; claim you have ever read about these schemes: there is no proof of it. There is a &lt;em&gt;measurement&lt;/em&gt;, taken with a model that the people who built it will happily tell you is simplified and conservative. To understand how ML-KEM and ML-DSA would break, you have to meet the ruler that says how strong they are today.&lt;/p&gt;
&lt;p&gt;The best known attacks all reduce to lattice reduction, and the workhorse is BKZ, the block-wise reduction introduced by Schnorr and Euchner in 1994 [@bkz-1994].&lt;/p&gt;

Block Korkine-Zolotarev reduction improves a lattice basis by repeatedly calling a subroutine -- an &quot;SVP oracle&quot; -- that solves the shortest-vector problem exactly inside projected blocks of $\beta$ consecutive basis vectors. A larger block size $\beta$ produces shorter vectors and can break harder instances, but the oracle&apos;s cost grows sharply with $\beta$. Concrete security is quoted as &quot;the block size $\beta$ that BKZ must reach to solve this instance.&quot;
&lt;p&gt;The whole security estimate then collapses onto the cost of one oracle call. The cheapest known way to run that oracle is lattice sieving, and in 2016 Becker, Ducas, Gama, and Laarhoven pinned its cost: a sieve solves SVP in a block of size $\beta$ in time $2^{0.292\beta + o(\beta)}$ using $2^{0.208\beta}$ memory [@bdgl16-sieving]. That exponent, $0.292$, is one of the most consequential constants in modern cryptography. The conservative way to price a whole attack is to charge for just that single most expensive call and ignore everything else.&lt;/p&gt;

The deliberately pessimistic (for the defender) cost model that prices an entire lattice attack at the cost of one SVP-oracle call at the required block size: $2^{0.292\beta}$ classical, $2^{0.265\beta}$ quantum. It ignores the many other operations a real attack needs, the cost of memory, and any structure the ring might offer. Because it charges the attacker so little, a scheme that looks secure under core-SVP has margin to spare -- but the number is a modeling choice, not a theorem.
&lt;p&gt;The model originated with the NewHope proposal in 2016 [@newhope-2016]. It was operationalized by the LWE estimator of Albrecht, Player, and Scott, which turns a parameter set into a predicted block size and bit-cost [@aps-estimator-2015]; its maintained successor is the tool NIST parameters are checked against [@lattice-estimator-tool].The estimator is open source. Anyone can install it and re-read the ruler for any parameter set -- which is exactly why the margin is a public, moving number rather than a vendor secret. You can feel the ruler directly: the bit-cost is just the exponent, so a block size and a constant are all you need.&lt;/p&gt;
&lt;p&gt;{`
// Core-SVP prices an attack at ONE sieve-oracle call at block size beta.
// The base-2 log of the cost is simply constant * beta, so the exponent
// IS the bit-security number. No astronomically large integers needed.
const bits = (constant, beta) =&amp;gt; (constant * beta).toFixed(1);&lt;/p&gt;
&lt;p&gt;const beta = 406;                       // ML-KEM-512&apos;s required block size
console.log(&quot;ML-KEM-512, beta =&quot;, beta);
console.log(&quot;classical core-SVP  0.292&lt;em&gt;beta =&quot;, bits(0.292, beta), &quot;bits&quot;);
console.log(&quot;quantum   core-SVP  0.265&lt;/em&gt;beta =&quot;, bits(0.265, beta), &quot;bits&quot;);
console.log(&quot;refined quantum sieve 0.2570   =&quot;, bits(0.2570, beta), &quot;bits&quot;);&lt;/p&gt;
&lt;p&gt;// Now watch the ruler SLIP. Shave the classical constant a hair, from 0.292
// to 0.280 -- the kind of change a better sieve could deliver -- and see how
// many bits of &quot;security&quot; evaporate from the same, unchanged lattice.
console.log(&quot;if the constant drops to 0.280:&quot;, bits(0.280, beta), &quot;bits&quot;);
console.log(&quot;bits lost from a 0.012 change  =&quot;, (bits(0.292,beta) - bits(0.280,beta)).toFixed(1));
`}&lt;/p&gt;
&lt;p&gt;Run it and the classical figure lands near $2^{118}$ -- the pure core-SVP number for ML-KEM-512. Now notice what the last two lines show: nudging the exponent constant by twelve thousandths erases almost five bits from an &lt;em&gt;unchanged&lt;/em&gt; lattice. The ruler is not carved in stone. Its markings move whenever someone finds a better sieve. That is the entire thesis in one code block.&lt;/p&gt;
&lt;p&gt;And the disagreement is not hypothetical. The &lt;em&gt;same&lt;/em&gt; ML-KEM-512 lattice reads wildly differently depending on which model you trust.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost model for ML-KEM-512&lt;/th&gt;
&lt;th&gt;Reads as&lt;/th&gt;
&lt;th&gt;What it actually counts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Pure core-SVP&lt;/td&gt;
&lt;td&gt;about $2^{118}$&lt;/td&gt;
&lt;td&gt;one sieve-oracle call, $2^{0.292\beta}$ at $\beta \approx 406$ [@lattice-estimator-tool]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Estimator default (ring operations)&lt;/td&gt;
&lt;td&gt;about $2^{143.8}$&lt;/td&gt;
&lt;td&gt;ring operations across the whole attack, not just one call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NIST gate model&lt;/td&gt;
&lt;td&gt;$2^{135}$ to $2^{165}$&lt;/td&gt;
&lt;td&gt;logical gates with the cost of memory access priced in&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;One lattice. Three models. Tens of bits apart. NIST&apos;s own Kyber-512 analysis concedes the spread openly, estimating that the real gate count &quot;would range from $2^{135}$ to $2^{165}$&quot; depending on how you model memory [@nist-kyber512-faq]. That range is not a rounding error; it is the margin the thesis says is slipping, written down as a live interval by the standardizer itself.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The break is not a bang; it is a ruler slipping. There is no proof behind &quot;128-bit security&quot; for these schemes -- only a measurement, on a conservative and openly debated model whose defining property is that it moves. The likely break is not an event you watch happen. It is an erosion that has already begun, on a spreadsheet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That reframes the entire question the article opened with. We were looking for the dramatic moment a scheme &quot;cracks.&quot; There may never be one. There is a number, and it drifts.&lt;/p&gt;
&lt;p&gt;The debate over how to read the ruler is public and pointed. Daniel Bernstein has argued that NIST&apos;s Kyber-512 accounting mixes up its arithmetic.&lt;/p&gt;

&quot;NIST&apos;s primary error ... boils down to nonsensically multiplying two costs that should have been added.&quot; -- Daniel J. Bernstein, on the Kyber-512 gate-count dispute

The dispute is a case study in &quot;the margin is a model, not a fact.&quot; Bernstein contends that NIST&apos;s security accounting for Kyber-512 multiplies factors that should be summed, inflating the estimate and papering over how thin the Category 1 margin is [@bernstein-kyber512-2023]. NIST&apos;s Kyber-512 FAQ defends the choice and retains the parameter set at Category 1, publishing the $2^{135}$ to $2^{165}$ range as its honest uncertainty [@nist-kyber512-faq]. The design team&apos;s own conservative reading put Kyber-768 at roughly AES-192 strength and described the margins as holding &quot;under a very conservative analysis&quot; [@pq-crystals-kyber]. You do not have to adjudicate the fight to take the point: the people who build and standardize these schemes disagree, in print, about how many bits of security the smallest parameter set actually has. That disagreement *is* the ruler.
&lt;p&gt;One precaution before we watch the ruler move, because two different quantities share the same number.The sieving exponent $2^{0.292n}$ describes the cost of sieving in the full sieve dimension $n$; the core-SVP figure $2^{0.292\beta}$ describes one oracle call in a block of size $\beta$. They share the constant $0.292$ because both are sieving, but they measure different objects. Conflating them is a classic way to misread the ruler by hundreds of bits. Sieving is not the only oracle, either: the older approach, enumeration, runs in time $2^{\Theta(\beta \log \beta)}$ with only polynomial memory [@bkz2-chen-nguyen-2011]. Sieving wins on time at cryptographic block sizes, which is why the standards are set against it -- but the &quot;best&quot; oracle is itself a moving research target, another reason the ruler is provisional.&lt;/p&gt;
&lt;p&gt;Concretely, the trusted way to read the ruler is the primal attack.&lt;/p&gt;

flowchart TD
    A[&quot;Public key: a Module-LWE sample&quot;] --&amp;gt; B[&quot;Embed it into a lattice whose shortest vector encodes the secret&quot;]
    B --&amp;gt; C[&quot;Run BKZ with block size beta&quot;]
    C --&amp;gt; D[&quot;Each step calls the sieve SVP oracle, cost 2 to the 0.292 beta&quot;]
    D --&amp;gt; E[&quot;At large enough beta, the short secret vector appears&quot;]
    E --&amp;gt; F[&quot;Recover the secret: decryption key or signing key&quot;]
&lt;p&gt;The primal attack embeds the public key into a lattice engineered so its shortest vector &lt;em&gt;is&lt;/em&gt; the secret, then reduces until that vector surfaces [@aps-estimator-2015]. It is the binding constraint -- the number NIST fixes parameters against -- because it relies on no fragile statistical distinguisher, only on reaching the block size. A ruler that is a debated model rather than a proof has one defining property: it moves. And it has moved before.&lt;/p&gt;
&lt;h2&gt;6. The Likely Break: Erosion&lt;/h2&gt;
&lt;p&gt;The break already had a rehearsal. In 2022 a research unit of the Israeli Defense Forces known as MATZOV published an improved dual lattice attack and reported that it shaved measurable margin off the very schemes NIST was about to standardize [@matzov-2022]. No scheme collapsed. No key was recovered. A number moved on a spreadsheet -- and that is exactly what the likely break looks like.&lt;/p&gt;

&quot;Combining these improvements considerably reduces the security levels of Kyber, Saber and Dilithium ... bringing them below the thresholds defined by NIST.&quot; -- MATZOV, Report on the Security of LWE, 2022
&lt;p&gt;Read that quote against the thesis. One attack, aimed at the shared Module-LWE spine, moved &lt;em&gt;both&lt;/em&gt; Kyber (now ML-KEM) [@kyber-2018] and Dilithium (now ML-DSA) at once. That is correlated failure in miniature: not a metaphor, a measurement. And it moved them by &lt;em&gt;different&lt;/em&gt; amounts, because their parameters differ -- exactly the one-directional, unequal correlation Section 4 predicted.&lt;/p&gt;
&lt;p&gt;MATZOV was not a bolt from the blue. It was the latest step in a cryptanalysis lineage that has been quietly moving the ruler for forty years.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Advance&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Effect on the ruler&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;LLL basis reduction&lt;/td&gt;
&lt;td&gt;1982&lt;/td&gt;
&lt;td&gt;first efficient reduction; makes weak bases tractable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BKZ with enumeration&lt;/td&gt;
&lt;td&gt;1990s-2011&lt;/td&gt;
&lt;td&gt;block reduction; oracle cost $2^{\Theta(\beta \log \beta)}$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lattice sieving (BDGL16)&lt;/td&gt;
&lt;td&gt;2016&lt;/td&gt;
&lt;td&gt;cheaper oracle, $2^{0.292\beta}$ -- the modern classical constant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Improved dual attack (MATZOV)&lt;/td&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;dual sieving plus an FFT distinguisher; thins Kyber-512 below a clean 128&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Each row lowered the block size an attacker needs, or the cost per block -- which is the same thing as lowering the bit-security the ruler reports. None of them &quot;broke&quot; anything. All of them moved the number.&lt;/p&gt;
&lt;p&gt;But honesty about erosion cuts both ways, and the MATZOV figure is itself contested. In 2023, Ducas and Pulles examined the dual-attack family and found its success-probability heuristics internally inconsistent in some regimes -- a &quot;waterfall-floor&quot; behavior in which the predicted advantage is, in their words, presumably significantly overestimated [@ducas-pulles-2023].&lt;/p&gt;
&lt;p&gt;So the &lt;em&gt;precedent&lt;/em&gt; is solid: dual attacks improved and the estimates dropped. The &lt;em&gt;exact magnitude&lt;/em&gt; of the drop is a live, disputed number. This is why any specific bit-count in this debate must name its model and source -- and why &quot;the margin is a moving estimate&quot; is more accurate than any single figure.&lt;/p&gt;

The dual attack does not look for the short secret directly. It works in the *dual* lattice: it guesses part of the secret, then uses short vectors of the dual lattice as a statistical distinguisher -- run through a fast Fourier transform over the guessed coordinates -- to test whether the guess was right. MATZOV&apos;s contribution was a faster way to produce those dual vectors (dual sieving) and a sharper distinguisher [@matzov-2022]. The catch Ducas and Pulles identified is that the standard heuristic for the distinguisher&apos;s success probability is internally inconsistent: in some regimes it predicts a probability that a more careful analysis contradicts, producing the tell-tale &quot;waterfall-floor&quot; curve, so the claimed advantage is likely overstated [@ducas-pulles-2023]. This is why the *direction* of the erosion is trusted but the *magnitude* is not, and why the primal attack -- which has no such fragile distinguisher -- remains the number parameters are actually fixed against.
&lt;p&gt;There is also a large, reassuring gap between the theory and what anyone can actually do.The primal attack on ML-KEM-512 needs a block size of about $\beta \approx 406$ [@lattice-estimator-tool]. The public record for a solved shortest-vector challenge, tracked on the SVP Challenge Hall of Fame, stands near dimension 210 [@svp-challenge]. The distance between &quot;the block size the ruler says you need&quot; and &quot;the block size anyone has ever reached&quot; is the practical safety margin -- and it is enormous. The reference sieving implementations that hold those records are highly optimized and public [@g6k-2019], which makes the record a meaningful ceiling rather than a guess. Erosion is real, but the frontier of the &lt;em&gt;achievable&lt;/em&gt; is far below the frontier of the &lt;em&gt;estimated&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The key-encapsulation mechanism carries one more erosion axis of its own, and it is purely structural -- a property of the parameters, not of any particular program. ML-KEM&apos;s decryption is not guaranteed to succeed: there is a tiny probability that Module-LWE noise plus the rounding in ciphertext compression pushes a coordinate across a decoding boundary, and the recovered key is wrong.&lt;/p&gt;
&lt;p&gt;The design fixes this by parameter choice. The round-3 Kyber specification targets decryption-failure probabilities of $\delta = 2^{-139}$, $2^{-164}$, and $2^{-174}$ for the three levels -- all comfortably below $2^{-128}$ -- and the modulus $q = 3329$ was chosen partly to keep that probability negligible [@kyber-round3-spec].&lt;/p&gt;
&lt;p&gt;Why does this matter for a &lt;em&gt;break&lt;/em&gt;? Because decryption failures leak. D&apos;Anvers, Guo, and collaborators showed that observed failures can be turned into full secret-key recovery [@danvers-guo-2019]; &quot;failure boosting&quot; uses precomputation to hunt for failure-inducing ciphertexts [@danvers-vv-2019]; failures cluster, so one found failure makes the next more likely [@bindel-schanck-2020]; and &quot;directional&quot; boosting exploits that clustering, so the cost is dominated by finding the &lt;em&gt;first&lt;/em&gt; failure [@danvers-rossi-virdia-2020].&lt;/p&gt;
&lt;p&gt;It is a genuine structural attack surface -- and at the standardized parameters it is closed, because those same analyses find the required number of oracle queries sits above any practical limit thanks to the conservative $\delta$ [@danvers-vv-2019]. It is the mirror image of ML-DSA&apos;s extra forgery route: real, scheme-specific, and neutralized by the parameter margin, not by luck.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Concrete security for ML-KEM and ML-DSA is a measurement that erodes, not a lock that snaps. The realistic failure mode is the estimator reading a few bits lower after the next reduction paper, not a morning when the schemes stop working. This is why crypto-agility matters more than any single parameter choice, and why &quot;watch the estimator, not the headlines&quot; is the operative advice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That insight organizes the rest of the threat surface. Erosion is the likely route; two tail risks would not be gradual at all.&lt;/p&gt;

flowchart TD
    A[&quot;How Module-LWE would break&quot;] --&amp;gt; B[&quot;Erosion: better lattice reduction (LIKELY)&quot;]
    A --&amp;gt; C[&quot;Quantum: a Shor for lattices (FEARED)&quot;]
    A --&amp;gt; D[&quot;Ring: cyclotomic structural attack (WILDCARD)&quot;]
    B --&amp;gt; B2[&quot;Gradual: the ruler slips a few bits at a time&quot;]
    C --&amp;gt; C2[&quot;Sudden and total, but so far unrealized&quot;]
    D --&amp;gt; D2[&quot;Sudden and total, low probability, high impact&quot;]
&lt;p&gt;One boundary marker before we go on. None of this section is about KyberSlash. That family of timing and division side channels is an &lt;em&gt;implementation&lt;/em&gt; leak -- a bug in how a particular program computes, not a weakness in the mathematics -- and it belongs to the empirical sibling, &quot;How ML-KEM Breaks in Real Life.&quot; Erosion is the likely structural break. Take the quantum tail risk next, because it is the one everyone fears.&lt;/p&gt;
&lt;h2&gt;7. The Quantum Axis: Feared, Not Realized&lt;/h2&gt;
&lt;p&gt;The nightmare has a name -- &quot;a Shor for lattices&quot; -- and for about a week in April 2024 it looked like it had arrived. Yilei Chen posted a claimed polynomial-time quantum algorithm for LWE [@chen-2024-retracted]. Had it held, it would have implied a quantum polynomial-time solver for standard lattice problems within an approximation factor of $\tilde{\Omega}(n^{4.5})$ -- close enough to matter, and built on genuinely new machinery: a complex-Gaussian construction its author called a &quot;Karst wave,&quot; driven through a windowed quantum Fourier transform. For a few days the post-quantum transition held its breath.&lt;/p&gt;
&lt;p&gt;Then it broke -- the claim, not the schemes. Within days, Hongxun Wu and Thomas Vidick identified a fatal error in Step 9, and Chen retracted the result himself.&lt;/p&gt;

&quot;Step 9 of the algorithm contains a bug, which I don&apos;t know how to fix ... the claim of showing a polynomial time quantum algorithm for solving LWE ... does not hold.&quot; -- Yilei Chen, retraction note, 2024
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Chen algorithm is not a live threat and must not be cited as one. It is the single most important recent data point about the &lt;em&gt;absence&lt;/em&gt; of a quantum lattice break: the best attempt by a strong cryptographer, using new tools, failed at one step. That is evidence of difficulty, not of imminent collapse.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Set the fear against what quantum computers actually buy against lattices, which is modest. Quantum &lt;em&gt;sieving&lt;/em&gt; speeds up the SVP oracle from $2^{0.292\beta}$ to about $2^{0.265\beta}$, later refined to roughly $2^{0.2570\beta}$ [@chailloux-loyer-2021]. That is a discount on the exponent, not a change in kind -- and it assumes cheap, large-scale quantum RAM that does not exist. It shaves bits; it does not collapse the problem. The refined quantum constant is why the higher parameter sets keep a comfortable margin even against an idealized quantum sieve.&lt;/p&gt;
&lt;p&gt;Why does the big speedup keep not arriving? Because the structure Shor exploits is simply not present.&lt;/p&gt;

Shor&apos;s algorithm breaks RSA and elliptic curves by solving a hidden-subgroup problem over a *commutative* (abelian) group: it finds a hidden period using the quantum Fourier transform, and periodicity is the whole game. Lattice problems do not present that structure. The shortest-vector problem is about geometry -- distances in a grid -- not about a hidden arithmetic period a Fourier transform can extract. The one explicit bridge anyone has built from lattices to a hidden-subgroup problem, due to Regev in 2002, lands on the *dihedral* group, which is non-commutative and which Shor&apos;s period-finding machinery does not solve [@regev-quantum-2002]. So even the closest structural connection leads to a door Shor cannot open. This is the direct hand-off from the previous part in this series, &quot;How Q-Day Breaks Everything&quot;: lattices were chosen precisely because Shor&apos;s specific trick has nothing to grab. As Chris Peikert&apos;s field survey puts it, generic and relatively modest quantum speedups are the only known quantum advantage against these problems [@peikert-decade-2016].
&lt;p&gt;That leaves only Grover&apos;s algorithm, and it is not a structural break at all.Wu and Vidick found the Step-9 bug in Chen&apos;s algorithm independently and within days, which is itself a sign of how carefully the community watches this line of work. Separately, Grover&apos;s algorithm offers a generic square-root speedup on brute-force key search -- effectively halving the security level in the exponent -- which the standards simply absorb by choosing larger parameters. It is named once and set aside, because it applies to every cryptosystem equally and exploits nothing about lattices. Grover turns a $2^{n}$ search into a $2^{n/2}$ one; the parameter sets are sized so that even after that discount the key-search cost stays out of reach. It is a reason the numbers are what they are, not a route to a break.&lt;/p&gt;
&lt;p&gt;Quantum is the feared route that keeps not arriving. The other tail risk is quieter, older, and the one the ruler literally cannot price: the algebra of the ring itself.&lt;/p&gt;
&lt;h2&gt;8. The Wildcard: The Cyclotomic Ring&lt;/h2&gt;
&lt;p&gt;The core-SVP ruler measures one thing: how hard it is to find a short vector by generic lattice reduction. It does not measure whether the &lt;em&gt;algebra&lt;/em&gt; of the ring offers a shortcut that reduction never sees. That unpriced surface is the wildcard, and intellectual honesty demands steelmanning the people who worry about it, because they have been right before.&lt;/p&gt;
&lt;p&gt;Ring structure has been cashed in for real attacks. In 2016, Cramer, Ducas, Peikert, and Regev showed a quantum polynomial-time (classically sub-exponential) algorithm that recovers short generators of principal ideals in cyclotomic fields -- a structural shortcut that plain lattice reduction does not find [@cdpr-2016]. The same year, Albrecht, Bai, and Ducas broke &quot;overstretched&quot; NTRU by projecting the problem into a subfield, exploiting ring structure that appears when the modulus is very large [@albrecht-bai-ducas-2016].&lt;/p&gt;
&lt;p&gt;Neither attack touches ML-KEM or ML-DSA at their standardized parameters -- the first needs principal ideals with unusually short generators, the second a modulus far larger than the standards use -- but both prove the general point: structure is not free, and sometimes the attacker gets to spend it. This is why Daniel Bernstein and the NTRU Prime team argue the cyclotomic choice is an under-appreciated risk and deliberately avoid the most structured rings in their own designs [@bernstein-kyber512-2023].&lt;/p&gt;
&lt;p&gt;Now the counterweight, weighed just as fairly. First, Module-LWE was chosen partly to dilute exactly this risk: spreading the problem across a rank-$k$ module reduces the single-ring symmetry an algebraic attack would exploit. Second, at the standardized parameters, no known algebraic attack beats generic sieving -- the ideal and subfield attacks live in regimes the standards specifically avoid.&lt;/p&gt;
&lt;p&gt;Third, and most concretely, the newest analysis points the &lt;em&gt;other&lt;/em&gt; way. In 2025, Ducas, Engelberts, and de Perthuis studied module-lattice reduction directly and found that for the power-of-two cyclotomic ring -- exactly the ring ML-KEM and ML-DSA use -- the module structure gives the attacker no free reduction in block size [@ducas-mbkz-2025]. If anything it costs a little: their module-BKZ prediction needs a block size larger by roughly $(d-1)$. The ring the standards chose is, by this measure, a slight &lt;em&gt;disadvantage&lt;/em&gt; to the attacker, not a gift.&lt;/p&gt;
&lt;p&gt;The power-of-two choice is deliberate and load-bearing. Bernstein&apos;s NTRU Prime avoids power-of-two cyclotomics on principle, precisely because &lt;em&gt;other&lt;/em&gt; cyclotomic fields carry more exploitable algebra. And the 2025 module-reduction analysis finds that non-power-of-two cyclotomic fields can yield a sub-exponential module-BKZ gain, whereas the power-of-two ring yields none [@ducas-mbkz-2025]. The standards picked the ring that gives the attacker the least algebraic help, not the most.&lt;/p&gt;
&lt;p&gt;Put the three routes on one page and the wildcard sits where it belongs.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Likelihood&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;th&gt;Best evidence it is real&lt;/th&gt;
&lt;th&gt;Counterweight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Erosion (better reduction)&lt;/td&gt;
&lt;td&gt;Likely&lt;/td&gt;
&lt;td&gt;Gradual, partial&lt;/td&gt;
&lt;td&gt;MATZOV 2022 moved the published margin&lt;/td&gt;
&lt;td&gt;Huge gap: $\beta \approx 406$ needed vs SVP record near 210 [@lattice-estimator-tool] [@svp-challenge]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quantum (a Shor for lattices)&lt;/td&gt;
&lt;td&gt;Feared&lt;/td&gt;
&lt;td&gt;Sudden, total&lt;/td&gt;
&lt;td&gt;Chen 2024 attempt using new machinery&lt;/td&gt;
&lt;td&gt;Retracted in days; quantum sieve is only a modest discount&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ring (cyclotomic structure)&lt;/td&gt;
&lt;td&gt;Wildcard&lt;/td&gt;
&lt;td&gt;Sudden, total&lt;/td&gt;
&lt;td&gt;Ideal and subfield attacks on adjacent variants&lt;/td&gt;
&lt;td&gt;Diluted by modules; no free block-size at power-of-two (2025)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The honest reading of that table is not &quot;relax.&quot; It is &quot;the two catastrophic routes are unrealized and actively fenced off, while the likely route is gradual and observable.&quot; That asymmetry is the entire risk posture of lattice cryptography.&lt;/p&gt;
&lt;p&gt;NIST reads it the same way, and hedged accordingly. In March 2025 it selected the code-based key-encapsulation mechanism HQC as a backup to ML-KEM [@nist-hqc-announcement], explicitly as insurance against a systemic weakness in lattices [@nist-ir-8545]. That is not a vote of no confidence in ML-KEM; it is a standardizer refusing to make the entire post-quantum transition depend on a single hard problem.&lt;/p&gt;

If a lattice break is the fear, the answer is not to abandon lattices -- it is to keep a non-lattice fallback ready. NIST&apos;s portfolio is built for exactly this [@nist-pqc-project]. The hash-based signature SLH-DSA (FIPS 205) rests only on the security of hash functions, an assumption entirely disjoint from lattices [@fips-205]. The code-based HQC rests on the hardness of decoding random linear codes [@nist-ir-8545]. For the ring worry specifically, one can move down Section 3&apos;s spectrum toward unstructured LWE, paying the full efficiency price to remove ring structure entirely, or choose a non-power-of-two ring as NTRU Prime does [@bernstein-kyber512-2023]. Each option trades performance or key size for independence from the lattice-and-ring assumptions. That is what a hedge costs.
&lt;p&gt;The ring wildcard is low-probability, high-impact -- and honestly labeled as such. But naming it forces a deeper and more uncomfortable question. How much of any of this is actually &lt;em&gt;proven&lt;/em&gt;?&lt;/p&gt;
&lt;h2&gt;9. What Is Actually Proven&lt;/h2&gt;
&lt;p&gt;Here is the honest accounting, and it is more humbling than the marketing suggests. Lattice hardness is &lt;em&gt;unproven&lt;/em&gt; -- and, in a precise sense, it cannot be proven to the standard people quietly assume it meets.&lt;/p&gt;
&lt;p&gt;Start with the ceiling. The approximate shortest-vector problem relevant to cryptography -- GapSVP with an approximation factor around $\sqrt{n}$ -- was shown by Aharonov and Regev in 2005 to lie in $\mathrm{NP} \cap \mathrm{coNP}$ [@aharonov-regev-2005]. That single fact has a large consequence: a problem in $\mathrm{NP} \cap \mathrm{coNP}$ is very unlikely to be NP-hard, because if it were, the polynomial hierarchy would collapse. So lattice cryptography can &lt;em&gt;never&lt;/em&gt; be founded on NP-completeness. The dream of &quot;as hard as the hardest problems in NP&quot; is off the table by a theorem.&lt;/p&gt;
&lt;p&gt;The flip side is just as sobering: a genuine &lt;em&gt;proof&lt;/em&gt; that these problems are hard would prove $\mathrm{P} \neq \mathrm{NP}$ and settle the biggest open question in computer science. Nobody expects that proof. Security rests on the &lt;em&gt;failure of decades of effort&lt;/em&gt; to find an efficient algorithm, not on a lower bound.&lt;/p&gt;
&lt;p&gt;Then there are the reductions everyone points to -- Ajtai&apos;s, Regev&apos;s, Langlois and Stehle&apos;s. They are real and they are beautiful, but read their quantifiers carefully.&lt;/p&gt;

An *asymptotic* hardness result says a problem is hard &quot;for all large enough $n$,&quot; with unspecified constants. A *concrete* security claim says a specific instance -- $n = 256$, $q = 3329$ -- costs a specific number of operations to break. The worst-case-to-average-case reductions for lattices are asymptotic. They guarantee that *some* sufficiently large parameter is hard; they do not pin the bit-security of the exact parameters a standard ships.
&lt;p&gt;This is the gap the ruler papers over, and it has two halves. First, the reductions are asymptotic: they never certify $n = 256$ specifically, so the concrete strength of the standardized parameters is an estimate, not a corollary.&lt;/p&gt;
&lt;p&gt;Second, even the &lt;em&gt;estimate&lt;/em&gt; trusts a heuristic. The provable cost of solving SVP is around $2^{n}$, but concrete security is quoted using the heuristic sieving cost $2^{0.292n}$ that the estimator actually runs [@bdgl16-sieving]. The number protecting your data is the smaller, unproven one. Both halves point the same way: concrete lattice security is a carefully argued &lt;em&gt;belief&lt;/em&gt;, propped up by a conservative model, not a theorem.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; This is the same epistemic position RSA has always occupied -- on a younger assumption. RSA&apos;s security was never proven either; it rests on the enduring failure to factor efficiently. Lattice security rests on the enduring failure to reduce lattices efficiently. The difference is only age and exposure: factoring has been hammered for decades longer than Module-LWE has existed. &quot;Believed hard, and watched closely&quot; is the honest label for both.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That reframing turns the open problems from anxieties into a research agenda, and they are worth stating as the questions they are. Is there a large quantum speedup for lattices -- a working version of what Chen 2024 reached for? Is the cyclotomic ring structure exploitable at cryptographic sizes, or does the power-of-two choice hold? And how tight is the core-SVP model really -- what is the true cost of one sieve call, once memory and data movement are honestly priced? Each of these is being worked on in the open, and the answer to each moves the ruler.&lt;/p&gt;
&lt;p&gt;None of this means ML-KEM and ML-DSA are weak. It means their strength is a measured, moving, human judgment rather than a settled fact -- which is exactly why what you do with them on Monday matters.&lt;/p&gt;
&lt;h2&gt;10. What to Do on Monday&lt;/h2&gt;
&lt;p&gt;If the ruler moves, engineering to a single fixed number is the wrong instinct. Engineer for headroom, and engineer for change. Five moves follow directly from everything above.&lt;/p&gt;
&lt;p&gt;Prefer the higher parameter set for anything long-lived. ML-KEM offers levels 512, 768, and 1024; ML-DSA offers a matching ladder up to ML-DSA-87 [@fips-203] [@fips-204]. The smallest set, Kyber-512, is where the margin debate is sharpest, so for data that must stay secret for a decade, choose ML-KEM-1024 and the high ML-DSA level and buy yourself bits the estimator cannot easily erase. Even the design team&apos;s conservative reading places the middle set, Kyber-768, near AES-192 and treats it as the sensible default [@pq-crystals-kyber].&lt;/p&gt;
&lt;p&gt;Deploy in &lt;a href=&quot;https://paragmali.com/blog/q-day-has-not-happened-the-incident-already-has-harvest-now-/&quot; rel=&quot;noopener&quot;&gt;hybrid&lt;/a&gt;. Run the post-quantum key exchange alongside a classical one (X25519 or a P-curve) and combine both secrets, so a break of the lattice problem is not a single point of failure -- the classical layer still stands, and vice versa. This is the mainstream transition posture for exactly the reason this article gives: correlated failure across the lattice standards means a lattice break is systemic, and a non-lattice layer is the cheapest insurance against it.&lt;/p&gt;
&lt;p&gt;Build crypto-agility. The lesson of the moving ruler is that today&apos;s parameters are a snapshot. Architect so that swapping a parameter set -- or an entire algorithm -- is a configuration change, not a rewrite. The sibling articles on &lt;a href=&quot;https://paragmali.com/blog/you-cannot-rotate-what-you-cannot-see-crypto-agility-and-the/&quot; rel=&quot;noopener&quot;&gt;crypto-agility&lt;/a&gt; and &lt;a href=&quot;https://paragmali.com/blog/one-event-three-assumptions-five-answers-a-field-guide-to-th/&quot; rel=&quot;noopener&quot;&gt;the post-quantum toolkit&lt;/a&gt; go deeper here; the one-line version is that agility is the property that lets you re-read the ruler and act on it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 1. For long-lived secrets, default to ML-KEM-1024 and ML-DSA-87; reserve the smaller sets for ephemeral or low-value data. 2. Deploy post-quantum key exchange in hybrid with a classical algorithm, never alone. 3. Make algorithm and parameter choices swappable in configuration -- build for the swap you will eventually make. 4. Watch the lattice estimator and the cryptanalysis literature, not the headlines; the real signal is a few bits moving, not a dramatic announcement. 5. Keep a non-lattice backstop in your portfolio -- SLH-DSA for signatures, HQC for key encapsulation -- so a systemic lattice result is a migration, not a crisis [@fips-205] [@nist-ir-8545].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Watch the estimator, not the headlines. The break, if it comes the likely way, will show up first as a revised number in a tool most people never look at. The teams that will migrate calmly are the ones already tracking that number.&lt;/p&gt;
&lt;p&gt;These are not the moves of a field in crisis. They are the moves of a field that has learned to live with a believed-hard problem, and to read its ruler honestly.&lt;/p&gt;
&lt;h2&gt;11. Frequently Asked Questions, and a Closing Thought&lt;/h2&gt;


No. At the standardized parameters, no public attack recovers a key or forges a signature. What is happening is measurement, not breakage: cryptanalysts refine the estimated cost of the best attacks, and the numbers drift. The 2022 MATZOV result thinned the estimated margin of the smallest Kyber set, but even its magnitude is contested, and the block size a real attack needs remains far beyond anything ever demonstrated [@matzov-2022] [@ducas-pulles-2023].


No, and that is the entire reason they were chosen. Shor&apos;s algorithm breaks RSA and elliptic curves by finding hidden periodic structure over a commutative group; lattice problems do not expose that structure, and the one explicit bridge to a hidden-subgroup problem lands on the non-commutative dihedral group that Shor&apos;s method does not solve [@regev-quantum-2002]. The only known quantum advantage against lattices is a modest speedup of the sieving oracle [@peikert-decade-2016].


Only in the weak, generic sense that it speeds up brute-force search everywhere. Grover turns a cost of $2^{n}$ into $2^{n/2}$, so it effectively halves the exponent of a key search -- a discount the parameter sizes already absorb. It exploits nothing specific to lattices and is not a structural break.


Both standards rest on Module-LWE, so a single lattice-reduction advance debits both at once -- that is the correlation. It is one-directional and unequal: the two schemes use different moduli and ranks, so the same advance erodes them by different amounts, and ML-DSA carries an extra forgery route through Module-SIS that ML-KEM does not share [@fips-204]. The key-encapsulation mechanism, in turn, has its own extra route through decryption failures [@danvers-guo-2019]. Shared spine, not identical schemes.


No. Security bits come from the cost of lattice reduction, not from a larger modulus, and *more* ring structure can *add* attack surface rather than remove it -- an overly large modulus is exactly what makes overstretched-NTRU breakable [@albrecht-bai-ducas-2016]. The standards chose the power-of-two cyclotomic ring because it gives the attacker the least algebraic help [@ducas-mbkz-2025], not because bigger is better.


No. KyberSlash is an implementation timing leak -- a flaw in how specific software computed, not in the mathematics of Module-LWE. It is real and it mattered, but it lives outside this article&apos;s structural scope. The empirical sibling, &quot;How ML-KEM Breaks in Real Life,&quot; covers that whole family of implementation attacks.


For long-lived data, prefer the higher parameter sets (ML-KEM-1024, a high ML-DSA level) [@fips-203] [@fips-204]. Deploy post-quantum key exchange in hybrid with a classical algorithm so a lattice break is not a single point of failure, build crypto-agility so you can swap parameters or algorithms as a configuration change, and keep a non-lattice backstop such as SLH-DSA or HQC in your portfolio [@fips-205] [@nist-ir-8545].

&lt;p&gt;So return to the question the celebrations skipped. If a quantum computer cannot break ML-KEM and ML-DSA the way it broke RSA, how &lt;em&gt;would&lt;/em&gt; they break? The answer, assembled piece by piece, is a single sentence: two standards, one lattice, one ruler. They share the Module-LWE spine, and their strength is not proven but measured, on a core-SVP ruler that the field argues about in the open. The likely break is that ruler slipping a few bits at a time as reduction improves -- and because both standards read the same ruler, one slip debits both at once.&lt;/p&gt;
&lt;p&gt;The evidence lines up behind that reading. Erosion is not hypothetical: MATZOV already moved the margin once, and the only debate is by how much. The feared quantum collapse remains unrealized -- the best attempt was retracted within days over a bug at Step 9. The structural wildcard, the algebra of the cyclotomic ring, is genuinely unpriced by the ruler, but the newest analysis finds the power-of-two ring gives the attacker no free reduction, and NIST hedged anyway by standardizing code-based HQC.&lt;/p&gt;
&lt;p&gt;The verdict is not &quot;broken.&quot; It is &quot;believed hard, conservatively measured, and watched closely&quot; -- the same position RSA has long occupied, on a much younger assumption.&lt;/p&gt;
&lt;p&gt;Which is why the honest way to end is not with a warning but with a recalibration. If the break comes the likely way, it will not be a morning when the internet stops working. It will be a line in a changelog -- a revised constant in a tool most people never open, moving the ruler a few bits and asking, quietly, whether it is time to turn the parameter dial again.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;how-ml-kem-and-ml-dsa-would-break&quot; keyTerms={[
  { term: &quot;Module-LWE&quot;, definition: &quot;The shared hard problem under both ML-KEM and ML-DSA: LWE over a rank-k module of a polynomial ring, the tuned middle ground between unstructured LWE and Ring-LWE.&quot; },
  { term: &quot;Module-SIS&quot;, definition: &quot;A short-collision problem over modules; ML-DSA&apos;s extra assumption for unforgeability, which ML-KEM does not carry.&quot; },
  { term: &quot;Core-SVP model&quot;, definition: &quot;The conservative cost model that prices a whole lattice attack at one sieve-oracle call: 2^(0.292 beta) classical, 2^(0.265 beta) quantum. A debated measurement, not a proof.&quot; },
  { term: &quot;Block size beta&quot;, definition: &quot;The BKZ parameter that sets how large a projected block the SVP oracle must solve; security is quoted as the beta an attack must reach.&quot; },
  { term: &quot;Correlated failure&quot;, definition: &quot;Because both standards read the same Module-LWE ruler, one reduction advance debits both at once; one-directional and unequal across the two schemes.&quot; },
  { term: &quot;Cyclotomic ring&quot;, definition: &quot;The ring Z_q[X]/(X^256+1) both standards use; its extra algebra is the unpriced wildcard attack surface, chosen as a power-of-two form to minimize the attacker&apos;s algebraic help.&quot; },
  { term: &quot;Fiat-Shamir with aborts&quot;, definition: &quot;ML-DSA&apos;s signing method: rejection-sample any transcript that would leak the key, so signatures are distributed independently of the signing key.&quot; },
  { term: &quot;Erosion&quot;, definition: &quot;The likely break: better lattice reduction lowers the estimated bit-security a few bits at a time, as MATZOV 2022 demonstrated in miniature.&quot; }
]} questions={[
  { q: &quot;Why does a single advance against Module-LWE threaten both ML-KEM and ML-DSA at once?&quot;, a: &quot;Each public key is essentially a Module-LWE sample, so both are read off the same core-SVP ruler; a reduction advance lowers both estimates, though by different amounts because their parameters differ.&quot; },
  { q: &quot;Why is core-SVP called a measurement rather than a proof?&quot;, a: &quot;It is a deliberately conservative cost model with debated constants; the same ML-KEM-512 lattice reads 2^118, 2^143.8, or 2^135 to 2^165 depending on the model, so the number moves as models and attacks improve.&quot; },
  { q: &quot;Why does Shor&apos;s algorithm not break lattice schemes?&quot;, a: &quot;Shor exploits hidden periodic structure over commutative groups; lattice problems expose no such period, and the one bridge to a hidden-subgroup problem lands on the non-commutative dihedral group Shor cannot solve.&quot; },
  { q: &quot;What happened with the Chen 2024 quantum LWE claim?&quot;, a: &quot;It claimed a polynomial-time quantum algorithm for LWE but was retracted within days over a fatal Step-9 bug identified by Wu and Vidick; it is the strongest recent evidence that no quantum lattice break exists yet.&quot; },
  { q: &quot;Why did the standards choose the power-of-two cyclotomic ring?&quot;, a: &quot;The 2025 module-reduction analysis finds it gives the attacker no free block-size reduction, whereas other cyclotomic fields can yield a sub-exponential gain; the module structure also dilutes the exploitable ring symmetry.&quot; },
  { q: &quot;In what precise sense is lattice hardness unproven?&quot;, a: &quot;Approximate SVP sits in NP intersect coNP, so it cannot be NP-hard, and the worst-case-to-average-case reductions are asymptotic; concrete security is a believed-hard judgment resting on a heuristic cost model, not a theorem.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>post-quantum-cryptography</category><category>ml-kem</category><category>ml-dsa</category><category>module-lwe</category><category>lattice-reduction</category><category>cryptanalysis</category><category>core-svp</category><category>fips-203</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>One Event, Three Assumptions, Five Answers: A Field Guide to the Post-Quantum Toolkit</title><link>https://paragmali.com/blog/one-event-three-assumptions-five-answers-a-field-guide-to-th/</link><guid isPermaLink="true">https://paragmali.com/blog/one-event-three-assumptions-five-answers-a-field-guide-to-th/</guid><description>A field guide to the five NIST post-quantum primitives -- ML-KEM, ML-DSA, SLH-DSA, FN-DSA, HQC: math intuition, exact sizes, failures, and decision rules.</description><pubDate>Tue, 14 Jul 2026 01:32:13 GMT</pubDate><content:encoded>
Shor&apos;s 1994 algorithm condemned RSA, Diffie-Hellman, and elliptic curves [@shor-1994], and &quot;harvest now, decrypt later&quot; means the clock is already running on today&apos;s traffic. NIST&apos;s answer is not one replacement but a **toolkit**: three finalized standards -- ML-KEM for key exchange, ML-DSA and SLH-DSA for signatures, all published on 2024-08-13 [@fips-203] [@fips-204] [@fips-205] -- and two more still on the way, FN-DSA (Falcon) and HQC, both pre-final [@fips-206-perlner-2025] [@nist-ir-8545]. The five are spread deliberately across lattices, hash functions, and codes so that no single mathematical break takes everything down. There is no free lunch: every choice trades size against speed against how conservative the assumption is. And, tellingly, **nothing in the toolkit has been mathematically broken.** Every real-world failure so far has been an implementation leak -- KyberSlash&apos;s secret-dependent division [@kyberslash-site], Falcon&apos;s floating-point hazard [@fouque-gsnorm-2019] -- while the era&apos;s two famous cryptanalytic breaks, SIKE and Rainbow, hit schemes that never made the cut [@castryck-decru-sidh-2022] [@beullens-rainbow-2022].
&lt;h2&gt;1. Somebody Is Already Saving Your Handshake&lt;/h2&gt;
&lt;p&gt;Right now, somewhere, a machine may be recording this very TLS session -- not to read today, but to decrypt on the afternoon a large quantum computer finally boots. That is not a thriller premise. It is the stated design assumption behind a change that is already shipping in production TLS software, where the default key exchange offered is no longer plain X25519 but a hybrid whose second half is called ML-KEM [@openssl-35-notes]. The strange part is not that the field replaced the math. It is that replacing it took &lt;strong&gt;five&lt;/strong&gt; different algorithms, resting on &lt;strong&gt;three&lt;/strong&gt; unrelated hard problems, to answer a &lt;strong&gt;single&lt;/strong&gt; result published in 1994 -- and that, so far, not one of the five has actually been broken.&lt;/p&gt;
&lt;p&gt;The single result is Shor&apos;s algorithm. In 1994 Peter Shor showed that a large, fault-tolerant quantum computer could factor integers and compute discrete logarithms in polynomial time [@shor-1994]. That one capability condemns essentially every public-key system deployed on the internet: RSA rests on factoring, Diffie-Hellman and elliptic-curve cryptography rest on discrete logarithms. (This series covered those primitives directly in &lt;a href=&quot;https://paragmali.com/blog/rsa-is-a-trapdoor-not-a-cryptosystem-oaep-pss-and-the-25-yea/&quot; rel=&quot;noopener&quot;&gt;Part 14 on RSA&lt;/a&gt;, &lt;a href=&quot;https://paragmali.com/blog/the-curve-was-hard-the-gap-was-soft-a-field-guide-to-using-e/&quot; rel=&quot;noopener&quot;&gt;Part 15 on elliptic curves&lt;/a&gt;, and &lt;a href=&quot;https://paragmali.com/blog/nobody-broke-the-discrete-log-a-field-guide-to-diffie-hellma/&quot; rel=&quot;noopener&quot;&gt;Part 18 on Diffie-Hellman&lt;/a&gt;.) The moment a cryptographically relevant quantum computer exists, all three fall together.&lt;/p&gt;

An attack strategy in which an adversary records encrypted traffic today, stores it, and decrypts it years later once a quantum computer becomes available. It means the quantum threat is not purely in the future: any secret that must stay confidential past the arrival of quantum computing is already exposed the moment it crosses the wire.
&lt;p&gt;Harvest now, decrypt later is why this is urgent before any quantum computer exists. If your threat model includes an adversary who can afford disk space and patience, then a session key protecting a 20-year secret is already at risk today [@nist-pqc-project]. That is the reasoning behind migrating key establishment first, and it is why the hybrid X25519MLKEM768 key share now ships as a default key share in OpenSSL 3.5, and was enabled by default in OpenSSH 9.9 before becoming the default key exchange in OpenSSH 10.0 [@openssl-35-notes] [@openssh-99-notes] [@openssh-pq].&lt;/p&gt;
&lt;p&gt;So the threat is one thing, sharp and singular. Why is the answer five things? NIST did not standardize one post-quantum cipher; it assembled a &lt;strong&gt;toolkit&lt;/strong&gt; -- three finalized standards and two more in progress -- and spread it across three unrelated families of hard problem: structured lattices, hash functions, and error-correcting codes. The bet is that a mathematical breakthrough against one family is unlikely to touch the others. To see why the answer is a toolkit, not a single cipher: its parts are older than the threat they answer.&lt;/p&gt;
&lt;h2&gt;2. The Threat, and the Three Old Ideas That Outlived It&lt;/h2&gt;
&lt;p&gt;Here is the twist that makes the whole story make sense: the replacements predate the threat. The oldest members of the toolkit were invented for reasons that had nothing to do with quantum computers, and they turned out to be quantum-safe by accident.&lt;/p&gt;
&lt;p&gt;Robert McEliece published a code-based public-key cryptosystem in 1978, hiding a secret, efficiently decodable error-correcting code (a binary Goppa code) behind a scrambled generator matrix so that an attacker faces the task of decoding a random-looking linear code [@mceliece-1978]. One year later, Ralph Merkle showed how to build digital signatures out of nothing but a hash function, chaining one-time keys under a binary hash tree whose root is the public key [@merkle-thesis-1979]; he polished the construction a decade later as &quot;A Certified Digital Signature&quot; [@merkle-cds-1989]. Both predate Shor by fifteen-plus years. Both are still standing.&lt;/p&gt;
&lt;p&gt;Then, in 1994, the threat arrived. Shor&apos;s quantum algorithm solves factoring and discrete logarithm in polynomial time, condemning RSA, Diffie-Hellman, and elliptic curves the moment a large quantum computer runs it [@shor-1994]. Two years later Lov Grover found a quantum search algorithm with a quadratic speedup [@grover-1996]. Grover is the good news that bounds the damage: a mere square-root speedup means doubling a symmetric key or hash-output length restores the security margin, which is exactly why hash-based signatures are considered the most conservative branch of the toolkit.Shor is catastrophic (exponential to polynomial); Grover is survivable (a square-root factor). The asymmetry is the reason symmetric ciphers and hash functions merely need bigger parameters, while public-key cryptography needed entirely new hard problems.&lt;/p&gt;
&lt;p&gt;Lattices arrived on a separate track, and again for their own reasons. In 1996 Miklos Ajtai proved a startling worst-case-to-average-case reduction: breaking a &lt;em&gt;random&lt;/em&gt; instance of a certain lattice problem is as hard as breaking the &lt;em&gt;worst&lt;/em&gt; case [@ajtai-1996]. That single result promoted lattices from a curiosity to a rigorous foundation. In 1998 Hoffstein, Pipher, and Silverman published NTRU, the first lattice scheme compact and fast enough to consider deploying, working over a small polynomial ring with tiny coefficients [@ntru-1998].NTRU was first announced at the CRYPTO 1996 rump session but formally published at ANTS-III in 1998, so you will see both dates in the literature. Merkle&apos;s hash-tree work has the same two-date character: the 1979 thesis, then the 1989 CRYPTO paper.&lt;/p&gt;
&lt;p&gt;Oded Regev tied the knot in 2005 with Learning With Errors (LWE), a versatile assumption whose hardness reduces (quantumly) to worst-case lattice problems and whose one-sentence intuition -- add noise to linear algebra -- runs through every lattice member of the toolkit [@regev-lwe-2005].&lt;/p&gt;
&lt;p&gt;The last pieces are the mechanisms that make these foundations into safe schemes. The Fujisaki-Okamoto transform (1999) upgrades a weak encryption scheme into a strong one by re-encrypting on decryption and checking consistency [@fo-1999]. The GPV framework (2008) showed how to build lattice hash-and-sign signatures using a trapdoor and discrete-Gaussian sampling [@gpv-2007]. Lyubashevsky&apos;s &quot;Fiat-Shamir with aborts&quot; (2009) offered a rival way to sign, rejecting and restarting whenever a candidate would leak the key [@lyubashevsky-fswa-2009]. Ring-LWE (2010) moved LWE into polynomial rings for compact keys and fast arithmetic [@lpr-ringlwe-2010]. And in 2015, SPHINCS made hash-based signatures &lt;em&gt;stateless&lt;/em&gt;, removing the operational footgun that had kept Merkle&apos;s idea out of ordinary hands [@sphincs-2015].&lt;/p&gt;

timeline
    title Post-quantum foundations predate the 1994 threat
    1978 : McEliece code-based encryption
    1979 : Merkle hash-based signatures
    1994 : Shor algorithm breaks RSA and ECC
    1996 : Grover search : Ajtai hard lattices
    1998 : NTRU ring lattices
    2005 : Regev Learning With Errors
    2008 : GPV lattice hash-and-sign
    2009 : Fiat-Shamir with aborts
    2010 : Ring-LWE efficiency
    2015 : SPHINCS stateless hashing
&lt;p&gt;Read the timeline as three columns hiding in one line. Codes and hashes (1978, 1979) are the ancient, conservative branches. Lattices (1996 to 2010) are the young, efficient branch that took the most theoretical work to make safe. The mechanisms (FO, GPV, Fiat-Shamir-with-aborts) are the connective tissue that turns a hard problem into a usable cipher.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Who&lt;/th&gt;
&lt;th&gt;Idea&lt;/th&gt;
&lt;th&gt;Why it mattered&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1978&lt;/td&gt;
&lt;td&gt;McEliece&lt;/td&gt;
&lt;td&gt;Code-based encryption&lt;/td&gt;
&lt;td&gt;Oldest surviving PQC family; ancestor of HQC [@mceliece-1978]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1979&lt;/td&gt;
&lt;td&gt;Merkle&lt;/td&gt;
&lt;td&gt;Hash-based signatures&lt;/td&gt;
&lt;td&gt;Weakest possible assumption; ancestor of SLH-DSA [@merkle-thesis-1979]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1994&lt;/td&gt;
&lt;td&gt;Shor&lt;/td&gt;
&lt;td&gt;Quantum factoring and discrete log&lt;/td&gt;
&lt;td&gt;The single threat the toolkit answers [@shor-1994]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1996&lt;/td&gt;
&lt;td&gt;Ajtai&lt;/td&gt;
&lt;td&gt;Worst-case lattice hardness&lt;/td&gt;
&lt;td&gt;Made lattices a rigorous foundation [@ajtai-1996]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2005&lt;/td&gt;
&lt;td&gt;Regev&lt;/td&gt;
&lt;td&gt;Learning With Errors&lt;/td&gt;
&lt;td&gt;The assumption under ML-KEM and ML-DSA [@regev-lwe-2005]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2015&lt;/td&gt;
&lt;td&gt;Bernstein et al.&lt;/td&gt;
&lt;td&gt;Stateless hash signatures&lt;/td&gt;
&lt;td&gt;Made hash signatures deployable [@sphincs-2015]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Each of these old ideas was quantum-safe. And none was deployable as written. To see why, watch each one walk straight into a different wall.&lt;/p&gt;
&lt;h2&gt;3. Three Walls: Why the Old Ideas Could Not Ship&lt;/h2&gt;
&lt;p&gt;A cipher can be perfectly correct -- decrypting every honest message, verifying every honest signature -- and still be unusable, or worse, still hand over its secret key. The first generation of post-quantum schemes taught that lesson three times, each on a different axis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The first wall is size.&lt;/strong&gt; McEliece&apos;s cryptosystem has resisted cryptanalysis for more than forty-five years, which is a stronger track record than RSA has. But its public key is an entire generator matrix. In the modern Classic McEliece parameter sets, that means a public key from roughly 261 KB (for the &lt;code&gt;mceliece348864&lt;/code&gt; set) up to about 1.36 MB (for &lt;code&gt;mceliece8192128&lt;/code&gt;) [@classic-mceliece]. A megabyte of key material per connection is a non-starter for a TLS handshake that budgets a few kilobytes. McEliece is not broken; it is simply too big to carry. Its security was never the problem. Its shape was.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The second wall is state.&lt;/strong&gt; Merkle&apos;s hash-tree signatures, engineered into the modern XMSS and LMS schemes and standardized by NIST in SP 800-208, are compact and rest on the most conservative assumption in cryptography [@nist-sp-800-208]. But they are &lt;em&gt;stateful&lt;/em&gt;: the signer must advance a one-time-key index after every signature and must never, ever reuse one.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; NIST SP 800-208 warns that if an attacker obtains two signatures made with the same one-time key, &quot;it would become computationally feasible for that attacker to forge signatures on arbitrary messages&quot; [@nist-sp-800-208]. Restore a virtual machine from a snapshot, clone a key into a backup, or run two signer replicas, and you can silently reuse an index. The math is impeccable; the operational requirement -- perfect, rollback-proof, monotonic state, forever -- is what ordinary systems cannot guarantee.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;The third wall is the subtle one, and it reframes the whole problem: leakage.&lt;/strong&gt; The natural way to sign with a lattice is hash-and-sign in the style of GGH and its NTRU instantiation, NTRUSign: hash the message to a target point, then use your secret &quot;good&quot; basis to round to a nearby lattice point. A verifier checks the point is on the lattice and close to the target. It verifies perfectly. It is also fatally broken.&lt;/p&gt;
&lt;p&gt;In 2006, Phong Nguyen and Oded Regev showed why in a paper with a wonderful title: &quot;Learning a Parallelepiped&quot; [@nguyen-regev-2006]. Every signature is the difference between the hashed target and a lattice point, and those differences are distributed over the &lt;em&gt;fundamental parallelepiped&lt;/em&gt; of the secret basis. Collect a few hundred signatures, and you can reconstruct the shape of that parallelepiped -- which is to say, you can recover the secret key. The signer was leaking the key a little at a time, in the statistical shape of its own outputs, while every individual signature passed verification.&lt;/p&gt;

When the distribution of a scheme&apos;s public outputs (its signatures or its decryption behavior) depends on the secret key, an attacker who collects enough outputs can infer the key -- even though each individual output is valid. The break is statistical, not logical: nothing is forged, yet the key is recovered from the shape of honest data.
&lt;p&gt;Put the three walls side by side and a pattern appears. McEliece fails on size, stateful hashes fail on operational state, and NTRUSign fails on leakage -- three completely different axes. The naive strategy of &quot;pick the oldest unbroken idea and ship it&quot; runs aground because being unbroken is not the same as being safe to deploy. The NTRUSign failure is the sharpest version of the lesson, because it severs two ideas most people treat as one.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Correctness is not security. A scheme can verify every honest signature and still surrender its secret key through the statistical shape of a few hundred outputs. The real design goal is not &quot;find math no one has broken.&quot; It is &quot;make the outputs reveal nothing about the secret.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That reframing is the hinge of the entire toolkit. Once you decide the enemy is any correlation between your public outputs and your private key, the design problem becomes concrete: engineer the transcript, the ciphertext, and the failure behavior so they are provably independent of the secret. That single idea, applied four different ways, is the modern toolkit.&lt;/p&gt;
&lt;h2&gt;4. The Competition: One Fix, Four Times&lt;/h2&gt;
&lt;p&gt;The forcing function was not a single genius. It was an open, adversarial competition. NIST issued its public Call for Proposals in December 2016 and spent the next years pruning dozens of submissions across multiple rounds, documenting the reasoning in status reports as it went [@nistir-8413]. What emerged was not one lineage but four convergent tracks, running inside three unrelated hardness assumptions, each track advancing by fixing the specific flaw that sank its predecessor.&lt;/p&gt;

flowchart LR
    subgraph TA[&quot;Track A -- codes&quot;]
      A1[McEliece 1978] --&amp;gt; A2[Niederreiter] --&amp;gt; A3[QC-MDPC BIKE] --&amp;gt; A4[HQC]
    end
    subgraph TB[&quot;Track B -- hashes&quot;]
      B1[Lamport OTS] --&amp;gt; B2[Merkle WOTS] --&amp;gt; B3[XMSS LMS] --&amp;gt; B4[SPHINCS+]
    end
    subgraph TC[&quot;Track C -- lattice KEM&quot;]
      C1[NTRU] --&amp;gt; C2[LWE] --&amp;gt; C3[Ring-LWE] --&amp;gt; C4[Module-LWE]
    end
    subgraph TD[&quot;Track D -- lattice signatures&quot;]
      D1[GGH NTRUSign] --&amp;gt; D2[GPV Falcon]
      D1 --&amp;gt; D3[Fiat-Shamir Dilithium]
    end
    A4 --&amp;gt; TK[Five toolkit tips]
    B4 --&amp;gt; TK
    C4 --&amp;gt; TK
    D2 --&amp;gt; TK
    D3 --&amp;gt; TK
    P1[SIKE isogeny] -.broke 2022.-&amp;gt; XX[Pruned families]
    P2[Rainbow multivariate] -.broke 2022.-&amp;gt; XX
&lt;p&gt;&lt;strong&gt;Track A, codes, is a war on key size.&lt;/strong&gt; McEliece&apos;s matrix is enormous, so Niederreiter published the &quot;dual&quot; version that sends a compact syndrome instead of a full codeword -- smaller ciphertext, but the public key is still a matrix. Quasi-cyclic MDPC codes then collapsed that key to a few kilobytes by making the matrix reconstructable from a single row, an idea realized in the BIKE scheme [@mdpc-mceliece-2013].&lt;/p&gt;

The hard problem under every code-based scheme: given a random-looking parity-check matrix and a syndrome (the matrix applied to an unknown low-weight error), recover the error. Decoding a general random linear code is NP-hard; a code-based cryptosystem hides a secret, efficiently decodable code so that only the key holder can decode, while an attacker faces the random-code version.
&lt;p&gt;But BIKE walked into a wall of its own. Its iterative bit-flipping decoder occasionally fails, and -- this is the trap -- &lt;em&gt;those failures depend on the secret key&lt;/em&gt;. In 2016 Guo, Johansson, and Stankovski turned that into a full reaction attack: feed the decoder crafted ciphertexts, watch which ones fail, and recover the private key from the pattern of failures [@gjs-mdpc-2016]. The very feature that shrank the key opened a side channel.&lt;/p&gt;

The probability that correct decapsulation fails on an honest ciphertext. For post-quantum KEMs this is not merely a correctness nuisance: if the failure rate is non-negligible and correlated with the secret, each failure leaks information, and enough failures recover the key. DFR is therefore a security parameter, and a good scheme drives it to a cryptographically negligible level with a bound that does not depend on the secret.
&lt;p&gt;HQC is the fix: keep the quasi-cyclic key size, but decode with a &lt;em&gt;public&lt;/em&gt;, fixed code whose failure rate can be bounded analytically and does not depend on the secret. That is precisely why NIST chose HQC over BIKE -- its DFR analysis was judged more mature [@nist-ir-8545].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Track B, hashes, is a war on state&lt;/strong&gt;, and the whole story is the fight against one number: the leaf index. Lamport&apos;s one-time signature signs once per key; Merkle put many one-time keys under a tree so one root signs many messages; XMSS and LMS engineered that into standardized, stateful schemes [@nist-sp-800-208]; and SPHINCS removed the state entirely by choosing a random leaf from a space so vast that collisions are negligible, backed by a few-time signature to absorb the rare clash [@sphincs-2015]. SPHINCS+ then hardened it with tweakable hashes and a tighter few-time scheme called FORS [@sphincs-plus-framework-2019].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Track C, lattice KEMs, is a war over structure.&lt;/strong&gt; NTRU was fast but rested on a heuristic assumption; LWE bought a worst-case hardness reduction but needed a full random matrix as its key; Ring-LWE compressed that matrix to a single polynomial with fast NTT arithmetic [@lpr-ringlwe-2010]; and Module-LWE dialed the ring structure partway back down, trading a sliver of efficiency for a hedge against the possibility that too much algebraic structure helps the attacker [@crystals-kyber].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Track D, lattice signatures, is where the tree forks and both branches survive.&lt;/strong&gt; The GGH/NTRUSign transcript leak forced a choice, and the field kept two answers: GPV hash-and-sign, which samples from a discrete Gaussian whose shape is provably independent of the secret basis (this becomes Falcon), and Fiat-Shamir with aborts, which rejects and restarts until the transcript is key-independent (this becomes Dilithium) [@gpv-2007] [@lyubashevsky-fswa-2009].&lt;/p&gt;
&lt;p&gt;Stare at those four tracks and the same move appears in every one.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every surviving generation makes the transcript or the failure channel provably independent of the secret. Gaussian sampling and rejection sampling remove the signature-transcript leak; the Fujisaki-Okamoto transform removes the decryption-failure oracle; statelessness removes the operational-state leak; HQC&apos;s public decoder removes BIKE&apos;s secret-dependent failures. The toolkit is not five unrelated tricks. It is one principle instantiated five ways.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The competition also pruned in public, and the prunings are the best argument for the whole strategy.&lt;/p&gt;

Two schemes that had survived years of scrutiny fell in 2022, within months of each other. Ward Beullens broke Rainbow, a multivariate signature finalist, in what his paper title advertised as a weekend on a laptop [@beullens-rainbow-2022]. Then Wouter Castryck and Thomas Decru broke SIKE, an isogeny-based KEM, with a key-recovery attack that runs in about ten minutes on a single core [@castryck-decru-sidh-2022]. Both schemes had strong theory and years of failed attacks behind them. Both were destroyed by a single new idea. And both were *outside* the final toolkit -- Rainbow was not selected, and SIKE advanced to NIST&apos;s fourth round only to be broken before it could be selected. That is the empirical case for diversity in one sentence: no amount of survived cryptanalysis is a proof, so you hedge across unrelated assumptions rather than bet everything on one.
&lt;p&gt;This is the moment to state the honest ending up front -- the argument the rest of the article defends.&lt;/p&gt;

Nothing in the toolkit has been mathematically broken. Every real-world failure so far has been an implementation leak -- and the two famous algorithmic breaks of the era hit schemes that never made the cut.
&lt;p&gt;It helps to see every notable failure of the era in one place, sorted by what actually went wrong. Two of these are implementation leaks in surviving schemes (the math is intact); two are historical breaks of superseded designs; and two are the non-toolkit cryptanalytic breaks that justify the hedge.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Failure&lt;/th&gt;
&lt;th&gt;Scheme&lt;/th&gt;
&lt;th&gt;Root cause&lt;/th&gt;
&lt;th&gt;Lesson&lt;/th&gt;
&lt;th&gt;In the toolkit?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Parallelepiped leak&lt;/td&gt;
&lt;td&gt;GGH / NTRUSign&lt;/td&gt;
&lt;td&gt;Signature distribution depends on the secret basis [@nguyen-regev-2006]&lt;/td&gt;
&lt;td&gt;Make the transcript key-independent&lt;/td&gt;
&lt;td&gt;No -- superseded ancestor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reaction attack&lt;/td&gt;
&lt;td&gt;QC-MDPC / BIKE&lt;/td&gt;
&lt;td&gt;Secret-dependent decoding failures form an oracle [@gjs-mdpc-2016]&lt;/td&gt;
&lt;td&gt;Bound the DFR with a public decoder&lt;/td&gt;
&lt;td&gt;No -- not selected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIKE key recovery&lt;/td&gt;
&lt;td&gt;SIDH isogenies&lt;/td&gt;
&lt;td&gt;Torsion-point structure enables recovery [@castryck-decru-sidh-2022]&lt;/td&gt;
&lt;td&gt;A decade unbroken is not a proof&lt;/td&gt;
&lt;td&gt;No -- non-toolkit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rainbow weekend break&lt;/td&gt;
&lt;td&gt;Multivariate&lt;/td&gt;
&lt;td&gt;Structural attack on the oil-and-vinegar map [@beullens-rainbow-2022]&lt;/td&gt;
&lt;td&gt;Diversify assumptions&lt;/td&gt;
&lt;td&gt;No -- non-toolkit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KyberSlash&lt;/td&gt;
&lt;td&gt;ML-KEM (Kyber)&lt;/td&gt;
&lt;td&gt;Secret-dependent division timing [@kyberslash-site]&lt;/td&gt;
&lt;td&gt;Constant-time reduction; math untouched&lt;/td&gt;
&lt;td&gt;Yes -- implementation leak&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gram-Schmidt leak&lt;/td&gt;
&lt;td&gt;FN-DSA (Falcon)&lt;/td&gt;
&lt;td&gt;Floating-point sampler leaks basis norms [@fouque-gsnorm-2019]&lt;/td&gt;
&lt;td&gt;Use a vetted constant-time sampler&lt;/td&gt;
&lt;td&gt;Yes -- implementation hazard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Notice that the bottom two rows -- the only failures inside the toolkit -- are both in the &quot;implementation&quot; column, never the &quot;math&quot; column. That distinction is the spine of everything that follows. By 2024 the pruned tree had five surviving tips. Three of them became law on a single day.&lt;/p&gt;
&lt;h2&gt;5. Three Standards in One Day&lt;/h2&gt;
&lt;p&gt;On 2024-08-13, NIST published three Federal Information Processing Standards at once: FIPS 203 (ML-KEM) for key encapsulation, FIPS 204 (ML-DSA) and FIPS 205 (SLH-DSA) for signatures [@fips-203] [@fips-204] [@fips-205]. That single date is when post-quantum cryptography crossed from an open competition into the law of the land, the thing an auditor can require and a protocol can mandate.&lt;/p&gt;
&lt;p&gt;Each standard is the hardened descendant of a competition submission, and each carries one defining idea forward.&lt;/p&gt;

A KEM is a three-function object -- key generation, encapsulate, decapsulate -- that lets two parties agree on a random shared secret. Encapsulate takes a public key and returns a ciphertext plus a shared secret; decapsulate takes the ciphertext and the private key and returns the same shared secret. It is the post-quantum replacement for the key-exchange half of Diffie-Hellman, and it composes with a symmetric cipher through the KEM-DEM pattern this series covered in [Part 19 on HPKE](/blog/the-standard-was-boring-that-was-the-point-a-field-guide-to-/). Crucially, a KEM is not a drop-in for a static-static Diffie-Hellman handshake -- a distinction we return to in the limits.
&lt;p&gt;&lt;strong&gt;ML-KEM&lt;/strong&gt; is Module-LWE encryption wrapped in a Fujisaki-Okamoto transform with &lt;em&gt;implicit rejection&lt;/em&gt;, so that an invalid ciphertext yields a pseudo-random shared secret rather than an error -- there is no decapsulation-failure oracle to probe [@fips-203]. &lt;strong&gt;ML-DSA&lt;/strong&gt; is a Fiat-Shamir-with-aborts signature built entirely from uniform integers, chosen deliberately so the implementation needs no floating point and is easy to make constant-time [@fips-204]. &lt;strong&gt;SLH-DSA&lt;/strong&gt; is a stateless hash-based signature whose security rests on nothing but its hash function -- the conservative backstop [@fips-205].&lt;/p&gt;
&lt;p&gt;ML-KEM is the standardized CRYSTALS-Kyber; ML-DSA is Dilithium; SLH-DSA is SPHINCS+. These are the same schemes under new NIST names, with standardization edits (tweaked hashing, encodings, and parameter cleanups), not fresh designs. If you have working knowledge of Kyber, you already understand ML-KEM.&lt;/p&gt;
&lt;p&gt;Two things follow that people routinely get wrong. First, the renaming is not a redesign: &quot;Kyber&quot; and &quot;ML-KEM&quot; are essentially the same scheme [@crystals-kyber]. Second, the toolkit is not finished -- only three of the five are standardized, and the fourth and fifth are genuinely pre-final.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; FN-DSA (Falcon), destined for FIPS 206, was still in development as of this writing, with a final expected around late 2026 or 2027 [@fips-206-perlner-2025]. HQC was only &lt;em&gt;selected&lt;/em&gt; for standardization on 2025-03-11, with a draft FIPS still pending [@nist-ir-8545]. Do not deploy either in production yet. Every FN-DSA and HQC size in this article is pre-final and may change.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The migration is already underway on the finalized three. But a standard is a promise about an interface, not a proof of security. To defend a design in a review, you need what is under each name: the math, the exact sizes, and the specific way each one can still fail.&lt;/p&gt;
&lt;h2&gt;6. The Five Primitives in Depth&lt;/h2&gt;
&lt;p&gt;One workhorse, one default, one backstop, one compact hopeful, one insurance policy. That is the toolkit in five phrases: ML-KEM is the workhorse KEM, ML-DSA the default signature, SLH-DSA the conservative backstop, FN-DSA the compact hopeful, and HQC the non-lattice insurance policy. Three of the five are lattice schemes, so learn the lattice intuition once and reuse it three times.&lt;/p&gt;

LWE is &quot;add noise to linear algebra.&quot; Given a random matrix $A$ and the product $b = A\mathbf{s} + \mathbf{e}$ where $\mathbf{e}$ is small random noise, recovering the secret $\mathbf{s}$ is believed hard, classically and quantumly. Module-LWE is the same idea over a small polynomial ring, arranged as a rank-$k$ module so the security level is set by $k$ rather than by resizing everything. Raising $k$ adds structure-diluting hedge; lowering it saves bytes. ML-KEM and ML-DSA both live here; only the rank and the noise change.
&lt;p&gt;All byte sizes below are exact for the finalized three and explicitly pre-final for FN-DSA and HQC. Cycle counts come from the pqm4 Cortex-M4 benchmark harness unless labeled otherwise [@pqm4-benchmarks].Never compare a Cortex-M4 cycle count against an AVX2 desktop number directly -- they are different machines. HQC&apos;s own figures are measured on an Intel i7-11850H and Falcon&apos;s on an Intel i5-8259U, so those live on a different scale than the M4 numbers used for cross-scheme comparison.&lt;/p&gt;
&lt;h3&gt;6.1 ML-KEM (FIPS 203): the workhorse&lt;/h3&gt;
&lt;p&gt;ML-KEM is the standardization of CRYSTALS-Kyber, finalized as FIPS 203, and it is the only post-quantum primitive deployed at scale today [@fips-203] [@crystals-kyber]. Its security rests on Module-LWE over the ring $R_q = \mathbb{Z}_q[X]/(X^{256}+1)$ with modulus $q = 3329$; the module rank $k \in {2,3,4}$ selects ML-KEM-512, ML-KEM-768, and ML-KEM-1024.&lt;/p&gt;
&lt;p&gt;The scheme has two layers. The inner layer is an IND-CPA encryption scheme over the ring. The outer layer upgrades it to a CCA-secure KEM using the Fujisaki-Okamoto transform.&lt;/p&gt;

The FO transform turns a weak (chosen-plaintext-secure) encryption scheme into a strong (chosen-ciphertext-secure) KEM by re-encrypting on decapsulation and checking the result. The modern twist -- *implicit rejection* -- is that a failed check returns a deterministic pseudo-random shared secret derived from a secret seed $z$, never an error. Because every ciphertext yields a well-formed key, an attacker who submits tampered ciphertexts learns nothing from the response, closing the decapsulation-failure oracle that broke earlier schemes [@fo-1999] [@hhk-fo-2017].

sequenceDiagram
    participant S as Sender
    participant R as Receiver
    R-&amp;gt;&amp;gt;S: public encapsulation key ek
    Note over S: pick random m, derive shared key K and coins r
    S-&amp;gt;&amp;gt;R: ciphertext c that encapsulates m
    Note over R: decrypt c to m-prime, re-derive K-prime and r-prime
    Note over R: re-encrypt m-prime to c-prime and compare
    alt c-prime equals c
        Note over R: return true shared secret K-prime
    else mismatch
        Note over R: return pseudo-random key from secret z, no error
    end
&lt;p&gt;That implicit-rejection branch is the load-bearing idea. It is worth seeing in code just how little a tampered ciphertext reveals.&lt;/p&gt;
&lt;p&gt;{`
// Illustrative only -- NOT production crypto.
// ML-KEM decapsulation never reports &quot;invalid&quot;. On a re-encryption mismatch it
// returns a pseudo-random key derived from a per-key secret z, so a tampered
// ciphertext produces a well-formed but useless key -- no distinguishable signal.&lt;/p&gt;
&lt;p&gt;function toyHash(s) {
  let h = 2166136261 &amp;gt;&amp;gt;&amp;gt; 0;
  for (const c of String(s)) h = Math.imul(h ^ c.charCodeAt(0), 16777619) &amp;gt;&amp;gt;&amp;gt; 0;
  return (h &amp;gt;&amp;gt;&amp;gt; 0).toString(16).padStart(8, &apos;0&apos;);
}&lt;/p&gt;
&lt;p&gt;const z = &apos;per-key-secret-z&apos;; // implicit-rejection secret, never leaves the device&lt;/p&gt;
&lt;p&gt;// Receiver decrypts c to m&apos;, re-encrypts m&apos;, and compares the result to c.
function decapsulate(c, mDecrypted, cReencrypted) {
  if (cReencrypted === c) {
    return toyHash(&apos;real-shared-secret:&apos; + mDecrypted); // the genuine key
  }
  return toyHash(z + &apos;:&apos; + c);                           // pseudo-random reject key
}&lt;/p&gt;
&lt;p&gt;// Honest ciphertext: re-encryption matches, real key returned.
console.log(&apos;honest   :&apos;, decapsulate(&apos;c123&apos;, &apos;m&apos;, &apos;c123&apos;));
// Tampered ciphertext: mismatch -&amp;gt; still a key, still no error.
console.log(&apos;tampered :&apos;, decapsulate(&apos;c999&apos;, &apos;m-garbled&apos;, &apos;c123&apos;));
// The reject key is deterministic per (z, c) and looks like any other key,
// so the attacker cannot tell rejection from success. The oracle is closed.
`}&lt;/p&gt;
&lt;p&gt;The exact bytes are what a protocol actually carries. For ML-KEM the encapsulation key / decapsulation key / ciphertext / shared secret sizes are 800 / 1632 / 768 / 32 for ML-KEM-512, 1184 / 2400 / 1088 / 32 for ML-KEM-768, and 1568 / 3168 / 1568 / 32 for ML-KEM-1024 [@fips-203]. The decryption-failure rates are $2^{-138.8}$, $2^{-164.8}$, and $2^{-174.8}$ respectively -- negligible by design, which as we saw is a security requirement, not a mere nicety [@fips-203]. On Cortex-M4, ML-KEM-768 costs roughly 642k / 659k / 708k cycles for keygen / encapsulate / decapsulate [@pqm4-benchmarks].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Several Kyber implementations divided a &lt;em&gt;secret&lt;/em&gt; numerator by the public modulus $q = 3329$ inside compression, and on many CPUs division time depends on the inputs -- so the timing leaked secret data. That is KyberSlash [@kyberslash-site] [@kyberslash-eprint-2024]. The FIPS 203 mathematics was never in question; the fix is constant-time (Barrett-style) reduction. It is the toolkit&apos;s headline real-world failure, and it is an implementation bug, exactly as the thesis predicts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The three small prime moduli to remember: $q = 3329$ for ML-KEM, $q = 8380417$ for ML-DSA, and $q = 12289$ for Falcon. KyberSlash lived in the division by 3329.&lt;/p&gt;
&lt;p&gt;ML-KEM excels because it is small, fast, and easy to implement over small integers mod a fixed prime. It is the default post-quantum KEM in shipping software: the X25519MLKEM768 hybrid is a default key share in OpenSSL 3.5, and it was enabled by default in OpenSSH 9.9 before becoming the default key exchange in OpenSSH 10.0 [@openssl-35-notes] [@openssh-99-notes] [@openssh-pq]. Where it is least comfortable is its assumption: Module-LWE is younger and more structured than code- or hash-based hardness, which is the entire reason the field wants a non-lattice KEM in reserve.&lt;/p&gt;
&lt;h3&gt;6.2 ML-DSA (FIPS 204): the default signature&lt;/h3&gt;
&lt;p&gt;ML-DSA is the standardized CRYSTALS-Dilithium, and it is the signature you should reach for by default [@fips-204] [@crystals-dilithium]. It builds on the same Module-LWE ring world as ML-KEM (here with $q = 8380417$), but it signs by a completely different route than the hash-and-sign that leaked in NTRUSign.&lt;/p&gt;

Turn an interactive identification protocol into a signature by replacing the verifier&apos;s challenge with a hash (Fiat-Shamir), then add a rejection step: whenever the candidate signature would correlate with the secret, discard it and restart with fresh randomness. The signatures that survive are, by construction, distributed independently of the secret key. The cost is that signing runs a variable number of attempts [@lyubashevsky-fswa-2009].
&lt;p&gt;The signer commits to a masking vector $\mathbf{y}$, derives a sparse challenge $c$ by hashing the commitment together with the message, and forms $\mathbf{z} = \mathbf{y} + c\mathbf{s}_1$. If $\mathbf{z}$ strays outside a safe range, releasing it would leak the secret, so the signer aborts and tries again.&lt;/p&gt;

flowchart TD
    A[Sample fresh masking vector y] --&amp;gt; B[Derive sparse challenge c by hashing commitment and message]
    B --&amp;gt; C[Form candidate z as y plus c times secret s1]
    C --&amp;gt; D{&quot;Is z inside the safe range?&quot;}
    D -- No, would leak the secret --&amp;gt; A
    D -- Yes --&amp;gt; E[Publish signature challenge, z, hint]
&lt;p&gt;You can watch the loop behave. The number of attempts varies from signature to signature, and every released value stays inside the safe bound -- the mechanism that makes the transcript reveal nothing about the key.&lt;/p&gt;
&lt;p&gt;{`
// Illustrative only -- NOT production crypto.
// Keep sampling a masking value y until z = y + c*s1 lands in a safe range.
// Candidates that would correlate z with the secret are rejected; only
// key-independent z escape. Signing time therefore varies run to run.&lt;/p&gt;
&lt;p&gt;const GAMMA1 = 100;   // masking range
const BETA   = 20;    // how far c*s1 can push z
const secret = 37;    // s1, unknown to the verifier
const c = 1;          // toy sparse challenge
const rand = (n) =&amp;gt; Math.floor(Math.random() * n);&lt;/p&gt;
&lt;p&gt;function signOnce() {
  let attempts = 0;
  while (true) {
    attempts++;
    const y = rand(2 * GAMMA1) - GAMMA1;       // uniform masking
    const z = y + c * secret;
    if (Math.abs(z) &amp;lt; GAMMA1 - BETA) return { z, attempts }; // safe -&amp;gt; release
    // otherwise abort and retry with fresh y
  }
}&lt;/p&gt;
&lt;p&gt;let total = 0, n = 20000, maxAbsZ = 0;
for (let i = 0; i &amp;lt; n; i++) {
  const r = signOnce();
  total += r.attempts;
  maxAbsZ = Math.max(maxAbsZ, Math.abs(r.z));
}
console.log(&apos;avg attempts / signature:&apos;, (total / n).toFixed(2));
console.log(&apos;max |z| ever released   :&apos;, maxAbsZ, &apos;bound is&apos;, GAMMA1 - BETA);
console.log(&apos;variable attempt count is why ML-DSA signing time is not constant&apos;);
`}&lt;/p&gt;
&lt;p&gt;The Dilithium team chose this uniform-integer, rejection-based route deliberately, rather than Falcon&apos;s Gaussian sampler, and they were blunt about why.&lt;/p&gt;

&quot;Gaussian sampling is hard to implement securely and efficiently.&quot; -- the CRYSTALS-Dilithium team, on why ML-DSA uses uniform integers and no floating point [@crystals-dilithium].
&lt;p&gt;The private key / public key / signature sizes are 2560 / 1312 / 2420 for ML-DSA-44, 4032 / 1952 / 3309 for ML-DSA-65, and 4896 / 2592 / 4627 for ML-DSA-87, targeting NIST categories 2, 3, and 5 [@fips-204]. Verification is fast and constant-time; signing is fast but variable-time because of the abort loop, which is the single most important operational fact about the scheme. On Cortex-M4, ML-DSA-65 signing averages near 6.19M cycles but ranges from about 2.92M to 26.0M across a thousand runs [@pqm4-benchmarks].&lt;/p&gt;
&lt;p&gt;FIPS 204 supports both hedged (randomized) and deterministic signing; the hedged mode is the default and is more resilient to fault and bad-randomness mishaps. It also adds a context string of up to 255 bytes so applications can domain-separate their signatures and prevent cross-protocol reuse.&lt;/p&gt;
&lt;p&gt;ML-DSA excels as the general-purpose default: no floating point, easy constant-time code, moderate sizes, fast verification. Its weak spot is the signature-size wall this series flagged for interfaces in &lt;a href=&quot;https://paragmali.com/blog/the-math-held-the-interface-leaked-a-field-guide-to-digital-/&quot; rel=&quot;noopener&quot;&gt;Part 17 on digital signatures&lt;/a&gt; -- a 3309-byte signature is roughly fifty times an Ed25519 signature, and that multiplies through certificate chains.&lt;/p&gt;
&lt;h3&gt;6.3 SLH-DSA (FIPS 205): the conservative backstop&lt;/h3&gt;
&lt;p&gt;SLH-DSA is the standardized SPHINCS+, and it makes the most conservative bet in the toolkit: its security rests on nothing but the properties of its hash function, the same primitives this series covered in &lt;a href=&quot;https://paragmali.com/blog/the-fingerprint-two-files-shared-a-field-guide-to-cryptograp/&quot; rel=&quot;noopener&quot;&gt;Part 10 on cryptographic hashes&lt;/a&gt; [@fips-205] [@sphincs-plus-spec]. If every lattice and code assumption fell tomorrow, a signature that depends only on a hash would still stand.&lt;/p&gt;

SLH-DSA composes three hash-based gadgets. WOTS+ is a one-time signature that signs by revealing points along hash chains. FORS (&quot;Forest Of Random Subsets&quot;) is a *few-time* signature that signs the message digest and tolerates rare index collisions. A hypertree stacks many layers of Merkle trees, each layer&apos;s WOTS+ keys authenticating the roots below, up to one public root. Picking the FORS instance pseudo-randomly from the message removes the state that made XMSS dangerous [@sphincs-plus-framework-2019].

flowchart TD
    M[Message digest] --&amp;gt; R[Randomizer picks a FORS instance pseudo-randomly]
    R --&amp;gt; F[FORS few-time signature over the digest]
    F --&amp;gt; W[WOTS+ one-time key authenticates the FORS root]
    W --&amp;gt; H[Hypertree of Merkle layers, each signs the layer below]
    H --&amp;gt; PK[Single long-lived public root]
&lt;p&gt;The trade is stark. Public keys are tiny (32 to 64 bytes), but signatures are enormous and signing is slow. FIPS 205 defines twelve parameter sets -- three security levels, each with a &quot;small&quot; (&lt;code&gt;s&lt;/code&gt;) and &quot;fast&quot; (&lt;code&gt;f&lt;/code&gt;) variant, over SHA-2 and SHAKE. The public key / signature sizes run 32 / 7856 for 128s, 32 / 17088 for 128f, 48 / 16224 for 192s, 48 / 35664 for 192f, 64 / 29792 for 256s, and 64 / 49856 for 256f [@fips-205]. Signing hashes whole subtrees and costs hundreds of millions to billions of Cortex-M4 cycles, orders of magnitude slower than lattice signing [@pqm4-benchmarks]. The &lt;code&gt;s&lt;/code&gt;/&lt;code&gt;f&lt;/code&gt; knob only trades one pain for the other: smaller signatures mean slower signing.&lt;/p&gt;
&lt;p&gt;That profile makes SLH-DSA the right tool for low-volume, high-assurance signing -- firmware, boot chains, and software-update roots -- where you sign rarely, verify occasionally, and value a rock-bottom assumption over compactness.&lt;/p&gt;

If you can guarantee perfect state, the stateful hash signatures XMSS and LMS (NIST SP 800-208) are markedly smaller than SLH-DSA [@nist-sp-800-208]. The catch is the catch from Section 3: reuse a one-time leaf index and you enable forgery. They are the right call only in a tightly controlled setting -- a hardware security module or a firmware signer that can enforce monotonic, rollback-proof state. For everyone else, SLH-DSA trades bytes for the removal of that footgun, which is usually the better deal.
&lt;h3&gt;6.4 FN-DSA / Falcon: the compact hopeful (pre-final)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Falcon is destined to become FIPS 206, but that document was still in development as of this writing, with a final expected around late 2026 or 2027 [@fips-206-perlner-2025] [@digicert-fndsa]. Every name and size below is pre-final and comes from the Falcon specification, not from a FIPS [@falcon-spec]. Do not ship FN-DSA in production yet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Falcon instantiates the GPV hash-and-sign framework over NTRU lattices ($q = 12289$, dimension $n = 512$ or $1024$), and it produces the smallest signatures and keys of any standardized-track scheme [@falcon-spec] [@gpv-2007].&lt;/p&gt;

The safe way to do lattice hash-and-sign. A secret trapdoor lets the signer sample a short lattice vector near a hashed target from a discrete Gaussian whose distribution is provably independent of the secret basis. That independence is exactly what NTRUSign lacked -- it closes the parallelepiped leak by construction, rather than hoping the outputs happen not to correlate with the key.

flowchart LR
    M[Message] --&amp;gt; HP[Hash message to a point c in the ring]
    HP --&amp;gt; TS[Use NTRU trapdoor basis to target c]
    TS --&amp;gt; GS[Fast-Fourier Gaussian sampling, the delicate floating-point step]
    GS --&amp;gt; SV[Short vector s1, s2 near the lattice]
    SV --&amp;gt; SIG[Signature is a salt plus compressed s2]
&lt;p&gt;The payoff is compactness. Falcon-512 has an 897-byte public key and a 666-byte signature (roughly RSA-2048&apos;s classical security level, as this series discussed in Part 14, at a fraction of the byte size); Falcon-1024 is 1793 / 1280 [@falcon-spec]. On a desktop i5-8259U the reference code signs about 5948 times per second and verifies about 27933 times per second for Falcon-512 [@falcon-spec]. A Falcon-512 signature is under a third the size of ML-DSA-44&apos;s.&lt;/p&gt;
&lt;p&gt;So why is it the last of the five to standardize? Because the Gaussian sampler runs on floating-point arithmetic, and making floating point constant-time across compilers and CPUs is genuinely hard. Timing or precision leakage of the sampler&apos;s Gram-Schmidt norms can recover the secret key [@fouque-gsnorm-2019]. Mitigations exist -- Pornin&apos;s constant-time integer implementation and isochronous Gaussian sampling among them -- but they are intricate and platform-sensitive [@pornin-ctfalcon-2019] [@howe-isochronous-2019].&lt;/p&gt;
&lt;p&gt;Want concrete evidence that FN-DSA is pre-final? When researchers fetched the expected FIPS 206 Initial Public Draft URL during the source verification for this article, it returned HTTP 404 -- the draft was not yet published. The compact math is done; the standardization and safe-implementation work is not.&lt;/p&gt;
&lt;p&gt;Falcon is the right tool when signature and key bandwidth is the binding constraint &lt;em&gt;and&lt;/em&gt; you can guarantee a vetted constant-time implementation -- and even then, not before FIPS 206 lands. Until it does, prefer ML-DSA.&lt;/p&gt;
&lt;h3&gt;6.5 HQC: the non-lattice insurance policy (pre-final)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; NIST selected HQC on 2025-03-11 as a code-based KEM to stand alongside ML-KEM, with a draft FIPS expected in 2026 and a final around 2027 [@nist-ir-8545]. The parameters below come from the HQC specification and are pre-final [@hqc-spec]. Do not deploy it in production yet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;HQC (&quot;Hamming Quasi-Cyclic&quot;) is the toolkit&apos;s deliberate non-lattice hedge. Its security rests on the hardness of decoding random quasi-cyclic codes -- syndrome decoding, unrelated to lattices -- so a future lattice break would leave it untouched [@hqc-spec]. It solves the problem that sank BIKE by separating the secret from the decoder: HQC encrypts by adding a low-weight error and decodes with a &lt;em&gt;public&lt;/em&gt;, fixed code (a concatenation of Reed-Muller and Reed-Solomon codes) whose decoding-failure rate can be bounded analytically and does not depend on the secret. That bounded, secret-independent DFR is exactly why NIST preferred it over BIKE [@nist-ir-8545] [@gjs-mdpc-2016].&lt;/p&gt;
&lt;p&gt;The cost is bandwidth. The encapsulation key / decapsulation key / ciphertext / shared secret sizes are 2241 / 2321 / 4433 / 32 for HQC-1, 4514 / 4602 / 8978 / 32 for HQC-3, and 7237 / 7333 / 14421 / 32 for HQC-5 [@hqc-spec]. The ciphertext is roughly four to nine times ML-KEM&apos;s. HQC is the reserve KEM, not the first choice: you carry the extra kilobytes precisely because its assumption is unrelated to everything else in the box.&lt;/p&gt;
&lt;h3&gt;6.6 Tier C: the signposts&lt;/h3&gt;
&lt;p&gt;Four more schemes sit just outside the toolkit and are worth knowing by name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Classic McEliece&lt;/strong&gt; is the most conservative code-based KEM, unbroken since 1978, but with public keys from roughly 261 KB to over a megabyte [@classic-mceliece]. It was not selected for the FIPS set and is advancing on an ISO track; choose it only where a huge, static, long-lived key is acceptable and maximal conservatism is the goal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BIKE&lt;/strong&gt; is the quasi-cyclic KEM that HQC beat out; its secret-dependent decoding-failure rate was judged less mature than HQC&apos;s bounded public decoder, so NIST did not select it [@bike-suite] [@nist-ir-8545].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;XMSS and LMS&lt;/strong&gt; are the standardized stateful hash signatures -- compact, conservative, and safe only where perfect state is guaranteed [@nist-sp-800-208].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CSIDH&lt;/strong&gt; is the one post-quantum candidate for a non-interactive Diffie-Hellman-style shared key, but its quantum security is contested -- subexponential quantum attacks push it toward much larger parameters [@peikert-csieves-2019] -- and its isogeny cousin SIKE was broken in 2022 [@castryck-decru-sidh-2022]. Treat it as research, not deployment.&lt;/p&gt;
&lt;p&gt;Now the exact bytes, all in one place. The table below is the empirical anchor for every trade discussed next -- the literal number of bytes a protocol must carry for each choice.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Primitive&lt;/th&gt;
&lt;th&gt;Param set&lt;/th&gt;
&lt;th&gt;Family&lt;/th&gt;
&lt;th&gt;Public/enc key (B)&lt;/th&gt;
&lt;th&gt;Ciphertext or signature (B)&lt;/th&gt;
&lt;th&gt;NIST cat&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ML-KEM&lt;/td&gt;
&lt;td&gt;512&lt;/td&gt;
&lt;td&gt;lattice KEM&lt;/td&gt;
&lt;td&gt;800&lt;/td&gt;
&lt;td&gt;768&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Final [@fips-203]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML-KEM&lt;/td&gt;
&lt;td&gt;768&lt;/td&gt;
&lt;td&gt;lattice KEM&lt;/td&gt;
&lt;td&gt;1184&lt;/td&gt;
&lt;td&gt;1088&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Final [@fips-203]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML-KEM&lt;/td&gt;
&lt;td&gt;1024&lt;/td&gt;
&lt;td&gt;lattice KEM&lt;/td&gt;
&lt;td&gt;1568&lt;/td&gt;
&lt;td&gt;1568&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Final [@fips-203]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HQC&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;code KEM&lt;/td&gt;
&lt;td&gt;2241&lt;/td&gt;
&lt;td&gt;4433&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Pre-final [@hqc-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HQC&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;code KEM&lt;/td&gt;
&lt;td&gt;4514&lt;/td&gt;
&lt;td&gt;8978&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Pre-final [@hqc-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HQC&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;code KEM&lt;/td&gt;
&lt;td&gt;7237&lt;/td&gt;
&lt;td&gt;14421&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Pre-final [@hqc-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML-DSA&lt;/td&gt;
&lt;td&gt;44&lt;/td&gt;
&lt;td&gt;lattice sig&lt;/td&gt;
&lt;td&gt;1312&lt;/td&gt;
&lt;td&gt;2420&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Final [@fips-204]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML-DSA&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;td&gt;lattice sig&lt;/td&gt;
&lt;td&gt;1952&lt;/td&gt;
&lt;td&gt;3309&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Final [@fips-204]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML-DSA&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;td&gt;lattice sig&lt;/td&gt;
&lt;td&gt;2592&lt;/td&gt;
&lt;td&gt;4627&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Final [@fips-204]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FN-DSA/Falcon&lt;/td&gt;
&lt;td&gt;512&lt;/td&gt;
&lt;td&gt;lattice sig&lt;/td&gt;
&lt;td&gt;897&lt;/td&gt;
&lt;td&gt;666&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Pre-final [@falcon-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FN-DSA/Falcon&lt;/td&gt;
&lt;td&gt;1024&lt;/td&gt;
&lt;td&gt;lattice sig&lt;/td&gt;
&lt;td&gt;1793&lt;/td&gt;
&lt;td&gt;1280&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Pre-final [@falcon-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SLH-DSA&lt;/td&gt;
&lt;td&gt;128s&lt;/td&gt;
&lt;td&gt;hash sig&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;7856&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Final [@fips-205]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SLH-DSA&lt;/td&gt;
&lt;td&gt;128f&lt;/td&gt;
&lt;td&gt;hash sig&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;17088&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Final [@fips-205]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SLH-DSA&lt;/td&gt;
&lt;td&gt;192s&lt;/td&gt;
&lt;td&gt;hash sig&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;16224&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Final [@fips-205]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SLH-DSA&lt;/td&gt;
&lt;td&gt;192f&lt;/td&gt;
&lt;td&gt;hash sig&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;35664&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Final [@fips-205]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SLH-DSA&lt;/td&gt;
&lt;td&gt;256s&lt;/td&gt;
&lt;td&gt;hash sig&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;29792&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Final [@fips-205]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SLH-DSA&lt;/td&gt;
&lt;td&gt;256f&lt;/td&gt;
&lt;td&gt;hash sig&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;49856&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Final [@fips-205]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Two footnotes complete the picture. For the KEMs, the decapsulation (secret) keys are larger than the encapsulation keys -- 1632 / 2400 / 3168 bytes for ML-KEM and 2321 / 4602 / 7333 bytes for HQC -- and both produce a 32-byte shared secret [@fips-203] [@hqc-spec]. For ML-DSA, the private keys are 2560 / 4032 / 4896 bytes [@fips-204]. Now the uncomfortable question: given all five, which do you actually deploy, and what do you give up to get it?&lt;/p&gt;
&lt;h2&gt;7. Choosing Inside the Toolkit&lt;/h2&gt;
&lt;p&gt;There is no universal winner, and looking for one is the wrong frame. In practice you make two decisions -- which KEM, and which signature -- plus one deployment choice about hybrids. Everything else follows from the bytes in the master table and the assumption you are willing to trust.&lt;/p&gt;
&lt;p&gt;The KEM decision is really ML-KEM versus HQC, because the other code-based options are signposts rather than shipping choices.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;ML-KEM-768 (final)&lt;/th&gt;
&lt;th&gt;HQC-3 (pre-final)&lt;/th&gt;
&lt;th&gt;Classic McEliece (signpost)&lt;/th&gt;
&lt;th&gt;BIKE (signpost)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Assumption&lt;/td&gt;
&lt;td&gt;Module-LWE (lattice)&lt;/td&gt;
&lt;td&gt;quasi-cyclic syndrome decoding (code)&lt;/td&gt;
&lt;td&gt;Goppa-code decoding&lt;/td&gt;
&lt;td&gt;QC-MDPC decoding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enc. key&lt;/td&gt;
&lt;td&gt;1184 B&lt;/td&gt;
&lt;td&gt;4514 B&lt;/td&gt;
&lt;td&gt;261 KB to ~1.36 MB&lt;/td&gt;
&lt;td&gt;few KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ciphertext&lt;/td&gt;
&lt;td&gt;1088 B&lt;/td&gt;
&lt;td&gt;8978 B&lt;/td&gt;
&lt;td&gt;~100 to 200 B&lt;/td&gt;
&lt;td&gt;few KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best-known attack&lt;/td&gt;
&lt;td&gt;lattice sieving $\approx 2^{0.292\beta}$&lt;/td&gt;
&lt;td&gt;information-set decoding (exp.)&lt;/td&gt;
&lt;td&gt;information-set decoding (exp.)&lt;/td&gt;
&lt;td&gt;ISD, plus a reaction attack given a failure oracle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DFR&lt;/td&gt;
&lt;td&gt;$2^{-164.8}$&lt;/td&gt;
&lt;td&gt;bounded, secret-independent&lt;/td&gt;
&lt;td&gt;negligible&lt;/td&gt;
&lt;td&gt;secret-dependent (the problem)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maturity&lt;/td&gt;
&lt;td&gt;final and deployed&lt;/td&gt;
&lt;td&gt;selected 2025, pre-final&lt;/td&gt;
&lt;td&gt;ISO track, not in FIPS&lt;/td&gt;
&lt;td&gt;not selected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best suited for&lt;/td&gt;
&lt;td&gt;default KEM everywhere&lt;/td&gt;
&lt;td&gt;non-lattice diversity backup&lt;/td&gt;
&lt;td&gt;huge static keys, max conservatism&lt;/td&gt;
&lt;td&gt;superseded by HQC&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;ML-KEM wins on size and ubiquity. HQC&apos;s entire reason to exist is that its assumption is unrelated to ML-KEM&apos;s, so a lattice break would not take both down -- and you pay roughly eight times the ciphertext for that insurance [@fips-203] [@hqc-spec] [@nist-ir-8545].&lt;/p&gt;
&lt;p&gt;The signature decision spans three finalists on very different paradigms.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;ML-DSA-65 (final)&lt;/th&gt;
&lt;th&gt;FN-DSA / Falcon-512 (pre-final)&lt;/th&gt;
&lt;th&gt;SLH-DSA-128s (final)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Construction&lt;/td&gt;
&lt;td&gt;Fiat-Shamir with aborts&lt;/td&gt;
&lt;td&gt;GPV hash-and-sign over NTRU&lt;/td&gt;
&lt;td&gt;stateless hash-based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assumption&lt;/td&gt;
&lt;td&gt;Module-LWE and Module-SIS&lt;/td&gt;
&lt;td&gt;NTRU and SIS (lattice)&lt;/td&gt;
&lt;td&gt;hash function only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public key&lt;/td&gt;
&lt;td&gt;1952 B&lt;/td&gt;
&lt;td&gt;897 B&lt;/td&gt;
&lt;td&gt;32 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signature&lt;/td&gt;
&lt;td&gt;3309 B&lt;/td&gt;
&lt;td&gt;666 B&lt;/td&gt;
&lt;td&gt;7856 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing&lt;/td&gt;
&lt;td&gt;fast, variable-time&lt;/td&gt;
&lt;td&gt;fast, floating-point sampler&lt;/td&gt;
&lt;td&gt;very slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation risk&lt;/td&gt;
&lt;td&gt;low (no floating point)&lt;/td&gt;
&lt;td&gt;high (constant-time floating point is hard)&lt;/td&gt;
&lt;td&gt;low (hashing only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maturity&lt;/td&gt;
&lt;td&gt;final, the default&lt;/td&gt;
&lt;td&gt;FIPS 206 in development&lt;/td&gt;
&lt;td&gt;final&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best suited for&lt;/td&gt;
&lt;td&gt;general-purpose default&lt;/td&gt;
&lt;td&gt;size-critical, constant-time guaranteed&lt;/td&gt;
&lt;td&gt;firmware and roots, low volume&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;There is no free lunch in that table [@fips-204] [@falcon-spec] [@fips-205]. Falcon is smallest but hardest to implement safely and not yet final; SLH-DSA is the safest to trust but by far the largest and slowest; ML-DSA is the sensible middle and the recommended default.&lt;/p&gt;
&lt;p&gt;To feel the gap, anchor on the classical world this series has used throughout. An Ed25519 signature is 64 bytes; an X25519 public key is 32. Nothing in the post-quantum toolkit comes close, as Part 15 on elliptic curves makes vivid.&lt;/p&gt;
&lt;p&gt;The smallest post-quantum signature, Falcon-512 at 666 bytes, is about ten times larger and carries a floating-point hazard; the most conservative, SLH-DSA-128s at 7856 bytes, is about one hundred and twenty times larger; and the default KEM ciphertext, ML-KEM-768 at 1088 bytes, is about thirty-four times an X25519 share [@falcon-spec] [@fips-205] [@fips-203]. Every column of these tables buys one property -- small size, easy constant-time code, a conservative assumption, or non-lattice diversity -- by giving up another.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; No post-quantum primitive wins on every axis. The five are not a menu awaiting a single winner; they are deliberate coverage of a trade surface, chosen so that whatever your binding constraint -- bytes, speed, assumption conservatism, or implementation safety -- one of them is the defensible answer.&lt;/p&gt;
&lt;/blockquote&gt;

The toolkit is five points on a trade surface, not an arbitrary menu.
&lt;p&gt;One more choice cuts across both decisions: hybrid versus pure. The shipping default, X25519MLKEM768, runs a classical X25519 exchange and a post-quantum ML-KEM-768 encapsulation together and combines both shared secrets, so the session stays secure as long as &lt;em&gt;either&lt;/em&gt; half holds [@openssl-35-notes]. During a migration that is the conservative posture: it defends against a future quantum computer and against an implementation bug in the young post-quantum half at once -- a belt-and-suspenders design, the security-definition thinking of Part 1 made concrete. These trades feel like engineering. Underneath them sits something humbler: we cannot prove any of it is hard.&lt;/p&gt;
&lt;h2&gt;8. What We Cannot Prove&lt;/h2&gt;
&lt;p&gt;Here is the headline most readers do not expect: none of the five rests on an unconditional hardness proof. &quot;Standardized by NIST&quot; does not mean &quot;proven secure.&quot; It means &quot;no efficient attack is known, backed by decades of failed attempts and, for lattices, an unusually strong reduction.&quot; That is a different and more honest claim.&lt;/p&gt;
&lt;p&gt;The lattice story is the one people most often overstate. Ajtai and then Regev proved worst-case-to-average-case reductions: breaking random instances is as hard as breaking the worst case [@ajtai-1996] [@regev-lwe-2005]. That is remarkable, and it is genuinely reassuring.&lt;/p&gt;
&lt;p&gt;But three caveats matter. First, those reductions are cleanest for &lt;em&gt;plain&lt;/em&gt; LWE, while the standards use &lt;em&gt;structured&lt;/em&gt; Module-LWE and NTRU, whose reductions are weaker or looser. Second, the actual parameters are not chosen from the reduction at all; they are sized against the best-known attack, lattice sieving, whose cost is heuristically $\approx 2^{0.292\beta}$ classically and roughly $2^{0.265\beta}$ quantumly under debated memory assumptions [@bdgl-sieving-2015]. Third, at the approximation factors these schemes use, the underlying lattice problems sit in $\mathsf{NP} \cap \mathsf{coNP}$, so they are not NP-hard under standard assumptions [@aharonov-regev-2005]. A genuine super-polynomial lower bound for any of them would prove $\mathsf{P} \neq \mathsf{NP}$ -- which no one can currently do.&lt;/p&gt;
&lt;p&gt;Codes and hashes are no different in kind. General syndrome decoding is NP-hard, but HQC&apos;s security depends on the &lt;em&gt;average-case&lt;/em&gt; hardness of decoding random quasi-cyclic codes, which is an assumption, not a theorem [@hqc-spec]. SLH-DSA reduces tightly to standard properties of its hash function, with no algebraic structure to exploit -- the most conservative bet in the box, but still a bet [@fips-205].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Realize what this means taken together: the security of the entire toolkit is a &lt;em&gt;monitored cryptanalytic bet&lt;/em&gt;, not a proof. The strong lattice reductions do not cover the structured schemes actually deployed; the parameters are justified empirically; and a real hardness proof for any of them would settle the biggest open question in computer science. This is precisely why the field standardized a diversified portfolio and keeps a non-lattice spare. The humility is not a weakness in the design -- it &lt;em&gt;is&lt;/em&gt; the design.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two results in this area are not assumptions but hard walls, and they pull in opposite directions. The first is Shor&apos;s algorithm itself: no choice of RSA, Diffie-Hellman, or elliptic-curve parameters can ever be post-quantum, because the attack is a capability of the adversary, not a bound you can tune [@shor-1994]. The second constrains the replacements.&lt;/p&gt;

A NIKE lets two parties who know only each other&apos;s long-term public keys compute a shared secret with no interaction -- the static-static magic of Diffie-Hellman, where two published keys silently agree. A KEM does not provide this: encapsulation produces a fresh ciphertext that must be sent, so at least one message is required. There is no efficient, well-trusted post-quantum NIKE (the only candidate, CSIDH, has contested quantum security under subexponential quantum attack [@peikert-csieves-2019]).
&lt;p&gt;That second wall -- KEM is not NIKE -- is why post-quantum migration is not a mechanical find-and-replace. Any protocol that relied on Diffie-Hellman&apos;s non-interactive static-static agreement has to be redesigned around an interactive KEM handshake, as Part 18 on Diffie-Hellman foreshadowed. It is a design-level impossibility, not a tuning problem.&lt;/p&gt;
&lt;p&gt;One more subtlety links two sections: for the FO-transformed KEMs, the decryption-failure rate is a &lt;em&gt;security&lt;/em&gt; bound, not merely a correctness figure. A noticeable, secret-correlated failure rate is an oracle -- the exact mechanism behind the BIKE reaction attack -- which is why ML-KEM specifies rates like $2^{-164.8}$ and HQC insists on an analytically bounded one [@gjs-mdpc-2016].&lt;/p&gt;
&lt;p&gt;Put it all together and the shape of the toolkit becomes inevitable. The theoretically perfect primitive would have elliptic-curve-sized keys and signatures, fast constant-time software with no floating point, a conservative and well-understood assumption, and strong chosen-ciphertext or unforgeability guarantees. No known construction reaches all four corners at once: lattices are small and fast on a young, structured assumption; hashes are conservative but huge; codes offer diversity but cost kilobytes. The five primitives are the field&apos;s best simultaneous coverage of that surface. If we cannot prove hardness, the honest posture is to keep asking what we still cannot do -- and to keep a spare.&lt;/p&gt;
&lt;h2&gt;9. The Frontier the Toolkit Does Not Close&lt;/h2&gt;
&lt;p&gt;A field guide should be honest about what remains open. Seven problems sit on the near horizon, and together they explain why the toolkit is best understood as a monitored bet with an insurance policy attached.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The signature-size wall.&lt;/strong&gt; No post-quantum signature reaches the 64-byte classical world while keeping a conservative assumption &lt;em&gt;and&lt;/em&gt; an easy constant-time implementation. Falcon-512 is 666 bytes but floating-point; ML-DSA-44 is 2420 bytes; SLH-DSA-128s is 7856 bytes and up. Certificate chains, TLS handshakes, DNSSEC responses, and firmware manifests all multiply signature size by depth, so a few-kilobyte signature reshapes protocols. NIST&apos;s ongoing &quot;Additional Digital Signature Schemes&quot; on-ramp is the active response, hunting for small-signature options on different assumptions [@nist-pqc-project].This on-ramp is deliberately looking beyond lattices -- for schemes whose assumptions differ from ML-DSA and Falcon -- so that a future small-signature standard also widens the toolkit&apos;s assumption diversity rather than deepening its lattice exposure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Constant-time Falcon without floating point.&lt;/strong&gt; Falcon&apos;s fast-Fourier Gaussian sampler is defined over floating-point arithmetic, and a portable, high-precision, provably constant-time sampler is hard to guarantee across compilers and CPUs. This is the chief obstacle to shipping FN-DSA safely and the reason it standardizes last [@pornin-ctfalcon-2019] [@howe-isochronous-2019]. The motivating attack -- key recovery from Gram-Schmidt norm leakage -- is concrete, not hypothetical [@fouque-gsnorm-2019].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shrinking code-based ciphertexts.&lt;/strong&gt; HQC buys assumption diversity at 4.4 to 14.4 KB ciphertexts, and the smaller-key alternative (BIKE) was set aside precisely because its secret-dependent failure rate is a reaction-attack surface. An open goal is a code-based KEM with McEliece-like conservatism, ML-KEM-like size, and a provable secret-independent DFR [@nist-ir-8545].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Formally verified, side-channel-hardened implementations of all five.&lt;/strong&gt; KyberSlash showed that even widely used reference code can leak through timing [@kyberslash-site]. Machine-checked constant-time implementations of ML-KEM exist, but ML-DSA&apos;s variable-time abort loop and FN-DSA&apos;s floating point are materially harder to verify end to end. The standards are only as safe as the code that runs them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is the algebraic structure free?&lt;/strong&gt; Ring-LWE, Module-LWE, and NTRU all add ring structure for compact keys and fast transforms. No attack exploits that structure at the standardized parameters, but there is no proof it is as hard as unstructured LWE -- and all three lattice primitives share the exposure, so a structural breakthrough could touch most of the toolkit at once. The Module-LWE design dilutes structure as a hedge, but the conjecture that it is essentially as hard as plain LWE remains believed and unproven.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Migrating static-static protocols.&lt;/strong&gt; Because a KEM is not a NIKE, any protocol that assumed non-interactive Diffie-Hellman agreement must be redesigned, not reconfigured. Interactive hybrid handshakes cover key establishment well; a practical, trusted post-quantum NIKE does not exist.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The real quantum cost of sieving.&lt;/strong&gt; The quantum sieving exponent near $2^{0.265\beta}$ depends on memory and qRAM models whose real-world cost is uncertain, and NIST&apos;s security categories inherit that uncertainty [@bdgl-sieving-2015]. Conservative defaults -- recommending Category-3 ML-KEM-768 rather than the smaller set -- absorb the doubt, but a settled cost model would tighten every lattice parameter.&lt;/p&gt;
&lt;p&gt;None of that blocks you from shipping the right thing today. Here is exactly what to ship.&lt;/p&gt;
&lt;h2&gt;10. Exact Decision Rules&lt;/h2&gt;
&lt;p&gt;Enough theory. Here are defensible defaults you can carry into a design review, phrased as &quot;use X with these parameters in case Y.&quot;&lt;/p&gt;

flowchart TD
    Q1{&quot;Signing or key exchange?&quot;}
    Q1 -- Key exchange --&amp;gt; K1{&quot;Bandwidth very tight and Category 1 acceptable?&quot;}
    K1 -- Yes --&amp;gt; KEM512[ML-KEM-512 in a hybrid]
    K1 -- No --&amp;gt; K2{&quot;Long-term or Category 5 secret?&quot;}
    K2 -- Yes --&amp;gt; KEM1024[ML-KEM-1024 in a hybrid]
    K2 -- No --&amp;gt; KEM768[ML-KEM-768 hybrid, the default]
    Q1 -- Signing --&amp;gt; S1{&quot;Low-volume firmware or root of trust?&quot;}
    S1 -- Yes --&amp;gt; SLH[SLH-DSA-128s or 128f]
    S1 -- No --&amp;gt; S2{&quot;Is signature size the hard limit?&quot;}
    S2 -- No --&amp;gt; MLDSA[ML-DSA-65, the default]
    S2 -- Yes --&amp;gt; FN[Consider FN-DSA, vetted constant-time only, after FIPS 206]
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Key establishment (TLS, SSH, VPN):&lt;/strong&gt; use &lt;strong&gt;ML-KEM-768 in a hybrid&lt;/strong&gt; (X25519MLKEM768). It is the shipping default and the conservative middle category [@openssl-35-notes] [@openssh-99-notes]. Drop to ML-KEM-512 only under tight bandwidth with Category-1 acceptance; step up to ML-KEM-1024 for Category-5 or long-lived secrets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;General-purpose signatures:&lt;/strong&gt; use &lt;strong&gt;ML-DSA-65&lt;/strong&gt; (Category 3). No floating point, easy constant-time, moderate sizes [@fips-204].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Firmware, boot, root-of-trust (low volume, maximum conservatism):&lt;/strong&gt; use &lt;strong&gt;SLH-DSA-128s&lt;/strong&gt; for smaller signatures or &lt;strong&gt;128f&lt;/strong&gt; for faster signing. You sign rarely, so absorb the large signature in exchange for a hash-only assumption [@fips-205].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When signature size is the binding constraint:&lt;/strong&gt; consider &lt;strong&gt;FN-DSA / Falcon&lt;/strong&gt; -- but only with a vetted constant-time implementation, and &lt;strong&gt;not in production until FIPS 206 is final&lt;/strong&gt; [@fips-206-perlner-2025]. Until then, prefer ML-DSA.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For KEM assumption diversity:&lt;/strong&gt; plan for &lt;strong&gt;HQC&lt;/strong&gt; as a standardized non-lattice backup &lt;strong&gt;once its FIPS lands&lt;/strong&gt;, not today [@nist-ir-8545]. If you need maximal conservatism now and can absorb a huge static key, Classic McEliece is the code-based option outside the FIPS set [@classic-mceliece].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The single most useful thing you can build is an intuition for how many bytes each choice adds. Run the numbers.&lt;/p&gt;
&lt;p&gt;{`
// Illustrative only. Estimate the extra bytes post-quantum adds versus classical
// X25519 / Ed25519, for a KEM share and for a 3-certificate chain.&lt;/p&gt;
&lt;p&gt;const sizes = {
  &apos;Ed25519&apos;:      { sig: 64,   pk: 32 },
  &apos;ML-DSA-65&apos;:    { sig: 3309, pk: 1952 },
  &apos;Falcon-512&apos;:   { sig: 666,  pk: 897 },
  &apos;SLH-DSA-128s&apos;: { sig: 7856, pk: 32 },
};&lt;/p&gt;
&lt;p&gt;// A chain of 3 certificates, each carrying one signature + one public key.
function chainBytes(name) {
  const s = sizes[name];
  return (s.sig + s.pk) * 3;
}&lt;/p&gt;
&lt;p&gt;for (const n of [&apos;Ed25519&apos;,&apos;ML-DSA-65&apos;,&apos;Falcon-512&apos;,&apos;SLH-DSA-128s&apos;]) {
  console.log(n.padEnd(14), String(chainBytes(n)).padStart(6), &apos;bytes over a 3-cert chain&apos;);
}&lt;/p&gt;
&lt;p&gt;console.log(&apos;---&apos;);
const x25519Share = 32 + 32;            // classical key share, round trip
const mlkemAdds   = 1184 + 1088;        // ML-KEM-768 key + ciphertext
console.log(&apos;KEM share, classical X25519 :&apos;, x25519Share, &apos;bytes&apos;);
console.log(&apos;KEM share, ML-KEM-768 hybrid:&apos;, x25519Share + mlkemAdds, &apos;bytes&apos;);
`}&lt;/p&gt;
&lt;p&gt;Rules pick the primitive; discipline keeps it safe. A short pitfall list, drawn straight from the failure catalog:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Do not divide a secret by the modulus in variable time.&lt;/strong&gt; That was KyberSlash; use constant-time (Barrett) reduction and a library whose constant-time behavior has been tested [@kyberslash-site].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefer hedged (randomized) signing for ML-DSA, and feed it a good RNG.&lt;/strong&gt; The randomized mode is the default and is more resilient to fault and nonce mishaps [@fips-204].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use context strings&lt;/strong&gt; to domain-separate signatures across applications and prevent cross-protocol reuse [@fips-204].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep implicit rejection constant-time.&lt;/strong&gt; Never let a KEM surface a decapsulation failure as a distinguishable error or timing tell.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do not hand-roll any of these.&lt;/strong&gt; Every primitive has subtle side channels; use standard libraries.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; During migration, run post-quantum alongside classical (X25519MLKEM768) so a break or bug in either half is survivable, and migrate &lt;em&gt;key establishment&lt;/em&gt; before signatures -- harvest-now-decrypt-later already threatens today&apos;s recorded traffic, while forged signatures require an attacker who is present in the future [@openssl-35-notes].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On availability: the finalized three are production-ready across the toolchain. OpenSSL 3.5 ships X25519MLKEM768 as a default key share, OpenSSH enabled &lt;code&gt;mlkem768x25519-sha256&lt;/code&gt; by default in 9.9 and made it the default in 10.0, and ML-KEM and ML-DSA are broadly available across open-source libraries -- liboqs, BoringSSL, AWS-LC, Microsoft SymCrypt, Bouncy Castle, and pyca/cryptography -- with formally verified ML-KEM through the libcrux line [@openssl-35-notes] [@openssh-pq] [@open-quantum-safe]. FN-DSA and HQC are experimental only until their FIPS documents are final. For a sense of how this looks in real deployments, this blog&apos;s companion posts trace &lt;a href=&quot;https://paragmali.com/blog/post-quantum-cryptography-on-windows-the-thirty-year-migrati/&quot; rel=&quot;noopener&quot;&gt;the post-quantum migration on Windows&lt;/a&gt; and &lt;a href=&quot;https://paragmali.com/blog/the-thirty-year-migration-ships-in-a-pip-install-how-post-qu/&quot; rel=&quot;noopener&quot;&gt;the moment ML-KEM arrived in an ordinary &lt;code&gt;pip install&lt;/code&gt;&lt;/a&gt;. The forthcoming Part 21 on crypto-agility and cryptographic bills of materials covers how to keep these choices swappable as the toolkit evolves.&lt;/p&gt;

Post-quantum migration now has deadlines attached. NIST&apos;s guidance and its IR 8547 transition plan point toward deprecating quantum-vulnerable algorithms by 2035, and comparable government profiles set similar horizons [@nist-pqc-project]. The practical reading is simple: inventory where you use RSA, Diffie-Hellman, and ECC now, because a decade is not long for a full cryptographic transition, and the harvest-now clock started before the standards were even published.

If you have OpenSSL 3.5 or later installed, you can list its post-quantum groups and signature algorithms with `openssl list -kem-algorithms` and `openssl list -signature-algorithms`. Seeing `ML-KEM-768` and `X25519MLKEM768` in that output is the concrete, on-your-own-machine version of this entire article: the migration is not a forecast, it is already in your crypto library [@openssl-35-notes].
&lt;p&gt;The rules above answer &quot;what.&quot; These next answer the questions that come up in review.&lt;/p&gt;
&lt;h2&gt;11. Questions From the Review Room&lt;/h2&gt;


No. There is no cryptanalytic break of any of the five. The only real-world failures are implementation leaks -- KyberSlash&apos;s secret-dependent division timing [@kyberslash-site] and Falcon&apos;s floating-point Gram-Schmidt leakage [@fouque-gsnorm-2019] -- and both are fixed by better code, not new math. The era&apos;s two famous breaks, SIKE and Rainbow, hit schemes that were never selected for the toolkit [@castryck-decru-sidh-2022] [@beullens-rainbow-2022].


Against a classical attacker, yes. Against harvest-now-decrypt-later, not for long-lived secrets: an adversary can record today&apos;s session and decrypt it once a quantum computer arrives, which is why you migrate key establishment first and why hybrids are already shipping [@nist-pqc-project] [@openssl-35-notes].


Not in general. A KEM is not a non-interactive key exchange -- there is no trusted post-quantum static-static agreement -- so protocols that relied on that property must be redesigned around an interactive KEM handshake rather than reconfigured in place.


No. FN-DSA (Falcon) was still in development toward FIPS 206 as of this writing [@fips-206-perlner-2025], and HQC was only selected on 2025-03-11 with a draft FIPS pending [@nist-ir-8545]. Do not ship either in production yet.


Because no single primitive wins on size, speed, assumption conservatism, and maturity at once, and because spreading the toolkit across three unrelated hard problems -- lattices, hashes, and codes -- means one mathematical break cannot take everything down. The 2022 breaks of SIKE and Rainbow, both outside the toolkit, are the empirical argument for that hedge [@nist-ir-8545] [@castryck-decru-sidh-2022].


Essentially yes. ML-KEM (FIPS 203) is the standardized CRYSTALS-Kyber with standardization edits, and the same relationship holds for Dilithium to ML-DSA and SPHINCS+ to SLH-DSA [@fips-203] [@crystals-kyber]. If you learned Kyber, you already know ML-KEM.


No and no. All five primitives run on ordinary classical hardware today [@nist-pqc-project]. Quantum key distribution is a physics-layer technique that uses quantum hardware to exchange keys; post-quantum cryptography is classical software designed to resist quantum *attacks*. They solve related problems by completely different means.

&lt;p&gt;Step back to the shape of the whole thing. One event in 1994 condemned all deployed public-key cryptography [@shor-1994]. The field&apos;s answer was not a single replacement but a portfolio hedged across three unrelated assumptions and tuned to five different binding constraints, three of them already law and two still in progress. The most striking fact remains the quietest one: after a decade of open, adversarial cryptanalysis, nothing in the toolkit has been broken -- only its early code has leaked.&lt;/p&gt;
&lt;p&gt;The real test is still ahead. When the next break comes, and history suggests one eventually will, the entire point of this design is that it lands on one assumption family while the others carry the load. That is not a promise that the math is unbreakable. It is a bet, made in the open, that diversity outlasts any single idea -- and a spare, HQC, waiting in reserve for the day the bet is called.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;the-post-quantum-toolkit&quot; keyTerms={[
  { term: &quot;ML-KEM (FIPS 203)&quot;, definition: &quot;The standardized Module-LWE key-encapsulation mechanism; the deployed post-quantum KEM, small and fast, secured by FO with implicit rejection.&quot; },
  { term: &quot;ML-DSA (FIPS 204)&quot;, definition: &quot;The default post-quantum signature; a Fiat-Shamir-with-aborts lattice scheme using uniform integers and no floating point.&quot; },
  { term: &quot;SLH-DSA (FIPS 205)&quot;, definition: &quot;The conservative backstop signature; stateless hash-based, resting only on hash-function security, with tiny keys but very large signatures.&quot; },
  { term: &quot;FN-DSA / Falcon&quot;, definition: &quot;Pre-final (FIPS 206 in development). GPV hash-and-sign over NTRU with the smallest signatures, but a hard-to-implement floating-point sampler.&quot; },
  { term: &quot;HQC&quot;, definition: &quot;Pre-final (selected 2025-03-11). A code-based KEM providing non-lattice assumption diversity, with a public decoder and a bounded, secret-independent failure rate.&quot; },
  { term: &quot;Harvest now, decrypt later&quot;, definition: &quot;Recording encrypted traffic today to decrypt once quantum computers exist; the reason key establishment migrates first.&quot; },
  { term: &quot;Fujisaki-Okamoto with implicit rejection&quot;, definition: &quot;The transform giving KEMs chosen-ciphertext security by returning a pseudo-random key on failure, closing the decapsulation-failure oracle.&quot; },
  { term: &quot;Fiat-Shamir with aborts&quot;, definition: &quot;Signing by reject-and-restart so the released transcript is provably independent of the secret key.&quot; },
  { term: &quot;Transcript leakage&quot;, definition: &quot;When public outputs statistically depend on the secret key, so enough valid outputs recover it, as in the NTRUSign parallelepiped break.&quot; },
  { term: &quot;KEM is not NIKE&quot;, definition: &quot;A key-encapsulation mechanism cannot replace non-interactive static-static Diffie-Hellman, so some protocols need redesign, not a drop-in swap.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>post-quantum-cryptography</category><category>ml-kem</category><category>ml-dsa</category><category>slh-dsa</category><category>falcon</category><category>hqc</category><category>lattice-cryptography</category><category>cryptography</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>The Thirty-Year Migration Ships in a pip install: How Post-Quantum Cryptography Crossed from Standard to Shipping Code</title><link>https://paragmali.com/blog/the-thirty-year-migration-ships-in-a-pip-install-how-post-qu/</link><guid isPermaLink="true">https://paragmali.com/blog/the-thirty-year-migration-ships-in-a-pip-install-how-post-qu/</guid><description>Post-quantum cryptography spent thirty years reaching a pip install. ML-KEM and ML-DSA shipped in pyca/cryptography v48 weeks ahead of the federal deadline.</description><pubDate>Tue, 30 Jun 2026 00:00:00 GMT</pubDate><content:encoded>
Post-quantum cryptography spent thirty years crossing from theory (Shor, 1994) to lattice math (Learning With Errors, 2005) to NIST standards (FIPS 203 and 204, 2024) -- and in 2026 it finally reached shipping code. On May 4, 2026, `pyca/cryptography` v48.0.0 put ML-KEM and ML-DSA into the default `pip` wheels, roughly seven weeks *before* Executive Order 14412 set the federal deadlines. But shipping the primitive is necessary, not sufficient: ML-KEM and ML-DSA are one to two orders of magnitude larger than the X25519 and Ed25519 they replace, and a key-encapsulation mechanism is not a drop-in for Diffie-Hellman. The remaining work -- integrating these into TLS, SSH, X.509, and package signing -- is the real last mile, because a primitive is not a protocol.
&lt;h2&gt;1. The Last Mile Is a &lt;code&gt;pip install&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;On May 4, 2026, the migration Peter Shor set in motion thirty-two years earlier quietly crossed its last mile -- not in a standards body, not at a White House signing, but in a routine &lt;code&gt;pip install&lt;/code&gt;. That day, &lt;code&gt;pyca/cryptography&lt;/code&gt; v48.0.0 added ML-KEM and ML-DSA to the default wheels that sit beneath Ansible, Certbot, and a package downloaded more than a billion times a month [@pyca-changelog] [@tob-2026]. Seven weeks &lt;em&gt;later&lt;/em&gt;, an executive order would set the federal deadlines for exactly this migration [@eo14412] -- but the code had already arrived.&lt;/p&gt;
&lt;p&gt;That ordering is the whole story, and it is the opposite of the one most people tell. The usual narrative treats the 2024 NIST standards or the 2026 executive order as the moment post-quantum cryptography &quot;became real.&quot; The dated record says otherwise: the primitive shipped first, in a version-bump nobody outside a handful of maintainers noticed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The pip install beat the policy. &lt;code&gt;pyca/cryptography&lt;/code&gt; v48.0.0 shipped ML-KEM and ML-DSA on May 4, 2026; Executive Order 14412 set the federal deadlines on June 22, 2026 -- forty-nine days later. The shipping code was already in a billion-download-a-month wheel before the mandate existed [@pyca-changelog] [@eo14412].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Trail of Bits, which wrote much of the code that made this possible, put the milestone plainly.&lt;/p&gt;

Post-quantum cryptography is now one `pip-install` away. -- Trail of Bits, on the arrival of ML-KEM and ML-DSA in `pyca/cryptography` [@tob-2026]
&lt;p&gt;This is a strange kind of anticlimax. A threat that dooms RSA, Diffie-Hellman, and elliptic-curve cryptography was described in 1994. It took a decade to find math that plausibly resists it, another decade for that math to become efficient enough to deploy, a six-year public competition to pick winners, and a formal standardization in 2024. And then the thing that actually put quantum-resistant cryptography in front of most working programmers was a distribution change: the same primitives, previously reachable only in specialist builds, landing in the wheel everyone already installs.&lt;/p&gt;

timeline
    title From a quantum threat to shipping code
    1994 : Shor&apos;s algorithm breaks RSA, DH, and ECC in theory
    1996 : Ajtai proves worst-case lattice hardness
    2005 : Regev defines Learning With Errors
    2012 : Module-LWE yields kilobyte-scale keys
    2016 : NIST opens its post-quantum competition
    2022 : NIST selects Kyber, Dilithium, Falcon, and SPHINCS+
    2024 : FIPS 203, 204, and 205 finalized on August 13
    May 2026 : pyca cryptography v48 ships ML-KEM and ML-DSA
    Jun 2026 : Executive Order 14412 sets the federal deadlines
&lt;p&gt;There is a catch, and it is the reason this article exists. Shipping the primitive is the easy part. ML-KEM and ML-DSA are not smaller, faster, tidier versions of the algorithms they replace; they are dramatically larger, they have a different &lt;em&gt;shape&lt;/em&gt;, and they violate assumptions that thousands of protocols and buffers quietly encoded around 32-byte keys and 64-byte signatures. A standardized, &lt;code&gt;pip&lt;/code&gt;-installable primitive is a genuine milestone. It is also not a working TLS handshake, a signed X.509 certificate, or a package-signing scheme. In a phrase this article will earn: a primitive is not a protocol.&lt;/p&gt;
&lt;p&gt;So here is the question. If the primitive is a &lt;code&gt;pip install&lt;/code&gt; away, why is the migration still a thirty-year project -- and how did the code beat the executive order?&lt;/p&gt;
&lt;h2&gt;2. The Threat That Started a Thirty-Year Clock&lt;/h2&gt;
&lt;p&gt;In 1994, Peter Shor showed that a sufficiently large quantum computer could factor integers and compute discrete logarithms in polynomial time [@shor1994]. That one result quietly condemned almost every public-key system in deployment. RSA rests on the hardness of factoring; Diffie-Hellman and elliptic-curve cryptography rest on discrete logarithms. Shor&apos;s algorithm breaks all three at once. It is not a faster attack that a bigger key can outrun -- it is a &lt;em&gt;correctness&lt;/em&gt; failure of the assumption those systems are built on.Shor&apos;s 1994 paper is cited under two titles: the FOCS conference version, &quot;Algorithms for Quantum Computation: Discrete Logarithms and Factoring,&quot; and the expanded arXiv and SIAM version, &quot;Polynomial-Time Algorithms for Prime Factorization and Discrete Logarithms on a Quantum Computer&quot; [@shor1994].&lt;/p&gt;

Classical cryptographic algorithms -- ones that run on ordinary computers -- designed to remain secure even against an adversary with a large-scale quantum computer. PQC is not quantum cryptography: it uses no quantum hardware. It replaces the *hard problems* (factoring, discrete log) that quantum computers solve with problems (such as finding short vectors in a lattice) that they are not known to solve efficiently.

A 1994 quantum algorithm that factors integers and solves the discrete-logarithm problem in polynomial time. Its existence means that RSA, Diffie-Hellman, and elliptic-curve cryptography are all breakable by a large enough quantum computer, which is the entire reason the post-quantum migration exists [@shor1994].
&lt;h3&gt;Why symmetric cryptography survives&lt;/h3&gt;
&lt;p&gt;The quantum threat is asymmetric in an important way: it targets public-key cryptography, not the symmetric ciphers and hashes underneath it. The relevant quantum tool for symmetric keys is Grover&apos;s algorithm, which gives only a quadratic speedup on a brute-force search [@grover1996]. The folk summary is that Grover halves the security level, turning a 128-bit key into 64 bits.That halving is a naive query-count bound, not a real cost. A depth-limited quantum search is far more expensive: NIST&apos;s own evaluation criteria peg the effective quantum cost of breaking AES-128 near $2^{170}/\text{MAXDEPTH}$ rather than $2^{64}$ [@nist-cfp-eval], and Grassl and colleagues give the concrete Grover-on-AES resource estimates behind that figure [@grassl-2016]. Because Grover parallelizes only as the square root of the number of machines, serial depth dominates [@zalka-1999]. Even AES-128 keeps a wide margin; moving to AES-256 is a precaution, not a rescue. The practical upshot is clean: symmetric keys need at most a modest bump, so the migration is overwhelmingly a public-key story [@nist-cfp-eval] [@grassl-2016].&lt;/p&gt;
&lt;h3&gt;Why the migration cannot wait for the hardware&lt;/h3&gt;
&lt;p&gt;Here is the part that surprises people. You do not need a working quantum computer today for the threat to be operational today. An adversary can record encrypted traffic now and simply store it, then decrypt it years later once a cryptographically relevant quantum computer exists. Anything that must stay confidential past the arrival of that machine is already exposed.&lt;/p&gt;

An attack strategy in which an adversary captures and stores encrypted data today, betting on decrypting it in the future once quantum computers can break the key exchange that protected it. HNDL makes the quantum threat a *present-day* problem for any data with a long confidentiality lifetime, even though the quantum computer does not yet exist.
&lt;p&gt;Thirty-two years after Shor, Executive Order 14412 opens by restating exactly this rationale as national-security fact [@eo14412].&lt;/p&gt;

Ongoing cyber activity against our Nation also presents the risk of adversaries collecting United States information now, and decrypting it later once large-scale quantum computers are operational. -- Executive Order 14412 [@eo14412]

Because HNDL is the operative threat, the near-term reason to adopt post-quantum key establishment is not that a quantum computer is imminent -- it is that *today&apos;s* confidential traffic has a shelf life that outlasts the hardware timeline. Trail of Bits made the point sharply in a 2024 essay arguing that quantum resistance is not even the main benefit of post-quantum cryptography: the discipline of a clean migration and modern, agile primitives pays off regardless of when the machine arrives [@tob-2024] [@eo14412].
&lt;p&gt;The field even got its name in this period. The PQCrypto workshop series began gathering researchers around the problem in 2006, and the 2009 Springer volume &lt;em&gt;Post-Quantum Cryptography&lt;/em&gt; framed the multi-decade replacement thesis that the community has been executing ever since [@pqcrypto-workshop] [@pqc-book-2009].The coinage of the phrase &quot;post-quantum cryptography&quot; is usually attributed to Daniel J. Bernstein around 2003 to 2006, but that attribution is folk knowledge; the firm anchors are the 2006 workshop and the 2009 book [@pqcrypto-workshop] [@pqc-book-2009].&lt;/p&gt;
&lt;p&gt;If factoring and discrete log are dead in the quantum model, the obvious next question is what we build on instead. Several candidate hard problems were on the table. Only one of them turned into the workhorse behind the algorithms that just shipped in your &lt;code&gt;pip&lt;/code&gt; cache -- and understanding why the others lost is the fastest way to understand what makes the winner trustworthy.&lt;/p&gt;
&lt;h2&gt;3. The Math That Survives Quantum&lt;/h2&gt;
&lt;p&gt;After Shor, cryptographers had a menu of hard problems that quantum computers were not known to crack: hash functions, error-correcting codes, systems of multivariate quadratic equations, isogenies between elliptic curves, and lattices. Four of the five had a disqualifying flaw for a general-purpose default. One did not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hash-based signatures&lt;/strong&gt; are the most conservative option on the menu, because their only assumption is that a hash function behaves like a hash function. Merkle proposed the idea in 1979 [@rfc8391], and it survives today as SLH-DSA. But hash-based schemes sign; they cannot establish a key, so they can never be the whole answer. The early stateful forms carry a vicious footgun -- reuse a one-time key by losing track of internal state and you leak the private key [@sp800-208] -- and the stateless successor, SPHINCS+, buys safety with large, slow signatures [@sphincs-plus] [@tob-2026].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code-based encryption&lt;/strong&gt; has an even longer unbroken record. McEliece&apos;s 1978 cryptosystem hides a structured error-correcting code as a random-looking matrix; half a century and many attack papers later, including quantum ones, its security has held [@classic-mceliece]. Its ciphertexts are tiny. The problem is the public key: Classic McEliece keys run from roughly 261 KB to more than 1 MB [@classic-mceliece]. That is fine for a niche, fatal for a default that has to fit inside a TLS handshake.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multivariate&lt;/strong&gt; and &lt;strong&gt;isogeny&lt;/strong&gt; schemes both looked promising and both broke during the standardization era -- a story worth its own section (Section 4).&lt;/p&gt;
&lt;p&gt;That leaves &lt;strong&gt;lattices&lt;/strong&gt;, and the reason they won is a two-step story of beauty followed by engineering.&lt;/p&gt;
&lt;h3&gt;Step one: beauty (worst-case hardness)&lt;/h3&gt;
&lt;p&gt;In 1996, Miklos Ajtai proved something remarkable: you can build cryptographic instances whose average-case hardness is guaranteed by the worst-case hardness of a lattice problem [@ajtai1996]. In most of cryptography you hope your random instance is hard; Ajtai showed a family where a random instance is provably as hard as the hardest instance in the class. In 2005, Oded Regev turned this into a usable assumption -- Learning With Errors -- complete with a quantum worst-case-to-average-case reduction and a working public-key encryption scheme [@regev-lwe].&lt;/p&gt;

The problem of recovering a secret vector $s$ given many noisy linear equations $b = As + e$, where $A$ is public and random and $e$ is small random noise. Without the noise this is trivial linear algebra; with it, recovering $s$ is believed hard even for quantum computers. LWE is the assumption underneath ML-KEM and ML-DSA [@regev-lwe].
&lt;p&gt;LWE is beautiful, and in its raw form it is unshippable. A plain-LWE public key is essentially a big random matrix, so its size grows like $O(n^2)$ in the security parameter -- megabytes, not kilobytes. Beauty was not enough.&lt;/p&gt;
&lt;h3&gt;Step two: engineering (algebraic structure)&lt;/h3&gt;
&lt;p&gt;The fix was to give LWE algebraic structure. Ring-LWE (2010) works over a ring of polynomials instead of a flat vector space, collapsing the quadratic overhead and letting the Number-Theoretic Transform multiply polynomials quickly; its own authors describe removing LWE&apos;s &quot;inherent quadratic overhead&quot; [@ring-lwe]. Module-LWE (2012) generalized this to short vectors of ring elements, giving designers a tunable dial between raw LWE and full Ring-LWE [@module-lwe]. The size effect is the whole game: from $O(n^2)$ down to $O(n)$, from megabytes to kilobytes. That single step is what turned lattice cryptography from a theorist&apos;s toy into the deployable engine behind ML-KEM and ML-DSA.&lt;/p&gt;

A middle-ground version of LWE defined over modules -- short vectors whose entries are elements of a polynomial ring. It sits between unstructured LWE (large, most conservative) and Ring-LWE (compact, most structured), letting a scheme trade size against how much algebraic structure it assumes. Module-LWE is the specific hard problem under CRYSTALS-Kyber and CRYSTALS-Dilithium, standardized as ML-KEM and ML-DSA [@module-lwe].

flowchart TD
    A[&quot;Classical public key (RSA, DH, ECC)&quot;] --&amp;gt;|Shor 1994 breaks all three| B[&quot;Need a quantum-hard problem&quot;]
    B --&amp;gt; C[&quot;Hash-based (SLH-DSA): conservative backstop, large and slow&quot;]
    B --&amp;gt; D[&quot;Code-based (McEliece): unbroken, but keys near 1 MB&quot;]
    B --&amp;gt; E[&quot;Multivariate (Rainbow): broken in a weekend, 2022&quot;]
    B --&amp;gt; F[&quot;Isogeny (SIKE): broken in about ten minutes, 2022&quot;]
    B --&amp;gt; G[&quot;Lattice (LWE): worst-case hardness, but O(n^2) keys&quot;]
    G --&amp;gt; H[&quot;Ring-LWE and Module-LWE: O(n) kilobyte keys&quot;]
    H --&amp;gt; I[&quot;ML-KEM and ML-DSA: the deployed workhorse&quot;]
&lt;p&gt;There is an honest catch in step two, and it matters for the rest of this article. Adding structure is what buys the kilobyte keys, but structure is also extra assumption.Is the algebraic structure &quot;free&quot;? The worst-case reduction for Ring-LWE and Module-LWE runs to &lt;em&gt;ideal&lt;/em&gt; or &lt;em&gt;module&lt;/em&gt; lattices -- a smaller, more special class than general lattices [@peikert-2015]. No known attack cashes that extra structure in at the standardized parameters; the best attack remains generic lattice sieving at $2^{0.292\beta}$, the same cost as for unstructured LWE [@bdgl16]. Module-LWE deliberately dilutes the structure, as its own built-in hedge [@module-lwe]. But &quot;the structure is free&quot; is a conjecture, not a theorem -- which is exactly why the standardized portfolio keeps a hash-only backstop, SLH-DSA, that would survive even if that conjecture failed [@fips205]. The community&apos;s answer to that residual doubt is not to pretend it away; it is to keep a scheme from a completely different family in reserve. Hold that thought -- it is the reason the eventual standard is a portfolio, not a single winner.&lt;/p&gt;
&lt;p&gt;Kilobyte-scale lattice schemes existed by 2018 [@kyber] [@dilithium]. So why did it take a six-year global tournament to decide which ones to trust?&lt;/p&gt;
&lt;h2&gt;4. From a Problem to a Portfolio&lt;/h2&gt;
&lt;p&gt;NIST did not crown one algorithm. Starting in 2016, it ran an open, public, break-or-defend competition -- publish your candidate, publish your attacks, let years of adversarial scrutiny do the filtering [@nist-pqc-project]. Google had already run a taste of the future in 2016, wiring an experimental post-quantum key exchange called CECPQ1 into Chrome and its front ends to see what breaks at internet scale, then retiring it precisely because it was not yet standardized [@google-cecpq]. The lesson was clear: experiments are cheap, but a default needs a standard behind it.&lt;/p&gt;
&lt;p&gt;On July 5, 2022, NIST announced its first selections: CRYSTALS-Kyber for key establishment, and CRYSTALS-Dilithium, Falcon, and SPHINCS+ for signatures [@nist-2022]. Three of the four are lattice schemes; the fourth, SPHINCS+, is hash-based. NIST named Dilithium the primary signature, Falcon the option for applications that need smaller signatures, and SPHINCS+ the backup built on &quot;a different math approach&quot; [@nist-2022]. That portfolio is a deliberate hedge: a compact, versatile lattice family as the workhorse, plus a signature scheme whose security rests on nothing but hash functions.&lt;/p&gt;
&lt;h3&gt;The tournament produced casualties&lt;/h3&gt;
&lt;p&gt;The hedge was not paranoia. It was a lesson the competition taught in real time.&lt;/p&gt;
&lt;p&gt;The isogeny KEM SIKE was one of the most elegant candidates, with the smallest keys of anything in the field, and it advanced to the fourth round. Then, in 2022, Wouter Castryck and Thomas Decru broke it -- not with a quantum computer, but on a laptop.Castryck and Decru recovered the SIKE private key by exploiting the torsion-point images the protocol reveals, via Kani&apos;s reducibility criterion. Their Magma implementation &quot;breaks SIKEp434, which aims at security level 1, in about ten minutes on a single core&quot; [@sike-break]. A years-vetted, fourth-round candidate fell to one new mathematical idea. Around the same time, Ward Beullens broke the multivariate signature scheme Rainbow, a third-round finalist, recovering its secret key in an average of 53 hours -- one weekend -- on a standard laptop [@rainbow-break].&lt;/p&gt;

SIKE and Rainbow are the empirical argument for diversity. Both were serious, years-scrutinized candidates; both collapsed to a single new attack during standardization [@sike-break] [@rainbow-break]. If a finalist can fall that fast, betting the entire internet on one hard problem is reckless. That is why NIST standardized a small, deliberately diverse set and kept a hash-only backstop from a different family -- the same reasoning that keeps SLH-DSA in the portfolio even though ML-DSA is faster and smaller.
&lt;p&gt;Even NTRU, one of the oldest and most compact lattice schemes (Hoffstein, Pipher, and Silverman, 1996), did not make the cut. It was a finalist, but its security rested on a more heuristic argument than the CRYSTALS schemes&apos; cleaner reductions, and it carried a history of patent encumbrance that only lapsed in 2017 [@ntru]. NIST&apos;s rationale was multi-factor, but the outcome was telling: given two workable lattice families, the committee preferred the one with the tidier hardness story and no intellectual-property baggage.&lt;/p&gt;

flowchart LR
    subgraph LAT[&quot;Lattice family (selected)&quot;]
      L1[&quot;Ring-LWE and Module-LWE&quot;] --&amp;gt; L2[&quot;Kyber and Dilithium selected 2022&quot;]
    end
    subgraph HEDGE[&quot;Conservative hedge&quot;]
      H1[&quot;Hash-based SPHINCS+ selected as backstop&quot;]
    end
    subgraph DEAD[&quot;Broken during standardization&quot;]
      D1[&quot;Isogeny SIKE broken 2022&quot;]
      D2[&quot;Multivariate Rainbow broken 2022&quot;]
    end
    N[&quot;NTRU finalist, not selected&quot;] -.-&amp;gt; L2
&lt;p&gt;The following table condenses the generational story: which ideas advanced, which were demoted to a niche or a backstop, and which broke outright.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Since&lt;/th&gt;
&lt;th&gt;Core idea&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;RSA / DH / ECC&lt;/td&gt;
&lt;td&gt;1976&lt;/td&gt;
&lt;td&gt;Factoring and discrete log&lt;/td&gt;
&lt;td&gt;Quantum-doomed (Shor) [@shor1994]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hash-based (Merkle to SLH-DSA)&lt;/td&gt;
&lt;td&gt;1979&lt;/td&gt;
&lt;td&gt;One-time keys over a hash tree&lt;/td&gt;
&lt;td&gt;Active backstop, signatures only [@sp800-208] [@sphincs-plus]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code-based (Classic McEliece)&lt;/td&gt;
&lt;td&gt;1978&lt;/td&gt;
&lt;td&gt;Hide a Goppa code as a random matrix&lt;/td&gt;
&lt;td&gt;Niche: unbroken but ~1 MB keys [@classic-mceliece]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lattice theory (Ajtai; Regev/LWE)&lt;/td&gt;
&lt;td&gt;1996 / 2005&lt;/td&gt;
&lt;td&gt;Worst-case-hard lattices; LWE&lt;/td&gt;
&lt;td&gt;Foundation, but O(n^2) raw sizes [@ajtai1996] [@regev-lwe]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NTRU&lt;/td&gt;
&lt;td&gt;1996&lt;/td&gt;
&lt;td&gt;Ring-based lattice encryption&lt;/td&gt;
&lt;td&gt;Superseded finalist, not selected [@ntru]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ring/Module-LWE to ML-KEM/ML-DSA&lt;/td&gt;
&lt;td&gt;2012 / 2024&lt;/td&gt;
&lt;td&gt;Structured lattices, NTT&lt;/td&gt;
&lt;td&gt;Standardized workhorse [@module-lwe] [@fips204]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Isogeny SIDH/SIKE&lt;/td&gt;
&lt;td&gt;2011&lt;/td&gt;
&lt;td&gt;Supersingular isogeny walks&lt;/td&gt;
&lt;td&gt;Broken in about ten minutes, 2022 [@sike-break]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multivariate Rainbow&lt;/td&gt;
&lt;td&gt;2005&lt;/td&gt;
&lt;td&gt;Multivariate quadratic systems&lt;/td&gt;
&lt;td&gt;Broken in a weekend, 2022 [@rainbow-break]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Falcon / FN-DSA&lt;/td&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;NTRU lattice with Gaussian sampling&lt;/td&gt;
&lt;td&gt;Standard pending as FIPS 206 [@nist-2022]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A short list of winning algorithms is still just math on paper. What turns &quot;we chose Kyber&quot; into something a whole software supply chain can build on?&lt;/p&gt;
&lt;h2&gt;5. Why the Rename Mattered&lt;/h2&gt;
&lt;p&gt;On August 13, 2024, NIST finalized three standards. Kyber became ML-KEM (FIPS 203), Dilithium became ML-DSA (FIPS 204), and SPHINCS+ became SLH-DSA (FIPS 205) [@fips203] [@fips204] [@fips205]. It is tempting to read this as bureaucratic relabeling. It is the opposite: the rename is the moment the algorithms stopped being research artifacts and became a contract.&lt;/p&gt;

A Federal Information Processing Standard: a document published by NIST that fixes exact parameter sets, byte-level encodings, and algorithm behavior so that independent implementations interoperate and can be validated against a common reference. A FIPS standard is a specification -- a shared, machine-checkable contract -- not a piece of software [@fips203].
&lt;p&gt;The value of a FIPS document is that it pins down the boring, load-bearing details. A research paper can leave an encoding ambiguous or offer three parameter options; a standard says &lt;em&gt;these&lt;/em&gt; parameter sets, &lt;em&gt;these&lt;/em&gt; byte counts, &lt;em&gt;this&lt;/em&gt; wire encoding, and nothing else. That is what lets a hardware team, a TLS library, and a Python wheel independently implement ML-KEM and have their outputs match to the byte.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A common misconception is that the FIPS PDF ships the known-answer test vectors. It does not. The standard fixes the parameter sets and byte counts, but the validation vectors -- the inputs and expected outputs implementers check against -- are published and maintained through NIST&apos;s ACVP and CAVP validation program, in the &lt;code&gt;usnistgov/ACVP-Server&lt;/code&gt; repository (folders such as &lt;code&gt;ML-KEM-keyGen-FIPS203&lt;/code&gt; and &lt;code&gt;ML-DSA-sigGen-FIPS204&lt;/code&gt;), not inside the standard&apos;s text [@acvp-server]. The standard fixes the bytes; the validation program publishes the vectors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The three standards divide the work cleanly.&lt;/p&gt;

The Module-Lattice-Based Key-Encapsulation Mechanism: the standardized key-establishment primitive, derived from CRYSTALS-Kyber, with security tied to Module-LWE. It comes in three parameter sets -- ML-KEM-512, ML-KEM-768, and ML-KEM-1024 -- in increasing order of security strength [@fips203].

The Module-Lattice-Based Digital Signature Algorithm: the standardized general-purpose signature, derived from CRYSTALS-Dilithium. It is a Fiat-Shamir-with-aborts lattice signature that samples from the uniform distribution -- a design the Dilithium team chose specifically because &quot;Gaussian sampling is hard to implement securely and efficiently&quot; [@fips204] [@dilithium].
&lt;p&gt;SLH-DSA (FIPS 205) rounds out the set as the hash-only backstop -- slower and larger, but resting on assumptions no lattice attack can touch [@fips205]. Key establishment, everyday signatures, and a conservative signature hedge: three jobs, three standards, one portfolio.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Standardization, not the algorithm, is what lets a whole software community move at once. The algorithm was ready in 2018; what a whole community of libraries, protocols, and hardware needs is a fixed set of byte counts and validated test vectors they can all target independently. FIPS 203 and 204 supplied exactly that -- and that is the &quot;standard&quot; pole of the crossing this article traces [@fips203] [@fips204] [@acvp-server].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But a standard is still only a specification. It does not compile, it does not ship in a wheel, and it does not integrate itself into a single protocol. FIPS 204 tells you that an ML-DSA-65 signature is exactly 3,309 bytes; it does not tell you what happens to the fifty protocols and hardware buffers that were quietly built around 64-byte signatures.&lt;/p&gt;
&lt;p&gt;The standard fixes the byte counts. What happens when those byte counts are fifty times bigger than the ones every protocol was quietly built around?&lt;/p&gt;
&lt;h2&gt;6. Why the Numbers Break the Protocols&lt;/h2&gt;
&lt;p&gt;An Ed25519 signature is 64 bytes. Its post-quantum replacement, ML-DSA-65, is 3,309 bytes [@tob-2026] [@fips204]. Now multiply that by every place a protocol, a certificate format, a hardware buffer, or a database column quietly assumed 64.&lt;/p&gt;
&lt;p&gt;This is the pivot of the whole article. The primitive is real, standardized, and about to be a &lt;code&gt;pip install&lt;/code&gt; away -- and it does not fit where the old one did.&lt;/p&gt;
&lt;h3&gt;The size table&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Classical&lt;/th&gt;
&lt;th&gt;Post-quantum&lt;/th&gt;
&lt;th&gt;Public key&lt;/th&gt;
&lt;th&gt;Wire output&lt;/th&gt;
&lt;th&gt;Blow-up&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Signature&lt;/td&gt;
&lt;td&gt;Ed25519&lt;/td&gt;
&lt;td&gt;ML-DSA-65&lt;/td&gt;
&lt;td&gt;32 B to 1,952 B&lt;/td&gt;
&lt;td&gt;64 B sig to 3,309 B sig&lt;/td&gt;
&lt;td&gt;~61x key, ~52x sig&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Key exchange&lt;/td&gt;
&lt;td&gt;X25519&lt;/td&gt;
&lt;td&gt;ML-KEM-768&lt;/td&gt;
&lt;td&gt;32 B to 1,184 B&lt;/td&gt;
&lt;td&gt;32 B shared to 1,088 B ciphertext&lt;/td&gt;
&lt;td&gt;~37x key, ~34x wire&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Those multipliers -- roughly 34x to 61x -- come straight from the Trail of Bits size tables and FIPS 204&apos;s Appendix B [@tob-2026] [@fips204].Private keys are not the problem. Both ML-DSA-65 and ML-KEM-768 can store their private keys compactly as 32-byte and 64-byte seeds, respectively [@tob-2026]. The pressure is entirely on the values that travel on the wire: public keys, signatures, and ciphertexts. Those are exactly the objects protocols frame with fixed-width length fields. The size story alone would be a migration headache. But size is only half of what breaks. The other half is shape.&lt;/p&gt;
&lt;h3&gt;A KEM is not a Diffie-Hellman&lt;/h3&gt;
&lt;p&gt;The instinct is to treat ML-KEM as &quot;X25519, but bigger.&quot; It is not. X25519 is a Diffie-Hellman exchange: both parties publish a share, and both combine their own secret with the other&apos;s share to arrive at the same value. ML-KEM is a &lt;em&gt;key-encapsulation mechanism&lt;/em&gt;, which has a different message shape entirely.&lt;/p&gt;

A key-establishment primitive with three operations. The receiver generates a keypair and publishes the public (encapsulation) key. A sender runs encapsulate on that public key, producing a fresh shared secret together with a ciphertext; the sender keeps the secret and transmits the ciphertext. The receiver runs decapsulate on the ciphertext to recover the same shared secret. Unlike Diffie-Hellman, only one side draws the secret, and there is no &quot;combine my share with yours&quot; step [@fips203].
&lt;p&gt;Trail of Bits states the distinction directly: in a KEM &quot;one party encapsulates a fresh shared secret to the receiver&apos;s public key, and the receiver decapsulates it,&quot; which is &quot;fundamentally different from Diffie-Hellman&quot; [@tob-2026]. The consequence for real systems is severe. A protocol that assumed the symmetric, two-share choreography of Diffie-Hellman cannot simply swap in ML-KEM; the message flow itself has to be redesigned, not merely re-parameterized.&lt;/p&gt;

sequenceDiagram
    participant A as Alice
    participant B as Bob
    Note over A,B: Diffie-Hellman, both sides contribute a share
    A-&amp;gt;&amp;gt;B: public share A
    B-&amp;gt;&amp;gt;A: public share B
    Note over A,B: each side combines to reach the same secret
    Note over A,B: ML-KEM, only one side encapsulates
    B-&amp;gt;&amp;gt;A: publishes public key
    A-&amp;gt;&amp;gt;B: ciphertext from encapsulate
    Note over A,B: Bob runs decapsulate to recover the same secret
&lt;h3&gt;The 4,096-byte wall&lt;/h3&gt;
&lt;p&gt;The abstract worry becomes concrete at a specific number. Move up one ML-DSA security level, from ML-DSA-65 to ML-DSA-87, and the signature grows from 3,309 bytes to 4,627 bytes [@fips204]. That crosses a boundary that a lot of hardware was built around.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;Trusted Platform Module&lt;/a&gt; speaks a command protocol with a maximum command size that is commonly 4,096 bytes, and the protocol has no chunking -- a command either fits or it cannot be sent. ML-DSA-87&apos;s 4,627-byte signature does not fit; ML-DSA-65&apos;s 3,309-byte signature does. The catch is that 4,096 is a common value, not a universal constant: TPM 2.0 buffer sizes are implementation-defined and queried at runtime, and the TCG reference implementation is tighter still -- &lt;code&gt;MAX_COMMAND_SIZE&lt;/code&gt; is defined as &lt;code&gt;4096-0x80&lt;/code&gt;, or 3,968 bytes, with a 1,024-byte input buffer [@tpm2-spec] [@mstpm-ref]. Either way, one extra security level silently crosses a fixed hardware boundary that nobody sized for kilobyte signatures [@fips204].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can check the arithmetic yourself. The snippet below computes the blow-up ratios and tests ML-DSA-87&apos;s signature against both a 4,096-byte budget and the tighter 3,968-byte reference budget.&lt;/p&gt;
&lt;p&gt;{`
// verified byte counts: FIPS 204 Appendix B and the Trail of Bits size tables
const ed25519 = { key: 32, sig: 64 };
const mldsa65 = { key: 1952, sig: 3309 };
const x25519  = 32;
const mlkem768 = { key: 1184, ct: 1088 };&lt;/p&gt;
&lt;p&gt;console.log(&quot;ML-DSA-65 signature is &quot; + (mldsa65.sig / ed25519.sig).toFixed(0) + &quot;x an Ed25519 signature&quot;);
console.log(&quot;ML-DSA-65 public key is &quot; + (mldsa65.key / ed25519.key).toFixed(0) + &quot;x an Ed25519 key&quot;);
console.log(&quot;ML-KEM-768 public key is &quot; + (mlkem768.key / x25519).toFixed(0) + &quot;x an X25519 key&quot;);&lt;/p&gt;
&lt;p&gt;// the 4,096-byte wall: does one signature fit one TPM command?
const COMMON_TPM = 4096;        // a common maximum command size
const TCG_REF    = 4096 - 0x80; // TCG reference MAX_COMMAND_SIZE = 3968
const mldsa87sig = 4627;        // ML-DSA-87 signature&lt;/p&gt;
&lt;p&gt;const fits = (sig, budget) =&amp;gt; (sig &amp;gt; budget ? &quot;OVERFLOWS&quot; : &quot;fits&quot;);
console.log(&quot;ML-DSA-87 (4627 B) vs 4096 B budget: &quot; + fits(mldsa87sig, COMMON_TPM));
console.log(&quot;ML-DSA-87 (4627 B) vs 3968 B budget: &quot; + fits(mldsa87sig, TCG_REF));
console.log(&quot;ML-DSA-65 (3309 B) vs 3968 B budget: &quot; + fits(3309, TCG_REF));
`}&lt;/p&gt;
&lt;p&gt;Trail of Bits generalizes the warning beyond TPMs: if you maintain a protocol or wire format that hardcodes Ed25519-sized signatures or X25519-sized public keys, &quot;the surrounding fields, length prefixes, and chunking assumptions need to grow with it&quot; [@tob-2026]. Length prefixes sized for a single byte of count, record framing that assumed a signature fit in one packet, database columns declared &lt;code&gt;CHAR(64)&lt;/code&gt; -- each is a small, quiet assumption that the standardized sizes break.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; A primitive is not a protocol. Standardizing ML-KEM and ML-DSA -- even shipping them in a default wheel -- does not migrate a single handshake. The primitive is larger, differently shaped, and hostile to the fixed-width assumptions baked into TLS records, X.509 certificates, SSH packets, and hardware command buffers. Installing it is the easy part; making the protocols around it accept it is the migration [@tob-2026] [@fips204].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the primitive is real, standardized, and about to be a &lt;code&gt;pip install&lt;/code&gt; away -- yet it silently breaks the protocols we would drop it into. Who actually shipped it, and how did they get it into more than a billion downloads a month?&lt;/p&gt;
&lt;h2&gt;7. The Crossing: How the Primitive Reached a Billion Downloads&lt;/h2&gt;
&lt;p&gt;The milestone on May 4, 2026 was not a new algorithm. ML-KEM and ML-DSA had existed in specialist builds of &lt;code&gt;pyca/cryptography&lt;/code&gt; for over a year -- reachable only if you compiled the library against AWS-LC or BoringSSL. What changed in v48.0.0 was distribution: the primitives landed in the default wheel that everyone already installs.&lt;/p&gt;
&lt;p&gt;The changelog says it plainly. Version 48.0.0 added support for &lt;code&gt;mlkem&lt;/code&gt; and &lt;code&gt;mldsa&lt;/code&gt; &quot;when using OpenSSL 3.5.0 or later, in addition to the existing AWS-LC and BoringSSL support,&quot; and concludes: &quot;This means post-quantum algorithms are now available to users of our wheels&quot; [@pyca-changelog]. That last clause is the crossing. Not &quot;available if you rebuild against a special backend,&quot; but available to users of the ordinary wheels, from an ordinary &lt;code&gt;pip install&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;The evolution here is distribution, not mathematics&lt;/h3&gt;

flowchart TD
    S[&quot;FIPS 203 and 204 standard (2024)&quot;] --&amp;gt; B1[&quot;OpenSSL 3.5.0 (2025)&quot;]
    S --&amp;gt; B2[&quot;AWS-LC and BoringSSL (earlier)&quot;]
    B2 -.-&amp;gt;|specialist builds only, 2024 to early 2026| G[&quot;Backend-gated access&quot;]
    B1 --&amp;gt;|default build| W[&quot;pyca cryptography v48 wheel (May 2026)&quot;]
    G -.-&amp;gt; W
    W --&amp;gt; D[&quot;Ansible, Certbot, Airflow, paramiko&quot;]
    D --&amp;gt; P[&quot;The whole Python software supply chain&quot;]
&lt;p&gt;The gate that opened was a backend one. &lt;code&gt;pyca/cryptography&lt;/code&gt; delegates its heavy cryptography to a C library, and until recently only the non-default backends AWS-LC and BoringSSL exposed the post-quantum primitives. OpenSSL 3.5.0, released April 8, 2025, added support for ML-KEM, ML-DSA, and SLH-DSA to the mainstream backend [@openssl-35]. Once the default wheels could be built against an OpenSSL that carried the primitives, the last distribution barrier fell. The sequence is: standard, then backend-gated builds, then default wheels [@pyca-changelog] [@openssl-35].&lt;/p&gt;
&lt;p&gt;There is a security point hiding in that sequence. &lt;code&gt;pyca/cryptography&lt;/code&gt; does not reimplement ML-KEM or ML-DSA in Python; it delegates to the vetted C backend and exposes a thin, cross-tested binding [@tob-2026]. That is why the milestone is a packaging event, not a cryptographic one. It is also why the OpenSSL 3.5.0 floor is not an inconvenience but the whole mechanism: the primitive a developer calls is the same backend implementation that already ships in browsers and servers, reached through new Rust bindings rather than rewritten in a memory-unsafe hurry. Distribution, not reimplementation, is what crossed the last mile.&lt;/p&gt;
&lt;p&gt;Why does one Python library matter this much? Reach. &lt;code&gt;pyca/cryptography&lt;/code&gt; is the foundational cryptography library for the Python community, sitting underneath widely used tools including Ansible, Certbot, Apache Airflow, and paramiko [@tob-2026] [@deps-dev]. Because so much of the Python world depends on it, one release put quantum-resistant primitives within a single &lt;code&gt;pip install&lt;/code&gt; of an enormous body of software.Trail of Bits reports &lt;code&gt;pyca/cryptography&lt;/code&gt; as the eleventh most-downloaded package on PyPI, with about 1.2 billion downloads in the last month [@tob-2026] [@pypistats]. A change to a dependency that widely used is a change to the reachable capability of the entire community above it.&lt;/p&gt;
&lt;h3&gt;Who built it&lt;/h3&gt;
&lt;p&gt;The post-quantum work in &lt;code&gt;pyca/cryptography&lt;/code&gt; was a funded, credited effort, not a weekend patch. Trail of Bits, with support from the Sovereign Tech Agency, wrote the Rust bindings, the cross-binding API and tests, and the AWS-LC backend support; the library&apos;s maintainers, Paul Kehrer and Alex Gaynor, contributed other-backend work and review [@tob-2026] [@sovereign-tech].&lt;/p&gt;

This article deliberately owns the shipping-code and Python axis of the migration. The complementary platform-and-operating-system axis -- how Windows exposes post-quantum primitives through SymCrypt, CNG, Schannel, and the TPM -- is the subject of this blog&apos;s separate post, [*Post-Quantum Cryptography on Windows*](/blog/post-quantum-cryptography-on-windows-the-thirty-year-migrati/). Where that post asks which operating-system primitive ships in which release, this one asks what it means when the whole Python supply chain can `pip install` post-quantum crypto, and what still does not work.
&lt;h3&gt;What the API looks like&lt;/h3&gt;
&lt;p&gt;The signature API mirrors the existing asymmetric surface: generate a key, get its public key, sign, verify. The KEM API is where the shape difference from Section 6 becomes code -- encapsulate returns a &lt;code&gt;(shared_secret, ciphertext)&lt;/code&gt; pair, not a single shared value both sides derive.&lt;/p&gt;
&lt;p&gt;{`&lt;/p&gt;
Signatures (FIPS 204): mirrors the familiar sign / verify shape
&lt;p&gt;from cryptography.hazmat.primitives.asymmetric import mldsa
private_key = mldsa.MLDSA65PrivateKey.generate()
public_key  = private_key.public_key()
signature   = private_key.sign(b&quot;message&quot;)
public_key.verify(signature, b&quot;message&quot;)   # raises InvalidSignature on failure&lt;/p&gt;
Key establishment (FIPS 203): a KEM, not Diffie-Hellman
&lt;p&gt;from cryptography.hazmat.primitives.asymmetric import mlkem
private_key = mlkem.MLKEM768PrivateKey.generate()
public_key  = private_key.public_key()
shared_secret_sender, ciphertext = public_key.encapsulate()
shared_secret_receiver = private_key.decapsulate(ciphertext)
assert shared_secret_sender == shared_secret_receiver
`}&lt;/p&gt;
&lt;p&gt;Two caveats keep this honest. First, v48 ships ML-KEM and ML-DSA but not SLH-DSA; Trail of Bits notes only that they have &quot;started working on it&quot; [@tob-2026]. Second, the OpenSSL 3.5.0 requirement is real -- the primitives are exposed only when the wheel is backed by a version that carries them [@pyca-changelog]. The availability matrix makes the pattern visible: the primitive columns are nearly all &quot;Yes,&quot; while real protocol integration remains sparse.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Artifact&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;ML-KEM&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;ML-DSA&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;SLH-DSA&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;Hybrid KEX default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Crypto backend&lt;/td&gt;
&lt;td&gt;OpenSSL 3.5.0 (2025-04-08)&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;Yes&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;Yes&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;Yes&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;X25519MLKEM768 (TLS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Crypto backend&lt;/td&gt;
&lt;td&gt;AWS-LC / BoringSSL&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;Yes&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;Yes&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;no&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python library&lt;/td&gt;
&lt;td&gt;pyca/cryptography v48.0.0 (2026-05-04)&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;Yes&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;Yes&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;no (WIP)&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;delegates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python library&lt;/td&gt;
&lt;td&gt;pyca/cryptography v49.0.0 (2026-06-12)&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;Yes&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;Yes (plus X.509)&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;no&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;delegates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSH protocol&lt;/td&gt;
&lt;td&gt;OpenSSH 9.9 (2024-09-19)&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;hybrid KEX&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;no&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;no&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;mlkem768x25519-sha256&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Sources: OpenSSL 3.5.0 release notes [@openssl-35]; the pyca changelog [@pyca-changelog]; OpenSSH 9.9 notes [@openssh-99]; the Trail of Bits write-up [@tob-2026].&lt;/p&gt;
&lt;p&gt;The code shipped the primitive in May. The federal government set its deadlines in June. Which one was driving the other?&lt;/p&gt;
&lt;h2&gt;8. The Clock, and Why the Code Got There First&lt;/h2&gt;
&lt;p&gt;Seven weeks after the wheels shipped, the White House put a clock on the wall. Executive Order 14412, &quot;Securing the Nation Against Advanced Cryptographic Attacks,&quot; was signed on June 22, 2026 [@eo14412]. It sets hard federal deadlines: migrate key establishment to post-quantum cryptography by December 31, 2030; migrate digital signatures by December 31, 2031; stand up a NIST migration pilot by December 31, 2027; and have CISA issue cryptographic-bill-of-materials minimum-elements guidance within 270 days [@eo14412].&lt;/p&gt;

timeline
    title Two tracks, and the code point lands first
    section Code track
        OpenSSL 3.5.0 2025-04-08 : PQC in the mainstream backend
        pyca v48.0.0 2026-05-04 : ML-KEM and ML-DSA in default wheels
        pyca v49.0.0 2026-06-12 : X.509 support, current at EO signing
    section Policy track
        NSM-10 and CNSA 2.0 2022 : intent set, but no shipping code
        OMB M-23-02 2022 : agency inventory guidance
        EO 14412 2026-06-22 : deadlines 2027, 2030, 2031
&lt;p&gt;The policy intent is older than the code. The National Security Memorandum 10 (May 2022) [@nsm10], the NSA&apos;s CNSA 2.0 suite (September 2022) [@cnsa2], and OMB memorandum M-23-02 (November 2022) [@omb-m2302] had already told federal systems that a post-quantum migration was coming. What none of them could do was make the primitive installable. That is the asymmetry worth sitting with: the intent was set in 2022, but the shipping code arrived in 2026 -- and it arrived ahead of the deadline that finally gave the intent teeth.&lt;/p&gt;
&lt;h3&gt;The executive order&apos;s own definitions are asymmetric&lt;/h3&gt;
&lt;p&gt;One precise detail here is easy to get wrong, and getting it right sharpens the argument.&lt;/p&gt;
&lt;p&gt;The executive order does not define its two migration targets symmetrically.Section 2 defines &quot;key establishment&quot; with the same meaning it has in FIPS 203 -- which is ML-KEM, a post-quantum standard -- so the key-establishment mandate points straight at the standardized primitive. But it defines &quot;digital signature&quot; with the same meaning it has in FIPS 186-5, the &lt;em&gt;classical&lt;/em&gt; Digital Signature Standard covering RSA, ECDSA, and EdDSA; the post-quantum signature standard, FIPS 204 (ML-DSA), is not named in the definitions [@eo14412-fedreg] [@fips186-5] [@fips204]. The signature mandate is therefore operative, not definitional: Section 4(b) still requires migrating signatures to post-quantum cryptography by 2031, but it reaches that goal through the deadline text rather than by defining a signature as a post-quantum object. Key establishment is defined &lt;em&gt;into&lt;/em&gt; a post-quantum standard; signatures are mandated &lt;em&gt;toward&lt;/em&gt; post-quantum cryptography by a deadline while still being defined against the classical standard [@eo14412-fedreg] [@fips186-5]. That is not a contradiction -- it reflects that key establishment carries the urgent, harvest-now-decrypt-later confidentiality risk, while signatures do not, a distinction Section 9 develops.&lt;/p&gt;
&lt;h3&gt;The pip install beat the policy&lt;/h3&gt;
&lt;p&gt;Stated plainly: the shipping code led, and the policy followed. The full four-date timeline -- and why &quot;the same week&quot; is a misconception -- is in the callout below [@pyca-changelog] [@eo14412].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A tempting version of this story claims the library and the executive order shipped the same week. They did not. Four dated facts settle it: &lt;code&gt;pyca/cryptography&lt;/code&gt; v48.0.0 shipped the primitives on 2026-05-04; v49.0.0 followed on 2026-06-12; Executive Order 14412 was signed on 2026-06-22; and Trail of Bits published its write-up on 2026-06-30. No pyca release landed in the executive order&apos;s week -- the code arrived about seven weeks earlier [@pyca-changelog] [@eo14412] [@tob-2026].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the article&apos;s second turn, paid off. It was not the 2024 standard, and not the 2026 executive order, that put quantum-resistant cryptography in front of ordinary developers. It was two distribution events: standardization fixing the byte counts, and a default-wheel release shipping the code. The second beat the mandate. Federal policy still matters enormously for who &lt;em&gt;must&lt;/em&gt; migrate and by when, and the platform axis of that migration on Windows is its own long story in this blog&apos;s sibling post. But on the shipping-code axis, decree did not lead. Distribution did.&lt;/p&gt;
&lt;p&gt;If the code beat the mandate and the standard is finalized, the migration should be basically done. It is not. Why not?&lt;/p&gt;
&lt;h2&gt;9. What Shipping the Primitive Does Not Solve&lt;/h2&gt;
&lt;p&gt;Here is the uncomfortable truth beneath the celebration: nobody can prove that lattice problems are hard, and the assumption is younger than the one it replaces.&lt;/p&gt;
&lt;p&gt;The security of ML-KEM and ML-DSA rests on two pillars. The first is the worst-case-to-average-case reduction from Ajtai and Regev, which ties breaking a random instance to solving the hardest instance of a lattice problem [@ajtai1996] [@regev-lwe]. The second is the best-known attack: lattice sieving, whose cost is $2^{0.292\beta}$ classically in the relevant blocksize, with no known exponential quantum speedup [@bdgl16]. The entire security argument lives in the gap between &quot;no proof of hardness&quot; and that attack cost. A proven super-polynomial lower bound would settle $P \ne NP$, since these lattice problems sit in NP -- so we are not getting a proof soon. This is the same epistemic position RSA has always occupied, except on a younger assumption.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Integer factoring has been studied since antiquity; structured-lattice hardness in its deployed form dates to roughly 2012. That youth, plus the open &quot;is the structure free?&quot; question from Section 3, plus the fact that SIKE and Rainbow both fell during standardization, is exactly why the portfolio keeps SLH-DSA -- a signature whose security rests on hash functions alone and would survive even if lattice cryptanalysis advanced dramatically [@fips205] [@peikert-2015] [@sike-break] [@rainbow-break].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Two threat horizons, not one&lt;/h3&gt;
&lt;p&gt;A subtle but important point: the quantum threat does not arrive on the same schedule for confidentiality and for authentication.&lt;/p&gt;
&lt;p&gt;Harvest-now-decrypt-later is a &lt;em&gt;confidentiality&lt;/em&gt; horizon. An adversary can record an encrypted session today and decrypt it whenever a quantum computer arrives, so key establishment must be quantum-resistant now for any secret with a long shelf life. Signature forgery is an &lt;em&gt;authentication&lt;/em&gt; threat with no retroactive version: you cannot forge yesterday&apos;s signature tomorrow, because a signature only needs to resist forgery until the moment it is verified and trusted [@eo14412]. That is why the order&apos;s key-establishment deadline (2030) falls a year before its signature deadline (2031): the confidentiality clock is the more urgent one [@eo14412].&lt;/p&gt;
&lt;h3&gt;Why the answer is a portfolio&lt;/h3&gt;
&lt;p&gt;No single scheme is simultaneously tiny, tightly reduced to a decades-old assumption, and trivially side-channel-safe. That ideal primitive does not exist, which is precisely why the standard is a portfolio rather than a single winner.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;ML-KEM (203)&lt;/th&gt;
&lt;th&gt;ML-DSA (204)&lt;/th&gt;
&lt;th&gt;SLH-DSA (205)&lt;/th&gt;
&lt;th&gt;FN-DSA/Falcon (206)&lt;/th&gt;
&lt;th&gt;Classic McEliece&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Key establishment&lt;/td&gt;
&lt;td&gt;Signature&lt;/td&gt;
&lt;td&gt;Signature&lt;/td&gt;
&lt;td&gt;Signature&lt;/td&gt;
&lt;td&gt;Key establishment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard problem&lt;/td&gt;
&lt;td&gt;Module-LWE&lt;/td&gt;
&lt;td&gt;Module-LWE&lt;/td&gt;
&lt;td&gt;Hash preimage&lt;/td&gt;
&lt;td&gt;NTRU lattice&lt;/td&gt;
&lt;td&gt;Goppa decoding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public key&lt;/td&gt;
&lt;td&gt;1,184 B&lt;/td&gt;
&lt;td&gt;1,952 B&lt;/td&gt;
&lt;td&gt;32 to 64 B&lt;/td&gt;
&lt;td&gt;compact&lt;/td&gt;
&lt;td&gt;261 KB to 1.3 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;1,088 B ct&lt;/td&gt;
&lt;td&gt;3,309 B sig&lt;/td&gt;
&lt;td&gt;many KB sig&lt;/td&gt;
&lt;td&gt;small sig&lt;/td&gt;
&lt;td&gt;128 to 240 B ct&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assumption age&lt;/td&gt;
&lt;td&gt;~2012&lt;/td&gt;
&lt;td&gt;~2012&lt;/td&gt;
&lt;td&gt;decades&lt;/td&gt;
&lt;td&gt;~1996&lt;/td&gt;
&lt;td&gt;45+ years&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;In pyca v48&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no (pending)&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Sources: FIPS 203, 204, and 205 [@fips203] [@fips204] [@fips205]; the CRYSTALS pages for the lattice schemes [@kyber] [@dilithium]; Classic McEliece for the code-based sizes [@classic-mceliece]; and the pyca changelog for what v48 includes [@pyca-changelog].&lt;/p&gt;
&lt;p&gt;Two more standing hedges belong here, because they shape the practical advice in Section 11.&lt;/p&gt;

A key-establishment construction that runs a classical exchange (such as X25519) and a post-quantum KEM (such as ML-KEM-768) together and combines both shared secrets, so the session stays secure as long as *either* component is unbroken. Hybrids protect against both a surprise lattice break and an implementation bug in the new code, at the cost of sending both sets of bytes [@openssl-35].

The property of a system that can swap cryptographic algorithms without re-architecting the protocols and formats around them. Crypto-agility is the standing hedge against the next migration: build the seams now so that replacing a broken primitive later is a configuration change, not another thirty-year project.
&lt;p&gt;If the math is settled enough to standardize and ship, and the limits are understood, where is the actual remaining work?&lt;/p&gt;
&lt;h2&gt;10. The Protocols Are the Remaining Work&lt;/h2&gt;
&lt;p&gt;Here is the thesis in one line: the primitive is a &lt;code&gt;pip install&lt;/code&gt; away, and it is still nearly useless to most developers. That is not a paradox. It is the definition of the remaining work.&lt;/p&gt;
&lt;p&gt;The defining open problem is protocol integration. TLS, SSH, X.509 and the public-key infrastructure built on it, and package signing all have to be redesigned around KEM-shaped, kilobyte-scale objects without breaking the length fields, buffers, and packet-size assumptions surveyed in Section 6 [@tob-2026]. Trail of Bits is blunt about what that means for the average engineer.&lt;/p&gt;

You&apos;re unlikely to use PQ algorithms directly in tools like Certbot or Ansible until common protocols add support. -- Trail of Bits [@tob-2026]
&lt;p&gt;The good news is that the hardest-to-defer half is already moving.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Hybrid key establishment -- the part with the harvest-now-decrypt-later urgency -- is solved and deployed. OpenSSH 9.9 (September 19, 2024) made &lt;code&gt;mlkem768x25519-sha256&lt;/code&gt; available by default [@openssh-99], and OpenSSL 3.5.0 made X25519MLKEM768 its default TLS keyshare [@openssl-35]. Authentication is the laggard: post-quantum signatures inside protocols and certificate chains trail behind, and even in &lt;code&gt;pyca/cryptography&lt;/code&gt;, X.509 certificate signing with ML-DSA only arrived in v49.0.0 on June 12, 2026 [@pyca-changelog].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The portfolio is also still incomplete in the shipping code. SLH-DSA, the conservative hash-based backstop, is not yet in &lt;code&gt;pyca/cryptography&lt;/code&gt;; the maintainers have only started on it [@tob-2026]. Falcon, standardized as FN-DSA, remains pending as FIPS 206 in 2026, held up in part because its floating-point Gaussian sampler is hard to implement safely at standardization quality [@tob-2026] [@nist-2022]. So even a developer who wants the full toolbox cannot yet &lt;code&gt;pip install&lt;/code&gt; all of it.&lt;/p&gt;
&lt;p&gt;And some problems have nothing to do with new code. Long-lived trust anchors -- root certificates and firmware keys with lifetimes measured in decades -- must migrate while still interoperating with everything already deployed, and they run straight into the fixed-size hardware limits from Section 6, where an extra security level can overrun a command buffer that has no chunking [@tpm2-spec]. The deeper governance problem is crypto-agility: building systems so that the &lt;em&gt;next&lt;/em&gt; forced migration -- prompted by, say, a lattice break of the kind that felled SIKE -- does not take another thirty years [@sike-break].&lt;/p&gt;
&lt;p&gt;None of this is theoretical anymore. So what should a working engineer actually do on Monday?&lt;/p&gt;
&lt;h2&gt;11. Using It Today&lt;/h2&gt;
&lt;p&gt;Concrete and actionable: the one command, the one gotcha, and the three decisions.&lt;/p&gt;
&lt;p&gt;The command is &lt;code&gt;pip install &quot;cryptography&amp;gt;=48&quot;&lt;/code&gt;. The gotcha is that the version pin alone does not guarantee you get anything post-quantum.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; First, &lt;code&gt;pip install &quot;cryptography&amp;gt;=48&quot;&lt;/code&gt; does not by itself guarantee post-quantum support: ML-KEM and ML-DSA appear only when the wheel is backed by OpenSSL 3.5.0 or later, AWS-LC, or BoringSSL, and the changelog cautions that functionality is not guaranteed across every OpenSSL build [@pyca-changelog] [@openssl-35]. Second, unless you author the protocol or library yourself, do not hand-roll a wire format around a raw KEM -- the size and shape traps from Section 6 are exactly what vetted protocol work exists to absorb [@tob-2026].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The API is small enough to hold in your head.A version pin alone is not enough: as the callout above warns, the primitives appear only when the wheel is built against a supported backend [@pyca-changelog]. The &lt;code&gt;mldsa&lt;/code&gt; module gives you generate, public_key, sign, and verify -- the familiar signature shape. The &lt;code&gt;mlkem&lt;/code&gt; module gives you encapsulate, which returns a &lt;code&gt;(shared_secret, ciphertext)&lt;/code&gt; pair, and decapsulate, which takes a ciphertext and returns the shared secret. There is deliberately no separate share-combining step: that is the KEM shape from Section 6, not a Diffie-Hellman exchange [@tob-2026].&lt;/p&gt;

Import the module and generate a key; a backend without support raises instead of silently degrading. Running `mlkem.MLKEM768PrivateKey.generate()` after `from cryptography.hazmat.primitives.asymmetric import mlkem` should complete without error. A clean run means your wheel is backed by a build that actually carries ML-KEM -- one of the supported backends named in the warning above -- while an exception means it is not [@pyca-changelog].
&lt;p&gt;Three decisions follow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which parameter set?&lt;/strong&gt; Default to ML-KEM-768 and ML-DSA-65 -- NIST Category 3, roughly AES-192, and more than 128 bits of security under conservative analysis [@kyber] [@dilithium]. Go higher only for data whose confidentiality must outlive decades, and when you do, watch the 4,096-byte wall from Section 6. Prefer ML-DSA over SLH-DSA as your default signature, and do not wait for Falcon in Python -- it is not standardized yet. Performance rarely decides this: even on a constrained ARM Cortex-M4, ML-KEM-768 runs in around a million cycles per operation, and on modern hardware the cost is imperceptible for normal use [@pqm4] [@tob-2026].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pure or hybrid?&lt;/strong&gt; Prefer hybrid where a protocol offers it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Use hybrid key establishment (X25519MLKEM768) wherever a protocol supports it -- it is already the TLS and SSH default and keeps you safe if either half is broken [@openssl-35] [@openssh-99] [@kyber]. And inventory before you install: build a cryptographic bill of materials, then migrate harvest-now-decrypt-later confidentiality assets first, since those carry the only clock that is already running [@eo14412].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where do you start?&lt;/strong&gt; Not with code -- with an inventory.&lt;/p&gt;

A machine-readable inventory of the cryptography a system uses: which algorithms, key sizes, protocols, and libraries appear where. A CBOM is the migration&apos;s first practical step -- you cannot replace what you cannot find -- and Executive Order 14412 directs CISA to publish minimum-elements guidance for exactly this kind of inventory [@eo14412].
&lt;p&gt;You can install the primitive in five seconds; you should deploy it with a plan. The last mile after the &lt;code&gt;pip install&lt;/code&gt; is yours.&lt;/p&gt;
&lt;h2&gt;12. Frequently Asked Questions&lt;/h2&gt;


No. It gives you primitives, not a protocol, and only when the wheel is backed by OpenSSL 3.5.0 or later, AWS-LC, or BoringSSL. Being able to call ML-KEM and ML-DSA is not the same as having a quantum-resistant TLS connection or certificate chain, which depend on protocol integration that is still in progress [@pyca-changelog] [@tob-2026].


No. ML-KEM is a key-encapsulation mechanism, not a Diffie-Hellman exchange: one side encapsulates a fresh secret to the other&apos;s public key rather than both sides combining shares. The message shape differs, and the objects are roughly 34 to 37 times larger, so protocols must be redesigned rather than merely re-parameterized [@tob-2026] [@fips203].


No. Earlier versions of the library could already expose ML-KEM and ML-DSA when built against AWS-LC or BoringSSL. What v48.0.0 changed was distribution: it put the primitives in the default OpenSSL-backed wheels, so a plain `pip install` reaches them [@pyca-changelog].


Not in the near term. Harvest-now-decrypt-later means an adversary can record today&apos;s encrypted traffic and decrypt it once a quantum computer exists, so the pressing driver is the confidentiality of data with a long shelf life, not the arrival date of the hardware [@tob-2024] [@eo14412].


Harvest-now-decrypt-later is a confidentiality horizon: recorded ciphertext can be broken retroactively, so key establishment is urgent now. Signature forgery is an authentication threat that only bites once a quantum computer exists, because you cannot forge a signature that was already verified and trusted in the past. That is why the federal key-establishment deadline precedes the signature deadline [@eo14412].


No. `pyca/cryptography` v48.0.0 shipped ML-KEM and ML-DSA on May 4, 2026; Executive Order 14412 was signed on June 22, 2026, about seven weeks later; and v49.0.0 (June 12) was the release current at the signing. No pyca release landed in the order&apos;s week [@pyca-changelog] [@eo14412].


No. Post-quantum cryptography is classical software -- ordinary algorithms on ordinary computers -- designed to resist quantum attack, which is exactly what FIPS 203 and 204 standardize [@fips203] [@fips204]. Quantum key distribution is a hardware and physics approach that transmits keys over quantum channels; it is a different technology often confused with PQC.

&lt;h2&gt;Conclusion: The Primitive Shipped, the Protocols Remain&lt;/h2&gt;
&lt;p&gt;A threat named in 1994 set a thirty-year relay in motion. Ajtai and Regev found lattice math that plausibly survives Shor&apos;s algorithm; Ring-LWE and Module-LWE made that math small enough to ship; an open competition from 2016 to 2022 chose a deliberately diverse portfolio and watched two serious candidates break along the way; and in August 2024, NIST turned the winners into standards with fixed byte counts and validated test vectors [@ajtai1996] [@regev-lwe] [@module-lwe] [@nist-2022] [@fips203] [@fips204].&lt;/p&gt;
&lt;p&gt;Then, on May 4, 2026, the primitive quietly crossed its last visible milestone -- not by decree, but by distribution. &lt;code&gt;pyca/cryptography&lt;/code&gt; v48.0.0 put ML-KEM and ML-DSA in the default wheels that a billion-download-a-month slice of the Python world already installs, roughly seven weeks before Executive Order 14412 set the federal deadlines [@pyca-changelog] [@eo14412]. The primitive shipped; the policy set the clock; and the protocols are the work that remains [@pyca-changelog] [@eo14412] [@tob-2026].&lt;/p&gt;
&lt;p&gt;That last clause is the whole point. ML-KEM and ML-DSA are larger, differently shaped, and hostile to the fixed-width assumptions that TLS, SSH, X.509, and hardware buffers were quietly built around. Installing the primitive took thirty years and now takes five seconds. Making the protocols accept it -- redesigning wire formats around KEM-shaped, kilobyte-scale objects without breaking the length fields and command budgets that assumed 32-byte keys and 64-byte signatures -- is the migration that is actually left. A primitive is not a protocol, and the last mile after the &lt;code&gt;pip install&lt;/code&gt; is the one we are still walking.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;pqc-ships-in-a-pip-install&quot; keyTerms={[
  { term: &quot;Post-quantum cryptography (PQC)&quot;, definition: &quot;Classical algorithms, run on ordinary computers, designed to resist attack by a large-scale quantum computer.&quot; },
  { term: &quot;Shor&apos;s algorithm&quot;, definition: &quot;A 1994 quantum algorithm that factors integers and solves discrete logarithms in polynomial time, breaking RSA, Diffie-Hellman, and elliptic-curve cryptography.&quot; },
  { term: &quot;Harvest-now, decrypt-later (HNDL)&quot;, definition: &quot;Recording encrypted data today to decrypt it later once quantum computers exist, which makes the threat present-day for long-lived secrets.&quot; },
  { term: &quot;Learning With Errors (LWE)&quot;, definition: &quot;Recovering a secret from noisy linear equations; believed hard even for quantum computers, and the basis of ML-KEM and ML-DSA.&quot; },
  { term: &quot;Module-LWE&quot;, definition: &quot;A structured, tunable version of LWE over modules that yields kilobyte-scale keys; the hard problem under CRYSTALS-Kyber and Dilithium.&quot; },
  { term: &quot;ML-KEM (FIPS 203)&quot;, definition: &quot;The standardized key-encapsulation mechanism for post-quantum key establishment, derived from CRYSTALS-Kyber.&quot; },
  { term: &quot;ML-DSA (FIPS 204)&quot;, definition: &quot;The standardized general-purpose post-quantum signature, derived from CRYSTALS-Dilithium, using Fiat-Shamir with aborts and uniform sampling.&quot; },
  { term: &quot;Key Encapsulation Mechanism (KEM)&quot;, definition: &quot;A key-establishment primitive where one side encapsulates a fresh secret to the other&apos;s public key and the other decapsulates it; not a Diffie-Hellman exchange.&quot; }
]} questions={[
  { q: &quot;Why does the quantum threat target public-key cryptography but only mildly affect symmetric ciphers?&quot;, a: &quot;Shor&apos;s algorithm breaks the factoring and discrete-log assumptions behind public-key schemes outright, while Grover gives only a quadratic speedup against symmetric keys, so a modest key-size bump restores the margin.&quot; },
  { q: &quot;Why is ML-KEM not a drop-in replacement for X25519?&quot;, a: &quot;A KEM has a different message shape than Diffie-Hellman (encapsulate and decapsulate rather than combining shares), and its outputs are roughly 34 to 37 times larger, so protocols must be redesigned, not just re-parameterized.&quot; },
  { q: &quot;What does the 4,096-byte wall illustrate, and why is 4,096 not universal?&quot;, a: &quot;ML-DSA-87&apos;s 4,627-byte signature overruns a common TPM command budget that has no chunking, while ML-DSA-65 fits; the budget is implementation-defined, and the TCG reference build is tighter at 3,968 bytes.&quot; },
  { q: &quot;In what concrete sense did the pip install beat the policy?&quot;, a: &quot;pyca/cryptography v48.0.0 shipped ML-KEM and ML-DSA on May 4, 2026, about seven weeks before Executive Order 14412 set the federal deadlines on June 22, 2026.&quot; },
  { q: &quot;Why does the standardized portfolio keep a hash-only backstop?&quot;, a: &quot;Lattice hardness is unproven and younger than factoring, the ring and module structure is a conjecture rather than a theorem, and SIKE and Rainbow both broke during standardization, so SLH-DSA is kept as a hedge that would survive a lattice break.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>post-quantum-cryptography</category><category>ml-kem</category><category>ml-dsa</category><category>lattice-cryptography</category><category>nist-standards</category><category>python</category><category>crypto-migration</category><author>noreply@paragmali.com (Parag Mali)</author></item></channel></rss>