<?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: aes-gcm</title><description>Posts tagged aes-gcm.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 19 Jul 2026 05:08:41 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/aes-gcm/rss.xml" rel="self" type="application/rss+xml"/><item><title>How AES Breaks in Real Life: The Attacks That Never Touched the Cipher</title><link>https://paragmali.com/blog/how-aes-breaks-in-real-life-the-attacks-that-never-touched-t/</link><guid isPermaLink="true">https://paragmali.com/blog/how-aes-breaks-in-real-life-the-attacks-that-never-touched-t/</guid><description>AES-the-cipher has never been broken in the field -- its deployments have. KRACK, repeated GCM nonces, and cache timing broke the wrapper, never the block.</description><pubDate>Fri, 17 Jul 2026 00:00:00 GMT</pubDate><content:encoded>
**AES-the-cipher has never been broken in the field. Your AES traffic was decrypted anyway.** The best publicly known attack on the full cipher costs about $2^{126}$ operations for AES-128 -- its own authors say it does &quot;not threaten the practical use of AES in any way&quot; [@biclique-2011]. Yet real Wi-Fi sessions were decrypted, real HTTPS connections were forged, and real AES keys were lifted out of running servers. None of it touched the 128-bit block math. AES is a *permutation*, not a cryptosystem: to protect a message you wrap it in an *implementation*, a *mode*, and a *protocol*, and it was those three wrappers that failed -- a T-table lookup leaked the key through cache timing [@bernstein-2005; @osvik-shamir-tromer-2006]; 184 live HTTPS servers repeated an AES-GCM nonce and weaponized Joux&apos;s 2006 forbidden attack into forgery [@nonce-disrespecting-2016; @joux-2006]; and KRACK&apos;s replayed handshake rewound the AES-CCMP nonce and reused a keystream [@krack-2017]. Every fix changed *how AES is used*, never AES.
&lt;h2&gt;1. AES Is Unbroken. Your AES Traffic Was Decrypted Anyway.&lt;/h2&gt;
&lt;p&gt;The best publicly known attack on the full AES cipher costs roughly $2^{126}$ operations for AES-128 -- a number so far beyond feasible that its own discoverers wrote it does &quot;not threaten the practical use of AES in any way&quot; [@biclique-2011]. To put $2^{126}$ in scale: if every one of the billions of computers on Earth checked a billion keys a second, you would still wait longer than the age of the universe, many times over. By any honest measure, the cipher stands.&lt;/p&gt;
&lt;p&gt;And yet, in the same decade that number was published, attackers decrypted live Wi-Fi sessions, forged authenticated HTTPS connections, and lifted AES keys straight out of running servers -- none of them going anywhere near that $2^{126}$ wall. How does a cipher nobody can break keep producing decrypted traffic and stolen keys?&lt;/p&gt;
&lt;p&gt;The resolution is the thesis of this article, and you can hold it right now: &lt;strong&gt;none of these breaks touched the 128-bit block math.&lt;/strong&gt; AES is a keyed &lt;em&gt;permutation&lt;/em&gt; -- a function that scrambles one 16-byte block into another -- and nothing more. It is not a cryptosystem. To protect a real message you wrap that permutation in three things: an &lt;em&gt;implementation&lt;/em&gt; that computes it on real silicon, a &lt;em&gt;mode&lt;/em&gt; that chains it across a message, and a &lt;em&gt;protocol&lt;/em&gt; that establishes keys and drives the mode. Each wrapper is a new, independent way to fail. And it was the wrappers, every time, that failed.&lt;/p&gt;
&lt;p&gt;That gives you a diagnostic sentence to carry through the rest of this piece. When your encrypted traffic falls, the question is never &quot;was AES broken?&quot; It is: &lt;em&gt;which layer around AES failed -- the implementation, the mode, or the protocol?&lt;/em&gt; By the end you will be able to drop KRACK, the GCM nonce scandal, and tomorrow&apos;s not-yet-published incident into that one question on sight.&lt;/p&gt;

To break AES in the field, you never touch AES. The table lookup leaks, the nonce repeats, the handshake rewinds -- and the 128-bit block math never moves.
&lt;p&gt;This is Part 1 of &lt;em&gt;How It Breaks in Real Life&lt;/em&gt;, a series with a single recurring claim: the primitive&apos;s mathematics almost never caused the break; the deployment did -- the nonce, the padding, key generation, a downgrade, a validation bug, or a deprecated-but-still-live algorithm. AES is the cleanest case, which is why it goes first. Its companion piece, &lt;em&gt;How AES Would Break&lt;/em&gt;, asks what it would take to move the block itself: the key schedule, related-key cryptanalysis, the slow erosion of the security margin. That is the &lt;em&gt;would-break-in-theory&lt;/em&gt; story. This is the &lt;em&gt;did-break-in-the-field&lt;/em&gt; one.&lt;/p&gt;
&lt;p&gt;If the cipher was intact and the block math never moved, then everything that broke was built &lt;em&gt;around&lt;/em&gt; it. To see how &quot;unbroken cipher&quot; and &quot;decrypted traffic&quot; can both be true, you have to go back to what AES actually is -- and, more to the point, what it is not.&lt;/p&gt;
&lt;h2&gt;2. Why a Cipher Is Not a Cryptosystem&lt;/h2&gt;
&lt;p&gt;In October 2000, after a three-year open competition in which the world&apos;s cryptographers were &lt;em&gt;invited to attack&lt;/em&gt; the candidates, NIST selected Joan Daemen and Vincent Rijmen&apos;s Rijndael as the Advanced Encryption Standard [@nist-press-2000]. The choice followed a public evaluation of fifteen submissions narrowed to five finalists, judged on security, performance, and efficiency from servers to smart cards [@nist-aes-dev; @nist-jres-r1-1999; @nist-jres-r2-2001]. That adversarial process is why the core math has held for over two decades -- and why, when things break in the field, the fault lies elsewhere. Winning the competition made Rijndael a &lt;em&gt;cipher&lt;/em&gt;, not a cryptosystem.&lt;/p&gt;
&lt;p&gt;Here is the distinction the whole article turns on. AES, standardized as FIPS 197 in 2001 and editorially refreshed in 2023 with &lt;em&gt;no technical change&lt;/em&gt; to the algorithm, is a keyed &lt;strong&gt;128-bit permutation&lt;/strong&gt; [@fips-197]. It maps one 128-bit block to one 128-bit block under a 128-, 192-, or 256-bit key, and that is &lt;em&gt;all&lt;/em&gt; it does.AES applies 10, 12, or 14 rounds for the 128-, 192-, and 256-bit keys. The round function is identical across all three; key size changes only the round count and the key schedule that feeds it [@fips-197]. It has no notion of a message longer than 16 bytes, no integrity, no session or conversation. Feed it the same block and key twice and you get the same output twice. On its own it cannot safely encrypt a paragraph, let alone a Wi-Fi session.&lt;/p&gt;

A **block cipher** is a keyed permutation on fixed-size blocks -- AES maps one 16-byte block to another under a key. A **mode of operation** (CTR, CCM, GCM, and others) is the wrapper that chains that permutation across an arbitrary-length message and, in authenticated modes, adds integrity. The block cipher is the engine; the mode is the car. You do not drive an engine.
&lt;p&gt;To turn that engine into something that protects real data, you add three wrappers, and each one is a new, independent failure surface:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an &lt;strong&gt;implementation&lt;/strong&gt; that computes the permutation on a real CPU, and may leak through timing or cache behavior;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/the-ciphertext-was-unbreakable-the-attacker-rewrote-it-anyw/&quot; rel=&quot;noopener&quot;&gt;mode of operation&lt;/a&gt;&lt;/strong&gt; that chains the permutation across a whole message and, in AEAD modes, adds integrity -- and imposes a contract on how you feed it nonces;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;protocol&lt;/strong&gt; that establishes keys and drives the mode, and can mismanage them.&lt;/li&gt;
&lt;/ul&gt;

flowchart TD
    B[&quot;AES 128-bit permutation -- never broken in the field&quot;]
    I[&quot;Implementation layer -- computes the block in code or silicon&quot;]
    M[&quot;Mode layer -- chains the block, adds integrity, imposes a nonce contract&quot;]
    P[&quot;Protocol layer -- establishes keys and drives the mode&quot;]
    B --&amp;gt; I --&amp;gt; M --&amp;gt; P
    I -. break .-&amp;gt; AtkI[&quot;Cache timing leaks the key&quot;]
    M -. break .-&amp;gt; AtkM[&quot;A repeated nonce reuses a keystream&quot;]
    P -. break .-&amp;gt; AtkP[&quot;A replayed handshake rewinds the nonce&quot;]
&lt;p&gt;This map is the lens for everything that follows. The block sits at the center, untouched. The implementation wraps it, the mode wraps that, the protocol wraps that -- and the three field breaks in this article land on the three outer rings, in order, working outward from the silicon.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; AES has a &lt;strong&gt;128-bit block size&lt;/strong&gt; for all three variants; only the &lt;em&gt;key&lt;/em&gt; is 128, 192, or 256 bits. When this article says &quot;the 128-bit block math never moved,&quot; it means the block permutation, not the key. Hold onto a foreshadow: key size will turn out to be irrelevant to every break here. Against nonce reuse and a reinstalled handshake key, AES-256 fails exactly as fast as AES-128; against cache timing it is just as vulnerable, though a longer key takes proportionally more leakage to extract.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One more piece of honesty before we watch the wrappers fail. The series this article opens says the primitive&apos;s math &lt;em&gt;almost&lt;/em&gt; never causes the break -- &quot;almost,&quot; not &quot;never&quot; -- and the hedge is load-bearing.Every break in this article is independent of key size. That is not a rhetorical flourish; it is a literal property of cache timing, nonce reuse, and handshake replay, none of which involve guessing key bits.&lt;/p&gt;

Some deployed primitives genuinely fell as *math*, not deployment. DES died to brute force because its 56-bit key was too short, which is *why* NIST ran the AES competition in the first place. RC4&apos;s keystream biases were turned into real plaintext recovery against TLS [@alfardan-2013]. MD5 and SHA-1 fell to collision attacks -- the SHAttered project produced the first SHA-1 collision at roughly $2^{63}$ hash computations [@shattered-2017]. Those are real breaks of the primitive&apos;s mathematics. AES is simply not one of them, which is what makes its deployment-versus-primitive split so clean. Never harden &quot;almost never&quot; into &quot;the math never breaks.&quot;
&lt;p&gt;Three wrappers, three contracts, three ways to fail -- none of them the cipher. Before watching each one break in the field, you need to see the contracts up close: what a mode actually promises, what a nonce is, and why the humble table lookup is a loaded gun.&lt;/p&gt;
&lt;h2&gt;3. The Layers Around the Block, and the Contracts They Impose&lt;/h2&gt;
&lt;p&gt;Every one of the three field breaks is the violation of a single, specific promise. If you see the promise clearly now, the break will look obvious later. So here are all three contracts, one per layer, in order.&lt;/p&gt;
&lt;h3&gt;The implementation contract: a lookup should not leak what it looked up&lt;/h3&gt;
&lt;p&gt;Computing AES the naive way -- byte by byte through its S-box and its field multiplications -- is slow in software. So fast implementations fold an entire round into precomputed lookup tables. Four tables of about 1 KB each, conventionally called &lt;code&gt;T0&lt;/code&gt; through &lt;code&gt;T3&lt;/code&gt;, turn each output column of a round into &lt;code&gt;T0[a] XOR T1[b] XOR T2[c] XOR T3[d]&lt;/code&gt;: four reads and three XORs, so a full round is four of those -- sixteen reads in all [@bernstein-2005].&lt;/p&gt;

A set of precomputed lookup tables (typically four tables of 256 four-byte entries, about 4 KB total) that fold AES&apos;s SubBytes, ShiftRows, and MixColumns steps into a handful of table reads per round. It is purely a speed optimization. The block permutation it computes is identical to the slow version -- but *how* it computes it now depends on secret-derived indices.
&lt;p&gt;The hidden assumption is that a table read takes the same time regardless of which entry you read. On a real CPU with a cache hierarchy, that is &lt;em&gt;false&lt;/em&gt;: the first access to a memory line is slow, a cached line is fast, and an attacker can measure the difference. And the indices &lt;code&gt;a, b, c, d&lt;/code&gt; are secret -- state bytes derived from the key XORed with the plaintext. So which table lines get touched, and therefore the timing, depends on the key. The implementation&apos;s contract is that a data-dependent lookup must not leak the data. The cache breaks it for free.&lt;/p&gt;
&lt;h3&gt;The mode contract: never repeat a (key, nonce) pair&lt;/h3&gt;
&lt;p&gt;A mode turns the one-block permutation into something that encrypts messages and detects tampering. Modern modes aim for AEAD.&lt;/p&gt;

Authenticated Encryption with Associated Data: a mode that provides confidentiality *and* integrity at once. It encrypts the plaintext and produces an authentication tag over both the ciphertext and some associated data (headers, sequence numbers) that is authenticated but not encrypted. GCM and CCM are AEAD modes; if the tag does not verify, the receiver rejects the message.
&lt;p&gt;The workhorse construction is counter mode. AES is run on a counter to produce a &lt;em&gt;keystream&lt;/em&gt;, and the keystream is XORed with the plaintext: keystream block $k_i = \mathrm{AES}_K(\text{nonce} \parallel i)$, and ciphertext $C_i = P_i \oplus k_i$. This is elegant and fast and fully parallel. It also carries one absolute obligation.&lt;/p&gt;

A **nonce** is a &quot;number used once.&quot; In counter-based modes the pair (key, nonce) must be **unique for every encryption under that key**. The nonce need not be secret or random -- a counter is fine -- but it must never repeat. This is the single most load-bearing rule in practical symmetric cryptography, and it is the rule every mode-and-protocol break in this article violates.
&lt;p&gt;Watch what happens if you break it. If two messages are encrypted under the same key &lt;em&gt;and the same nonce&lt;/em&gt;, they get the &lt;em&gt;same&lt;/em&gt; keystream. XOR the two ciphertexts and the keystream cancels:&lt;/p&gt;
&lt;p&gt;$$C_1 \oplus C_2 = (P_1 \oplus k) \oplus (P_2 \oplus k) = P_1 \oplus P_2$$&lt;/p&gt;
&lt;p&gt;The key never appears. The attacker who captures two same-nonce ciphertexts learns the XOR of the two plaintexts, and if they know or can guess one, they get the other -- with the cipher fully intact.&lt;/p&gt;

The failure that follows from a repeated (key, nonce) in a counter-based mode: identical keystream for two messages, so $C_1 \oplus C_2 = P_1 \oplus P_2$. The plaintext XOR leaks and the key is never touched. This one mechanic drives *both* the GCM break and the WPA2/CCMP break later in this article.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; A block cipher in a counter-based mode is a keystream generator. Feed it the same (key, nonce) twice and you get the same keystream, so $C_1 \oplus C_2 = P_1 \oplus P_2$ -- the plaintext XOR leaks and the key is never touched. The nonce-uniqueness contract is the one promise that stops this. Break it and the strongest cipher in the world protects nothing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can watch the cancellation happen. Nothing below is real AES -- the toy keystream stands in for AES-CTR output -- but the XOR algebra is exactly the algebra of the real break.&lt;/p&gt;
&lt;p&gt;{`
// Same (key, nonce) =&amp;gt; same keystream for BOTH messages. That is the whole bug.
const keystream = [0x9e, 0x37, 0xb1, 0xa4, 0x55, 0x0c, 0xd2, 0x6f];&lt;/p&gt;
&lt;p&gt;function xorBytes(a, b) {
  const out = [];
  for (let i = 0; i &amp;lt; a.length; i++) out.push(a[i] ^ b[i]);
  return out;
}
const toBytes = (s) =&amp;gt; Array.from(s).map((c) =&amp;gt; c.charCodeAt(0));&lt;/p&gt;
&lt;p&gt;const p1 = toBytes(&quot;ATTACK 0&quot;);
const p2 = toBytes(&quot;defend!!&quot;);&lt;/p&gt;
&lt;p&gt;const c1 = xorBytes(p1, keystream);   // what the attacker sees
const c2 = xorBytes(p2, keystream);   // what the attacker sees&lt;/p&gt;
&lt;p&gt;const leaked = xorBytes(c1, c2);      // C1 ^ C2, computed with NO key
const truth  = xorBytes(p1, p2);      // P1 ^ P2, the secret relationship&lt;/p&gt;
&lt;p&gt;console.log(&quot;C1 ^ C2 =&quot;, leaked.join(&quot;,&quot;));
console.log(&quot;P1 ^ P2 =&quot;, truth.join(&quot;,&quot;));
console.log(&quot;keystream cancelled?&quot;, JSON.stringify(leaked) === JSON.stringify(truth));
// Know one plaintext, recover the other. The cipher stayed perfectly strong.
`}&lt;/p&gt;
&lt;p&gt;GCM adds one more thing to worry about. Its integrity tag is built from a secret authentication subkey derived from the key alone, and &lt;a href=&quot;https://paragmali.com/blog/one-number-used-twice-how-a-repeated-nonce-hands-over-your-p/&quot; rel=&quot;noopener&quot;&gt;a repeated nonce&lt;/a&gt; exposes that subkey to attack as well -- which is how confidentiality loss becomes &lt;em&gt;forgery&lt;/em&gt;. We will pull that thread in the next section.&lt;/p&gt;
&lt;p&gt;Even with perfectly unique nonces, GCM has a budget. With random 96-bit nonces, NIST caps a single key at fewer than $2^{32}$ invocations, because random 96-bit values begin colliding around the birthday bound [@sp-800-38d]. Uniqueness is not just a coding rule; it is a counting problem.&lt;/p&gt;

When AES-GCM came to TLS 1.2, RFC 5288 let the implementation choose part of each record&apos;s nonce -- an &quot;explicit nonce&quot; -- and its own security-considerations text carried a &quot;Counter Reuse&quot; warning that a repeated counter is catastrophic [@rfc-5288]. The contract was not merely implied; it was written down, in the same document that shipped the feature. A decade later, a scan of the live Internet found servers breaking it anyway.
&lt;h3&gt;The protocol contract: install a key once, so its nonce only ever counts up&lt;/h3&gt;
&lt;p&gt;A mode still needs a protocol to establish keys and supply nonces. WPA2&apos;s 4-way handshake derives a fresh Pairwise Transient Key, and AES-CCMP then encrypts each frame with a nonce built from an incrementing packet number; CCM, like GCM, forbids repeating that counter under one key [@sp-800-38c; @ieee-80211i-2004]. The assumption is simple and, on its face, obviously true: a key is installed exactly once, so the packet number only ever counts &lt;em&gt;up&lt;/em&gt; and never rewinds.&lt;/p&gt;
&lt;p&gt;Here are the three contracts side by side. Keep the last column in view -- it is the bill each violation runs up.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;The contract it imposes&lt;/th&gt;
&lt;th&gt;What a violation costs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Implementation&lt;/td&gt;
&lt;td&gt;Code or silicon that computes the AES round&lt;/td&gt;
&lt;td&gt;A data-dependent lookup must not leak the data&lt;/td&gt;
&lt;td&gt;Cache/timing side channel recovers the key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mode&lt;/td&gt;
&lt;td&gt;CTR, GCM, CCM chaining the block across a message&lt;/td&gt;
&lt;td&gt;The (key, nonce) pair must be unique per encryption&lt;/td&gt;
&lt;td&gt;Keystream reuse leaks $P_1 \oplus P_2$; in GCM, forgery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;Handshake and key management driving the mode&lt;/td&gt;
&lt;td&gt;A key is installed once, so its nonce only counts up&lt;/td&gt;
&lt;td&gt;A reinstalled key rewinds the nonce, forcing reuse&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Three contracts, each reasonable, each &lt;em&gt;unenforced by the cipher&lt;/em&gt; -- the permutation cannot know whether you fed it a repeated nonce or read a leaky table. Which raises the only question that matters: in the real world, running on real servers and real routers, do these contracts actually hold? They do not. Here is where, when, and how each one broke.&lt;/p&gt;
&lt;h2&gt;4. Three Field Breaks, Three Layers, One Pattern&lt;/h2&gt;
&lt;p&gt;The comfortable belief is &quot;we standardized a strong cipher, so our encrypted traffic is safe.&quot; What follows are three independent refutations of that inference -- one at each layer around the block, ordered by when the field break landed. Read them as a catalog, not a lineage: these are not ciphers that replaced one another but three &lt;em&gt;simultaneous&lt;/em&gt; layers, every real deployment has all three at once, and the chronology is the attacker&apos;s frontier moving &lt;em&gt;outward&lt;/em&gt; as each inner layer hardened.&lt;/p&gt;

timeline
    title From the silicon outward -- one pattern, three layers
    2005-2006 : Implementation layer : Cache timing recovers AES keys (Bernstein, Osvik-Shamir-Tromer)
    2016 : Mode layer : 184 HTTPS servers repeat a GCM nonce (Böck et al., weaponizing Joux 2006)
    2017 : Protocol layer : KRACK rewinds the AES-CCMP nonce (Vanhoef and Piessens)
&lt;h3&gt;Generation 1: the implementation leaked (2005-2006)&lt;/h3&gt;
&lt;p&gt;In 2005, Daniel J. Bernstein did something the FIPS 197 math says is impossible: he recovered a full AES key &lt;em&gt;remotely&lt;/em&gt;, over a network -- without breaking AES at all [@bernstein-2005; @bernstein-index]. The target was a server doing nothing but AES under clean timing conditions, so the demonstration was remote in principle rather than turnkey -- and alarming precisely because it was not purely local. It ran ordinary T-table AES, whose secret-dependent indices left the encryption&apos;s timing faintly correlated with the key; enough samples pinned the key bytes. A year later, Dag Arne Osvik, Adi Shamir, and Eran Tromer formalized the idea into two reusable cache attacks -- &lt;strong&gt;Prime+Probe&lt;/strong&gt; and &lt;strong&gt;Evict+Time&lt;/strong&gt; -- recovering keys with a modest number of encryptions on a shared machine [@osvik-shamir-tromer-2006].&lt;/p&gt;

Recovering a secret from the physical *side effects* of a computation -- its timing, its cache footprint, its power draw -- rather than from the algorithm&apos;s inputs and outputs. A cache-timing attack on T-table AES watches which cache lines the lookups touch; because the touched lines depend on key-derived indices, the access pattern leaks the key.
&lt;p&gt;The mechanism is worth seeing as a chain, because every link is outside the cipher:&lt;/p&gt;

flowchart LR
    K[&quot;Secret index = key byte XOR plaintext byte&quot;] --&amp;gt; L[&quot;Which T-table cache line is touched&quot;]
    L --&amp;gt; M[&quot;Cache hit or miss changes measurable timing&quot;]
    M --&amp;gt; R[&quot;Attacker narrows and then pins the key byte&quot;]
&lt;p&gt;You can feel the leak in miniature. A real CPU caches memory in lines of 64 bytes, so a 256-entry table falls into a handful of cache lines. The attacker never sees the secret index -- only which &lt;em&gt;line&lt;/em&gt; was touched. Watch a single observation cut the keyspace:&lt;/p&gt;
&lt;p&gt;{`
// A CPU caches memory in 64-byte lines, so 256 one-byte table entries fall into
// a few &quot;cache lines.&quot; The attacker sees ONLY which line was touched -- not the index.
const LINE = 64;
const touchedLine = (index) =&amp;gt; Math.floor(index / LINE);&lt;/p&gt;
&lt;p&gt;const secretKeyByte = 0xB7;                   // unknown to the attacker
const plaintextByte = 0x2A;                   // attacker-chosen, known
const realIndex = secretKeyByte ^ plaintextByte;
const observed = touchedLine(realIndex);      // the only thing that leaks&lt;/p&gt;
&lt;p&gt;// Which key bytes are consistent with the observed cache line?
const candidates = [];
for (let k = 0; k &amp;lt; 256; k++) {
  if (touchedLine(k ^ plaintextByte) === observed) candidates.push(k);
}
console.log(&quot;observed cache line:&quot;, observed);
console.log(&quot;key-byte candidates remaining:&quot;, candidates.length, &quot;of 256&quot;);
console.log(&quot;true key byte still in the set?&quot;, candidates.includes(secretKeyByte));
// One measurement: 256 -&amp;gt; 64. Vary the known plaintext, intersect the sets, and the byte falls out.
`}&lt;/p&gt;
&lt;p&gt;The insight is the sharpest edge of the whole thesis, so state it plainly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Cache timing recovers AES keys in the field -- that is real, and it is the reason &quot;AES is unbroken&quot; does not mean &quot;your key is safe.&quot; But the leak lives in the T-table&apos;s &lt;em&gt;memory-access pattern&lt;/em&gt;, not in the permutation. The table is a speed optimization; swap it for a leak-free implementation and the key stops leaking while the cipher stays byte-for-byte identical. Keys fall, the cipher stands. Keep that distinction sharp -- collapsing it is the reader&apos;s default error.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The fix pointed straight at the next era, and it changed how AES is &lt;em&gt;computed&lt;/em&gt;, never what AES computes. Two responses followed: &lt;strong&gt;constant-time bitsliced software&lt;/strong&gt;, which replaces the tables with data-independent boolean logic so no secret ever indexes memory [@kasper-schwabe-2009]; and, decisively, &lt;strong&gt;hardware AES-NI&lt;/strong&gt;, which executes each round in silicon with no lookup tables and data-independent latency [@intel-aes-ni]. Once AES-NI reached mainstream CPUs in the early 2010s, this surface largely closed -- and the attacker&apos;s frontier moved one ring outward, to the mode.The formalization is due to &lt;strong&gt;Osvik, Shamir, and Tromer&lt;/strong&gt; -- not Biham, a common misattribution [@osvik-shamir-tromer-2006].&lt;/p&gt;
&lt;h3&gt;Generation 2: the mode&apos;s contract was violated (2006, then 2016)&lt;/h3&gt;
&lt;p&gt;In June 2006, Antoine Joux submitted a public comment to NIST with a quietly devastating observation about GCM, now known as the &quot;forbidden attack&quot; [@joux-2006]. GCM, designed by David McGrew and John Viega, authenticates with a &lt;a href=&quot;https://paragmali.com/blog/the-tag-verified-the-cipher-held-the-forgery-went-through-a-/&quot; rel=&quot;noopener&quot;&gt;one-time polynomial MAC&lt;/a&gt; over the field $\mathrm{GF}(2^{128})$, keyed by a secret subkey derived from the encryption key alone [@mcgrew-viega-2004].&lt;/p&gt;

GCM&apos;s authentication secret, computed as $H = \mathrm{AES}_K(0^{128})$ -- the encryption of an all-zero block under the key. Every authentication tag is a polynomial in $H$ evaluated over the ciphertext, masked by $\mathrm{AES}_K(J_0)$ where $J_0$ comes from the nonce. Security depends on $H$ staying secret, which in turn depends on the nonce never repeating.
&lt;p&gt;Joux&apos;s point: if a (key, nonce) pair repeats, the mask $\mathrm{AES}_K(J_0)$ is &lt;em&gt;identical&lt;/em&gt; across the two messages, so the difference of their tags becomes a polynomial equation over $\mathrm{GF}(2^{128})$ whose unknown is $H$. Solve for the roots and you recover $H$; with $H$ in hand, you can forge a valid authentication tag for a message you chose -- universal forgery [@joux-2006]. The confidentiality loss from keystream reuse was already bad; this makes &lt;em&gt;integrity&lt;/em&gt; fall too.&lt;/p&gt;

flowchart TD
    N[&quot;Same (key, nonce) used for two messages&quot;] --&amp;gt; KS[&quot;Identical CTR keystream&quot;]
    KS --&amp;gt; C[&quot;C1 XOR C2 equals P1 XOR P2, confidentiality lost&quot;]
    N --&amp;gt; J[&quot;Identical tag mask AES_K of J0&quot;]
    J --&amp;gt; EQ[&quot;Tag difference becomes a polynomial equation in H over GF(2 to the 128)&quot;]
    EQ --&amp;gt; F[&quot;Roots reveal the subkey H, enabling forgery&quot;]
&lt;p&gt;For ten years this was a footnote -- a warning about a contract nobody, surely, would break. Then, in 2016, Hanno Böck, Aaron Zauner, Sean Devlin, Juraj Somorovsky, and Philipp Jovanovic scanned the Internet and found it broken in the wild [@nonce-disrespecting-2016]. Their paper, &quot;Nonce-Disrespecting Adversaries,&quot; reported &lt;strong&gt;184 live HTTPS servers actually repeating GCM nonces&lt;/strong&gt; -- &quot;which fully breaks the authenticity of the connections&quot; -- among them large corporations, financial institutions, and a credit-card company, plus more than 70,000 servers using random nonces at volume risk.&lt;/p&gt;
&lt;p&gt;They then did the thing Joux only described: they weaponized the repeats into working forgeries and injected content into live sessions. The root cause was mundane and entirely operational -- buggy hardware and firmware nonce generators, and counters that reset. The mode&apos;s assumption failed; AES did exactly what it was told.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; GCM will not stop you from repeating a nonce. Never generate a nonce you might repeat across process restarts, threads, forks, or virtual-machine clones and snapshots. A saved counter that resets to zero on restart is worse than useless -- it guarantees the reuse. AES-256 offers exactly zero protection here: key size is irrelevant to nonce reuse.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two precisions keep this honest. First, the mechanism is layer-agnostic in the worst way: this is the &lt;em&gt;same keystream-reuse atom&lt;/em&gt; from Section 3, now carrying a forgery payload because GCM&apos;s integrity also leans on the nonce. Second, resist the tempting overstatement.&lt;strong&gt;Precision lock.&lt;/strong&gt; One nonce reuse is &lt;em&gt;already&lt;/em&gt; a break: it immediately leaks $C_1 \oplus C_2 = P_1 \oplus P_2$ and gives one root-finding equation for $H$. But &lt;em&gt;uniquely pinning&lt;/em&gt; $H$ for reliable universal forgery generally needs at least two collisions. Say &quot;one reuse is already catastrophic, and more reuse pins the subkey&quot; -- never &quot;one reuse recovers the key&quot; [@joux-2006]. The evidence for live reuse is the Böck et al. scan, five authors, 184 servers -- not the frequently miscited IBM Domino CVE [@nonce-disrespecting-2016].&lt;/p&gt;
&lt;p&gt;The fixes, once again, changed the &lt;em&gt;usage&lt;/em&gt; and left the cipher alone: nonce-misuse-resistant AES-GCM-SIV, where a repeat leaks only whether two messages were equal [@rfc-8452], and TLS 1.3&apos;s deterministic per-record nonce, which deletes the implementation-chosen &quot;explicit nonce&quot; that RFC 5288 had exposed [@rfc-8446]. As the mode hardened, the frontier moved one final ring outward -- to the protocol.&lt;/p&gt;
&lt;h3&gt;Generation 3: the protocol reused the nonce (2017)&lt;/h3&gt;
&lt;p&gt;WPA2&apos;s 4-way handshake exists to install a fresh key on both sides. The client installs its Pairwise Transient Key after message 3, and AES-CCMP then encrypts every frame with a nonce built from a packet number that only counts up. For reliability, the standard lets message 3 be retransmitted -- and there the trap was set. In 2017, Mathy Vanhoef and Frank Piessens showed that an attacker who captures and &lt;em&gt;replays message 3&lt;/em&gt; forces the client to reinstall a key it is already using, resetting the CCMP packet number and replay counter to their starting values [@krack-2017]. The nonce rewinds. The keystream repeats. This is KRACK: Key Reinstallation Attack.&lt;/p&gt;

Installing a key that is already in use. Because installing a key also initializes its associated nonce or packet-number counter, reinstalling an in-use key *rewinds* that counter to its starting value -- forcing the same (key, nonce) pairs, and therefore the same keystream, to be used again. KRACK triggers this by replaying a handshake message the protocol was willing to accept twice.

sequenceDiagram
    participant C as Client
    participant A as Access Point
    participant M as Attacker
    A-&amp;gt;&amp;gt;C: Message 1 (ANonce)
    C-&amp;gt;&amp;gt;A: Message 2 (SNonce)
    A-&amp;gt;&amp;gt;C: Message 3 (install key)
    Note over C: Installs PTK, packet number starts counting up
    C-&amp;gt;&amp;gt;A: Message 4 (acknowledge)
    M-&amp;gt;&amp;gt;C: Replay Message 3
    Note over C: Reinstalls the same key, packet number resets to start
    Note over C,A: Nonce reused, keystream repeats, frames become decryptable
&lt;p&gt;The insight is the same shape as before, delivered one layer further out: AES-CCMP did &lt;em&gt;exactly what it was told&lt;/em&gt;. The permutation was flawless; the state machine told it to reuse a nonce, and it obeyed. The consequence is keystream reuse -- identical (key, nonce) yields $C_1 \oplus C_2 = P_1 \oplus P_2$ -- so a known-plaintext frame yields the keystream and decrypts the colliding frame.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scope lock.&lt;/strong&gt; Against AES-CCMP specifically, KRACK forces nonce-reuse &lt;em&gt;decryption and replay&lt;/em&gt; -- not forgery and not AES key recovery. Forgery arises for the TKIP and GCMP cases, not CCMP. The especially devastating all-zero-key variant was an Android and Linux &lt;code&gt;wpa_supplicant&lt;/code&gt; implementation bug that reinstalled an all-zero key, still not a break of AES [@krack-2017].&lt;/p&gt;
&lt;p&gt;The fix was a backwards-compatible patch to the handshake state machine -- refuse to reinstall an in-use key -- shipped across Android, Linux, Apple, Windows, and OpenBSD in 2017 [@krack-2017]. Structurally, the Wi-Fi Alliance announced WPA3 in 2018 [@wifi-wpa3-2018]; its Personal mode swaps WPA2&apos;s pre-shared-key authentication for the SAE (Dragonfly) key exchange and mandates anti-reinstallation checks plus management-frame protection. The 4-way handshake still installs the pairwise key, so KRACK immunity comes from that mandatory hardening -- the same defense WPA2 received as a patch -- not from SAE removing the handshake [@dragonblood-2019]. The protocol changed. AES did not.&lt;/p&gt;
&lt;h3&gt;The pattern, seen all at once&lt;/h3&gt;
&lt;p&gt;Put the three side by side and the shape is unmistakable. Same violated contract in three costumes; same untouched block every time.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Incident&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Root cause&lt;/th&gt;
&lt;th&gt;Fix (usage, not cipher)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Bernstein; Osvik-Shamir-Tromer cache timing [@bernstein-2005; @osvik-shamir-tromer-2006]&lt;/td&gt;
&lt;td&gt;2005-2006&lt;/td&gt;
&lt;td&gt;Implementation&lt;/td&gt;
&lt;td&gt;Secret-dependent T-table indices leak via cache/timing&lt;/td&gt;
&lt;td&gt;A data-dependent lookup leaks the data&lt;/td&gt;
&lt;td&gt;Constant-time bitslicing; AES-NI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Joux forbidden attack; Böck et al. scan [@joux-2006; @nonce-disrespecting-2016]&lt;/td&gt;
&lt;td&gt;2006, 2016&lt;/td&gt;
&lt;td&gt;Mode&lt;/td&gt;
&lt;td&gt;Repeated GCM nonce reuses keystream and exposes $H$&lt;/td&gt;
&lt;td&gt;Buggy nonce generators break uniqueness&lt;/td&gt;
&lt;td&gt;AES-GCM-SIV; TLS 1.3 derived nonces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KRACK [@krack-2017]&lt;/td&gt;
&lt;td&gt;2017&lt;/td&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;Replayed message 3 rewinds the CCMP nonce&lt;/td&gt;
&lt;td&gt;State machine reinstalls an in-use key&lt;/td&gt;
&lt;td&gt;Handshake patch; WPA3-SAE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Biclique baseline [@biclique-2011]&lt;/td&gt;
&lt;td&gt;2011&lt;/td&gt;
&lt;td&gt;The cipher itself&lt;/td&gt;
&lt;td&gt;Best single-key attack: $2^{126.1}$ for AES-128&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;None needed -- &quot;no practical impact&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Seen one at a time, these look like three unrelated bugs -- a cache thing, a TLS thing, a Wi-Fi thing. Seen together, they are a single pattern: every time, a contract &lt;em&gt;around&lt;/em&gt; the permutation was violated, real traffic or keys fell, and the 128-bit block math did not move. That pattern is the whole point, and it is worth naming out loud.&lt;/p&gt;
&lt;h2&gt;5. The Fixes Changed How AES Is Used, Never AES&lt;/h2&gt;
&lt;p&gt;Stop treating the three incidents as separate stories. Line them up and one realization collapses the subject: &lt;em&gt;every&lt;/em&gt; field break attacked a layer around the permutation, and &lt;em&gt;every&lt;/em&gt; fix changed how AES is &lt;em&gt;used&lt;/em&gt; -- never AES itself.&lt;/p&gt;
&lt;p&gt;This is not a eureka discovery. It is an engineering discipline, and it is visible only because the same shape repeats three times across 2005, 2016, and 2017. Look at what each fix actually touched:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Constant-time bitsliced code and hardware AES-NI compute the round with no data-dependent memory access [@kasper-schwabe-2009; @intel-aes-ni]. The tables are gone; the permutation they computed is unchanged.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mode.&lt;/strong&gt; AES-GCM-SIV makes a repeated nonce merely detectable rather than catastrophic -- a repeat leaks only whether two messages were equal, never the subkey $H$ [@rfc-8452]. TLS 1.3 derives each nonce deterministically from the record sequence number, deleting the footgun RFC 5288 had exposed [@rfc-8446]. The nonce plumbing changed; AES did not.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocol.&lt;/strong&gt; The KRACK patch forbids reinstalling an in-use key, and WPA3 makes that anti-reinstallation defense mandatory (alongside management-frame protection) while swapping WPA2&apos;s pre-shared-key authentication for the SAE key exchange; the 4-way handshake persists, hardened rather than removed [@krack-2017; @wifi-wpa3-2018; @dragonblood-2019]. The state machine changed; AES did not.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not one of these altered the block permutation. They hardened wrappers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The cipher is the fixed point around which everything else evolved. Every field break attacked a layer around the permutation, and every remedy -- constant-time and AES-NI, misuse-resistant AEAD and derived nonces, patched handshakes and WPA3 -- hardened a &lt;em&gt;wrapper&lt;/em&gt;. Soundness requires the weakest of the three layers to hold, and hardening any one of them is an exercise in &lt;em&gt;usage&lt;/em&gt;, not cryptanalysis.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is a dynamic hiding in the chronology, and it is no coincidence. As AES-NI closed the implementation gap around 2010, the weakest remaining link -- the attacker&apos;s frontier -- moved to the mode, where the 2016 scan found it. As misuse-resistant modes and derived nonces closed that, the frontier moved to the protocol, where KRACK found it in 2017. The layers did not take turns being weak; the attacker simply always works the &lt;em&gt;current&lt;/em&gt; weakest one. That is why &quot;we use a strong cipher&quot; was never the right unit of analysis. The right unit is the weakest wrapper you are still running.&lt;/p&gt;

This article is the *did-break-in-the-field* story. Its companion, *How AES Would Break*, is the *would-break-in-theory* one: the key schedule, related-key attacks such as the Biryukov-Khovratovich results on AES-256 that only exist in a related-key model correct deployments never create [@biryukov-khovratovich-2009], and the slow erosion of the security margin. Different question, different article. And the general craft of constant-time code, fault resistance, and key custody belongs to a third sibling on secure implementation. This piece links out to both rather than re-teaching them, because the point here is narrow and sharp: the wrappers broke, and the wrappers were fixed.
&lt;p&gt;If every fix is a species of &quot;use AES correctly,&quot; then the state of the art is just the catalog of what &quot;correctly&quot; means at each layer in 2026 -- and, tellingly, where even correct-by-the-book still is not quite enough.&lt;/p&gt;
&lt;h2&gt;6. What Correct AES Deployment Looks Like in 2026&lt;/h2&gt;
&lt;p&gt;The modern answer is unglamorous, and that is exactly the point: be sound at all three layers at once, because a hardened mode does nothing for a leaky implementation, and a constant-time implementation does nothing for a protocol that rewinds its nonce. Here is the correct-deployment endpoint, keyed to the three failure loci.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Use hardware AES -- Intel and AMD AES-NI, or ARMv8&apos;s cryptographic extension -- which runs each round in silicon with no lookup tables and data-independent latency [@intel-aes-ni]. Where the CPU lacks AES instructions, fall back to a &lt;strong&gt;constant-time bitsliced&lt;/strong&gt; software implementation that never lets a secret index memory [@kasper-schwabe-2009]. Mainstream libraries typically make this selection at runtime, preferring hardware AES with a constant-time fallback.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mode.&lt;/strong&gt; Use a &lt;a href=&quot;https://paragmali.com/blog/the-aead-decision-matrix-seven-ciphers-three-edges-one-choic/&quot; rel=&quot;noopener&quot;&gt;vetted AEAD&lt;/a&gt;, never a hand-rolled chain of primitives. AES-GCM is the performance leader when you can &lt;em&gt;guarantee&lt;/em&gt; nonce uniqueness -- either random 96-bit nonces kept under the NIST budget of fewer than $2^{32}$ invocations per key [@sp-800-38d], or TLS 1.3&apos;s deterministic per-record nonce derived from the sequence number [@rfc-8446]. Where uniqueness cannot be guaranteed, use &lt;strong&gt;AES-GCM-SIV&lt;/strong&gt;, which survives a repeat gracefully [@rfc-8452].&lt;/p&gt;

An authenticated-encryption scheme that does not fail catastrophically when a nonce repeats. In an MRAE scheme such as AES-GCM-SIV, a repeated (nonce, message) pair leaks only the fact that the two plaintexts were identical -- never the keystream across distinct messages, never the subkey $H$. It is the provably strongest guarantee achievable once you admit that nonces sometimes repeat.
&lt;p&gt;&lt;strong&gt;Protocol.&lt;/strong&gt; At the link layer, patch WPA2 against key reinstallation or move to WPA3, which mandates anti-reinstallation checks and management-frame protection to close the defect while still running a 4-way handshake to install the pairwise key [@krack-2017; @wifi-wpa3-2018; @dragonblood-2019]. At the transport layer, prefer TLS 1.3 over 1.2: it deletes the explicit-nonce footgun and the downgrade and renegotiation hazards that made 1.2 fragile [@rfc-8446].&lt;/p&gt;
&lt;p&gt;There is one caveat that keeps this from being a victory lap, and it is a good illustration of how deep the &quot;usage&quot; story goes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &quot;AES-NI is constant-time by construction&quot; is true by &lt;em&gt;design intent&lt;/em&gt;, but on Ice Lake and later Intel cores, and Armv8.4-A and later, data-operand-independent timing -- including for AES instructions -- is only &lt;em&gt;guaranteed&lt;/em&gt; when the processor&apos;s data-independent-timing mode is explicitly enabled [@intel-doit; @biggers-2023]. A constant-time algorithm is necessary but not sufficient for constant-time execution; part of the guarantee lives below your software, in a mode you now have to request.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The practical upshot is that &quot;constant-time&quot; has quietly become a setting rather than an assumption.On recent Intel cores the mode is called DOITM (Data Operand Independent Timing Mode); on Arm it is the DIT (Data-Independent Timing) processor-state bit. Eric Biggers raised the cross-vendor issue publicly in 2023, and it is the reason security-sensitive code on the newest silicon must ask for timing guarantees rather than inherit them [@biggers-2023; @intel-doit].&lt;/p&gt;
&lt;p&gt;&quot;Use a vetted AEAD, use hardware AES, patch your handshake&quot; is the whole answer for greenfield code. But engineers inherit constraints -- a fixed nonce source, a distributed system that cannot coordinate a counter, a CPU with no AES instructions. So the real question is rarely &quot;what is best.&quot; It is &quot;what are my options, ranked, and exactly when does each one apply?&quot;&lt;/p&gt;
&lt;h2&gt;7. Closing Each Gap: The Competing Defenses&lt;/h2&gt;
&lt;p&gt;At two of the three layers a practitioner actually has a &lt;em&gt;choice&lt;/em&gt;, and the honest framing is a set of trade-offs, not a single winner. Take the two design spaces in turn.&lt;/p&gt;
&lt;h3&gt;The side channel: hardware AES-NI versus software bitslicing&lt;/h3&gt;
&lt;p&gt;These two coexist because they optimize different constraints. Where the CPU has AES instructions, AES-NI is the fastest option and constant-time by construction (subject to the DOIT/DIT caveat from the previous section) [@intel-aes-ni]. Where it does not -- older cores, small embedded parts -- constant-time bitsliced software gives a verifiable timing guarantee at the cost of speed and implementation effort [@kasper-schwabe-2009]. The one option that is never acceptable in security code is the original T-table implementation.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;T-table AES (broken)&lt;/th&gt;
&lt;th&gt;Bitsliced constant-time software&lt;/th&gt;
&lt;th&gt;Hardware AES-NI / ARMv8&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Secret-dependent memory access&lt;/td&gt;
&lt;td&gt;Yes (about 4 KB of tables)&lt;/td&gt;
&lt;td&gt;None (boolean logic)&lt;/td&gt;
&lt;td&gt;None (silicon datapath)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timing side-channel resistance&lt;/td&gt;
&lt;td&gt;Fails [@bernstein-2005; @osvik-shamir-tromer-2006]&lt;/td&gt;
&lt;td&gt;Constant-time by construction&lt;/td&gt;
&lt;td&gt;Data-independent by design; DOIT/DIT mode needed on Ice Lake+/Armv8.4+ [@intel-doit]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throughput&lt;/td&gt;
&lt;td&gt;Fast (pre-attack)&lt;/td&gt;
&lt;td&gt;Good when blocks are batched&lt;/td&gt;
&lt;td&gt;Fastest; line-rate AEAD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block-parallelism needed&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (weak for a single block)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware requirement&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;CPU AES instructions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best suited for&lt;/td&gt;
&lt;td&gt;Nothing security-sensitive&lt;/td&gt;
&lt;td&gt;No-AES-NI or verifiable software&lt;/td&gt;
&lt;td&gt;Everything with the instruction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;The nonce: four live strategies&lt;/h3&gt;
&lt;p&gt;This is the design space where the 2016 scan drew blood, so it deserves the careful table. The four options trade nonce size, streaming ability, and misuse tolerance against each other.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;AES-GCM, random 96-bit nonce&lt;/th&gt;
&lt;th&gt;AES-GCM, TLS 1.3 counter nonce&lt;/th&gt;
&lt;th&gt;AES-GCM-SIV (MRAE)&lt;/th&gt;
&lt;th&gt;XChaCha20-Poly1305&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Nonce size&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;96-bit (derived)&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;192-bit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passes&lt;/td&gt;
&lt;td&gt;1 (streaming)&lt;/td&gt;
&lt;td&gt;1 (streaming)&lt;/td&gt;
&lt;td&gt;2 (buffered)&lt;/td&gt;
&lt;td&gt;1 (streaming)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On accidental repeat&lt;/td&gt;
&lt;td&gt;Catastrophic (leaks $P_1 \oplus P_2$; two collisions give $H$ and forgery)&lt;/td&gt;
&lt;td&gt;Structurally prevented per connection&lt;/td&gt;
&lt;td&gt;Graceful (leaks only message equality)&lt;/td&gt;
&lt;td&gt;Catastrophic on a true repeat, but essentially never collides at random&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Safe budget per key&lt;/td&gt;
&lt;td&gt;Under $2^{32}$ messages [@sp-800-38d]&lt;/td&gt;
&lt;td&gt;Per-connection sequence, no reuse if the counter is sound&lt;/td&gt;
&lt;td&gt;Effectively unbounded against misuse&lt;/td&gt;
&lt;td&gt;About $2^{96}$ random nonces before collision risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relative speed&lt;/td&gt;
&lt;td&gt;Fastest (line rate)&lt;/td&gt;
&lt;td&gt;Fastest&lt;/td&gt;
&lt;td&gt;About 0.92 cpb on Broadwell, 14-19% slower than OpenSSL GCM [@gueron-lindell-2015]&lt;/td&gt;
&lt;td&gt;Fast in constant-time software, no AES-NI needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primitive&lt;/td&gt;
&lt;td&gt;AES&lt;/td&gt;
&lt;td&gt;AES&lt;/td&gt;
&lt;td&gt;AES&lt;/td&gt;
&lt;td&gt;ChaCha20 (not AES)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Read the table as a decision, not a ranking. If you own a reliable per-connection counter, deterministic-nonce AES-GCM is both fastest and safe -- that is what TLS 1.3 does [@rfc-8446]. If you &lt;em&gt;cannot&lt;/em&gt; guarantee uniqueness -- distributed writers, stateless functions, restart- or clone-prone systems -- AES-GCM-SIV is the provably strongest answer under misuse, at the price of a second pass and a buffered message [@rfc-8452; @rogaway-shrimpton-2006]. And if AES is not mandated and you just want &quot;a random nonce is always safe,&quot; XChaCha20-Poly1305&apos;s 192-bit nonce makes accidental collision astronomically unlikely [@xchacha-draft] -- a different primitive, included as the most common answer to the nonce footgun rather than as an AES deployment.&lt;/p&gt;
&lt;p&gt;Every option here changes &lt;em&gt;how AES is used&lt;/em&gt; -- or swaps AES out entirely -- and each buys its safety with a specific cost: a pass, a throughput hit, a hardware dependency, a different primitive. Which makes the honest way to close the technical arc a question about limits: how little does the attacker actually need, and how much can the defender actually guarantee?&lt;/p&gt;
&lt;h2&gt;8. Theoretical Limits: What Is Provably True on Both Sides&lt;/h2&gt;
&lt;p&gt;The thesis has two sides, and each has its own provable frontier. The surprise is the asymmetry: the cipher side is essentially closed, and all the hard, unavoidable limits live in the deployment.&lt;/p&gt;
&lt;h3&gt;The cipher side: the math that did not break&lt;/h3&gt;
&lt;p&gt;Biclique cryptanalysis is the &lt;em&gt;entire&lt;/em&gt; published erosion of the full-cipher security margin. Bogdanov, Khovratovich, and Rechberger reported the first single-key attacks on the full cipher at $2^{126.1}$, $2^{189.7}$, and $2^{254.4}$ for AES-128, AES-192, and AES-256 -- with no related-key assumption [@biclique-2011]. Against brute force at $2^{128}$, $2^{192}$, and $2^{256}$, that is a gain of at most roughly 1.6 to 2.3 bits: a factor of a few, not a factor that matters.A &quot;bit&quot; of security is a doubling of attacker work, so shaving 2 bits makes the attack about four times faster than brute force -- still astronomically far from feasible.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;AES-128&lt;/th&gt;
&lt;th&gt;AES-192&lt;/th&gt;
&lt;th&gt;AES-256&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Brute-force cost&lt;/td&gt;
&lt;td&gt;$2^{128}$&lt;/td&gt;
&lt;td&gt;$2^{192}$&lt;/td&gt;
&lt;td&gt;$2^{256}$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best known single-key attack (biclique)&lt;/td&gt;
&lt;td&gt;$2^{126.1}$&lt;/td&gt;
&lt;td&gt;$2^{189.7}$&lt;/td&gt;
&lt;td&gt;$2^{254.4}$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Margin removed&lt;/td&gt;
&lt;td&gt;about 1.9 bits&lt;/td&gt;
&lt;td&gt;about 2.3 bits&lt;/td&gt;
&lt;td&gt;about 1.6 bits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Practical threat&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relevance to the field breaks above&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;There is no proof that any attack on AES &lt;em&gt;must&lt;/em&gt; cost as much as exhaustive search -- concrete block ciphers essentially never come with such a theorem -- so confidence rests on more than two decades of open cryptanalysis since the competition, not on an impossibility result [@fips-197]. But the reading is unambiguous, and the authors said it themselves.&lt;/p&gt;

The best known attacks on the full AES &quot;do not threaten the practical use of AES in any way.&quot; -- Bogdanov, Khovratovich, and Rechberger, 2011 [@biclique-2011]
&lt;p&gt;Notice the defender&apos;s column in the table never moves, and key size is irrelevant to every operational break in the sections above. The cipher side is, for practical purposes, a closed question.&lt;/p&gt;
&lt;h3&gt;The deployment side: where the real limits live&lt;/h3&gt;
&lt;p&gt;Now the asymmetry. Three &lt;em&gt;provable&lt;/em&gt; boundaries constrain real systems, and none of them is about AES&apos;s strength:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The GCM birthday bound.&lt;/strong&gt; With random 96-bit nonces, collision risk grows by the birthday bound, so NIST caps a single key at fewer than $2^{32}$ invocations [@sp-800-38d]. This is a structural limit of random-nonce GCM, independent of the cipher -- the mathematical reason &quot;just use random nonces at massive scale&quot; eventually fails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The AEAD trilemma.&lt;/strong&gt; No single scheme is simultaneously single-pass and line-rate, fully nonce-misuse-resistant, &lt;em&gt;and&lt;/em&gt; large-nonce. GCM gives you the first, GCM-SIV the second, XChaCha the third-and-a-half; you cannot have all three at once [@rfc-8452]. And misuse-resistant AE is provably the &lt;em&gt;strongest possible&lt;/em&gt; guarantee once nonces may repeat -- an attacker can always at least detect that the same message was encrypted, and a well-designed SIV scheme leaks nothing more [@rogaway-shrimpton-2006].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ISA-guaranteed whole-machine constant time is impossible in general.&lt;/strong&gt; The instruction set does not, in general, promise data-independent instruction timing, so even AES and XOR instructions may be data-dependent on recent cores unless the timing mode is enabled [@intel-doit; @biggers-2023]. A constant-time &lt;em&gt;algorithm&lt;/em&gt; cannot by itself guarantee constant-time &lt;em&gt;execution&lt;/em&gt;; part of the guarantee lives below the software, and the general craft of getting it right is the subject of the &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;secure-implementation sibling&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The cipher-secure and system-secure claims are different, and the gap between them is &lt;em&gt;inherent&lt;/em&gt;, not accidental. The cipher side has a negligible margin nibble -- under two bits. The deployment side has the real, provable limits: the GCM birthday bound, the single-pass / misuse-resistant / large-nonce trilemma, and the structural impossibility of ISA-guaranteed constant time. Key size buys nothing against any of them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the cipher side is closed and the deployment side has hard limits, then the live frontier is wherever those deployment limits are still being hit in the wild. That is not a solved problem. It is an active one.&lt;/p&gt;
&lt;h2&gt;9. Open Problems: Where AES Still Breaks in the Field&lt;/h2&gt;
&lt;p&gt;The cipher side is closed; the deployment side is not. Here are the places the same three-layer pattern is still live -- each an &lt;em&gt;operational&lt;/em&gt; frontier, consistent with the thesis that the weakest link is the wrapper, not the block.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guaranteeing nonce uniqueness in distributed, multi-writer, restart-prone systems.&lt;/strong&gt; This is the exact gap that produced Generation 2: buggy counters and generators on 184 live servers repeated GCM nonces [@nonce-disrespecting-2016]. The best partial answer, MRAE via AES-GCM-SIV, makes a repeat &lt;em&gt;detectable&lt;/em&gt; rather than catastrophic [@rfc-8452] -- but the single-pass, fully misuse-resistant, large-nonce scheme the trilemma forbids remains unrealized. In a world of stateless functions, cloned VMs, and shared keys across a fleet, &quot;just keep a counter&quot; is still an unsolved systems problem, not a solved one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-VM cache side channels in multi-tenant clouds.&lt;/strong&gt; The 2005-2006 threat model assumed a shared physical machine; virtualization brought it back at scale. Irazoqui, Inci, Eisenbarth, and Sunar recovered AES keys &lt;em&gt;across virtual-machine boundaries&lt;/em&gt; using Flush+Reload with memory deduplication [@irazoqui-2014]. Hardware AES removes the &lt;em&gt;table&lt;/em&gt; channel, which is why AES-NI and constant-time code remain load-bearing in 2026.Even instruction timing can be data-dependent on recent cores unless the timing mode is enabled, so cloud tenancy keeps the Generation-1 question open even for hardware AES [@biggers-2023].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fault and differential-fault attacks.&lt;/strong&gt; Inducing a computation fault -- through voltage glitching, a laser, or rowhammer-style effects -- can recover an AES key from a handful of faulty ciphertexts [@piret-quisquater-2003]. This is again an implementation and hardware failure, not a cipher failure; the depth belongs to the secure-implementation sibling, but it is a live operational locus wherever an attacker has physical or near-physical access.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The long tail of devices without hardware AES.&lt;/strong&gt; Constant-time software is slower than AES-NI, and the performance gap quietly tempts developers back toward leaky tables on the smallest parts [@kasper-schwabe-2009]. On many of those devices the pragmatic answer is to ship a constant-time stream cipher such as ChaCha20 instead of fighting AES&apos;s software side channels [@xchacha-draft].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Formal verification of protocol state machines,&lt;/strong&gt; so the next KRACK is caught before it ships. TLS 1.3 was co-designed with formal analysis and has verified component implementations, such as those in the HACL* library [@hacl-2017]. Wi-Fi&apos;s SAE was &lt;em&gt;not&lt;/em&gt; fully immunized: Dragonblood found downgrade, denial-of-service, and side-channel leaks the authors argue are &quot;inherent to Dragonfly,&quot; and even patched software remained affected by a novel leak [@dragonblood-2019]. The state of the art at the protocol layer is &lt;em&gt;better&lt;/em&gt;, not &lt;em&gt;finished&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Every open problem here is the same sentence in new clothes: a contract around the permutation is hard to keep in the real world. Which means the practical guide almost writes itself -- it is the thesis made operational, each rule routed to the incident it prevents.&lt;/p&gt;
&lt;h2&gt;10. What to Do on Monday&lt;/h2&gt;
&lt;p&gt;Everything above collapses into a short decision procedure and a shorter list of nevers, each rule tied to the incident it prevents.&lt;/p&gt;

flowchart TD
    S[&quot;Deploying AES&quot;] --&amp;gt; Q1{&quot;CPU has AES instructions?&quot;}
    Q1 --&amp;gt;|Yes| HW[&quot;Use AES-NI or ARMv8 crypto, enable timing mode on newest cores&quot;]
    Q1 --&amp;gt;|No| CT[&quot;Use constant-time bitsliced software&quot;]
    HW --&amp;gt; Q2{&quot;Can you guarantee nonce uniqueness?&quot;}
    CT --&amp;gt; Q2
    Q2 --&amp;gt;|Yes| GCM[&quot;AES-GCM with deterministic nonces, TLS 1.3 style&quot;]
    Q2 --&amp;gt;|No| Q3{&quot;Is AES mandated?&quot;}
    Q3 --&amp;gt;|Yes| SIV[&quot;AES-GCM-SIV, misuse-resistant&quot;]
    Q3 --&amp;gt;|No| XC[&quot;XChaCha20-Poly1305, 192-bit nonce&quot;]
&lt;p&gt;The rules behind the tree:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Use a library that selects AES-NI or ARMv8 crypto at runtime and falls back to constant-time software; never table-based AES in security code; on the newest cores, be aware the data-independent-timing mode may need to be requested [@intel-aes-ni; @intel-doit]. &lt;em&gt;Prevents Generation 1: cache-timing key recovery.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mode and nonce.&lt;/strong&gt; Reliable per-connection counter, as in TLS or QUIC? Use AES-GCM with deterministic nonces [@rfc-8446]. Cannot &lt;em&gt;guarantee&lt;/em&gt; uniqueness across restarts, threads, or clones? Use AES-GCM-SIV [@rfc-8452]. Want &quot;a random nonce is always safe&quot; and AES is not mandated? Use XChaCha20-Poly1305 [@xchacha-draft]. Never hand-roll a mode, and never choose your own explicit GCM nonce. &lt;em&gt;Prevents Generation 2: nonce reuse and forgery.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocol.&lt;/strong&gt; Patch WPA2 against key reinstallation or move to WPA3, keep clients updated, and prefer TLS 1.3 over 1.2 [@krack-2017; @rfc-8446]. &lt;em&gt;Prevents Generation 3: handshake-driven nonce rewind.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The single highest-value check you can add to code review is a nonce-reuse detector. It is the exact contract the 184 servers violated, and it fits in a few lines.&lt;/p&gt;
&lt;p&gt;{`
// Scan a stream of (key, nonce) pairs and flag the first repeat.
function findNonceReuse(records) {
  const seen = new Set();
  for (const r of records) {
    const tag = r.key + &quot;|&quot; + r.nonce;
    if (seen.has(tag)) return { reused: true, key: r.key, nonce: r.nonce };
    seen.add(tag);
  }
  return { reused: false };
}&lt;/p&gt;
&lt;p&gt;const stream = [
  { key: &quot;k1&quot;, nonce: &quot;00000001&quot; },
  { key: &quot;k1&quot;, nonce: &quot;00000002&quot; },
  { key: &quot;k1&quot;, nonce: &quot;00000001&quot; },   // counter reset after a restart -- the bug
];&lt;/p&gt;
&lt;p&gt;console.log(findNonceReuse(stream));
// { reused: true, key: &apos;k1&apos;, nonce: &apos;00000001&apos; } -- catch it in review, not in an incident.
`}&lt;/p&gt;
&lt;p&gt;Now hold each pitfall up to the mirror. Every one of these confident sentences reproduces a specific, named incident.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The confident mistake&lt;/th&gt;
&lt;th&gt;The incident it reproduces&lt;/th&gt;
&lt;th&gt;The fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Table-based AES is fine in security code&lt;/td&gt;
&lt;td&gt;Bernstein; Osvik-Shamir-Tromer cache timing [@bernstein-2005; @osvik-shamir-tromer-2006]&lt;/td&gt;
&lt;td&gt;AES-NI or constant-time software&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeating a nonce across restarts, threads, or clones is unlikely to matter&lt;/td&gt;
&lt;td&gt;The 184-server GCM forgery scan [@nonce-disrespecting-2016]&lt;/td&gt;
&lt;td&gt;AES-GCM-SIV or a disciplined counter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-256 is safer against these attacks&lt;/td&gt;
&lt;td&gt;Every break here -- key size is irrelevant [@nonce-disrespecting-2016]&lt;/td&gt;
&lt;td&gt;Fix the wrapper, not the key size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constant-time source means constant-time execution&lt;/td&gt;
&lt;td&gt;The DOIT/DIT timing caveat [@intel-doit; @biggers-2023]&lt;/td&gt;
&lt;td&gt;Enable the timing mode where required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An unpatched WPA2 handshake is good enough&lt;/td&gt;
&lt;td&gt;KRACK [@krack-2017]&lt;/td&gt;
&lt;td&gt;Patch WPA2 or deploy WPA3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

When you review encryption code, find where the nonce comes from and ask exactly one question: can this value repeat across a restart, a fork, a thread, or a clone? If you cannot prove it never repeats, you are reading a latent Generation-2 incident. Reach for AES-GCM-SIV or a 192-bit-nonce AEAD instead of arguing about how improbable a collision seems.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 1. AES-NI or ARMv8 crypto, with a constant-time software fallback. 2. A vetted AEAD -- deterministic-nonce AES-GCM where a per-connection counter is reliable, AES-GCM-SIV where uniqueness is hard, XChaCha20-Poly1305 where AES is not mandated. 3. Patched WPA2 or WPA3, and TLS 1.3 over 1.2.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The checklist is short because the lesson is one sentence. Before restating it, clear the handful of confident, wrong sentences that keep this bug alive in design meetings.&lt;/p&gt;
&lt;h2&gt;11. Frequently Asked Questions&lt;/h2&gt;


No. The best publicly known attack on the full cipher, biclique cryptanalysis, costs about $2^{126}$ operations for AES-128 -- a fraction-of-a-bit improvement over brute force with zero practical impact, and its authors say it does &quot;not threaten the practical use of AES in any way&quot; [@biclique-2011]. Every break in this article happened in a layer around the cipher, not in the cipher.


Yes -- via cache-timing side channels [@bernstein-2005; @osvik-shamir-tromer-2006]. But that is *not* a break of the cipher. The T-table implementation&apos;s memory-access pattern leaked the key; the block permutation did not. Swap the leaky tables for a constant-time implementation and the key stops leaking while AES stays byte-for-byte identical. &quot;Unbroken cipher&quot; and &quot;stolen key&quot; are both true at once.


Be precise here. One reuse immediately leaks $P_1 \oplus P_2$ through keystream reuse, and it gives one equation for the GHASH subkey $H$. But *pinning* $H$ for reliable universal forgery generally needs at least two collisions [@joux-2006]. One reuse is already catastrophic -- do not understate it -- but do not say &quot;one reuse recovers the key&quot; either.


No. Every break here is implementation, mode, or protocol; key size provides no protection against cache timing, nonce reuse, or a reinstalled handshake key [@nonce-disrespecting-2016]. For the nonce-reuse and handshake breaks AES-256 fails exactly as fast as AES-128; for cache timing it is just as vulnerable, though a longer key takes proportionally more leakage to extract. If someone proposes AES-256 as the fix for any incident in this article, they have misdiagnosed the layer.


No. Against AES-CCMP, KRACK forces nonce-reuse decryption and replay, not AES key recovery [@krack-2017]. The especially damaging all-zero-key case was an Android and Linux `wpa_supplicant` implementation bug, not a weakness in AES. No block-math weakness is involved, and no AES key is recovered by the attack itself.


No. A padding oracle is a mode-and-validation failure in CBC deployments -- the receiver leaks whether decrypted padding was valid -- and it never touches the AES permutation. It is the same moral as this article (a wrapper broke), in a different deployment, and it is covered in a dedicated padding-oracle sibling. AES itself is not the weak link there either.

&lt;p&gt;Every correction points at the same root: the cipher was never the weak link. Time to say the sentence the whole article was built to earn.&lt;/p&gt;
&lt;h2&gt;12. To Break AES in the Field, You Never Touch AES&lt;/h2&gt;
&lt;p&gt;Return to the paradox we opened with, now resolved. The best attack on the full cipher is a fraction-of-a-bit shave with no practical impact [@biclique-2011] -- and yet Wi-Fi sessions were decrypted, HTTPS connections forged, and keys lifted from running servers, because every one of those breaks happened in a wrapper the cipher knows nothing about. The implementation leaked through cache timing [@bernstein-2005; @osvik-shamir-tromer-2006]. The mode&apos;s nonce contract was violated on 184 live servers, weaponizing Joux&apos;s decade-old forbidden attack into forgery [@nonce-disrespecting-2016; @joux-2006]. The protocol rewound its nonce when a replayed handshake reinstalled a key [@krack-2017]. Three layers, three field breaks, and the 128-bit block math untouched in all three.&lt;/p&gt;
&lt;p&gt;And every fix changed how AES is &lt;em&gt;used&lt;/em&gt;, never AES: constant-time code and AES-NI at the implementation, misuse-resistant AEAD and derived nonces at the mode, patched handshakes and WPA3 at the protocol [@kasper-schwabe-2009; @rfc-8452; @rfc-8446; @wifi-wpa3-2018]. The cipher is the fixed point; the engineering happened all around it.&lt;/p&gt;

A cipher is not a cryptosystem. When your traffic falls, do not ask whether AES broke -- ask which wrapper did: the implementation, the mode, or the protocol.
&lt;p&gt;One last honesty, because the series depends on it. The claim is &quot;almost never,&quot; not &quot;never.&quot; Scoped to AES, the split is pristine -- the block math never fell in deployment. But some deployed primitives genuinely broke as &lt;em&gt;math&lt;/em&gt;: DES&apos;s 56-bit key, RC4&apos;s keystream biases [@alfardan-2013], and the &lt;a href=&quot;https://paragmali.com/blog/the-fingerprint-two-files-shared-a-field-guide-to-cryptograp/&quot; rel=&quot;noopener&quot;&gt;MD5 and SHA-1 collisions&lt;/a&gt; [@shattered-2017]. AES has not joined them, and naming the cases where cryptanalysis won is what keeps the thesis honest rather than triumphant.&lt;/p&gt;
&lt;p&gt;The cipher was never the weak link -- and no bigger key would have saved a single one of these systems. That is why this is Part 1 of a series about how things break &lt;em&gt;in real life&lt;/em&gt;, not a chapter on block-cipher cryptanalysis. The companion piece, &lt;em&gt;How AES Would Break&lt;/em&gt;, takes up the other question: what it would take to move the block itself. This one answered the question that actually decrypts traffic. It was never the cipher. It was the wrapper, every time.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;how-aes-breaks-in-real-life&quot; keyTerms={[
  { term: &quot;Block cipher vs. mode of operation&quot;, definition: &quot;AES is a keyed permutation on one 16-byte block; a mode (CTR, GCM, CCM) chains it across a whole message and turns it into a cryptosystem.&quot; },
  { term: &quot;Nonce / IV&quot;, definition: &quot;A number used once. Counter-based modes require the (key, nonce) pair to be unique per encryption, or the keystream repeats.&quot; },
  { term: &quot;AEAD&quot;, definition: &quot;Authenticated Encryption with Associated Data: confidentiality and integrity together, with headers authenticated but not encrypted. GCM and CCM are AEAD modes.&quot; },
  { term: &quot;Keystream reuse&quot;, definition: &quot;Identical (key, nonce) yields identical keystream, so the XOR of two ciphertexts equals the XOR of their plaintexts. The key is never touched.&quot; },
  { term: &quot;T-table&quot;, definition: &quot;Precomputed lookup tables that fold an AES round into a few reads. A speed optimization whose secret-dependent indices leak through the cache.&quot; },
  { term: &quot;Cache-timing attack&quot;, definition: &quot;Recovering a secret from the timing or cache footprint of data-dependent memory access, not from the algorithm output.&quot; },
  { term: &quot;GHASH subkey H&quot;, definition: &quot;GCM&apos;s authentication secret, the encryption of an all-zero block under the key. A repeated nonce turns tag differences into equations that reveal it.&quot; },
  { term: &quot;Key reinstallation&quot;, definition: &quot;Installing an already-in-use key, which rewinds its nonce or packet-number counter and forces keystream reuse. The mechanism KRACK exploits.&quot; },
  { term: &quot;MRAE&quot;, definition: &quot;Nonce-misuse-resistant authenticated encryption, such as AES-GCM-SIV, where a repeated nonce leaks only message equality, never the subkey.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>cryptography</category><category>aes</category><category>aes-gcm</category><category>nonce-reuse</category><category>krack</category><category>side-channel-attack</category><category>authenticated-encryption</category><category>tls</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>The AEAD Decision Matrix: Seven Ciphers, Three Edges, One Choice</title><link>https://paragmali.com/blog/the-aead-decision-matrix-seven-ciphers-three-edges-one-choic/</link><guid isPermaLink="true">https://paragmali.com/blog/the-aead-decision-matrix-seven-ciphers-three-edges-one-choic/</guid><description>AES-GCM, ChaCha20-Poly1305, CCM, OCB3, GCM-SIV, AEGIS, and Ascon, compared by the three sharp edges that decide every deployment: nonce, hardware, commitment.</description><pubDate>Thu, 09 Jul 2026 15:04:00 GMT</pubDate><content:encoded>
Every modern AEAD makes the same three promises, and they differ only at the sharp edges where those promises stop. Three edges decide a real deployment: the **nonce contract** (catastrophic on reuse, or misuse-resistant), the **performance and hardware profile** (AES-NI plus CLMUL, constant-time software, or a few thousand gates), and **commitment** (does one ciphertext bind to exactly one key?). &quot;Which AEAD should I use?&quot; is not a ranking from worst to best. It is a function: default to AES-GCM or ChaCha20-Poly1305, and escalate to AES-GCM-SIV, AES-CCM, Ascon, OCB3, or AEGIS only when a specific edge demands it. Every famous break -- invisible salamanders, nonce reuse on live TLS, `CCM_8` forgeries -- was a deployment stepping on an edge, not a broken cipher.
&lt;h2&gt;1. Two Failures That Should Have Been Impossible&lt;/h2&gt;
&lt;p&gt;In 2018, a team of cryptographers handed Facebook a single encrypted file that decrypted to two completely different, perfectly meaningful images, and whose authentication tag verified correctly for &lt;em&gt;both&lt;/em&gt;, under two different keys [@dodis2018-salamander]. The cipher was AES-GCM, the internet&apos;s default authenticated encryption. Nothing about it was broken. That is the unsettling part: AES-GCM did &lt;em&gt;exactly&lt;/em&gt; what it promised. It had just never promised the thing everyone assumed it did.&lt;/p&gt;
&lt;p&gt;The result defeated Facebook Messenger&apos;s abuse-reporting scheme, which relied on the encrypted attachment being &lt;em&gt;bound&lt;/em&gt; to the key that produced it. The authors called their construction &quot;invisible salamanders&quot; [@dodis2018-salamander]. Your reflex on reading this -- &quot;but it is &lt;em&gt;authenticated&lt;/em&gt;, so how did the tag pass?&quot; -- is the entire subject of this article. The word &quot;authenticated&quot; carries less than you think.&lt;/p&gt;
&lt;p&gt;Now the second failure, because one break only shows one edge. In 2016, researchers scanning the live internet found 184 HTTPS servers reusing a &lt;code&gt;(key, nonce)&lt;/code&gt; pair under AES-GCM [@bock2016]. A repeated nonce in GCM is not a hygiene slip that costs you a little margin. It instantly leaks the XOR of the two plaintexts, and -- via an attack Antoine Joux had described to NIST a decade earlier, in 2006 -- it lets an attacker forge arbitrary messages [@joux2006]. The confidentiality half of that failure is easy to see for yourself.&lt;/p&gt;
&lt;p&gt;{`
// A stream-cipher-style AEAD (GCM, ChaCha20-Poly1305) turns the key+nonce
// into a keystream, then XORs it with the plaintext. Reuse the nonce and
// you reuse the keystream -- so it cancels out of the XOR of two ciphertexts.
const keystream = [0x9e, 0x37, 0xb1, 0xf2, 0x4a];   // same (key, nonce) =&amp;gt; same keystream
const xor = (a, b) =&amp;gt; a.map((x, i) =&amp;gt; x ^ b[i]);&lt;/p&gt;
&lt;p&gt;const p1 = [...&apos;HELLO&apos;].map(c =&amp;gt; c.charCodeAt(0));
const p2 = [...&apos;WORLD&apos;].map(c =&amp;gt; c.charCodeAt(0));&lt;/p&gt;
&lt;p&gt;const c1 = xor(p1, keystream);   // ciphertext 1
const c2 = xor(p2, keystream);   // ciphertext 2, SAME nonce&lt;/p&gt;
&lt;p&gt;// Attacker sees only c1 and c2, never the key or keystream:
const leaked = xor(c1, c2);      // == p1 XOR p2, the keystream is gone
const recovered = xor(leaked, p2);  // and if p2 is ever guessed, p1 falls out
console.log(&apos;c1 XOR c2 leaks P1 XOR P2:&apos;, leaked.join(&apos;,&apos;));
console.log(&apos;recovered P1:&apos;, String.fromCharCode(...recovered));
`}&lt;/p&gt;
&lt;p&gt;Neither of these was a broken cipher. AES-GCM met its specification in both cases. The salamander bound nothing to a key because AES-GCM was never designed to; the TLS servers leaked plaintext because they violated the one contract GCM cannot survive. Both failures were the same shape: a deployment reached for an AEAD and then stepped on the one sharp edge its designers had moved somewhere the deployment could not avoid.&lt;/p&gt;
&lt;p&gt;That is the thesis of this field guide. Authenticated encryption with associated data (AEAD) fused confidentiality and integrity so completely that composing them by hand became a solved problem. The remaining hard problem is choosing &lt;em&gt;among&lt;/em&gt; AEADs, and that choice turns on three edges: the &lt;strong&gt;nonce contract&lt;/strong&gt;, the &lt;strong&gt;performance and hardware profile&lt;/strong&gt;, and the &lt;strong&gt;commitment&lt;/strong&gt; axis.&lt;/p&gt;
&lt;p&gt;Part 1 of this series defined an AEAD&apos;s guarantees as &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-/&quot; rel=&quot;noopener&quot;&gt;IND-CPA plus INT-CTXT&lt;/a&gt;; commitment is a robustness property &lt;em&gt;beyond&lt;/em&gt; both. Part 6 showed the padding-oracle cost of the botched integrity AEAD was built to remove.The nonce-reuse breaks are widely mis-cited to CVE-2016-0270. That CVE actually names IBM Domino, and the NVD entry itself warns it has been &quot;incorrectly used for GCM nonce reuse issues in other products&quot; [@cve-2016-0270].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; &quot;Which AEAD should I use?&quot; is not a ranking. It is a function over three edges: pick the construction whose failure mode your deployment can &lt;em&gt;guarantee&lt;/em&gt; it will never trigger. The salamander triggered the commitment edge; the TLS servers triggered the nonce edge. Same lesson, two edges.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If &quot;authenticated&quot; does not mean &quot;bound to one key,&quot; and &quot;encrypted&quot; does not survive a repeated nonce, then what &lt;em&gt;exactly&lt;/em&gt; does an AEAD promise, and where does each promise stop? To answer that, we have to go back to the moment when &quot;encrypt&quot; and &quot;authenticate&quot; were still two separate calls.&lt;/p&gt;
&lt;h2&gt;2. From Two Calls to One&lt;/h2&gt;
&lt;p&gt;Here is a question that sounds trivial and is not: you have a cipher and you have a message authentication code (MAC). In which order do you apply them? Most engineers guess. The wrong guess shipped in SSL, IPsec, and SSH, and it took the field a decade of theory to sort out which guess was which.&lt;/p&gt;
&lt;p&gt;There are three orderings. &lt;strong&gt;Encrypt-and-MAC&lt;/strong&gt; authenticates the plaintext and appends the tag beside the ciphertext (SSH). &lt;strong&gt;MAC-then-Encrypt&lt;/strong&gt; authenticates the plaintext, then encrypts plaintext and tag together (SSL and, for years, TLS). &lt;strong&gt;Encrypt-then-MAC&lt;/strong&gt; encrypts, then authenticates the &lt;em&gt;ciphertext&lt;/em&gt; (IPsec).&lt;/p&gt;
&lt;p&gt;In 2000, Mihir Bellare and Chanathip Namprempre proved these are not interchangeable: only Encrypt-then-MAC generically preserves both privacy and integrity for &lt;em&gt;any&lt;/em&gt; secure cipher and &lt;em&gt;any&lt;/em&gt; secure MAC [@bn2000]. A year later, Hugo Krawczyk showed the authenticate-then-encrypt method used in SSL is not generically secure while Encrypt-then-MAC is [@krawczyk2001]. Part 6 is the sequel: MAC-then-encrypt is exactly the door a &lt;a href=&quot;https://paragmali.com/blog/they-read-your-plaintext-without-breaking-your-cipher-a-fiel/&quot; rel=&quot;noopener&quot;&gt;padding oracle&lt;/a&gt; walks through.&lt;/p&gt;

One keyed call that provides confidentiality of the plaintext, integrity of the plaintext, and integrity (but not secrecy) of an extra header called the associated data. The uniform interface was standardized in RFC 5116 [@rfc5116].
&lt;p&gt;The lesson cut deeper than &quot;pick Encrypt-then-MAC.&quot; If two correct primitives can combine into an &lt;em&gt;insecure&lt;/em&gt; whole, hand-composition is a footgun no matter how good the parts are. The fix was to make a &lt;em&gt;single&lt;/em&gt; primitive own both goals, so no protocol designer could botch the join.&lt;/p&gt;
&lt;p&gt;Charanjit Jutla showed the way in 2001 with IAPM and IACBC, modes that delivered message integrity in essentially one pass, almost for free [@jutla2001]. The same year, Phillip Rogaway and coauthors published OCB, a one-pass block-cipher mode built for exactly this [@ocb2001]. Then, in 2002, Rogaway named the primitive: real messages carry a header -- routing bytes, version numbers, sequence counters -- that must be &lt;em&gt;authenticated&lt;/em&gt; but not &lt;em&gt;encrypted&lt;/em&gt;, because intermediaries need to read it. His &quot;Authenticated-Encryption with Associated-Data&quot; formalized that extra input [@rogaway2002-ad].&lt;/p&gt;

The header bytes an AEAD authenticates but does not encrypt: routing information, protocol versions, sequence numbers. Tampering with the associated data makes tag verification fail, but the associated data itself travels in the clear [@rogaway2002-ad].
&lt;p&gt;By 2008, David McGrew closed the loop with RFC 5116, which defined the universal interface every construction in this article implements: &lt;code&gt;AEAD-Encrypt(key, nonce, associated_data, plaintext)&lt;/code&gt; returns &lt;code&gt;ciphertext || tag&lt;/code&gt;, and the matching decrypt either returns the plaintext or a single, uninformative failure [@rfc5116]. One call in, one call out, no way to reverse the order of two primitives because there is only one primitive.&lt;/p&gt;

A value that must be unique for every encryption under a given key. The mode, not the label, sets the exact requirement: some AEADs tolerate only uniqueness, others tolerate randomness, and a few tolerate repetition. Nonce generation is the subject of Part 2 of this series.

timeline
    title The road to the AEAD portfolio
    2000 : Encrypt-then-MAC proven the safe order
    2001 : IAPM and OCB, single-pass native AE
    2002 : Rogaway names AEAD and adds associated data
    2003 : CCM standardized in RFC 3610
    2004 : GCM published by McGrew and Viega
    2006 : Joux forbidden attack, SIV misuse-resistance
    2008 : RFC 5116 fixes the universal interface
    2013 : CAESAR opens, AEGIS announced
    2016 : Nonce reuse found on live TLS servers
    2018 : Invisible salamanders break message franking
    2019 : CAESAR portfolio chosen, OCB2 broken
    2021 : Partitioning oracles weaponize non-commitment
    2025 : NIST standardizes Ascon-AEAD128
&lt;p&gt;The interface was settled by 2008. But an interface is a promise about &lt;em&gt;shape&lt;/em&gt;, not about &lt;em&gt;sharp edges&lt;/em&gt;. Two constructions that satisfy &lt;code&gt;AEAD-Encrypt&lt;/code&gt; to the letter can fail in completely different ways, and the very first AEADs to ship proved it. The one that reached the most devices did not even win on technical merit. It won because of a patent.&lt;/p&gt;
&lt;h2&gt;3. The Welded Modes: CCM and GCM&lt;/h2&gt;
&lt;p&gt;The first AEAD to reach a billion devices was not chosen by a cryptographer. It was chosen, in effect, by a patent lawyer. When IEEE 802.11i (the security amendment that became WPA2) needed an authenticated mode, the elegant candidate was OCB -- but OCB was patent-encumbered, and the working group would not build a wireless standard on it. So 802.11i standardized the plodding, unpatented alternative: &lt;strong&gt;AES-CCM&lt;/strong&gt;. By device count, that decision made CCM one of the most widely deployed AEADs in the world.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AES-CCM = Counter mode + CBC-MAC.&lt;/strong&gt; Doug Whiting, Russ Housley, and Niels Ferguson specified it in RFC 3610 in 2003, and NIST blessed it as SP 800-38C the next year [@rfc3610][@sp80038c]. It runs the message through CBC-MAC for the tag, then encrypts with &lt;a href=&quot;https://paragmali.com/blog/the-ciphertext-was-unbreakable-the-attacker-rewrote-it-anyw/&quot; rel=&quot;noopener&quot;&gt;counter (CTR) mode&lt;/a&gt;: two passes, a strictly serial MAC, and the message length needed up front, which makes streaming awkward. What that price buys is frugality -- nothing but AES, a tiny code footprint, no second primitive to implement.&lt;/p&gt;
&lt;p&gt;That profile is why CCM owns the constrained niche -- Bluetooth Low Energy [@bluetooth-core], Zigbee [@ieee802154], and the TLS &lt;code&gt;CCM_8&lt;/code&gt; ciphersuites. IEEE 802.11i also made CCMP the mandatory data-confidentiality protocol for WPA2 [@ieee80211i], and CCM rode WPA2/CCMP into the overwhelming majority of Wi-Fi hardware over the following decade.Zigbee and 802.15.4 use a variant called CCM*, which additionally permits integrity-only or encryption-only operation, unlike the strict RFC 3610 CCM that always does both. So the same plodding, all-AES mode anchors two very different worlds: the smallest constrained devices and the Wi-Fi layer that WPA2 secures. These are the building blocks from Part 5, welded to a MAC.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AES-GCM = Counter mode + GHASH.&lt;/strong&gt; David McGrew and John Viega published Galois/Counter Mode in 2004, and NIST standardized it as SP 800-38D in 2007 [@mcgrew2004-gcm][@sp80038d]. GCM is everything CCM is not: one pass, fully parallelizable, and, on any CPU with AES-NI and CLMUL, blisteringly fast. It is the internet default, and AES-128-GCM is the single mandatory-to-implement (MUST) AEAD cipher suite in TLS 1.3, per RFC 8446 Section 9.1 -- a status the spec grants to no other AEAD [@rfc8446]. To understand every later failure, you need one fact about how its tag works.&lt;/p&gt;

An authenticator of the form $\text{tag} = H_k(\text{message}) + s$, where $H_k$ is a fast keyed universal hash and $s$ is a **one-time** secret mask. It is unforgeable only if $s$ is never reused. Repeat the mask and the algebraic structure of $H_k$ leaks. This is the shared root of both GHASH (AES-GCM) and Poly1305 (ChaCha20-Poly1305) [@bernstein-poly1305].
&lt;p&gt;GCM&apos;s tag is a one-time Wegman-Carter MAC. GHASH evaluates a polynomial over the finite field $\mathrm{GF}(2^{128})$, with the ciphertext and associated-data blocks as coefficients, at a single secret point $H = \operatorname{AES}_k(0^{128})$. It then masks the result with a per-nonce keystream block:&lt;/p&gt;
&lt;p&gt;$$T = \operatorname{GHASH}_H(A, C) \oplus \operatorname{AES}_k(J_0), \qquad H = \operatorname{AES}_k(0^{128})$$&lt;/p&gt;
&lt;p&gt;where $J_0$ is the initial counter block derived from the nonce. The mask $\operatorname{AES}_k(J_0)$ is the one-time secret $s$. It is one-time &lt;em&gt;only because the nonce is unique&lt;/em&gt;. Repeat the nonce and you repeat $J_0$, so you repeat the mask, and now two tags share it -- which turns GHASH&apos;s linear structure into a system of polynomial equations an attacker can solve.&lt;/p&gt;

The universal hash inside AES-GCM: a polynomial in the secret point $H = \operatorname{AES}_k(0^{128})$ evaluated over $\mathrm{GF}(2^{128})$. Because the polynomial is linear in its coefficients, recovering $H$ lets an attacker forge tags for chosen messages [@joux2006].

flowchart LR
    N[&quot;Nonce and counter&quot;] --&amp;gt; CTR[&quot;AES counter mode&quot;]
    K[&quot;Key&quot;] --&amp;gt; CTR
    CTR --&amp;gt; KS[&quot;Keystream&quot;]
    P[&quot;Plaintext&quot;] --&amp;gt; X((&quot;XOR&quot;))
    KS --&amp;gt; X
    X --&amp;gt; C[&quot;Ciphertext&quot;]
    C --&amp;gt; GH[&quot;GHASH polynomial at secret point H&quot;]
    AD[&quot;Associated data&quot;] --&amp;gt; GH
    K --&amp;gt; H[&quot;H is AES of the zero block&quot;]
    H --&amp;gt; GH
    GH --&amp;gt; M((&quot;XOR one-time mask&quot;))
    K --&amp;gt; J[&quot;AES of the first counter block&quot;]
    J --&amp;gt; M
    M --&amp;gt; T[&quot;Authentication tag&quot;]
&lt;p&gt;That single design choice hands GCM two sharp edges the rest of this article pays for. The first is the &lt;strong&gt;nonce contract&lt;/strong&gt;: reuse is not a weakness, it is a detonator.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For every nonce-respecting AEAD -- AES-GCM, ChaCha20-Poly1305, AES-CCM, OCB3, AEGIS, and Ascon -- one repeated &lt;code&gt;(key, nonce)&lt;/code&gt; pair is an immediate, total break of confidentiality for those two messages, and, with a second collision, of authenticity for the whole key [@joux2006].One nonce collision leaks $P_1 \oplus P_2$ right away. Uniquely pinning the secret point $H$ for universal forgery generally needs at least two collisions, since a single pair of equations leaves multiple candidate roots. &quot;One repeat is game over for those messages&quot; is correct; &quot;one repeat exposes $H$&quot; is not quite [@bock2016].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The second edge is quieter and just as dangerous, because it is two different numbers people constantly merge into one.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; SP 800-38D fixes a &lt;strong&gt;per-message&lt;/strong&gt; plaintext limit of $2^{39}-256$ bits (about 64 GiB), set by 32-bit counter-mode block-space exhaustion, and, separately, a &lt;strong&gt;per-key&lt;/strong&gt; invocation cap of roughly $2^{32}$ messages when nonces are random 96-bit values, driven by the birthday bound on nonce collision [@sp80038d]. These are two different mechanisms, not two readings of one bound (the full derivation is in Section 8). The multi-user bounds that justify TLS 1.3&apos;s nonce randomization are tight [@htt2018-gcm]. Enforce both limits. Conflating them is the single most common accuracy error on this primitive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GCM gave the internet a one-pass, hardware-fast AEAD, and in the same stroke handed it a mode where one repeated nonce is not a bug but a catastrophe. This is the same GCM negotiated inside shipping Windows protocols such as &lt;a href=&quot;https://paragmali.com/blog/rotating-every-cipher-schannel-and-the-twenty-year-algorithm/&quot; rel=&quot;noopener&quot;&gt;Schannel TLS&lt;/a&gt; and SMB 3 encryption [@ms-schannel-tls][@ms-smb-encryption]. Antoine Joux saw the danger in 2006 [@joux2006]. It took the rest of the world ten years, and a scan of the live internet, to believe him.&lt;/p&gt;
&lt;h2&gt;4. A Trunk With Branches&lt;/h2&gt;
&lt;p&gt;The family tree of AEAD is not a ladder from worst to best. Draw it that way and none of the modern constructions make sense, because none of them strictly dominates GCM. Draw it correctly and the whole field snaps into focus: it is a &lt;strong&gt;trunk with branches&lt;/strong&gt;. The trunk is linear -- generic composition, then single-pass native AE, then the welded deployed modes CCM and GCM. Then, at GCM, the tree &lt;em&gt;splits&lt;/em&gt;, because GCM&apos;s edges each forced a &lt;em&gt;separate&lt;/em&gt; successor. No later generation wins. That is the entire point.&lt;/p&gt;

flowchart TD
    G0[&quot;Generic composition, Encrypt-then-MAC&quot;] --&amp;gt; G1[&quot;Single-pass native AE, IAPM and OCB&quot;]
    G1 --&amp;gt; G2[&quot;Welded deployed modes, CCM and GCM&quot;]
    G2 --&amp;gt; E1[&quot;Nonce edge&quot;]
    G2 --&amp;gt; E2[&quot;Hardware edge&quot;]
    G2 --&amp;gt; E3[&quot;Commitment edge&quot;]
    E1 --&amp;gt; S1[&quot;SIV and AES-GCM-SIV, misuse-resistant&quot;]
    E2 --&amp;gt; S2[&quot;ChaCha20-Poly1305, constant-time in software&quot;]
    E2 --&amp;gt; S4[&quot;AEGIS and Ascon, hardware and footprint co-design&quot;]
    E3 --&amp;gt; S3[&quot;Committing transforms, added on top&quot;]
&lt;h3&gt;The hardware edge: ChaCha20-Poly1305&lt;/h3&gt;
&lt;p&gt;GHASH is hard to make constant-time without the CLMUL instruction, and table-based AES is both slow and timing-leaky without AES-NI. Around 2013, that was the reality on most phones and ARM chips: no AES hardware, so GCM was either slow or a cache-timing side channel. Daniel Bernstein&apos;s answer kept GCM&apos;s exact nonce-respecting contract but threw out the parts that needed special silicon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChaCha20&lt;/strong&gt; is an ARX cipher -- addition, rotation, XOR -- with no S-box tables to leak timing, so it is constant-time by construction [@bernstein-chacha]. &lt;strong&gt;Poly1305&lt;/strong&gt; is a one-time Wegman-Carter MAC over a prime field rather than $\mathrm{GF}(2^{128})$, and its one-time key is derived from a ChaCha keystream block [@bernstein-poly1305].Poly1305&apos;s one-time key comes from a ChaCha-derived block, not from AES. ChaCha20-Poly1305 never calls AES at all -- a common misconception, since GCM&apos;s mask does use AES.&lt;/p&gt;
&lt;p&gt;The IETF standardized the pair as an AEAD in RFC 8439 [@rfc8439], and it now protects TLS 1.3, WireGuard, OpenSSH, and the &lt;code&gt;age&lt;/code&gt; file-encryption tool [@wireguard-protocol][@openssh-chacha][@age-spec]. Its normative status is widely overstated: in TLS 1.3, ChaCha20-Poly1305 is a &lt;em&gt;recommended&lt;/em&gt; (SHOULD) cipher suite, not mandatory-to-implement, per RFC 8446 Section 9.1 -- a default by adoption, not by requirement [@rfc8446]. It is not weaker than GCM; it is the same nonce contract on a different, table-free engine.XChaCha20-Poly1305 extends the nonce to 192 bits, large enough that random nonces essentially never collide. That is a &lt;em&gt;mitigation&lt;/em&gt; of nonce-collision anxiety, not misuse-resistance -- reuse the full 192-bit nonce and it fails exactly like GCM.&lt;/p&gt;
&lt;h3&gt;The nonce edge: misuse-resistance and SIV&lt;/h3&gt;
&lt;p&gt;Every mode so far detonates on a repeated nonce, and reuse keeps happening in the real world: cloned virtual machines that resume with identical RNG state, counters reset by a crash, embedded devices with weak entropy at first boot. If the operator cannot guarantee uniqueness, the fix is a mode that &lt;em&gt;survives&lt;/em&gt; the operator&apos;s mistake. In 2006, Phillip Rogaway and Thomas Shrimpton formalized exactly that goal and built the first construction for it [@rs2006].&lt;/p&gt;

An AEAD whose failure under a repeated nonce is graceful, not catastrophic. Repeating a `(key, nonce, associated_data, plaintext)` tuple leaks only whether two encryptions were of the *same* message -- message equality -- and nothing else. It never leaks a plaintext XOR and never hands over the authentication subkey [@rs2006][@rfc8452].
&lt;p&gt;The mechanism is a single clean idea: derive the initialization vector &lt;em&gt;synthetically&lt;/em&gt;, as a pseudorandom function of the entire message, rather than accepting it from the caller. The tag &lt;em&gt;is&lt;/em&gt; the IV.&lt;/p&gt;

A construction in which the initialization vector is computed as a MAC over the associated data and the full plaintext, then reused as the authentication tag. Two different messages under a repeated nonce produce different synthetic IVs, so their keystreams differ and nothing leaks [@rs2006].

flowchart TD
    K[&quot;Key&quot;] --&amp;gt; MAC[&quot;MAC over associated data and full plaintext&quot;]
    AD[&quot;Associated data&quot;] --&amp;gt; MAC
    N[&quot;Nonce&quot;] --&amp;gt; MAC
    P[&quot;Plaintext&quot;] --&amp;gt; MAC
    MAC --&amp;gt; IV[&quot;Synthetic IV, which is also the tag&quot;]
    IV --&amp;gt; CTR[&quot;Counter-mode encryption&quot;]
    K --&amp;gt; CTR
    P --&amp;gt; CTR
    CTR --&amp;gt; C[&quot;Ciphertext&quot;]
    IV --&amp;gt; T[&quot;Tag sent alongside ciphertext&quot;]
&lt;p&gt;That picture also explains the price, which returns as a theorem in Section 8: to compute the IV you must read the whole message first, so SIV cannot emit its first ciphertext byte until it has seen the last plaintext byte. It is inherently two-pass.&lt;/p&gt;
&lt;p&gt;Two deployable forms exist. &lt;strong&gt;AES-SIV&lt;/strong&gt;, standardized by Dan Harkins in RFC 5297, targets deterministic authenticated encryption and key wrapping [@rfc5297]. &lt;strong&gt;AES-GCM-SIV&lt;/strong&gt;, from Shay Gueron, Adam Langley, and Yehuda Lindell in RFC 8452, keeps AES-NI and CLMUL speed while adding misuse-resistance, building on the Gueron-Lindell GCM-SIV design [@rfc8452][@gl2015-gcmsiv].AES-GCM-SIV hashes with POLYVAL, a little-endian sibling of GHASH, and derives a fresh message-authentication and encryption key per nonce -- a structure whose tight multi-user bounds were later established by Bose, Hoang, and Tessaro [@bht2018].&lt;/p&gt;

&quot;...two authenticated encryption algorithms that are nonce misuse resistant -- that is, they do not fail catastrophically if a nonce is repeated.&quot; -- RFC 8452 [@rfc8452]
&lt;p&gt;Read that phrasing carefully, because it is the most misquoted sentence about SIV. &quot;Do not fail catastrophically&quot; is not &quot;do not fail.&quot; A repeated nonce in AES-GCM-SIV still leaks message equality: an attacker learns that two ciphertexts encrypt the same plaintext, which is a real and sometimes serious leak. SIV makes reuse &lt;em&gt;survivable&lt;/em&gt;, never &lt;em&gt;free&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;The elegance detour: OCB3 and the patent that chose a standard&lt;/h3&gt;
&lt;p&gt;Two edges now had answers, each on its own branch. A third construction sits off to the side -- not because it is worse, but because history was unkind to it. &lt;strong&gt;OCB3&lt;/strong&gt;, finalized by Ted Krovetz and Phillip Rogaway in 2011 and standardized as RFC 7253, is arguably the most elegant AEAD ever standardized: one block-cipher key, one pass, fully parallel, roughly one cipher call per block [@kr2011-ocb3][@rfc7253].&lt;/p&gt;
&lt;p&gt;Its mechanism is where the elegance lives. Each block is masked by a key-derived offset -- $\text{Offset}&lt;em&gt;i = \text{Offset}&lt;/em&gt;{i-1} \oplus L_{\text{ntz}(i)}$, a Gray-code walk over precomputed $L$ values -- and wrapped as $C_i = \text{Offset}_i \oplus \operatorname{ENCIPHER}(K, P_i \oplus \text{Offset}_i)$, while a &lt;em&gt;single&lt;/em&gt; running plaintext checksum, $\text{Checksum} = P_1 \oplus P_2 \oplus \cdots$, produces the tag in the &lt;em&gt;same pass&lt;/em&gt; [@rfc7253]. No second key, no separate MAC. It matches or beats GCM in software. And it lost anyway -- not for a technical reason.A widely repeated claim is that OCB3 is &lt;em&gt;inverse-free&lt;/em&gt;. It is not. OCB-DECRYPT recovers each block as $P_i = \text{Offset}_i \oplus \operatorname{DECIPHER}(K, C_i \oplus \text{Offset}_i)$, calling the block-cipher inverse $E_K^{-1}$ (RFC 7253 Section 4.3), so a hardware implementation needs both the AES encrypt &lt;em&gt;and&lt;/em&gt; decrypt circuits [@rfc7253]. Inverse-free is the property of the CTR, stream, and sponge modes -- AES-GCM, AES-CCM, ChaCha20-Poly1305, AEGIS, and Ascon -- and OCB is precisely the lineage that trades it away for single-primitive elegance.&lt;/p&gt;

OCB was patented from birth. When the 802.11i working group picked WPA2&apos;s cipher in 2003, it passed over OCB precisely because of those patents and chose the unencumbered CCM instead. Rogaway later granted free licenses for open-source and non-military use, but the damage was done: every major protocol had already standardized on GCM and ChaCha20-Poly1305 in the years the patents were live. In 2021 Rogaway released OCB into the public domain outright -- too late to matter [@kr2021-ocb]. The honest answer to &quot;when should I reach for OCB3 in 2026?&quot; is &quot;almost never, and the reason is a patent grave, not a design flaw.&quot;
&lt;h3&gt;The dead end: OCB2 and the limits of &quot;provably secure&quot;&lt;/h3&gt;
&lt;p&gt;There is one more branch, and it is a warning. Between OCB1 and OCB3 sat OCB2, an ISO-standardized refinement with a security proof. In 2019, Akiko Inoue, Tetsu Iwata, Kazuhiko Minematsu, and Bertram Poettering broke it outright: universal forgery &lt;em&gt;and&lt;/em&gt; full plaintext recovery, because OCB2 used the XEX* tweakable cipher outside the regime its proof actually covered [@inoue2019-ocb2].&lt;/p&gt;

The OCB2 break is the cautionary counterpoint to every &quot;but it has a proof&quot; argument. OCB2 was standardized by ISO/IEC and carried a published security proof, and it was still broken end to end. A proof secures a *model*; if the construction steps outside the model&apos;s assumptions, the proof guarantees nothing. Tellingly, the same attack left OCB1 and OCB3 untouched [@inoue2019-ocb2] -- a dead-end twig on a branch whose siblings survived.
&lt;p&gt;Two of GCM&apos;s three edges now had dedicated successors, and the family tree looked complete. But every construction so far -- GCM, ChaCha20-Poly1305, even the misuse-resistant SIV family -- quietly shared a third assumption nobody had thought to check: that &quot;authenticated&quot; meant &quot;bound to one key.&quot; In 2018, that assumption broke in production, on the desk of a Facebook security engineer holding a single file with two faces.&lt;/p&gt;
&lt;h2&gt;5. The Commitment Reckoning and the CAESAR Crucible&lt;/h2&gt;
&lt;p&gt;Now we can explain the salamanders. Recall the mechanism from Section 3: a GCM tag is a one-time Wegman-Carter value, $\operatorname{GHASH}_H(A,C) \oplus \operatorname{AES}_k(J_0)$, and GHASH is &lt;em&gt;linear&lt;/em&gt; in its coefficients. An attacker who gets to pick two keys, $k_1$ and $k_2$, can treat &quot;make the tag verify under both&quot; as a system of linear equations over $\mathrm{GF}(2^{128})$ and simply solve it, producing one ciphertext that decrypts to two chosen, meaningful plaintexts and passes verification under each key [@dodis2018-salamander].&lt;/p&gt;
&lt;p&gt;Nothing is broken. GCM guarantees confidentiality and integrity; it never promised that a ciphertext binds to a single key. That promise has a name, and until 2018 almost nobody was asking for it.&lt;/p&gt;

A graded robustness property beyond confidentiality and integrity. CMT-1 means a ciphertext binds to exactly one *key*; CMT-4 means it binds to the full *context* -- key, nonce, associated data, and message. Bellare and Hoang proved that CMT-1 does not imply CMT-4: committing to the key is strictly weaker than committing to everything [@bh2022-commit]. RFC 9771 standardized the vocabulary [@rfc9771].
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; &quot;Authenticated&quot; never meant &quot;committed.&quot; An AEAD&apos;s guarantees -- IND-CPA plus INT-CTXT -- say nothing about binding a ciphertext to one key. Commitment is a third, orthogonal axis. That is why every default AEAD was non-committing and nobody noticed for fifteen years: the property was simply outside the definition everyone was proving.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two ideas define the modern state of the art, and both come from &lt;em&gt;refusing&lt;/em&gt; to treat &quot;cipher plus separate hash&quot; as the end of the design space.&lt;/p&gt;
&lt;p&gt;The first is &lt;strong&gt;robustness as an explicit goal&lt;/strong&gt; -- against the operator and against the adversary who supplies the key. The operator side is MRAE from Section 4, elevated from a mode into a principle. The adversary side is committing AEAD, and its timeline is a tidy example of a theoretical curiosity becoming an operational threat.&lt;/p&gt;
&lt;p&gt;Invisible salamanders (2018) showed a non-committing AEAD could defeat message franking [@dodis2018-salamander]. Then, in 2021, Julia Len, Paul Grubbs, and Thomas Ristenpart turned it into a weapon: &lt;strong&gt;partitioning oracle attacks&lt;/strong&gt; use the missing commitment to recover passwords and other low-entropy keys, crafting one ciphertext that decrypts under many candidate keys and using each success or failure to bisect the key space [@len2021-partition].&lt;/p&gt;
&lt;p&gt;Mihir Bellare and Viet Tung Hoang then built the graded CMT-1 through CMT-4 theory and cheap transforms that add full commitment with no ciphertext-size increase [@bh2022-commit]; Ange Albertini and coauthors independently catalogued the abuses and a padding-based fix [@albertini2022], with further theory from John Chan and Phillip Rogaway [@chan2022]. Sanketh Menda and coauthors then showed the gap is portfolio-wide, with context-discovery attacks against CCM, EAX, SIV, GCM, and OCB3 [@menda2023]. RFC 9771 (2025) finally fixed the vocabulary the field had been improvising [@rfc9771].&lt;/p&gt;

A vetted AEAD gives you confidentiality and integrity and stops there. Commitment is a third axis nobody put in the definition -- which is exactly why one ciphertext could wear two faces.
&lt;p&gt;The second idea is &lt;strong&gt;native co-design&lt;/strong&gt;: stop bolting a cipher to a hash and instead build the AEAD &lt;em&gt;around&lt;/em&gt; the hardware or footprint you actually have. Hongjun Wu and Bart Preneel&apos;s AEGIS (2013) is the AES-hardware extreme [@wu2013-aegis].&lt;/p&gt;
&lt;p&gt;It keeps a large internal state -- eight 128-bit words in AEGIS-128L -- seeded directly from the key and nonce; the &lt;strong&gt;AES round function&lt;/strong&gt; updates that state as it absorbs associated data and plaintext, encryption &lt;em&gt;squeezes&lt;/em&gt; a keystream out of the state, and the tag comes from the &lt;em&gt;finalized&lt;/em&gt; state. One primitive, one pass, no separate hash, and the IETF draft records that all variants are inverse-free and built from the AES encryption round [@aegis-draft18].&lt;/p&gt;
&lt;p&gt;That structure is &lt;em&gt;why&lt;/em&gt; AEGIS outruns GCM on AES silicon, and &lt;em&gt;why&lt;/em&gt; nonce reuse is catastrophic: the whole state is a function of &lt;code&gt;(key, nonce)&lt;/code&gt;, so a repeat lets an attacker unwind it. Its commitment story is a nuance, not a headline -- a 128-bit AEGIS tag delivers only about 64-bit committing security, while a 256-bit tag pushes cross-key collisions out of reach, so AEGIS is &lt;em&gt;partially&lt;/em&gt; committing by tag length, neither fully committing nor flatly broken [@aegis-draft18].&lt;/p&gt;
&lt;p&gt;At the other extreme, Ascon -- by Christoph Dobraunig, Maria Eichlseder, Florian Mendel, and Martin Schläffer -- uses a single lightweight permutation in a sponge, giving a tiny gate count and a side-channel-friendly structure for constrained hardware [@ascon2021].&lt;/p&gt;

flowchart LR
    KN[&quot;Key and nonce&quot;] --&amp;gt; ST[&quot;Large internal state, eight 128-bit words&quot;]
    ST --&amp;gt; UP[&quot;AES round function update&quot;]
    AD[&quot;Associated data&quot;] --&amp;gt; UP
    P[&quot;Plaintext&quot;] --&amp;gt; UP
    UP --&amp;gt; KS[&quot;Squeezed keystream&quot;]
    P --&amp;gt; X((&quot;XOR&quot;))
    KS --&amp;gt; X
    X --&amp;gt; C[&quot;Ciphertext&quot;]
    UP --&amp;gt; FIN[&quot;Finalized state&quot;]
    FIN --&amp;gt; T[&quot;Authentication tag&quot;]

A mode built from one public permutation whose state is split into a &quot;rate&quot; (absorbs input and is squeezed for output) and a &quot;capacity&quot; (the hidden security margin). A single permutation absorbs the key, nonce, associated data, and plaintext, then squeezes keystream and a tag -- no separate cipher and hash. Ascon is a sponge [@ascon2021].
&lt;p&gt;What forced this whole portfolio into existence was a contest. The &lt;strong&gt;CAESAR competition&lt;/strong&gt; (2013-2019), organized by Daniel Bernstein, was a public, multi-year, break-it-in-the-open bake-off [@caesar-home]. Its most important decision was structural: rather than crown a single winner, it selected a &lt;em&gt;portfolio across three use cases&lt;/em&gt; -- itself the thesis of this article. The winners were Ascon and ACORN for lightweight use, AEGIS-128 and OCB for high-performance use, and Deoxys-II (first choice) and COLM for defense in depth [@caesar-portfolio].Deoxys-II is built on the TWEAKEY framework for tweakable block ciphers, by Jérémy Jean, Ivica Nikolić, Thomas Peyrin, and Yannick Seurin [@caesar-portfolio].&lt;/p&gt;
&lt;p&gt;Note carefully: &lt;strong&gt;Deoxys-II is a CAESAR winner, not an also-ran&lt;/strong&gt; -- it simply was never deployed at scale. The real also-rans are the candidates eliminated during the competition, including MORUS, which took a certificational break from Tomer Ashur, Maria Eichlseder, and coauthors and did not make the final portfolio [@morus2018].&lt;/p&gt;
&lt;p&gt;The competition ended in 2019 with no single champion, on purpose. So where does that leave a working engineer in 2026, staring at seven names in a crypto library&apos;s documentation? To choose well, you need the current map: exactly what each construction is, where it wins, and where it bites.&lt;/p&gt;
&lt;h2&gt;6. The 2026 Portfolio, Precisely&lt;/h2&gt;
&lt;p&gt;The current portfolio has a stable shape: two defaults and five specialists. By deployment, the two internet defaults are AES-GCM and ChaCha20-Poly1305 -- but normatively they are not equals. In TLS 1.3 only AES-128-GCM is mandatory-to-implement (MUST); AES-256-GCM and ChaCha20-Poly1305 are both &lt;em&gt;recommended&lt;/em&gt; (SHOULD), the same normative level as each other, per RFC 8446 Section 9.1 [@rfc8446]. Everything else is a deliberate escalation. Here is each construction on its edges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AES-GCM.&lt;/strong&gt; Counter mode plus a one-time GHASH tag; one pass, parallel, &lt;code&gt;O(1)&lt;/code&gt; online state [@mcgrew2004-gcm]. Excels on any CPU with AES-NI and CLMUL, which is every server and most modern clients. Struggles on hardware without those instructions and, above all, on nonce discipline: reuse is fatal and the two ceilings are easy to breach [@sp80038d]. Adoption: the internet default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChaCha20-Poly1305.&lt;/strong&gt; ARX stream cipher plus a prime-field one-time MAC; constant-time in pure software with no lookup tables [@rfc8439]. Excels precisely where GCM struggles -- phones, embedded ARM, any target without AES hardware. Same nonce contract as GCM, so it struggles on the exact same reuse cliff. Adoption: TLS 1.3, WireGuard, OpenSSH [@wireguard-protocol][@openssh-chacha].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AES-CCM.&lt;/strong&gt; Counter mode plus CBC-MAC; two passes, serial, needs the length up front, but all-AES and tiny [@rfc3610]. Excels in constrained stacks (BLE [@bluetooth-core], Zigbee [@ieee802154]) and inside WPA2 [@ieee80211i]. Struggles on throughput and streaming, and the truncated &lt;code&gt;CCM_8&lt;/code&gt; tag trades a real forgery budget for eight bytes [@rfc3610]. Adoption: enormous by device count.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AES-GCM-SIV and AES-SIV.&lt;/strong&gt; Synthetic-IV misuse-resistant modes; two-pass by necessity [@rfc8452][@rfc5297]. Excel when nonce uniqueness cannot be guaranteed: reuse degrades to leaking message equality rather than catastrophe. Struggle on streaming (they must buffer) and still leak equality, so they are survivable, not free. AES-GCM-SIV runs near AES-GCM speed on server hardware, around 0.92 cycles per byte on Broadwell in the original design [@gl2015-gcmsiv]. Adoption: growing where reuse risk is real.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OCB3.&lt;/strong&gt; One block-cipher key, one pass, fully parallel, roughly one cipher call per block -- technically superb [@kr2011-ocb3][@rfc7253]. Excels on elegance and software speed. Struggles on adoption, for the patent reasons in Section 4; it is nonce-respecting like GCM; and, unlike the CTR and stream modes, it is &lt;strong&gt;not&lt;/strong&gt; inverse-free -- decryption calls the AES inverse circuit (RFC 7253 Section 4.3), a genuine hardware cost [@rfc7253]. Adoption: minimal, despite standardization.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AEGIS.&lt;/strong&gt; Keystream and authentication driven straight from the AES round function over a large nonce-seeded state; the throughput frontier, around 0.48 cycles per byte for AEGIS-128L on 4 KB messages, faster than CCM, GCM, and OCB [@wu2013-aegis][@aegis-v11]. Excels on raw speed when you control both endpoints. Struggles on maturity and contract: nonce-respecting (catastrophic on reuse, since its whole state is nonce-seeded) and only &lt;em&gt;partially&lt;/em&gt; committing -- about 64-bit committing security at a 128-bit tag, stronger at a 256-bit tag [@aegis-draft18].&lt;/p&gt;
&lt;p&gt;Critically, &lt;strong&gt;AEGIS is still an active Internet-Draft, &lt;code&gt;draft-irtf-cfrg-aegis-aead-18&lt;/code&gt; from October 2025, not an RFC&lt;/strong&gt; -- it states plainly that it &quot;is not an IETF product and is not a standard,&quot; and it expires on 8 April 2026 [@aegis-draft18].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ascon-AEAD128.&lt;/strong&gt; A single 320-bit lightweight permutation in a sponge; tiny state, side-channel-friendly [@ascon2021]. Excels on constrained hardware and gate count. Struggles on server throughput, where AEGIS and GCM win. It is nonce-respecting, but -- unlike the CTR and stream modes -- it commits to its inputs &lt;em&gt;without&lt;/em&gt; any added transform: the tag is squeezed from the sponge&apos;s large hidden capacity after that capacity has already absorbed the key, so one ciphertext binds natively to the key it was produced under. RFC 9771 lists Ascon-AEAD128 as both key-committing and full-committing as-is, not merely as a candidate for a bolt-on fix [@rfc9771]. The currency fact matters here: &lt;strong&gt;NIST SP 800-232 is final (August 2025) and standardizes Ascon-AEAD128&lt;/strong&gt;, a &lt;em&gt;tweaked&lt;/em&gt; variant of CAESAR Ascon-128 using a larger data-absorption rate -- widely reported as 128-bit, up from the CAESAR design&apos;s 64-bit, with the exact parameter in the SP 800-232 body [@sp800232][@nist-ascon-2023]. It is not byte-identical to CAESAR Ascon [@ascon-site].&lt;/p&gt;
&lt;p&gt;A profile only helps if you can actually call the construction, so here is where each one ships as of mid-2026, with each cell cited to that project&apos;s official documentation.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;Where it ships (libraries and frameworks)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM&lt;/td&gt;
&lt;td&gt;OpenSSL/BoringSSL [@openssl-aes][@boringssl-aead], Go &lt;code&gt;crypto/cipher&lt;/code&gt; [@go-cipher], Java JCA [@java-jca], .NET CNG [@dotnet-aesgcm], WebCrypto (the only AEAD in the browser) [@webcrypto], libsodium (hardware-gated) [@libsodium-aegis]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChaCha20-Poly1305 / XChaCha20&lt;/td&gt;
&lt;td&gt;OpenSSL/BoringSSL [@openssl-chacha][@boringssl-aead], libsodium (default for random-nonce APIs) [@libsodium-aegis], Go &lt;code&gt;x/crypto&lt;/code&gt; [@go-chacha], WireGuard [@wireguard-protocol], OpenSSH [@openssh-chacha], &lt;code&gt;age&lt;/code&gt; [@age-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-CCM&lt;/td&gt;
&lt;td&gt;mbedTLS [@mbedtls-ccm], wolfSSL [@wolfssl-ccm], Wi-Fi [@ieee80211i] / BLE [@bluetooth-core] / Zigbee [@ieee802154] firmware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV&lt;/td&gt;
&lt;td&gt;BoringSSL/OpenSSL [@boringssl-aead][@openssl-aes] and several bindings; less universal than the defaults&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-SIV&lt;/td&gt;
&lt;td&gt;&lt;code&gt;miscreant&lt;/code&gt;-lineage (deterministic / key-wrap) libraries [@miscreant]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCB3&lt;/td&gt;
&lt;td&gt;some libraries (public domain since 2021 [@kr2021-ocb]); rarely a default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEGIS&lt;/td&gt;
&lt;td&gt;libsodium (&lt;code&gt;crypto_aead_aegis128l&lt;/code&gt; / &lt;code&gt;aegis256&lt;/code&gt;) [@libsodium-aegis] and a growing set of high-performance libraries; not a TLS suite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ascon-AEAD128&lt;/td&gt;
&lt;td&gt;reference and third-party implementations [@ascon-site]; adoption ramping since SP 800-232 [@sp800232]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Two entries on that map decide real architectures. &lt;strong&gt;In the browser, AES-GCM is the only AEAD you can call.&lt;/strong&gt;WebCrypto&apos;s &lt;code&gt;SubtleCrypto.encrypt&lt;/code&gt; recognizes RSA-OAEP, AES-CTR, AES-CBC, and AES-GCM, and AES-GCM is the only one of those that authenticates. Browser JavaScript that needs an AEAD without bundling a crypto library therefore has exactly one option [@webcrypto]. And AEGIS, still pre-RFC, is nonetheless callable in production today through libsodium&apos;s &lt;code&gt;crypto_aead_aegis128l&lt;/code&gt; and &lt;code&gt;crypto_aead_aegis256&lt;/code&gt; APIs -- deployability and standardization are not the same axis [@libsodium-aegis].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Eight constructions -- the seven cipher families, with the SIV line counted in its two deployable forms (AES-GCM-SIV and AES-SIV) -- all linear-time, all vetted, and not one strictly dominates the others. CAESAR chose a portfolio across three use cases on purpose, and NIST added Ascon for the constrained end. There is no &quot;best AEAD,&quot; and any article or vendor that names one is hiding an assumption about your deployment [@caesar-portfolio].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two more items complete the 2026 map. The CAESAR defense-in-depth winners, Deoxys-II and COLM, remain excellent and essentially undeployed [@caesar-portfolio]. And committing transforms -- the fix for the commitment edge -- exist and are cheap, but as of mid-2026 none is &lt;em&gt;mandated&lt;/em&gt; in a shipping standard; RFC 9771 supplies vocabulary, not a required construction [@rfc9771][@bh2022-commit].&lt;/p&gt;
&lt;p&gt;Laid side by side, those eight look interchangeable. They are not, and the tool that makes the difference legible is a single table built on the three edges.&lt;/p&gt;
&lt;h2&gt;7. The Decision Matrix&lt;/h2&gt;
&lt;p&gt;This is the one screen to memorize. Everything in the previous six sections collapses into two tables and a flowchart, all built on the same three edges.&lt;/p&gt;
&lt;p&gt;The first table answers the only question that matters at selection time: for each construction, what happens on the &lt;em&gt;first repeated nonce&lt;/em&gt;, what hardware does it want, and does one ciphertext bind to one key?&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;First repeated nonce&lt;/th&gt;
&lt;th&gt;Hardware profile&lt;/th&gt;
&lt;th&gt;Commitment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM&lt;/td&gt;
&lt;td&gt;Catastrophic: leaks P1 XOR P2, enables forgery&lt;/td&gt;
&lt;td&gt;AES-NI + CLMUL fast&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChaCha20-Poly1305&lt;/td&gt;
&lt;td&gt;Catastrophic: same one-time-MAC cliff&lt;/td&gt;
&lt;td&gt;Constant-time in software&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-CCM&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;td&gt;All-AES, tiny footprint&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV&lt;/td&gt;
&lt;td&gt;Graceful: leaks message equality only&lt;/td&gt;
&lt;td&gt;AES-NI + CLMUL&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-SIV&lt;/td&gt;
&lt;td&gt;Graceful: leaks message equality only&lt;/td&gt;
&lt;td&gt;All-AES, two-pass&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCB3&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;td&gt;Fast one-pass software&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEGIS&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;td&gt;AES round function, fastest&lt;/td&gt;
&lt;td&gt;Not fully committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ascon-AEAD128&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;td&gt;A few thousand gates&lt;/td&gt;
&lt;td&gt;Committing from the sponge, no transform&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Read down the commitment column and the reckoning of Section 5 gets sharper than a flat &quot;nobody commits.&quot; Every deployed CTR, stream, and welded construction -- AES-GCM, ChaCha20-Poly1305, AES-CCM, the SIV family, and OCB3 -- is non-committing by default, which is exactly what the salamander and the portfolio-wide context-discovery attacks exploit [@dodis2018-salamander][@menda2023]. Two constructions break the pattern, and it is no accident that both fuse the tag with the cipher state instead of bolting on a separate hash: AEGIS partially commits through tag length, and Ascon commits natively from its sponge [@aegis-draft18][@rfc9771]. So commitment is not a uniform failure across the portfolio -- the commitment edge is a real axis of variation, with Ascon at the strong end, AEGIS in between, and the CTR, stream, and welded modes needing a bolt-on transform. Read the nonce column and only the SIV family survives a repeat, and only by leaking equality [@rfc8452]. The second table adds the structural and performance facts you need once the edges are settled.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;Passes / parallel&lt;/th&gt;
&lt;th&gt;Online state&lt;/th&gt;
&lt;th&gt;Nonce&lt;/th&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Reported speed&lt;/th&gt;
&lt;th&gt;Inverse-free?&lt;/th&gt;
&lt;th&gt;Best suited for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM&lt;/td&gt;
&lt;td&gt;1 pass, parallel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;~1 cpb with AES-NI&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;The default, server and client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChaCha20-Poly1305&lt;/td&gt;
&lt;td&gt;1 pass&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Fast in pure software&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Targets without AES hardware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-CCM&lt;/td&gt;
&lt;td&gt;2 pass, serial&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;7 to 13 byte&lt;/td&gt;
&lt;td&gt;128-bit (&lt;code&gt;CCM_8&lt;/code&gt;: 64)&lt;/td&gt;
&lt;td&gt;Modest&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Constrained stacks, WPA2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV&lt;/td&gt;
&lt;td&gt;2 pass&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt; buffered&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;~0.92 cpb on Broadwell&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Nonce-reuse risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-SIV&lt;/td&gt;
&lt;td&gt;2 pass&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt; buffered&lt;/td&gt;
&lt;td&gt;None or supplied&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Modest&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Key wrap, deterministic AE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCB3&lt;/td&gt;
&lt;td&gt;1 pass, parallel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;up to 120-bit&lt;/td&gt;
&lt;td&gt;up to 128-bit&lt;/td&gt;
&lt;td&gt;Fast in software&lt;/td&gt;
&lt;td&gt;No (needs AES decrypt)&lt;/td&gt;
&lt;td&gt;Elegance (now patent-clear)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEGIS&lt;/td&gt;
&lt;td&gt;1 pass, parallel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;128 or 256-bit&lt;/td&gt;
&lt;td&gt;128 or 256-bit&lt;/td&gt;
&lt;td&gt;~0.48 cpb (AEGIS-128L)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Maximum throughput, both endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ascon-AEAD128&lt;/td&gt;
&lt;td&gt;1 pass&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Small, not server-fast&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;New constrained designs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Reported speeds are platform-dependent and should be read against live cross-platform benchmarks rather than a single headline number; the AEGIS and GCM-SIV figures come from their design papers, and the ECRYPT benchmarking project tracks the rest across many CPUs [@wu2013-aegis][@gl2015-gcmsiv][@bench-aead]. One column earns a second look: OCB3 is the only full-treatment construction that is &lt;em&gt;not&lt;/em&gt; inverse-free, so it alone needs the AES decrypt circuit in hardware -- the honest cost behind its elegance [@rfc7253].&lt;/p&gt;
&lt;p&gt;The tables classify. To &lt;em&gt;choose&lt;/em&gt;, turn them into a procedure. The flowchart below is the thesis rendered as a decision tree: branch on the nonce guarantee first (it is the edge that fails hardest), then on hardware, and treat commitment as an orthogonal final step because no default provides it.&lt;/p&gt;

flowchart TD
    Q1{&quot;Can you guarantee a unique nonce per key?&quot;}
    Q1 --&amp;gt;|No| SIV[&quot;AES-GCM-SIV: move on the nonce edge&quot;]
    Q1 --&amp;gt;|Yes| Q2{&quot;AES-NI and CLMUL on both endpoints?&quot;}
    Q2 --&amp;gt;|Yes| GCM[&quot;AES-GCM&quot;]
    Q2 --&amp;gt;|No| Q2b{&quot;Server or mobile software, or a constrained device?&quot;}
    Q2b --&amp;gt;|Software| CC[&quot;ChaCha20-Poly1305&quot;]
    Q2b --&amp;gt;|Constrained| ASC[&quot;Ascon-AEAD128&quot;]
    SIV --&amp;gt; Q3{&quot;Must one ciphertext bind to exactly one key?&quot;}
    GCM --&amp;gt; Q3
    CC --&amp;gt; Q3
    ASC --&amp;gt; Q3
    Q3 --&amp;gt;|Yes| ADD[&quot;Add a key-commitment transform, unless it already commits like Ascon&quot;]
    Q3 --&amp;gt;|No| DONE[&quot;Ship it&quot;]
&lt;p&gt;The argument is now explicit and testable. &quot;Which AEAD?&quot; reduces to &quot;which edge can your deployment &lt;em&gt;guarantee&lt;/em&gt; it never triggers?&quot; If you cannot guarantee nonce uniqueness, move right on the nonce edge to the SIV family. If you have no AES hardware, move on the hardware edge to ChaCha20-Poly1305 or, for a constrained device, Ascon. If a ciphertext must bind to exactly one key, you must &lt;em&gt;add&lt;/em&gt; something on the commitment edge, because none of the defaults gives it to you. You can even write the function down.&lt;/p&gt;
&lt;p&gt;{`
// &quot;Which AEAD?&quot; is a function of three edges, not a ranking.
function chooseAEAD({ nonceUnique, hasAesHardware, constrained, mustCommitToKey }) {
  let pick;
  if (!nonceUnique) {
    pick = &apos;AES-GCM-SIV&apos;;        // edge 1: cannot guarantee unique nonces
  } else if (hasAesHardware) {
    pick = &apos;AES-GCM&apos;;            // the internet default when AES-NI + CLMUL are present
  } else if (constrained) {
    pick = &apos;Ascon-AEAD128&apos;;      // edge 2: no AES hardware, only a few thousand gates
  } else {
    pick = &apos;ChaCha20-Poly1305&apos;;  // edge 2: no AES hardware, constant-time in software
  }
  // edge 3 is orthogonal: most picks do not commit, so you must ADD a transform --
  // except Ascon, which already commits natively from its sponge (RFC 9771).
  const alreadyCommits = pick === &apos;Ascon-AEAD128&apos;;
  return (mustCommitToKey &amp;amp;&amp;amp; !alreadyCommits)
    ? pick + &apos; + key-commitment transform (this construction does not bind to one key)&apos;
    : pick;
}&lt;/p&gt;
&lt;p&gt;console.log(chooseAEAD({ nonceUnique: true,  hasAesHardware: true,  constrained: false, mustCommitToKey: false }));
console.log(chooseAEAD({ nonceUnique: false, hasAesHardware: true,  constrained: false, mustCommitToKey: false }));
console.log(chooseAEAD({ nonceUnique: true,  hasAesHardware: false, constrained: false, mustCommitToKey: false }));
console.log(chooseAEAD({ nonceUnique: true,  hasAesHardware: true,  constrained: false, mustCommitToKey: true  }));
`}&lt;/p&gt;

&quot;Which AEAD should I use?&quot; is not a ranking from worst to best. It is a function: pick the one whose failure mode your deployment can guarantee it will never trigger.
&lt;p&gt;The table tells you which edge to move. It does not tell you why you sometimes &lt;em&gt;cannot&lt;/em&gt; move all of them at once -- why there is no row that is graceful on reuse &lt;em&gt;and&lt;/em&gt; single-pass &lt;em&gt;and&lt;/em&gt; fully committing &lt;em&gt;and&lt;/em&gt; fastest. That absence is not a gap in the engineering. It is a theorem.&lt;/p&gt;
&lt;h2&gt;8. The Limits Are Theorems&lt;/h2&gt;
&lt;p&gt;Everything so far has been a design choice: move an edge here, pay for it there. Now the hard walls -- the places where no cleverness helps, because a proof says so. There are four, and each maps to an edge; the standard graduate references develop these bounds in full [@boneh-shoup][@katz-lindell].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GCM&apos;s two ceilings, correctly attributed (the nonce edge).&lt;/strong&gt; GCM&apos;s two limits from SP 800-38D are not conservative engineering guesses; they are where the security proof runs out -- and they come from two &lt;em&gt;different&lt;/em&gt; mechanisms people constantly merge into one.&lt;/p&gt;
&lt;p&gt;The per-message limit of $2^{39}-256$ bits (about 64 GiB) is &lt;strong&gt;32-bit counter-mode block-space exhaustion&lt;/strong&gt;, not a GHASH property: with a 96-bit nonce GCM forms the initial counter block $J_0 = \mathrm{IV} \parallel 0^{31} \parallel 1$, the increment function advances only the low 32 bits, so counter mode emits at most $2^{32}-2$ keystream blocks, and $(2^{32}-2)\times 128$ bits $= 2^{39}-256$ bits; exceed it and the counter wraps, repeating a keystream block -- a two-time pad (SP 800-38D Section 5.2.1.1) [@sp80038d].&lt;/p&gt;
&lt;p&gt;The per-key cap of roughly $2^{32}$ messages under random 96-bit nonces is a different quantity entirely: the birthday bound on nonce collision, where with $q$ messages the probability of a repeat scales as $q^2 / 2^{96}$, so $q \approx 2^{32}$ keeps it negligible (SP 800-38D Section 8.3) [@sp80038d]. Hoang, Tessaro, and Thiruvengadam proved these multi-user bounds tight, validating the nonce-randomization mechanism TLS 1.3 uses [@htt2018-gcm].&lt;/p&gt;
&lt;p&gt;Tag length obeys its own bound: for a one-time Wegman-Carter MAC, forgery probability grows with the number of attempts and shrinks with tag length -- exactly why a 64-bit &lt;code&gt;CCM_8&lt;/code&gt; tag is a genuine, quantifiable forgery budget rather than a free optimization [@rfc3610].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Misuse-resistance cannot be online (the nonce edge, again).&lt;/strong&gt; This is the deepest limit in the article, and it explains a design decision that otherwise looks like laziness. Rogaway and Shrimpton proved that a deterministic, nonce-misuse-resistant AEAD &lt;em&gt;cannot&lt;/em&gt; be online or single-pass [@rs2006]. The reason is forced by the definition: to be misuse-resistant, the ciphertext must depend on the &lt;em&gt;entire&lt;/em&gt; plaintext (otherwise two messages sharing a prefix under a repeated nonce would leak that prefix), so the encryptor cannot emit even the first ciphertext byte until it has read the last plaintext byte. There is no implementation trick around it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; You cannot have both streaming and misuse-resistance. It is a theorem, not a missing feature: a misuse-resistant AEAD must read the whole message before it can output any ciphertext. That single impossibility is &lt;em&gt;why&lt;/em&gt; AES-GCM-SIV is two-pass, and why &quot;just make GCM misuse-resistant without slowing it down&quot; is a request for something that provably does not exist [@rs2006].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Commitment is an orthogonal axis (the commitment edge).&lt;/strong&gt; A conventional CTR-based AEAD like GCM is provably not key-committing -- the property is simply absent from &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-/&quot; rel=&quot;noopener&quot;&gt;IND-CPA and INT-CTXT&lt;/a&gt;, so no amount of using GCM &quot;correctly&quot; produces it. Worse, commitment is not one property but a lattice: Bellare and Hoang proved CMT-1 (bind to the key) does not imply CMT-4 (bind to the full context), a separation RFC 9771 later codified [@bh2022-commit][@rfc9771].&lt;/p&gt;
&lt;p&gt;And the attacks are cheaper than the naive birthday intuition suggests: Menda and coauthors found context-discovery attacks against CCM, EAX, SIV, GCM, and OCB3, including an $O(2^{n/3})$ attack on SIV using Wagner&apos;s k-tree algorithm -- well below the $2^{n/2}$ a birthday bound would suggest [@menda2023].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Releasing plaintext early is a strictly weaker world (all edges).&lt;/strong&gt; The fourth limit is about what your decrypt function is allowed to do before it finishes.&lt;/p&gt;

What an implementation exposes if it emits decrypted plaintext before checking the authentication tag. The formal integrity notion for this setting, INT-RUP, is codified in RFC 9771 Section 4.3.10; security that survives releasing unverified plaintext is strictly stronger than standard AEAD security, and most fast one-pass modes satisfy it only weakly -- which is why the safe API contract is verify-then-release: never act on plaintext until the tag checks out [@rfc9771].
&lt;p&gt;Now assemble the thought experiment. Imagine the ideal AEAD: graceful on nonce reuse &lt;em&gt;and&lt;/em&gt; fully committing &lt;em&gt;and&lt;/em&gt; online/single-pass &lt;em&gt;and&lt;/em&gt; fastest at both the server and constrained extremes. The second limit rules out &quot;misuse-resistant and online&quot; together. The third makes commitment an add-on that the CTR, stream, and welded defaults lack -- Ascon, uniquely, commits natively. The performance extremes pull in opposite directions -- AES round function for servers, a few thousand gates for sensors. You cannot have all of it in one construction, and this is not because nobody has been clever enough. It is because the properties provably conflict.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; No single construction closes all three edges at once. That is not a temporary state of the art -- it is a set of theorems about online-ness, commitment, and hardware. The portfolio is not a failure to converge on a winner; it is the mathematically necessary shape of the solution [@rs2006][@bh2022-commit].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So that is settled, provably. Which turns the interesting question inside out. Not &quot;which mode wins?&quot; but &quot;can we make the &lt;em&gt;robustness&lt;/em&gt; the default instead of the expert&apos;s opt-in?&quot; That is exactly where the field is fighting right now.&lt;/p&gt;
&lt;h2&gt;9. Where AEAD Still Bites&lt;/h2&gt;
&lt;p&gt;The classical problem is closed. For confidentiality and integrity, the bounds are tight and the constructions are vetted. The entire live frontier is about robustness: turning the properties nobody used to ask for into defaults nobody has to remember. Six problems are open, and every one of them has the same shape.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Committing AEAD by default.&lt;/strong&gt; Salamanders and partitioning oracles still bite wherever a committing transform is omitted, which today means almost everywhere [@dodis2018-salamander][@len2021-partition]. The frustrating part is that the fix is cheap: Bellare and Hoang give transforms that add full commitment with no ciphertext-size increase, and Albertini and coauthors give a padding-based alternative [@bh2022-commit][@albertini2022]. Yet as of mid-2026, none is &lt;em&gt;mandated&lt;/em&gt; by a shipping standard. RFC 9771 gives the field a shared vocabulary for the property but does not require any construction to have it [@rfc9771]. The open question is not &quot;how?&quot; but &quot;why is it still opt-in?&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Misuse-resistance by default.&lt;/strong&gt; If nonce reuse is a recurring operational reality, why is the misuse-resistant mode the escalation rather than the default? The answer is the theorem from Section 8: defaulting to SIV means defaulting to two-pass, non-streaming encryption, and a great deal of infrastructure assumes it can encrypt a stream as it arrives [@rs2006]. Whether that trade is worth making by default is an active argument, not a settled one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The release-of-unverified-plaintext trade space.&lt;/strong&gt; Between &quot;buffer everything and verify first&quot; and &quot;stream plaintext out immediately&quot; is a design space that streaming media, large-file transfer, and constrained receivers all care about, and the security definitions there -- INT-RUP and its relatives -- are still maturing [@rfc9771].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hardware co-design versus conservative margin.&lt;/strong&gt; AEGIS already beats AES-GCM on AES-NI hardware, and the appetite for line-rate encryption keeps growing [@wu2013-aegis]. Newer AES-round designs push the throughput frontier even higher, but they trade cryptanalytic maturity for speed, and their standardization status is unsettled -- AEGIS itself is still only an Internet-Draft, not an RFC [@aegis-draft18]. How much margin to spend for how much throughput is an open judgment call.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/post-quantum-cryptography-on-windows-the-thirty-year-migrati/&quot; rel=&quot;noopener&quot;&gt;Post-quantum reality&lt;/a&gt;, minus the myth.&lt;/strong&gt; This one is mostly a matter of correcting a widespread misconception.&lt;/p&gt;

For symmetric authenticated encryption the honest answer is: no, and you mostly need to change nothing. Grover&apos;s algorithm offers at most a square-root speedup on key search, which halves the effective key length [@grover1996], so a 128-bit key gives about 64 bits of margin against a hypothetical quantum attacker. The remedy is simply to prefer 256-bit keys -- ChaCha20 already uses one, and AES-256 is a configuration flag -- and to size tags with a margin. The post-quantum upheaval lives in key exchange and signatures, not the AEAD record layer, as developed in the post-quantum-cryptography-on-Windows post in this collection. Your record encryption survives the transition largely intact.
&lt;p&gt;&lt;strong&gt;Constant-time without special hardware.&lt;/strong&gt; GHASH is hard to implement in constant time without CLMUL, and table-based AES leaks timing without AES-NI -- the exact side-channel pressure that motivated both ChaCha20-Poly1305 and Ascon [@bernstein-chacha][@ascon2021]. On the smallest devices, where neither special instruction exists and power analysis is a live threat, side-channel-resistant AEAD is still an open engineering problem, and it is much of the reason NIST ran a lightweight competition at all.&lt;/p&gt;
&lt;p&gt;None of these has a finished answer. But notice the shape of every one: they are all attempts to move an &lt;em&gt;edge&lt;/em&gt; to a place where the deployer cannot step on it by mistake -- misuse-resistance you do not have to remember, commitment you do not have to add, side-channel safety you do not have to hand-tune. Which brings us back to the only rule that actually travels.&lt;/p&gt;
&lt;h2&gt;10. The Field Guide: Rules and Parameters&lt;/h2&gt;
&lt;p&gt;Everything above collapses into one default and a short list of deliberate escalations. Follow the ladder and you will never again pick an AEAD by folklore.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Default to &lt;strong&gt;AES-GCM&lt;/strong&gt; with a 96-bit nonce that is unique per key (prefer a counter over a random value), a hard cap well under $2^{32}$ messages per key, at most 64 GiB per message, and a full 128-bit tag. Use &lt;strong&gt;ChaCha20-Poly1305&lt;/strong&gt; under the same contract when you lack AES hardware. Leave the default only when a specific edge forces you, and only in the direction that edge points [@sp80038d][@rfc8439].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The escalation ladder, each rung mapped to the edge it moves:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cannot guarantee a unique nonce?&lt;/strong&gt; Escalate on the nonce edge to &lt;strong&gt;AES-GCM-SIV&lt;/strong&gt; [@rfc8452]. Cloned VMs, counters that reset on crash, weak first-boot entropy -- if any of these is in your threat model, the graceful failure is worth the second pass.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A stack mandates it, or the device is tiny?&lt;/strong&gt; Use &lt;strong&gt;AES-CCM&lt;/strong&gt; where WPA2, BLE, or Zigbee require it [@rfc3610], and &lt;strong&gt;Ascon-AEAD128&lt;/strong&gt; for &lt;em&gt;new&lt;/em&gt; constrained designs, now that it is a NIST standard [@sp800232].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deterministic encryption or key wrapping?&lt;/strong&gt; Use &lt;strong&gt;AES-SIV&lt;/strong&gt;, which needs no nonce at all and is built for exactly this [@rfc5297].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You want one-pass, single-primitive elegance?&lt;/strong&gt; &lt;strong&gt;OCB3&lt;/strong&gt; is now patent-clear, though rarely the right call given how entrenched the defaults are [@rfc7253][@kr2021-ocb].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You control both endpoints and need maximum throughput?&lt;/strong&gt; &lt;strong&gt;AEGIS&lt;/strong&gt; is the fastest option, if you can accept a pre-RFC specification [@aegis-draft18][@wu2013-aegis].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Must a ciphertext bind to exactly one key?&lt;/strong&gt; &lt;em&gt;Add&lt;/em&gt; a key-commitment transform -- for password-based encryption, key rotation, message franking, or multi-recipient encryption -- because no default provides it [@bh2022-commit].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://paragmali.com/blog/predictable-or-repeated-the-only-two-ways-cryptographic-rand/&quot; rel=&quot;noopener&quot;&gt;Nonce generation&lt;/a&gt; itself is the subject of Part 2 of this series; do not re-derive it here, but do treat &quot;unique per key&quot; as a hard contract, not a hope. On Windows, the &lt;a href=&quot;https://paragmali.com/blog/cng-architecture-bcrypt-ncrypt-ksps/&quot; rel=&quot;noopener&quot;&gt;CNG architecture&lt;/a&gt; post in this collection shows AES-GCM exposed through the &lt;code&gt;BCryptEncrypt&lt;/code&gt; API with an authenticated-cipher-mode information structure -- a concrete example of the parameters below appearing in a real API.&lt;/p&gt;
&lt;p&gt;Pair the ladder with the support map from Section 6 when you check feasibility: browser JavaScript means AES-GCM through WebCrypto, and a target with no AES hardware means ChaCha20-Poly1305 or, if it is also tiny, Ascon-AEAD128 [@webcrypto].&lt;/p&gt;
&lt;p&gt;The exact operational contract, per construction:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;Nonce&lt;/th&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Per-key limit&lt;/th&gt;
&lt;th&gt;Per-message limit&lt;/th&gt;
&lt;th&gt;On nonce reuse&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM&lt;/td&gt;
&lt;td&gt;96-bit, unique&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;~`2^32` msgs (random nonce)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2^39 - 256&lt;/code&gt; bits, ~64 GiB&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChaCha20-Poly1305&lt;/td&gt;
&lt;td&gt;96-bit, unique&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;~`2^32` msgs (random nonce)&lt;/td&gt;
&lt;td&gt;~256 GiB&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-CCM&lt;/td&gt;
&lt;td&gt;7 to 13 byte&lt;/td&gt;
&lt;td&gt;up to 128-bit (&lt;code&gt;CCM_8&lt;/code&gt;: 64)&lt;/td&gt;
&lt;td&gt;Set by nonce length&lt;/td&gt;
&lt;td&gt;Set by length field&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Improved (per-nonce derived keys)&lt;/td&gt;
&lt;td&gt;~64 GiB&lt;/td&gt;
&lt;td&gt;Graceful: message equality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-SIV&lt;/td&gt;
&lt;td&gt;None or supplied&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;Graceful: message equality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCB3&lt;/td&gt;
&lt;td&gt;up to 120-bit&lt;/td&gt;
&lt;td&gt;up to 128-bit&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEGIS&lt;/td&gt;
&lt;td&gt;128 or 256-bit&lt;/td&gt;
&lt;td&gt;128 or 256-bit&lt;/td&gt;
&lt;td&gt;Large (wide nonce)&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ascon-AEAD128&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Per SP 800-232&lt;/td&gt;
&lt;td&gt;Per SP 800-232&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The only two numeric limits you must hard-code are GCM&apos;s, because they are the ones people breach silently: cap messages per key well under $2^{32}$ and messages under 64 GiB each [@sp80038d]. ChaCha20-Poly1305&apos;s own ~256 GiB per-message ceiling comes the same way, from its 32-bit block counter over 64-byte blocks ($2^{32}\times 64$ bytes $= 2^{38}$ bytes), per RFC 8439 [@rfc8439]. AES-GCM-SIV&apos;s per-nonce key derivation buys better multi-user bounds, which is the whole reason RFC 8452 derives fresh keys rather than reusing one [@bht2018][@rfc8452].&lt;/p&gt;
&lt;p&gt;Every rung of that ladder has a mirror image: a misuse pattern that punishes the deployment for stepping on the edge it ignored. Each row below maps a real-code mistake to the named break that catches it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Misuse seen in real code&lt;/th&gt;
&lt;th&gt;Edge it triggers&lt;/th&gt;
&lt;th&gt;Named break&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Reusing a &lt;code&gt;(key, nonce)&lt;/code&gt; in GCM or AEGIS&lt;/td&gt;
&lt;td&gt;Nonce&lt;/td&gt;
&lt;td&gt;Nonce-Disrespecting Adversaries, 2016&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assuming an AEAD binds a ciphertext to one key&lt;/td&gt;
&lt;td&gt;Commitment&lt;/td&gt;
&lt;td&gt;Invisible salamanders; partitioning oracles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Truncating the tag to save bytes (&lt;code&gt;CCM_8&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Integrity budget&lt;/td&gt;
&lt;td&gt;Wegman-Carter forgery bound&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Treating AES-GCM-SIV reuse as &quot;free&quot;&lt;/td&gt;
&lt;td&gt;Nonce&lt;/td&gt;
&lt;td&gt;SIV leaks message equality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hand-rolling Encrypt-and-MAC&lt;/td&gt;
&lt;td&gt;Composition&lt;/td&gt;
&lt;td&gt;Bellare-Namprempre; Krawczyk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conflating GCM&apos;s two ceilings&lt;/td&gt;
&lt;td&gt;Nonce&lt;/td&gt;
&lt;td&gt;The two SP 800-38D limits&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The evidence for each is in the sections above: nonce reuse on live servers [@bock2016], the salamander and its weaponization [@dodis2018-salamander][@len2021-partition], the tag-length forgery budget [@rfc3610], the SIV equality leak [@rfc8452], the composition theorems [@bn2000][@krawczyk2001], and the two ceilings [@sp80038d]. One extra caution on attribution: the live-TLS nonce-reuse break is repeatedly mis-cited to CVE-2016-0270, which actually names IBM Domino and which the NVD itself flags as commonly misapplied to other products [@cve-2016-0270].&lt;/p&gt;

Search your codebase for any AEAD decryption that runs under an attacker-influenced key: password-based encryption, key wrapping, token decryption, or multi-recipient envelopes. If a decrypt path lets the caller supply or guess the key and then branches on whether decryption succeeded, you are exposed to a partitioning oracle and need a key-commitment transform on top of the AEAD [@len2021-partition][@bh2022-commit].
&lt;p&gt;That ladder is your inoculation against folklore. But folklore is sticky, so let us take the most common misconceptions head-on.&lt;/p&gt;
&lt;h2&gt;11. Seven Beliefs That Get Deployments Broken&lt;/h2&gt;


No. For every nonce-respecting mode -- AES-GCM, ChaCha20-Poly1305, AES-CCM, OCB3, AEGIS, and Ascon -- a single repeated `(key, nonce)` is an immediate, total break: it leaks the XOR of the two plaintexts, and a second collision hands over the authentication subkey for universal forgery [@joux2006][@bock2016]. Only the SIV family degrades gracefully, and only to leaking message equality [@rfc8452].


No. It makes reuse *survivable*, not free. A repeated nonce still leaks message equality -- an attacker learns that two ciphertexts encrypt the same plaintext -- which can matter a great deal in the right context. Use it as a safety net, not a license to stop managing nonces [@rfc8452][@rs2006].


No to both misreadings. It is a different trade-off on the hardware edge, not a weaker cipher: constant-time in pure software with no lookup tables, which makes it the *stronger* choice on hardware without AES-NI, where table-based AES leaks timing. And it is not mandatory-to-implement in TLS 1.3 -- it is a *recommended* (SHOULD) cipher suite, while only AES-128-GCM is the MUST, per RFC 8446 Section 9.1 [@rfc8446]. Recommended, not weaker, not mandatory.


No. Random 96-bit nonces are collision-safe only up to roughly $2^{32}$ messages per key, by the birthday bound. That per-key invocation cap is a different number from the per-message limit of about 64 GiB; enforce both, and prefer a counter over a random nonce when you can [@sp80038d][@htt2018-gcm].


No. Most AEADs are not key-committing. One AES-GCM ciphertext can be built to decrypt to two different meaningful plaintexts under two different keys, with the tag valid both times -- the invisible-salamanders result. If a ciphertext must bind to one key, add a commitment transform [@dodis2018-salamander][@bh2022-commit].


No. AEGIS leads on raw throughput, but it is nonce-respecting (catastrophic on reuse), not fully key-committing, and still an active Internet-Draft rather than an RFC -- it states plainly that it &quot;is not a standard&quot; and expires on 8 April 2026. Fastest is not the same as best for your deployment [@aegis-draft18][@wu2013-aegis].


No. Symmetric authenticated encryption survives the quantum transition. Grover&apos;s algorithm only halves effective key length [@grover1996], so prefer 256-bit keys and size tags with margin. The post-quantum upheaval is in key exchange and signatures, not the AEAD record layer. Separately, note that NIST&apos;s Ascon-AEAD128 is a tweaked variant of the CAESAR Ascon-128, not byte-identical [@sp800232].

&lt;h2&gt;The Function, Not the Ranking&lt;/h2&gt;
&lt;p&gt;Seven ciphers, one interface, three edges. Every break here was a deployment triggering an edge its designers deliberately moved elsewhere. The invisible salamanders triggered the commitment edge that AEAD never promised to close [@dodis2018-salamander]. The 184 TLS servers triggered the nonce edge that GHASH cannot survive [@bock2016]. The &lt;code&gt;CCM_8&lt;/code&gt; forgery budget is the tag-length edge priced in bits [@rfc3610]. The SIV equality leak is the residue of the one edge SIV &lt;em&gt;does&lt;/em&gt; close -- even the fix has a seam [@rfc8452]. And OCB3&apos;s near-total absence is the patent grave, an edge that was never technical at all [@kr2021-ocb].&lt;/p&gt;
&lt;p&gt;Put them together and the thesis is earned rather than asserted. &quot;Which AEAD should I use?&quot; is not a ranking from worst to best, because Section 8 proved there is no best -- no single construction can be misuse-resistant &lt;em&gt;and&lt;/em&gt; single-pass &lt;em&gt;and&lt;/em&gt; fully committing &lt;em&gt;and&lt;/em&gt; fastest at once. It is a function: pick the construction whose failure mode your deployment can &lt;em&gt;guarantee&lt;/em&gt; it will never trigger.&lt;/p&gt;
&lt;p&gt;Master the three edges and you can place any construction on the map, predict any misuse before it ships, and evaluate whatever the next competition invents -- key-derivation-bound AEADs, the TLS record layer&apos;s next mode, or a lightweight winner that does not exist yet. The names will change. The edges will not.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;the-aead-decision-matrix&quot; keyTerms={[
  { term: &quot;AEAD&quot;, definition: &quot;One keyed call giving confidentiality, plaintext integrity, and associated-data integrity&quot; },
  { term: &quot;Associated Data&quot;, definition: &quot;Header bytes authenticated but not encrypted, travelling in the clear&quot; },
  { term: &quot;Nonce&quot;, definition: &quot;A value that must be unique per key for a nonce-respecting mode&quot; },
  { term: &quot;MRAE&quot;, definition: &quot;Misuse-resistant AE, where nonce reuse leaks only message equality&quot; },
  { term: &quot;Wegman-Carter one-time MAC&quot;, definition: &quot;A tag of the form keyed-hash plus one-time mask, the shared root of GHASH and Poly1305&quot; },
  { term: &quot;GHASH&quot;, definition: &quot;GCM&apos;s linear universal hash at a secret point, recovering which forges tags&quot; },
  { term: &quot;Synthetic IV (SIV)&quot;, definition: &quot;An IV derived as a MAC of the whole message, so the tag is the IV&quot; },
  { term: &quot;Key commitment&quot;, definition: &quot;Binding a ciphertext to one key (CMT-1) up to the full context (CMT-4)&quot; },
  { term: &quot;Sponge&quot;, definition: &quot;One permutation that absorbs input and squeezes keystream and tag, as in Ascon&quot; },
  { term: &quot;Inverse-free&quot;, definition: &quot;A decryption path that never calls the block-cipher inverse, true of the CTR, stream, and sponge modes but not OCB3&quot; },
  { term: &quot;RUP&quot;, definition: &quot;Release of Unverified Plaintext, emitting plaintext before the tag is checked&quot; }
]} questions={[
  { q: &quot;What are the three edges that decide an AEAD choice?&quot;, a: &quot;The nonce contract, the performance and hardware profile, and commitment.&quot; },
  { q: &quot;Why is a repeated nonce catastrophic in AES-GCM?&quot;, a: &quot;It reuses the one-time Wegman-Carter mask, leaking the plaintext XOR and, with a second collision, the GHASH subkey for forgery.&quot; },
  { q: &quot;Why can a misuse-resistant AEAD not be single-pass?&quot;, a: &quot;Its ciphertext must depend on the whole message, so it must read the last plaintext byte before emitting any ciphertext, a Rogaway-Shrimpton theorem.&quot; },
  { q: &quot;Does authenticated mean a ciphertext binds to one key?&quot;, a: &quot;No. Commitment is an orthogonal axis, and most AEADs are not key-committing by default.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>aead</category><category>authenticated-encryption</category><category>aes-gcm</category><category>chacha20-poly1305</category><category>nonce-misuse</category><category>key-commitment</category><category>applied-cryptography</category><category>cryptography</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>One Number, Used Twice: How a Repeated Nonce Hands Over Your Private Key -- and How Determinism Takes It Back</title><link>https://paragmali.com/blog/one-number-used-twice-how-a-repeated-nonce-hands-over-your-p/</link><guid isPermaLink="true">https://paragmali.com/blog/one-number-used-twice-how-a-repeated-nonce-hands-over-your-p/</guid><description>A repeated ECDSA nonce leaks your private key with grade-school algebra; a reused AES-GCM IV forges ciphertext. Why -- and how determinism fixes both.</description><pubDate>Thu, 09 Jul 2026 10:13:36 GMT</pubDate><content:encoded>
Reuse one number and you can lose everything. A **repeated** ECDSA signing nonce leaks your private key with grade-school algebra: two signatures under the same nonce, one subtraction, one modular inverse, and the key falls out. That is how the Sony PlayStation 3 master key was recovered [@f0f]. A **repeated** AES-GCM initialization vector is just as fatal: it instantly leaks $P_1 \oplus P_2$ and hands an attacker the material to forge authenticated ciphertext [@joux] [@nda]. The fix for both is one counter-intuitive move: stop trusting runtime randomness for the once-per-operation number. Derive it (RFC 6979, EdDSA, hedged signatures) [@rfc6979] [@rfc8032], or make a repeat non-catastrophic (AES-GCM-SIV) [@rfc8452]. One distinction separates understanding from folklore: a *biased* nonce is a *different*, statistical attack needing many signatures, not one [@ns] [@ladderleak].
&lt;h2&gt;1. One Number, Used Twice&lt;/h2&gt;
&lt;p&gt;In December 2010, on stage at the 27th Chaos Communication Congress in Berlin, three researchers working under the name fail0verflow explained how they had recovered the master private key that anchors the entire PlayStation 3 chain of trust [@f0f]. There was no brute force, no exotic side channel, no supercomputer grinding for months. There were two signatures and the kind of algebra you learned before you were old enough to drive. Sony had signed its code with ECDSA, the elliptic-curve digital signature algorithm, and Sony had signed &lt;em&gt;every&lt;/em&gt; firmware image with the &lt;em&gt;same&lt;/em&gt; secret per-signature number.Two events that are often merged into one: fail0verflow &lt;em&gt;disclosed&lt;/em&gt; the constant-nonce flaw at 27C3 in December 2010; George Hotz, known as geohot, &lt;em&gt;separately&lt;/em&gt; published an extracted PS3 root key in January 2011 [@geohot]. The talk revealed the mechanism; the key release came afterward. Keep them distinct.&lt;/p&gt;
&lt;p&gt;Sit with how strange that is. The console&apos;s security rested on a signature scheme that most cryptographers would call sound. AES was not broken. The elliptic curve was not broken. The signature math was not broken. One input was reused, and the entire trust anchor fell out of a schoolbook manipulation that a motivated teenager could reproduce on paper.&lt;/p&gt;
&lt;p&gt;Now the mirror image, in a completely different primitive. In 2016, a team scanning the live internet found 184 public HTTPS servers repeating a different one-time number -- the AES-GCM initialization vector -- and reported that this &quot;fully breaks the authenticity of the connections&quot; [@nda]. Not the confidentiality of a lab toy: the authenticity of real TLS sessions on the open web, letting an attacker forge messages the server would accept as genuine.&lt;/p&gt;
&lt;p&gt;Same disease, entirely different organ. One is a signature that proves who you are; the other is the cipher that guards most of the web&apos;s traffic. Both staked everything on a number that was supposed to be used correctly exactly once.&lt;/p&gt;
&lt;p&gt;That shared bet is the subject of this article. Both primitives depend, silently, on a value that must be unique and unpredictable -- once, per key. The precise question: &lt;em&gt;what, exactly, does each stake on that number, and what is the exact cost of getting it wrong?&lt;/em&gt; For the repeat case, the answer is total and immediate -- and the algebra is short enough to print in full.&lt;/p&gt;

In cryptography, reusing one number can cost you everything.
&lt;p&gt;That is the punchline, and by the end you will have earned it rather than taken it on faith -- the full key-recovery algebra, Antoine Joux&apos;s cipher attack, the statistical cousin that needs only a &lt;em&gt;fraction&lt;/em&gt; of a leaked bit, and the deterministic designs that dissolve the whole failure family. But how can &lt;em&gt;two&lt;/em&gt; signatures undo an entire console&apos;s chain of trust? To see it, we first have to meet the number both of these primitives are quietly betting everything on.&lt;/p&gt;
&lt;h2&gt;2. The Secret Number Both Primitives Depend On&lt;/h2&gt;
&lt;p&gt;Two algorithms, designed decades and a world apart -- a discrete-logarithm signature and a &lt;a href=&quot;https://paragmali.com/blog/the-ciphertext-was-unbreakable-the-attacker-rewrote-it-anyw&quot; rel=&quot;noopener&quot;&gt;block-cipher mode of authenticated encryption&lt;/a&gt; -- turn out to share a single point of failure. Before we can watch it break, we need to know where the number comes from and why it has to exist at all.&lt;/p&gt;
&lt;p&gt;The signature side is the older lineage. ElGamal&apos;s 1985 signature scheme introduced a per-signature secret exponent [@elgamal], and when the United States standardized the Digital Signature Algorithm as FIPS 186 in 1994 [@fips186], that per-signature secret came along for the ride. Its elliptic-curve descendant, ECDSA, keeps it. The value is called the signing nonce, written $k$, and it is regenerated fresh for every single signature.&lt;/p&gt;

The per-signature secret scalar in (EC)DSA. For each signature the signer draws a new $k$ in the range $[1, n-1]$, where $n$ is the order of the curve&apos;s base point. It must be unique, secret, and uniformly distributed -- exactly once per key. It is never transmitted, yet every signature is computed from it.
&lt;p&gt;The cipher side is younger. When NIST standardized Galois/Counter Mode in SP 800-38D in 2007, the specification required that the initialization vector -- the $\text{IV}$, GCM&apos;s nonce -- be distinct for every message encrypted under a given key [@sp80038d]. Same structural demand, opposite secrecy requirement: the signing nonce must be secret, while the GCM nonce may be completely public. What both must be is &lt;em&gt;fresh&lt;/em&gt;.&lt;/p&gt;

The per-message value GCM mixes in so that encrypting under a fixed key never repeats its keystream. Uniqueness under a given key -- not secrecy -- is the entire contract. A public counter is a perfectly good GCM nonce; a *repeated* one is a catastrophe.
&lt;p&gt;Now put the two governing equations side by side. An ECDSA signature on a message whose hash (as an integer) is $z$, under private key $d$, is the pair $(r, s)$:&lt;/p&gt;
&lt;p&gt;$$r = (k \cdot G)_x \bmod n, \qquad s = k^{-1},(z + r,d) \bmod n$$&lt;/p&gt;
&lt;p&gt;Here $G$ is the fixed base point, $n$ its prime order, $d$ the private key, and $r$ is the x-coordinate of the curve point $k \cdot G$ reduced modulo $n$. The AES-GCM authentication tag on ciphertext $C$ with additional data $A$ is:&lt;/p&gt;
&lt;p&gt;$$T = E_K(J_0) \oplus \mathrm{GHASH}_H(A, C), \qquad H = E_K(0^{128})$$&lt;/p&gt;
&lt;p&gt;$E_K$ is AES under key $K$; $J_0$ is a pre-counter block derived from the IV; $\mathrm{GHASH}_H$ is a polynomial hash over the field $\mathrm{GF}(2^{128})$ keyed by the secret subkey $H$, which is simply AES applied to the all-zero block.&lt;/p&gt;
&lt;p&gt;Look at what both equations hide inside them. The signing equation multiplies the private key $d$ by the public $r$ and masks it behind $k$. The tag equation masks the keyed hash behind the one-time pad $E_K(J_0)$, which is a deterministic function of the nonce. In each case, one freshly chosen value is the only thing standing between a routine operation and a full disclosure. That gives us the single shared contract, short enough to fit on one line: &lt;strong&gt;the number must be unique and unpredictable, exactly once, per key.&lt;/strong&gt;&lt;/p&gt;

This is the in-depth sequel to [Part 2](/blog/predictable-or-repeated-the-only-two-ways-cryptographic-rand), which surveyed the two ways cryptographic randomness betrays you -- predictability and repetition -- across many primitives at breadth. Part 2 owns the general taxonomy; this post goes deep on two specific victims, the ECDSA nonce and the GCM IV, and derives the exact algebra of each collapse. We will not re-teach the two-knobs framework here; we will spend it.
&lt;p&gt;None of this was a secret to the designers. Bellare, Goldwasser, and Micciancio analyzed the danger of a poorly generated DSA nonce as early as their 1997 CRYPTO paper, &quot;The DSS case&quot; [@bgm], showing that a linear-congruential nonce generator breaks the scheme.Terminology drifts across modes, so fix it now: a &lt;em&gt;nonce&lt;/em&gt; need only be unique (CTR, GCM); an &lt;em&gt;IV&lt;/em&gt; for CBC must additionally be unpredictable; a &lt;em&gt;salt&lt;/em&gt; is unique and public and feeds a KDF. The mode dictates which property is load-bearing. Part 2 and the block-cipher-modes installment work through the distinctions; here we only need &quot;fresh, once, per key.&quot; The contract was understood from the beginning; nobody misunderstood the rule. They simply could not always keep it.&lt;/p&gt;
&lt;p&gt;The contract says &quot;never repeat.&quot; So begin with the crudest possible violation -- the &lt;em&gt;same&lt;/em&gt; number, twice -- and watch precisely how much it costs.&lt;/p&gt;
&lt;h2&gt;3. Two Signatures, One k, and Your Private Key&lt;/h2&gt;
&lt;p&gt;This is the entire thesis compressed into one page of algebra -- no lattice, no side channel, no probability, just subtraction and one division. How little work does &lt;em&gt;complete&lt;/em&gt; key recovery actually take?&lt;/p&gt;
&lt;p&gt;Start from the fact that makes it possible. The first signature component, $r = (k \cdot G)_x \bmod n$, depends only on the nonce $k$ and the fixed public base point $G$. It does not depend on the message. So if you sign two &lt;em&gt;different&lt;/em&gt; messages under the &lt;em&gt;same&lt;/em&gt; $k$, both signatures carry the &lt;em&gt;identical&lt;/em&gt; $r$. That repeated $r$ is the visible tell -- a fingerprint an attacker can spot by scanning a signature log, with no secret knowledge at all.This is exactly what fail0verflow read off the PlayStation 3: every firmware signature carried the same $r$, the public fingerprint of a constant $k$. You do not need to break anything to notice it; you just look for two signatures with a matching first half.&lt;/p&gt;
&lt;p&gt;Now write the two signing equations under that shared $k$:&lt;/p&gt;
&lt;p&gt;$$s_1 = k^{-1}(z_1 + r,d) \pmod n, \qquad s_2 = k^{-1}(z_2 + r,d) \pmod n$$&lt;/p&gt;
&lt;p&gt;Subtract the second from the first. The private key appears only inside the identical $r,d$ term, so it cancels completely:&lt;/p&gt;
&lt;p&gt;$$s_1 - s_2 = k^{-1}\big((z_1 + r,d) - (z_2 + r,d)\big) = k^{-1}(z_1 - z_2) \pmod n$$&lt;/p&gt;
&lt;p&gt;Every quantity on the right except $k$ is public: the two message hashes $z_1, z_2$ and the two signature halves $s_1, s_2$. So solve for the nonce directly:&lt;/p&gt;
&lt;p&gt;$$k = (z_1 - z_2),(s_1 - s_2)^{-1} \bmod n$$&lt;/p&gt;
&lt;p&gt;One subtraction on top, one modular inverse on the bottom. With $k$ in hand, substitute back into the first equation -- multiply through by $k$, subtract $z_1$, and divide by the public $r$:&lt;/p&gt;
&lt;p&gt;$$s_1 k = z_1 + r,d \implies d = (s_1 k - z_1),r^{-1} \bmod n$$&lt;/p&gt;
&lt;p&gt;That is the private key. Count the cost to the attacker: &lt;strong&gt;two&lt;/strong&gt; signatures, a handful of modular operations,Constant work here means a fixed number of field operations, independent of the key size. A 256-bit curve is no harder to break this way than a 160-bit one, because the attack never touches the key&apos;s length. and the recovery is &lt;em&gt;certain&lt;/em&gt; -- not probable, not &quot;on average,&quot; but exact, every time, the moment the repeat occurs. It solves a two-by-two linear system that the reuse handed over for free.&lt;/p&gt;

flowchart TD
    A[&quot;Two signatures made under the same nonce k&quot;] --&amp;gt; B[&quot;They share the same r, because r depends only on k and G&quot;]
    B --&amp;gt; C[&quot;Subtract the two s equations&quot;]
    C --&amp;gt; D[&quot;The r times d term cancels, leaving k as the only unknown&quot;]
    D --&amp;gt; E[&quot;One modular inverse recovers k&quot;]
    E --&amp;gt; F[&quot;Put k back into either s equation&quot;]
    F --&amp;gt; G[&quot;The private key d falls out, with certainty&quot;]
&lt;p&gt;You do not have to take the algebra on faith -- here is the whole attack as runnable code over a toy curve order, recovering the private key from public values alone:&lt;/p&gt;
&lt;p&gt;{`
// Recover the ECDSA private key d from two signatures sharing nonce k.
function egcd(a, b) {
  if (b === 0n) return [a, 1n, 0n];
  const [g, x, y] = egcd(b, a % b);
  return [g, y, x - (a / b) * y];
}
function modInv(a, n) {
  a = ((a % n) + n) % n;
  const [g, x] = egcd(a, n);
  if (g !== 1n) throw new Error(&apos;no inverse&apos;);
  return ((x % n) + n) % n;
}&lt;/p&gt;
&lt;p&gt;const n = 1103n;   // toy prime &quot;curve order&quot; (real curves use ~256-bit n)
const d = 937n;    // the SECRET key the attacker must not know
const k = 421n;    // the reused nonce (identical for both signatures)
const r = 668n;    // r = (k*G).x mod n -- SHARED because k is shared
const z1 = 123n, z2 = 456n;  // two different message hashes&lt;/p&gt;
&lt;p&gt;// Victim signs both messages with the SAME k:
const s1 = (modInv(k, n) * (z1 + r * d)) % n;
const s2 = (modInv(k, n) * (z2 + r * d)) % n;&lt;/p&gt;
&lt;p&gt;// Attacker sees only public (r, s1, z1, s2, z2). Recover k, then d:
const kRec = ((((z1 - z2) % n) + n) % n) * modInv((((s1 - s2) % n) + n) % n, n) % n;
const dRec = ((((s1 * kRec - z1) % n) + n) % n) * modInv(r, n) % n;&lt;/p&gt;
&lt;p&gt;console.log(&apos;shared r    :&apos;, r.toString());
console.log(&apos;recovered k :&apos;, kRec.toString(), &apos;(true k =&apos;, k.toString() + &apos;)&apos;);
console.log(&apos;recovered d :&apos;, dRec.toString(), &apos;(true d =&apos;, d.toString() + &apos;)&apos;);
console.log(dRec === d ? &apos;PRIVATE KEY RECOVERED from two signatures.&apos; : &apos;mismatch&apos;);
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Two signatures sharing one nonce equal certain, instant, total key recovery -- by hand, with pure algebra. Reuse is not a slope that gradually weakens security; it is a cliff. &quot;Reuse one number equals everything&quot; is a literal statement about ECDSA, not a rhetorical flourish.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is not a museum piece. The PlayStation 3 fell to exactly this -- a &lt;em&gt;constant&lt;/em&gt; $k$ across every firmware signature, two images sharing one $r$, the master key recovered [@f0f]. Section 5 catalogs the rest of the real-world chain, from that constant-nonce break down to biases of less than a single bit.&lt;/p&gt;
&lt;p&gt;Certainty from a literal repeat is the easy case -- easy for an attacker to run, and, as we will see, easy for a defender to eliminate. So attackers asked a sharper and far more dangerous question. What if the nonces are &lt;em&gt;never&lt;/em&gt; equal, only slightly, invisibly &lt;em&gt;skewed&lt;/em&gt;?&lt;/p&gt;
&lt;h2&gt;4. From Repeat to Bias: The Hidden Number Problem&lt;/h2&gt;
&lt;p&gt;You do not need the nonces to be &lt;em&gt;equal&lt;/em&gt;. You only need them to be a little bit &lt;em&gt;predictable&lt;/em&gt; -- and then to collect enough of them. This is where the story turns, because it dismantles the comforting fix you probably just thought of. If a literal repeat is the danger, surely &quot;make sure the nonces are always different&quot; closes it? It does not come close.&lt;/p&gt;
&lt;p&gt;Here is the shift in viewpoint. In Section 3, a repeat gave us an exact equation and we solved it. Now suppose each nonce is merely &lt;em&gt;skewed&lt;/em&gt; -- say the top few bits are always zero, or the generator leans slightly toward small values. No two nonces are equal, so the certainty attack never triggers. But each signature is now a &lt;em&gt;noisy linear equation&lt;/em&gt; relating the public data to the secret key $d$ modulo $n$, with the unknown nonce constrained to a smaller range than it should occupy. One such equation tells you almost nothing.&lt;/p&gt;
&lt;p&gt;Stack hundreds or thousands of them as the rows of a lattice, though, and the secret $d$ shows up as one unusually short vector hiding in that grid. A reduction algorithm hunts it down, and the key reads straight out.&lt;/p&gt;

The problem of recovering a hidden integer -- here, the private key -- from many samples that each reveal only a few most-significant bits of a related product modulo $n$. Dan Boneh and Ramarathnam Venkatesan introduced it in 1996, and it is the framework underneath every biased-nonce attack on (EC)DSA [@hnp].

An integer grid of points formed by adding and subtracting a fixed set of basis vectors. Biased-nonce recovery constructs a lattice whose unusually short vector encodes the secret key; a reduction algorithm finds that vector. We stay conceptual here -- the internals of LLL and the closest-vector problem belong to their own discussion.
&lt;p&gt;The genealogy is worth knowing, because each step needed &lt;em&gt;less&lt;/em&gt; leakage than the last. Boneh and Venkatesan framed the Hidden Number Problem in 1996 [@hnp]. Around 2000, Daniel Bleichenbacher showed that even a tiny statistical bias in DSA nonces is exploitable through a Fourier-analytic version of the same idea.Bleichenbacher&apos;s seminal biased-nonce result was never published as a standalone paper. It survives as a 2000 IEEE P1363 presentation and a 2005 CRYPTO rump-session talk, &quot;Experiments with DSA,&quot; and is reconstructed through the reference lists of later work such as Nguyen-Shparlinski and LadderLeak. A standalone Bleichenbacher paper on this would be a fabrication; the history genuinely has this shape.&lt;/p&gt;
&lt;p&gt;Nick Howgrave-Graham and Nigel Smart made the lattice attack practical in 2001, recovering keys from partially known nonces [@hgs]. Phong Nguyen and Igor Shparlinski then proved rigorous polynomial-time ECDSA key recovery from just a few leaked nonce bits per signature in 2003 [@ns]. Two decades on, LadderLeak pushed the frontier to its logical extreme, breaking ECDSA with &lt;em&gt;less than one bit&lt;/em&gt; of nonce leakage per signature [@ladderleak].&lt;/p&gt;
&lt;p&gt;Now the distinction that everything downstream depends on. The biased case is &lt;em&gt;not&lt;/em&gt; the repeat case with weaker numbers. It is a different kind of attack with a different cost profile, and conflating them is the single most common way this topic gets mistold.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A &lt;em&gt;repeated&lt;/em&gt; nonce leaks the key from &lt;em&gt;two&lt;/em&gt; signatures, with certainty (Section 3). A &lt;em&gt;biased&lt;/em&gt; nonce leaks nothing usable from any single signature; it takes &lt;em&gt;many&lt;/em&gt; signatures -- hundreds, thousands, or more -- aggregated by a lattice or Fourier reduction before the key emerges. &quot;One biased signature reveals your key&quot; is false. Keep the two cases apart or you will misquote the entire failure family.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Laid out side by side, the contrast is stark:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Repeated nonce&lt;/th&gt;
&lt;th&gt;Biased nonce&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Leak per signature&lt;/td&gt;
&lt;td&gt;The entire nonce (matches another)&lt;/td&gt;
&lt;td&gt;A few bits, or a fraction of one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signatures needed&lt;/td&gt;
&lt;td&gt;Two&lt;/td&gt;
&lt;td&gt;Many (hundreds to millions, per bias)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Method&lt;/td&gt;
&lt;td&gt;Subtraction and one modular inverse&lt;/td&gt;
&lt;td&gt;Lattice reduction or Fourier analysis (HNP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Result&lt;/td&gt;
&lt;td&gt;Certain and exact&lt;/td&gt;
&lt;td&gt;Statistical, high-probability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Work&lt;/td&gt;
&lt;td&gt;Schoolbook algebra by hand&lt;/td&gt;
&lt;td&gt;Serious computation on aggregated data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Defeated only by&lt;/td&gt;
&lt;td&gt;Distinct nonces&lt;/td&gt;
&lt;td&gt;Removing the bias, not just repeats&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

flowchart TD
    A[&quot;Many signatures, each nonce slightly biased&quot;] --&amp;gt; B[&quot;Each is a noisy linear equation in the secret d&quot;]
    B --&amp;gt; C[&quot;Stack the equations as rows of a lattice&quot;]
    C --&amp;gt; D[&quot;The secret d hides in one unusually short vector&quot;]
    D --&amp;gt; E[&quot;Lattice reduction finds that short vector&quot;]
    F[&quot;Read the private key d straight out of it&quot;]
    E --&amp;gt; F
&lt;p&gt;The lesson lands hard. If even a &lt;em&gt;fraction of one bit&lt;/em&gt; of bias, harvested across enough signatures, surrenders the key, then &quot;never literally repeat $k$&quot; is nowhere near enough of a rule, and &quot;use a better random number generator&quot; is a treadmill, not a fix. The only question left is how bad this got in real, shipped hardware -- devices built by careful engineers who knew all of this.&lt;/p&gt;
&lt;h2&gt;5. The Catastrophes in the Wild: ECDSA&lt;/h2&gt;
&lt;p&gt;The theory is alarming; the field results are worse. What follows is the evolution told as a body count, and the number to watch is the &lt;em&gt;leak the attacker needed&lt;/em&gt;. It shrinks with almost every entry, from an entire repeated nonce down to a fraction of a single bit, and every generation still won.&lt;/p&gt;
&lt;p&gt;The 2010 PlayStation 3 break sits at one end: a &lt;em&gt;constant&lt;/em&gt; nonce across all firmware signatures, the maximum possible leak, two signatures sufficient [@f0f]. In 2013 the Android &lt;code&gt;SecureRandom&lt;/code&gt; defect produced repeated and predictable signing nonces on mobile devices; because Bitcoin wallets sign transactions with ECDSA, attackers drained the vulnerable ones [@bitcoin]. Google&apos;s own writeup traced the root cause to improper initialization of the underlying PRNG in the Java Cryptography Architecture [@securerandom].The often-repeated figure of roughly 55 BTC stolen in the 2013 Android incident comes from secondary news reporting [@hackernews]. The primary bitcoin.org advisory [@bitcoin] names the flaw and the affected wallet apps but states no loss total. Treat the number as reported, not official.&lt;/p&gt;
&lt;p&gt;Then the leak starts shrinking. Minerva (2020) attacked real smart cards and cryptographic libraries that leaked the &lt;em&gt;bit-length&lt;/em&gt; of the nonce through timing -- a whisper of bias, not a repeat -- and recovered keys from &quot;just 500 signatures for simulated leakage data, 1200 for real cryptographic library data, and 2100 for smartcard data&quot; [@minerva].&lt;/p&gt;
&lt;p&gt;TPM-Fail (disclosed 2019, published at USENIX Security 2020) turned a timing side channel in Intel&apos;s firmware TPM (CVE-2019-11090) and an STMicroelectronics TPM (CVE-2019-16863) into nonce-bit leakage. It recovered an ECDSA key from the Intel fTPM in 4 to 20 minutes and, remotely, &quot;the authentication key of a virtual private network (VPN) server in 5 hours&quot; [@tpmfail] [@moghimi].&lt;/p&gt;
&lt;p&gt;LadderLeak (2020) then broke ECDSA with &lt;em&gt;less than one bit&lt;/em&gt; of nonce leakage per signature, exploiting a Montgomery-ladder side channel in OpenSSL [@ladderleak], a result published at ACM CCS 2020 [@ladderleak_doi]. And in 2024, PuTTY&apos;s use of P-521 exposed a structural bias so clean it needs almost no data at all (CVE-2024-31497) [@putty].&lt;/p&gt;

&quot;The first 9 bits of each ECDSA nonce are zero. This allows for full secret key recovery in roughly 60 signatures.&quot; -- the PuTTY P-521 disclosure [@putty]
&lt;p&gt;Sixty signatures. An attacker who had watched roughly sixty SSH handshakes, or collected sixty signed Git commits, could reconstruct the user&apos;s private key. The affected PuTTY versions ran from 0.68 through 0.80 (fixed in 0.81), and the same biased generator shipped in FileZilla, WinSCP, TortoiseGit, and TortoiseSVN [@putty]. Collect them into one table and the trend is impossible to miss:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Repeat or bias&lt;/th&gt;
&lt;th&gt;Leak per signature&lt;/th&gt;
&lt;th&gt;Signatures needed&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;2010&lt;/td&gt;
&lt;td&gt;Sony PS3 firmware&lt;/td&gt;
&lt;td&gt;Repeat (constant k)&lt;/td&gt;
&lt;td&gt;The entire nonce&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;[@f0f]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;Android Bitcoin wallets&lt;/td&gt;
&lt;td&gt;Repeat / predictable k&lt;/td&gt;
&lt;td&gt;Nonce reused or guessable&lt;/td&gt;
&lt;td&gt;A few&lt;/td&gt;
&lt;td&gt;[@bitcoin] [@securerandom]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;Minerva (cards, libraries)&lt;/td&gt;
&lt;td&gt;Bias (nonce bit-length)&lt;/td&gt;
&lt;td&gt;Timing reveals length&lt;/td&gt;
&lt;td&gt;500 to 2100&lt;/td&gt;
&lt;td&gt;[@minerva]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2019-2020&lt;/td&gt;
&lt;td&gt;TPM-Fail (Intel, STMicro TPMs)&lt;/td&gt;
&lt;td&gt;Bias (timing)&lt;/td&gt;
&lt;td&gt;Nonce high bits via timing&lt;/td&gt;
&lt;td&gt;Many&lt;/td&gt;
&lt;td&gt;[@tpmfail] [@moghimi]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;LadderLeak (OpenSSL ladder)&lt;/td&gt;
&lt;td&gt;Bias (sub-bit)&lt;/td&gt;
&lt;td&gt;Less than one bit&lt;/td&gt;
&lt;td&gt;Many&lt;/td&gt;
&lt;td&gt;[@ladderleak]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;PuTTY P-521 (CVE-2024-31497)&lt;/td&gt;
&lt;td&gt;Bias (structural)&lt;/td&gt;
&lt;td&gt;First 9 bits fixed at zero&lt;/td&gt;
&lt;td&gt;~60&lt;/td&gt;
&lt;td&gt;[@putty]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

flowchart LR
    A[&quot;1996 HNP framework: bias is exploitable in principle&quot;] --&amp;gt; B[&quot;2010 PS3: a constant nonce, the whole value repeats&quot;]
    B --&amp;gt; C[&quot;2013 Android: predictable and repeated nonces&quot;]
    C --&amp;gt; D[&quot;2020 Minerva and TPM-Fail: a few biased bits via timing&quot;]
    D --&amp;gt; E[&quot;2020 LadderLeak: less than one bit per signature&quot;]
    E --&amp;gt; F[&quot;2024 PuTTY P-521: nine fixed bits, about 60 signatures&quot;]
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Read the arc left to right and one lesson dominates: the leakage an attacker needs keeps &lt;em&gt;shrinking&lt;/em&gt;, from an entire repeated nonce to less than a single bit. No generator is perfectly unbiased, and -- as Part 2 argued -- you can never prove one is. Any residual bias, given enough signatures, eventually surrenders the key. &quot;Harden the random number generator&quot; buys time; it does not close the hole. That conclusion is the synthesis of the whole table, and it is what forces the search for a structural answer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Every entry above is a &lt;em&gt;signature&lt;/em&gt; scheme bleeding out its private key through the nonce. You would be forgiven for thinking this is an ECDSA problem. It is not. The exact same structural flaw -- one number that must be used once and is fatal on reuse -- was hiding inside a completely different primitive, the cipher that protects most of the traffic on the modern web.&lt;/p&gt;
&lt;h2&gt;6. The Other Primitive: AES-GCM&apos;s Forbidden Attack&lt;/h2&gt;
&lt;p&gt;Different math, a different decade, a different threat model -- and the exact same fatal dependency on one number used once. The puzzle here is sharper: AES-GCM&apos;s nonce is &lt;em&gt;public&lt;/em&gt;, so how can reusing a value the attacker already knows leak a forgery key? The answer is Antoine Joux&apos;s forbidden attack, and it mirrors the signature story beat for beat.&lt;/p&gt;
&lt;p&gt;Recall the tag from Section 2: $T = E_K(J_0) \oplus \mathrm{GHASH}_H(A, C)$, where $H = E_K(0^{128})$. Two facts about that formula are load-bearing. First, $H$ depends only on the key, so it is fixed for the whole life of that key. Second, $E_K(J_0)$ depends only on the key and the nonce, through the pre-counter block $J_0$. Reuse the nonce and $E_K(J_0)$ comes back &lt;em&gt;identical&lt;/em&gt;.&lt;/p&gt;

The secret 128-bit value $H = E_K(0^{128})$ -- AES applied to the all-zero block -- that keys GCM&apos;s polynomial authenticator over $\mathrm{GF}(2^{128})$. It never changes for a given key, and recovering it lets an attacker forge authentication tags at will.
&lt;p&gt;Now reuse one $(\text{key}, \text{IV})$ pair on two messages. Two things break, and they break separately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The confidentiality break, from a single collision.&lt;/strong&gt; GCM encrypts with counter mode: the ciphertext is the plaintext XORed with a keystream generated from $J_0$. Same key, same IV means the same $J_0$, means the &lt;em&gt;same keystream&lt;/em&gt;. So for two messages encrypted under the reused pair, $C \oplus C&apos; = P \oplus P&apos;$. The keystream cancels and the XOR of the two plaintexts falls out immediately, from just one collision, with no further work. If the attacker knows or guesses one plaintext, the other is fully revealed. Here is that leak as runnable code:&lt;/p&gt;
&lt;p&gt;{`
// Reuse one (key, IV) in a keystream mode -&amp;gt; C XOR C&apos; leaks P XOR P&apos;.
// GCM encrypts with AES-CTR: same (key, IV) reproduces the SAME keystream.
function xor(a, b) { return a.map((x, i) =&amp;gt; x ^ b[i]); }
const bytes = s =&amp;gt; Array.from(new TextEncoder().encode(s));
const hex = a =&amp;gt; a.map(x =&amp;gt; x.toString(16).padStart(2, &apos;0&apos;)).join(&apos;&apos;);&lt;/p&gt;
&lt;p&gt;// A fixed keystream stands in for AES-CTR(key, IV): identical for both messages.
const keystream = [0x9e,0x37,0x5a,0xc1,0x02,0xbb,0x44,0xd0,0x71,0x6f,0x88,0x2a];&lt;/p&gt;
&lt;p&gt;const P1 = bytes(&apos;transfer=10 &apos;).slice(0, keystream.length);
const P2 = bytes(&apos;transfer=9999&apos;).slice(0, keystream.length);&lt;/p&gt;
&lt;p&gt;const C1 = xor(P1, keystream);   // ciphertext 1
const C2 = xor(P2, keystream);   // ciphertext 2, SAME keystream&lt;/p&gt;
&lt;p&gt;// Attacker never sees the key or keystream -- only C1 and C2:
const leak = xor(C1, C2);        // == P1 XOR P2, the keystream cancels
console.log(&apos;C1 XOR C2 :&apos;, hex(leak));
console.log(&apos;P1 XOR P2 :&apos;, hex(xor(P1, P2)), &apos;(identical -&amp;gt; keystream is gone)&apos;);&lt;/p&gt;
&lt;p&gt;// If the attacker also knows P1, then P2 falls out immediately:
console.log(&apos;recover P2:&apos;, new TextDecoder().decode(new Uint8Array(xor(leak, P1))));
`}&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The authenticity break, from the tag difference.&lt;/strong&gt; This is Joux&apos;s contribution. Write the two tags under the reused pair and XOR them. The identical blind $E_K(J_0)$ cancels exactly:&lt;/p&gt;
&lt;p&gt;$$T \oplus T&apos; = \mathrm{GHASH}_H(A, C) \oplus \mathrm{GHASH}_H(A&apos;, C&apos;)$$&lt;/p&gt;
&lt;p&gt;Every block of $A, C, A&apos;, C&apos;$ is observable on the wire, and $\mathrm{GHASH}_H$ is a polynomial in $H$ over $\mathrm{GF}(2^{128})$ with those blocks as coefficients. So the right-hand side is a &lt;em&gt;known polynomial in the one unknown $H$&lt;/em&gt;, and it equals the observed left-hand side. Move everything to one side and you have a polynomial equation whose roots are candidate values for $H$; factoring it over $\mathrm{GF}(2^{128})$ yields that candidate set [@joux].&lt;/p&gt;
&lt;p&gt;Recover $H$ and, since $E_K(J_0) = T \oplus \mathrm{GHASH}_H(A, C)$ falls out too, the attacker can compute a valid tag for &lt;em&gt;any&lt;/em&gt; ciphertext they like under that nonce. That is a &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-&quot; rel=&quot;noopener&quot;&gt;universal forgery&lt;/a&gt;.&lt;/p&gt;

Antoine Joux&apos;s 2006 attack on GCM: reusing a $(\text{key}, \text{IV})$ pair cancels the tag&apos;s $E_K(J_0)$ blind, turning the difference of two tags into a known polynomial over $\mathrm{GF}(2^{128})$ whose roots are candidates for the subkey $H$. The name reflects that GCM&apos;s unique-IV rule is not a suggestion -- breaking it is forbidden [@joux].

flowchart TD
    A[&quot;Tag T equals E_K(J0) XOR GHASH_H of the message&quot;] --&amp;gt; B[&quot;J0 comes from the IV, H comes only from the key&quot;]
    B --&amp;gt; C[&quot;Reuse the same key and IV on a second message&quot;]
    C --&amp;gt; D[&quot;E_K(J0) is identical in both tags, so it cancels under XOR&quot;]
    D --&amp;gt; E[&quot;T XOR T-prime is a known polynomial in H over GF(2 to the 128)&quot;]
    E --&amp;gt; F[&quot;Its roots are the candidate values for the subkey H&quot;]
    F --&amp;gt; G[&quot;Two or more collisions pin H, enabling universal forgery&quot;]
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A &lt;em&gt;single&lt;/em&gt; $(\text{key}, \text{IV})$ collision leaks $P_1 \oplus P_2$ immediately and unconditionally -- confidentiality is gone at once. Recovering the subkey $H$ is a &lt;em&gt;separate&lt;/em&gt; step: one collision yields a &lt;em&gt;set of candidate roots&lt;/em&gt;, and pinning $H$ uniquely generally needs &lt;em&gt;two or more&lt;/em&gt; collisions. &quot;One reuse instantly recovers the authentication key&quot; overstates it. &quot;One reuse instantly destroys confidentiality and opens the road to forgery&quot; is exact.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is not confined to whiteboards. In 2016 the Nonce-Disrespecting Adversaries team scanned live TLS and &quot;identified 184 HTTPS servers repeating nonces, which fully breaks the authenticity of the connections&quot; [@nda].Joux&apos;s result is his 2006 public comment to NIST, whose embedded document title reads &quot;Authentication Failures in NIST version of GCM&quot; [@joux]. It is sometimes miscited as IACR ePrint 2006/187 -- but that number is a different paper, on HMAC and NMAC, by Kim, Biryukov, Preneel, and Hong [@eprint187]. Cite the NIST comment, not the ePrint. These were production HTTPS endpoints, not lab toys, and their nonce reuse let anyone forge authenticated records against them.The canonical live-TLS evidence for GCM nonce reuse is that paper [@nda], not CVE-2016-0270, which concerns IBM Domino rather than OpenSSL. If you see that CVE cited as the OpenSSL GCM-reuse bug, it is a misattribution.&lt;/p&gt;
&lt;p&gt;Two primitives, one disease: a once-per-operation number that is death on reuse. If the flaw is structural rather than a coding slip, then &quot;be more careful with your randomness&quot; cannot be the cure -- Section 5 already showed that treadmill has no end. The fix has to be architectural. What would that even look like?&lt;/p&gt;
&lt;h2&gt;7. Make the Number Deterministic&lt;/h2&gt;
&lt;p&gt;The cure for a randomness disaster turned out to be &lt;em&gt;less&lt;/em&gt; randomness. That sentence should feel wrong -- we have spent five sections watching bad randomness destroy keys, so surely the answer is &lt;em&gt;better&lt;/em&gt; randomness. It is not, and seeing why is the moment the whole subject clicks into place.&lt;/p&gt;
&lt;p&gt;Go back to what actually failed. The signing equation needs a $k$ that is unique and unpredictable. Every real break came from the &lt;em&gt;runtime source&lt;/em&gt; of that $k$: a constant, a repeated PRNG output, a biased generator, a timing leak. So Thomas Pornin&apos;s RFC 6979 asks a disarming question -- what if we never draw $k$ from a runtime source at all? Instead, &lt;em&gt;derive&lt;/em&gt; it, deterministically, from two things the signer already holds: the private key and the message [@rfc6979].&lt;/p&gt;

A signature whose per-message nonce is computed as a pseudorandom function of the private key and the message, using no runtime randomness at all. The same $(\text{key}, \text{message})$ pair always yields the same nonce, and therefore the same signature. RFC 6979 specifies this for (EC)DSA; EdDSA builds it into the scheme [@rfc6979] [@rfc8032].
&lt;p&gt;Concretely, RFC 6979 runs an HMAC-based deterministic random bit generator, seeded from the private key $x$ and the message hash, and rejection-samples its output into the valid range $[1, n-1]$. The two helper encodings simply turn the key and the hash into fixed-width byte strings so the HMAC has well-defined inputs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;h  = H(message)                              # hash the message
V  = 0x01 0x01 ... 0x01                       # hlen bytes of 0x01
K  = 0x00 0x00 ... 0x00                       # hlen bytes of 0x00
K  = HMAC(K, V || 0x00 || int2octets(x) || bits2octets(h))
V  = HMAC(K, V)
K  = HMAC(K, V || 0x01 || int2octets(x) || bits2octets(h))
V  = HMAC(K, V)
loop:
    T = &quot;&quot;                                     # accumulate qlen bits of output
    while bitlen(T) &amp;lt; qlen:                    # one HMAC block if qlen &amp;lt;= hlen; more if longer
        V = HMAC(K, V);  T = T || V
    k = bits2int(T)
    if 1 &amp;lt;= k &amp;lt;= n-1:  return k               # in range -&amp;gt; use it
    K = HMAC(K, V || 0x00);  V = HMAC(K, V)    # else reseed and retry
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look at what this buys. The generator is seeded by the private key and the message, and nothing else, and two consequences close the &lt;em&gt;generation&lt;/em&gt; side of the Part-A attack surface.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;repeat&lt;/strong&gt; case dies because two &lt;em&gt;different&lt;/em&gt; messages produce two &lt;em&gt;unrelated&lt;/em&gt; nonces, while the same message reproduces the same signature harmlessly -- there is no runtime generator whose collision could hand you a shared $k$. The &lt;strong&gt;bias&lt;/strong&gt; case dies wherever the bias was &lt;em&gt;born in a generator&lt;/em&gt;: with no runtime generator in the loop, there is nothing to skew and no entropy pool to under-initialize. Every Section-5 break that lived in the generator -- the repeated $k$ on the PS3, the predictable $k$ from a weak &lt;code&gt;SecureRandom&lt;/code&gt; -- has simply been removed from the design, because there is no generator left to fail.&lt;/p&gt;

Deterministic signers &quot;do not need access to a source of high-quality randomness.&quot; -- RFC 6979 [@rfc6979]
&lt;p&gt;And the compatibility story is almost too good: a verifier cannot even tell. The verification equation is unchanged, because a signature is still just a valid $(r, s)$ pair; only the signer&apos;s method of choosing $k$ changed. Deployments can switch to deterministic signing unilaterally. You do not have to take the &quot;same input, same output&quot; claim on trust either:&lt;/p&gt;
&lt;p&gt;{&lt;code&gt;// Deterministic nonce k = PRF(private key, message). // Real RFC 6979 uses HMAC-DRBG; this toy uses a small deterministic mixer // only to show the SHAPE: same (key,msg) =&amp;gt; same k; different msg =&amp;gt; unrelated k. const MASK = (1n &amp;lt;&amp;lt; 64n) - 1n; const n = (1n &amp;lt;&amp;lt; 61n) - 1n;              // toy prime modulus, k in [1, n-1] function rotl(x, r) { return ((x &amp;lt;&amp;lt; r) | (x &amp;gt;&amp;gt; (64n - r))) &amp;amp; MASK; } function prf(key, msg) {                  // deterministic, consults no RNG   let h = 1469598103934665603n;           // 64-bit offset basis   for (const ch of (key + &apos;|&apos; + msg)) {     h = (h ^ BigInt(ch.charCodeAt(0))) &amp;amp; MASK;     h = (h * 1099511628211n) &amp;amp; MASK;       // FNV-style multiply     h = rotl(h, 13n) ^ (h &amp;gt;&amp;gt; 7n);          // extra diffusion so 1 char avalanches   }   return (h % (n - 1n)) + 1n;              // map into [1, n-1] } const sk = &apos;private-key-0xA1B2&apos;; console.log(&apos;k(pay Bob 10) :&apos;, prf(sk, &apos;pay Bob 10&apos;).toString()); console.log(&apos;k(pay Bob 10) :&apos;, prf(sk, &apos;pay Bob 10&apos;).toString(), &apos;&amp;lt;- identical, no RNG consulted&apos;); console.log(&apos;k(pay Bob 11) :&apos;, prf(sk, &apos;pay Bob 11&apos;).toString(), &apos;&amp;lt;- unrelated&apos;); console.log(&apos;No source of runtime randomness was consulted.&apos;);&lt;/code&gt;}&lt;/p&gt;
&lt;p&gt;The same idea has a sibling that was born deterministic. EdDSA, and its popular instantiation Ed25519, does not bolt determinism on -- it designs the runtime randomness out from the start, computing its per-signature secret as a hash of a key-derived prefix and the message [@rfc8032].That is why Ed25519 has no separate &quot;use RFC 6979&quot; mode: there is no runtime nonce anywhere in the scheme to bias or repeat. Determinism is not an option you enable; it is the definition.&lt;/p&gt;
&lt;p&gt;Standards bodies followed the evidence: FIPS 186-5, the current US signature standard, now approves deterministic ECDSA &quot;as specified in IETF RFC 6979&quot; [@fips1865] [@fips1865pdf]. There is even a quiet operational bonus. A deterministic signer is &lt;em&gt;testable&lt;/em&gt;: you can ship known-answer test vectors and check byte-for-byte that an implementation is correct, which a randomized signer can never offer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The fix for a randomness failure was to remove the randomness. Derive the nonce from the private key and the message, and there is no runtime generator left to repeat or bias -- both failure modes vanish together.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Determinism looks like a clean, total victory. It is narrower than that, and the boundary matters. What it closes is the &lt;em&gt;generation&lt;/em&gt; side of Part A. It does nothing for the &lt;em&gt;usage&lt;/em&gt; side: recall that Minerva, TPM-Fail, and LadderLeak never touched a generator -- they read the nonce&apos;s leading bits out of the &lt;em&gt;timing&lt;/em&gt; of the scalar multiplication $k \cdot G$, and that leak is present no matter how $k$ was chosen [@minerva] [@tpmfail] [@ladderleak]. Determinism fixes &lt;em&gt;generation&lt;/em&gt;, not &lt;em&gt;usage&lt;/em&gt;; the defense against that class is a &lt;em&gt;constant-time&lt;/em&gt; scalar multiplication, a separate discipline that RFC 6979 neither provides nor promises. Worse, determinism can even &lt;em&gt;add&lt;/em&gt; exposure: by making signing perfectly repeatable, we hand a fault-injection attacker a perfectly repeatable target, a hazard RFC 6979&apos;s own security considerations acknowledge [@rfc6979]. If Go&apos;s standard library knows this well enough to refuse pure determinism on purpose, we had better find out what it is afraid of.&lt;/p&gt;
&lt;h2&gt;8. The Catch, and the Hedge&lt;/h2&gt;
&lt;p&gt;Here is a fact that should stop you: Go&apos;s standard library signs ECDSA &lt;em&gt;non-deterministically on purpose&lt;/em&gt;, and its source code says so in a comment. After seven sections arguing that runtime randomness is the enemy, one of the most widely used standard-library signers refuses to remove it. That is not carelessness. It is a second threat model.&lt;/p&gt;
&lt;p&gt;Determinism closed the randomness door, but it opened a different one. A deterministic signer computes the &lt;em&gt;same&lt;/em&gt; signature every time for a given input, which means an attacker who can run it twice on the same message gets two identical computations to compare -- and comparison is exactly the lever a fault attack pulls.&lt;/p&gt;

An attack that induces a hardware fault -- a voltage glitch, a clock glitch, a laser pulse -- during a computation, then compares the faulty output against a correct one to solve for the secret. Against a *deterministic* signer the attacker can obtain a correct signature and a faulted signature for the identical input, which is precisely what makes the difference exploitable.
&lt;p&gt;This is not hypothetical. Aranha, Orlandi, Takahashi, and Zaverucha proved that de-randomized Fiat-Shamir schemes -- EdDSA among them -- are vulnerable to differential fault attacks [@hedged]. And the standard itself agrees: FIPS 186-5 warns that fault attacks are &quot;of particular concern for ... deterministic signature schemes, as well as embedded or IoT devices and smartcards&quot; [@fips1865pdf]. The very property that made determinism testable and repeatable -- same input, same output -- is what hands a fault attacker a fixed target to hammer.&lt;/p&gt;
&lt;p&gt;The resolution is not to retreat to randomized signing, which reintroduces every repeat and bias failure. It is to take a small step back toward randomness, on purpose and in a controlled way: &lt;strong&gt;hedged signatures.&lt;/strong&gt;&lt;/p&gt;

A signature whose nonce is derived from the private key, the message, *and* a fresh random value $r$: $k = H(sk, m, r)$. If the random source fails, the construction degrades to the deterministic -- still safe -- case. If a fault is injected, the fresh $r$ means the signer is no longer a fixed, replayable target.
&lt;p&gt;Read that definition twice, because it is the whole trick. Hedging is not &quot;randomized signing with extra steps.&quot; It is a design that is safe &lt;em&gt;whichever&lt;/em&gt; thing goes wrong. Lose your entropy source entirely and you fall back to RFC 6979&apos;s determinism, which we already proved kills repeat and bias. Keep your entropy and you also get a moving target that defeats the fault attack determinism exposed. The randomness is present but no longer load-bearing.&lt;/p&gt;

&quot;Signatures generated by this package are not deterministic, but entropy is mixed with the private key and the message, achieving the same level of security in case of randomness source failure.&quot; -- Go `crypto/ecdsa` [@goecdsa]
&lt;p&gt;That is why Go hedges by default, and it is not alone. BoringSSL&apos;s FIPS module passes &quot;a SHA512 hash of the private key and digest as additional data into the RBG ... a hardening measure against entropy failure&quot; [@boringssl]. RFC 6979 itself sanctions hedged variants in its Section 3.6 [@rfc6979], and FIPS 186-5 specifies an &quot;Extra Random Bits&quot; method that draws a nonce at least 64 bits longer than needed so any statistical bias becomes negligible [@fips1865pdf].&lt;/p&gt;
&lt;p&gt;The honest caveats: hedging still consumes &lt;em&gt;some&lt;/em&gt; entropy, and its security proofs cover &lt;em&gt;specific&lt;/em&gt; fault classes rather than all conceivable faults. It is a well-chosen trade, not a free lunch.&lt;/p&gt;
&lt;p&gt;The right mental model is three parallel choices selected by threat model, not a podium with one winner:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Randomized&lt;/th&gt;
&lt;th&gt;Deterministic (RFC 6979 / EdDSA)&lt;/th&gt;
&lt;th&gt;Hedged&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;RNG needed at signing time&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Some (not load-bearing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Immune to repeats&lt;/td&gt;
&lt;td&gt;No (RNG can collide)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Immune to bias&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resists fault injection&lt;/td&gt;
&lt;td&gt;Yes (moving target)&lt;/td&gt;
&lt;td&gt;No (fixed target)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Known-answer test vectors&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standardized&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (RFC 6979, FIPS 186-5)&lt;/td&gt;
&lt;td&gt;Yes (RFC 6979 3.6; FIPS 186-5)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shipped by default in&lt;/td&gt;
&lt;td&gt;Legacy code&lt;/td&gt;
&lt;td&gt;Many libraries&lt;/td&gt;
&lt;td&gt;Go &lt;code&gt;crypto/ecdsa&lt;/code&gt;, BoringSSL FIPS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best when&lt;/td&gt;
&lt;td&gt;Rarely the right pick&lt;/td&gt;
&lt;td&gt;No fault threat in scope&lt;/td&gt;
&lt;td&gt;Hardware, embedded, smartcard, HSM&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; For any new (EC)DSA signer -- especially on hardware, embedded, smartcard, or HSM targets where fault injection is realistic -- hedge it: derive the nonce from the key, the message, and a little fresh entropy. You keep repeat and bias immunity even if the random source fails, and you deny the fixed target a fault attack needs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the signature side does not settle on a single champion. It settles on a &lt;em&gt;matched set&lt;/em&gt; of choices, each correct for a different adversary. That is a satisfying place to land -- but it is only half the patient. What is the symmetric-encryption analogue for the cipher we left bleeding in Section 6?&lt;/p&gt;
&lt;h2&gt;9. Fixing the Cipher: Nonce-Misuse-Resistant AEAD&lt;/h2&gt;
&lt;p&gt;The signature fix was &quot;derive the number.&quot; The cipher&apos;s fix rhymes: &lt;em&gt;derive the IV from the message itself&lt;/em&gt;, so that the worst a repeat can leak is the fact that two messages were byte-for-byte identical. Same instinct, symmetric setting.&lt;/p&gt;
&lt;p&gt;The idea predates AES-GCM-SIV. Phillip Rogaway and Thomas Shrimpton gave it a provable-security treatment in 2006, defining deterministic authenticated encryption and the Synthetic IV construction that realizes it [@rs_eprint] [@rs_doi]. It was standardized as AES-SIV in RFC 5297 [@rfc5297].&lt;/p&gt;

An initialization vector computed *from the message* -- together with the key and associated data -- rather than drawn at random. Because the IV is a function of the plaintext, two different plaintexts get different IVs automatically, and only byte-identical messages ever collide.

An authenticated cipher that, if a nonce is ever repeated, leaks at most whether two identical $(\text{key}, \text{nonce}, \text{plaintext}, \text{associated data})$ inputs were the same -- never the key, never arbitrary plaintext. Reuse degrades it gracefully rather than catastrophically.
&lt;p&gt;The modern instantiation is AES-GCM-SIV (RFC 8452) [@rfc8452]. It computes a keyed hash of the &lt;em&gt;entire&lt;/em&gt; plaintext and associated data using POLYVAL, and folds that into a synthetic IV that doubles as the authentication tag; the synthetic IV then seeds ordinary AES-CTR encryption.POLYVAL is a little-endian relative of GHASH, chosen deliberately so AES-GCM-SIV can reuse the same carry-less multiplication hardware that already accelerates AES-GCM. The parallel to GCM is by design, not coincidence.&lt;/p&gt;
&lt;p&gt;Two more refinements matter: fresh message-authentication and message-encryption keys are &lt;em&gt;derived per nonce&lt;/em&gt; from the master key, which also pushes back the birthday bound that limits plain GCM and raises the safe message limit to roughly $2^{50}$ per key [@gcmsiv_spec]. The price is structural and unavoidable: because the tag depends on the whole plaintext, you cannot emit the first ciphertext byte until you have read the last plaintext byte. AES-GCM-SIV is inherently &lt;em&gt;two-pass and not online&lt;/em&gt;.&lt;/p&gt;

flowchart TD
    A[&quot;Master key and nonce&quot;] --&amp;gt; B[&quot;Derive per-message auth and encryption keys&quot;]
    P[&quot;Plaintext and associated data&quot;] --&amp;gt; C[&quot;POLYVAL hash under the derived auth key&quot;]
    B --&amp;gt; C
    C --&amp;gt; D[&quot;Synthetic IV, which doubles as the authentication tag&quot;]
    D --&amp;gt; E[&quot;Seed AES-CTR encryption with the synthetic IV&quot;]
    B --&amp;gt; E
    E --&amp;gt; F[&quot;Output ciphertext and tag&quot;]
&lt;p&gt;Now state precisely what &quot;misuse-resistant&quot; earns you, because the phrase invites overclaiming. On a nonce repeat, AES-GCM-SIV discloses only whether the two messages &quot;were equal or not,&quot; which RFC 8452 identifies as &quot;the minimum amount of information that a deterministic algorithm can leak&quot; [@rfc8452]. Compare that to Section 6, where a single GCM repeat surrendered $P_1 \oplus P_2$ and set up universal forgery. The SIV construction converts a catastrophe into a whisper.&lt;/p&gt;

On nonce reuse, a misuse-resistant AEAD discloses only &quot;whether the messages were equal or not ... the minimum amount of information that a deterministic algorithm can leak.&quot; -- RFC 8452 [@rfc8452]
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &quot;Misuse-resistant&quot; does not mean reuse is harmless. On a repeat, AES-GCM-SIV still leaks that two identical messages were sent under the same nonce -- the provable minimum, but not nothing. You get &lt;em&gt;graceful&lt;/em&gt; degradation, not immunity. It is a safety net, not a license to reuse nonces deliberately.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is a parallel path worth knowing, though it solves a slightly different problem. XChaCha20-Poly1305 extends the nonce to 192 bits, which makes &lt;em&gt;random&lt;/em&gt; nonce selection collision-safe and lets systems stay stateless without a counter [@xchacha]. That is genuinely useful, but it is not true misuse resistance: an &lt;em&gt;exact&lt;/em&gt; nonce repeat still breaks Poly1305 the way any keystream reuse does. A big nonce makes accidental collisions astronomically unlikely; it does not make a deliberate repeat safe. Collect the options:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scheme&lt;/th&gt;
&lt;th&gt;Passes / online&lt;/th&gt;
&lt;th&gt;On nonce reuse&lt;/th&gt;
&lt;th&gt;Misuse-resistant?&lt;/th&gt;
&lt;th&gt;Nonce size&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM&lt;/td&gt;
&lt;td&gt;1 pass, online&lt;/td&gt;
&lt;td&gt;Catastrophic (Section 6)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;Fastest with a reliable unique counter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV&lt;/td&gt;
&lt;td&gt;2 pass, not online&lt;/td&gt;
&lt;td&gt;Leaks only message equality&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;POLYVAL and per-nonce keys [@rfc8452]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-SIV&lt;/td&gt;
&lt;td&gt;2 pass, not online&lt;/td&gt;
&lt;td&gt;Leaks only message equality&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Vector input&lt;/td&gt;
&lt;td&gt;Deterministic key-wrap [@rfc5297]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XChaCha20-Poly1305&lt;/td&gt;
&lt;td&gt;1 pass, online&lt;/td&gt;
&lt;td&gt;Random reuse unlikely; exact reuse breaks&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;192-bit&lt;/td&gt;
&lt;td&gt;Stateless random nonces [@xchacha]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Two families, one move. On the signature side we stopped trusting runtime randomness by &lt;em&gt;deriving&lt;/em&gt; the number; on the AEAD side we stop trusting it by making a repeat &lt;em&gt;non-catastrophic&lt;/em&gt;. It feels, at last, like the problem is solved. It is not -- and the reasons are not missing features anyone can build. Some of them are walls that no amount of engineering can move.&lt;/p&gt;
&lt;h2&gt;10. Theoretical Limits and the Open Frontier&lt;/h2&gt;
&lt;p&gt;Some of the walls we keep hitting are not missing features that a cleverer engineer will one day supply. They are proofs that you cannot have everything at once.&lt;/p&gt;

First: an online cipher cannot be misuse-resistant. To leak only equality on a repeat, the first bit of ciphertext must depend on the *entire* plaintext, which forces a second pass -- so &quot;streaming&quot; and &quot;misuse-resistant&quot; cannot both hold [@rfc8452]. Second: pure determinism cannot resist faults. The very repeatability that kills nonce reuse is the property a fault attack exploits, so resisting faults means reintroducing some randomness to hedge [@hedged]. Neither wall is a missing feature. Both are theorems. There is no single perfect primitive -- only a matched pair chosen per threat model.
&lt;p&gt;Those two impossibilities explain the shape of everything in Sections 7 through 9. AES-GCM-SIV is two-pass &lt;em&gt;because it has to be&lt;/em&gt;. Hedged signatures exist &lt;em&gt;because&lt;/em&gt; determinism alone cannot cover the fault case. We did not fail to find the one perfect design; the one perfect design is provably not there.&lt;/p&gt;
&lt;p&gt;A third limit is epistemic, and it is the quiet engine under this entire article.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can never prove a generator is unpredictable; you can only fail to prove it predictable. That asymmetry -- argued in &lt;a href=&quot;https://paragmali.com/blog/predictable-or-repeated-the-only-two-ways-cryptographic-rand&quot; rel=&quot;noopener&quot;&gt;Part 2&lt;/a&gt; -- is why &quot;harden the random number generator&quot; was never a structural fix. LadderLeak made the point unforgettable by winning with less than one bit of bias [@ladderleak]. Deriving the number sidesteps the unprovable question entirely: there is nothing left to certify.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And the biased-nonce frontier is still &lt;em&gt;descending&lt;/em&gt;: LadderLeak&apos;s sub-one-bit result is the current floor, not a proven bottom [@ladderleak]. The theoretical minimum bias that remains exploitable is an open question, and history says to bet on &quot;smaller than you think.&quot;&lt;/p&gt;
&lt;p&gt;Then there is the genuinely open ground, where the same disease is re-emerging one abstraction level up. In threshold and multi-party ECDSA, several parties must &lt;em&gt;jointly&lt;/em&gt; produce a nonce that is unbiased and secret from all of them, even when some participants misbehave. That is the Hidden Number Problem wearing a new coat: get the joint nonce generation subtly wrong and the biased-nonce attacks come straight back [@threshold]. On the AEAD side, none of the four ciphers we surveyed is &lt;em&gt;key-committing&lt;/em&gt;, and that gap is exploitable.&lt;/p&gt;

An authenticated cipher whose ciphertext binds to exactly one key, so it cannot be decrypted to a different valid plaintext under a different key. None of AES-GCM, AES-GCM-SIV, AES-SIV, or XChaCha20-Poly1305 is key-committing, which is precisely what enables partitioning-oracle attacks.
&lt;p&gt;Julia Len, Paul Grubbs, and Thomas Ristenpart showed that this non-committing property turns certain systems into partitioning oracles that recover passwords and keys [@len]. There is no drop-in standard for committing AEAD yet -- an active research front. It is worth being precise about what is &lt;em&gt;not&lt;/em&gt; open, though: AES-GCM-SIV and AES-SIV already sit exactly at the minimum-leakage lower bound for the misuse case, because &quot;leaks only equality&quot; is provably optimal for any deterministic scheme [@rfc8452]. That specific gap is closed; you cannot do better, and you do not need to.&lt;/p&gt;
&lt;p&gt;Step back and the emotional arc completes. We began thinking nonce reuse was sloppy hygiene, discovered it was a cliff, thought determinism sealed the cliff, learned determinism opened a fault door, and now find that some of the remaining doors are welded shut by theorems while others open onto genuinely unexplored rooms. None of that theory, however, changes what an engineer should actually do on Monday morning. After all of it, what do you type?&lt;/p&gt;
&lt;h2&gt;11. What a Practitioner Does Today&lt;/h2&gt;
&lt;p&gt;Everything above collapses into a decision tree that fits on an index card. You do not need to re-derive Joux&apos;s polynomial in a code review; you need two questions for signing and two for encryption.&lt;/p&gt;
&lt;p&gt;For &lt;strong&gt;signing&lt;/strong&gt;: for any (EC)DSA or DSA signer, derive the nonce with RFC 6979 or a hedged variant rather than drawing it at runtime [@rfc6979]. For greenfield systems, prefer Ed25519, which is deterministic by construction [@rfc8032]. If fault injection is a realistic threat -- smart cards, HSMs, IoT silicon an attacker can hold -- hedge, so an entropy failure degrades to safe determinism and a glitch still faces a moving target [@hedged] [@boringssl] [@goecdsa]. And never compute a nonce as &lt;code&gt;rand() mod n&lt;/code&gt; from a raw PRNG without the anti-bias margin FIPS 186-5 specifies as Extra Random Bits [@fips1865pdf]. On hardware whose timing an attacker can measure -- smart cards, TPMs, co-located VMs -- pair all of this with a &lt;em&gt;constant-time&lt;/em&gt; scalar multiplication: RFC 6979 fixes how $k$ is generated, not how it is used, so the Minerva, TPM-Fail, and LadderLeak timing leaks close only when $k \cdot G$ itself runs in constant time [@minerva] [@tpmfail] [@ladderleak].&lt;/p&gt;
&lt;p&gt;For &lt;strong&gt;AEAD&lt;/strong&gt;: if you can guarantee a unique nonce -- a reliable, non-resetting counter -- AES-GCM is the fastest choice, provided you cap invocations per key against the birthday bound and rekey before you approach it [@sp80038d] [@rfc8452]. If nonce uniqueness is even slightly uncertain -- multiple writers sharing a key, VM snapshots that replay state, forked or stateless workers -- reach for AES-GCM-SIV [@rfc8452] or the 192-bit-nonce XChaCha20-Poly1305 [@xchacha]. For deterministic key-wrapping, AES-SIV is purpose-built [@rfc5297].&lt;/p&gt;

flowchart TD
    S[&quot;Signing (EC)DSA or DSA&quot;] --&amp;gt; Q1{&quot;Fault injection in scope, such as smartcard or HSM or IoT&quot;}
    Q1 --&amp;gt;|Yes| H[&quot;Hedge: nonce from key, message, and fresh entropy&quot;]
    Q1 --&amp;gt;|No| G{&quot;Greenfield design&quot;}
    G --&amp;gt;|Yes| ED[&quot;Prefer Ed25519&quot;]
    G --&amp;gt;|No| R6[&quot;Deterministic RFC 6979&quot;]
    A[&quot;Choosing an AEAD&quot;] --&amp;gt; Q2{&quot;Reliable unique nonce counter&quot;}
    Q2 --&amp;gt;|Yes| GCM[&quot;AES-GCM, cap invocations and rekey&quot;]
    Q2 --&amp;gt;|No| MR[&quot;AES-GCM-SIV or XChaCha20-Poly1305&quot;]
&lt;p&gt;The same choices read cleanly as a do-and-do-not table:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Call this&lt;/th&gt;
&lt;th&gt;Never this&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Signing, general&lt;/td&gt;
&lt;td&gt;RFC 6979 deterministic or hedged&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rand() mod n&lt;/code&gt; from a raw PRNG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing, greenfield&lt;/td&gt;
&lt;td&gt;Ed25519&lt;/td&gt;
&lt;td&gt;Home-rolled DSA nonce logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing, hardware or embedded&lt;/td&gt;
&lt;td&gt;Hedged (key, message, entropy)&lt;/td&gt;
&lt;td&gt;Pure determinism on a fault-exposed device&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing, measurable hardware&lt;/td&gt;
&lt;td&gt;Constant-time scalar multiplication&lt;/td&gt;
&lt;td&gt;Variable-time scalar multiplication an attacker can time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEAD, reliable counter&lt;/td&gt;
&lt;td&gt;AES-GCM, capped per key and rekeyed&lt;/td&gt;
&lt;td&gt;AES-GCM past its invocation limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEAD, uncertain uniqueness&lt;/td&gt;
&lt;td&gt;AES-GCM-SIV or XChaCha20-Poly1305&lt;/td&gt;
&lt;td&gt;Plain AES-GCM with hopeful nonces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deterministic key-wrap&lt;/td&gt;
&lt;td&gt;AES-SIV (RFC 5297)&lt;/td&gt;
&lt;td&gt;A data-plane GCM key reused for wrapping&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

These abstractions land on concrete Windows components. Signature and nonce generation run through the Cryptography API: Next Generation stack, whose internals the [CNG architecture article](/blog/cng-architecture-bcrypt-ncrypt-ksps) works through. TLS record nonces are the responsibility of [SChannel](/blog/rotating-every-cipher-schannel-and-the-twenty-year-algorithm), the platform&apos;s TLS implementation. And every one of those values ultimately draws on the [Windows RNG](/blog/a-key-is-only-as-unguessable-as-the-dice-that-made-it-inside), whose seeding and clone-defense decide whether the &quot;unique and unpredictable, once, per key&quot; contract actually holds in practice. Read those three together and this article&apos;s rules become a specific call stack.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Signing: derive the nonce (RFC 6979), prefer Ed25519, hedge on hardware. AEAD: use AES-GCM only with a guaranteed-unique counter and an invocation cap; otherwise reach for AES-GCM-SIV or a 192-bit-nonce cipher. One instinct sits under both: never trust a runtime draw to be unique and unpredictable &quot;just once.&quot;&lt;/p&gt;
&lt;/blockquote&gt;

Sign the same message twice, with the same key, and compare the two signatures. If they are byte-for-byte identical, the signer is deterministic (RFC 6979 or Ed25519). If they differ, it is randomized or hedged. Ed25519 in most libraries will match exactly; Go&apos;s `crypto/ecdsa` will not, by design. That one comparison tells you which row of the Section 8 table you are standing in -- and whether an entropy failure at runtime would be survivable.
&lt;p&gt;Two rules for two primitives, resting on a single instinct. That instinct is strong enough to design around -- but a handful of persistent myths still surface in code review and threat models, and each one hides a real misunderstanding of the mechanism. Let us dismantle them one at a time.&lt;/p&gt;
&lt;h2&gt;12. Frequently Asked Questions&lt;/h2&gt;


No, and this distinction matters more than almost anything else here. A *repeated* nonce leaks the key from *two* signatures with certainty, through the subtraction in Section 3. A *biased* nonce is statistical: each signature is one noisy equation, and recovery needs *many* of them aggregated by a lattice or Fourier reduction [@ns] [@ladderleak]. One biased signature on its own leaks nothing you can use. &quot;One biased signature reveals your key&quot; is the single most common misstatement in this area.


Not against every adversary. Determinism removes the repeat and generation-side bias failures completely (it does not stop a side-channel leak of $k$ during the scalar multiplication $k \cdot G$, which needs a *constant-time* implementation, not determinism), but it turns the signer into a fixed, replayable target for differential fault analysis -- proven for de-randomized Fiat-Shamir schemes including EdDSA [@hedged], and flagged by FIPS 186-5 as a special concern for deterministic schemes on embedded and smartcard devices [@fips1865pdf]. That is exactly why hedged signatures exist.


No. It degrades gracefully instead of catastrophically. On a repeat it discloses only whether two messages were identical -- the provable minimum for any deterministic scheme -- never the key and never arbitrary plaintext [@rfc8452]. &quot;Graceful&quot; is not &quot;free.&quot; Do not reuse nonces on purpose in the belief that the SIV mode makes it costless.


No, and precision matters. A single collision instantly leaks $P_1 \oplus P_2$ and destroys confidentiality [@joux]. Recovering the authentication subkey $H$ is a *separate* step: one collision yields a set of candidate roots, and pinning $H$ uniquely generally needs two or more collisions [@joux]. Live TLS servers doing this were found forgeable in 2016 [@nda], but the mechanism is &quot;confidentiality gone at once, forgery after enough collisions,&quot; not &quot;one reuse equals the key.&quot;


Because you cannot certify unpredictability, only fail to falsify it -- and sub-bit bias is still fatal across enough signatures. LadderLeak won with less than one bit of leakage [@ladderleak]. Hardening the generator raises the bar; it does not change the structure. Deriving the number does.


Only within the birthday bound, and only if uniqueness genuinely holds. Random 96-bit nonces start colliding near $2^{48}$ messages, which is why usage caps per key exist [@rfc8452]. Worse, multi-writer keys, VM clones, and process forks silently re-emit the same nonce no matter how carefully you generated it. If uniqueness is uncertain, switch to AES-GCM-SIV [@rfc8452] or XChaCha20-Poly1305&apos;s 192-bit nonce [@xchacha]; this reuse has been observed in the wild [@nda].


No. Lattice- and Fiat-Shamir-based post-quantum signatures inherit the same sensitivity to per-signature randomness; several are precisely the de-randomized Fiat-Shamir schemes shown vulnerable to fault attacks [@hedged]. Migrating to post-quantum cryptography re-instantiates nonce discipline -- it does not retire it.

&lt;h2&gt;13. One Cure for Two Catastrophes&lt;/h2&gt;
&lt;p&gt;Return to that stage in Berlin in 2010, but now you can see the whole shape of the thing. The PlayStation 3 master key did not fall to a broken cipher or a weak curve; it fell to &lt;em&gt;one number, used twice&lt;/em&gt;, and two signatures&apos; worth of subtraction [@f0f]. The same shape swept real Bitcoin wallets when Android&apos;s generator repeated nonces [@bitcoin].&lt;/p&gt;
&lt;p&gt;Then the required leak kept shrinking -- bit-length timing on smart cards [@minerva], side channels in TPMs [@tpmfail], less than a single bit in LadderLeak [@ladderleak], nine fixed bits and sixty signatures in PuTTY [@putty] -- and the very same disease surfaced in a cipher, where 184 live TLS servers reusing a GCM nonce were shown forgeable [@nda].&lt;/p&gt;
&lt;p&gt;Every one of those failures shares a single sentence. Both primitives bet everything on a number that had to be unique and unpredictable exactly once, and both collapsed the moment that bet was lost. And the cures share a single sentence too. Deterministic signing derives the number from the key and the message so there is nothing left to repeat or bias [@rfc6979], while a &lt;em&gt;constant-time&lt;/em&gt; scalar multiplication closes the side-channel leaks that determinism never touched; hedged signing keeps a sliver of entropy so a fault has no fixed target [@hedged]; misuse-resistant encryption derives the IV from the message so a repeat leaks only that two messages matched [@rfc8452].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Two primitives, one disease, one cure: stop trusting runtime randomness for the once-per-operation number. Derive it, or make a repeat non-catastrophic. Everything else in this article is a footnote to that sentence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Part 2 of this series taught the two ways randomness betrays you; this was the promised descent into what those betrayals actually cost and how the field designed them away. The punchline you were promised at the start has been earned line by line: in cryptography, reusing one number can cost you everything -- so build systems that never require you to trust yourself to use it only once.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;nonce-reuse-ecdsa-aes-gcm&quot; keyTerms={[
  { term: &quot;Signing nonce (k)&quot;, definition: &quot;The per-signature secret scalar in (EC)DSA; it must be unique, secret, and unpredictable, exactly once per key.&quot; },
  { term: &quot;GCM nonce (IV)&quot;, definition: &quot;The per-message value in AES-GCM; it must be unique under a given key, though it may be public.&quot; },
  { term: &quot;Repeat vs. bias&quot;, definition: &quot;A repeated nonce leaks the key from two signatures with certainty; a biased nonce is statistical and needs many signatures.&quot; },
  { term: &quot;Hidden Number Problem (HNP)&quot;, definition: &quot;Recovering a secret from many samples that each reveal a few bits of a related product mod n; the frame for biased-nonce attacks.&quot; },
  { term: &quot;GHASH subkey (H)&quot;, definition: &quot;The secret AES-of-zero value that keys GCM&apos;s polynomial authenticator; recovering it enables universal forgery.&quot; },
  { term: &quot;Forbidden attack&quot;, definition: &quot;Joux&apos;s GCM attack: reusing an IV cancels the tag blind, exposing a polynomial whose roots are candidates for H.&quot; },
  { term: &quot;Deterministic signature&quot;, definition: &quot;A signature whose nonce is a pseudorandom function of the key and message, using no runtime randomness (RFC 6979, EdDSA).&quot; },
  { term: &quot;Hedged signature&quot;, definition: &quot;A nonce derived from key, message, and fresh entropy; safe if the RNG fails and against fault injection.&quot; },
  { term: &quot;Nonce-misuse-resistant AEAD&quot;, definition: &quot;An AEAD that on nonce reuse leaks at most message equality, never the key or arbitrary plaintext (AES-GCM-SIV, AES-SIV).&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>cryptography</category><category>ecdsa</category><category>aes-gcm</category><category>nonce-reuse</category><category>digital-signatures</category><category>aead</category><category>rfc-6979</category><category>applied-crypto</category><author>noreply@paragmali.com (Parag Mali)</author></item></channel></rss>