<?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: side-channel-attacks</title><description>Posts tagged side-channel-attacks.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sat, 25 Jul 2026 08:57:51 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/side-channel-attacks/rss.xml" rel="self" type="application/rss+xml"/><item><title>Never Decrypted: When Math Is Too Slow, Silicon Keeps the Secret -- Confidential Computing and GPU TEEs</title><link>https://paragmali.com/blog/never-decrypted-when-math-is-too-slow-silicon-keeps-the-secr/</link><guid isPermaLink="true">https://paragmali.com/blog/never-decrypted-when-math-is-too-slow-silicon-keeps-the-secr/</guid><description>How trusted execution environments keep a secret in silicon, not math, why attestation is the linchpin of confidential AI, and where the silicon model breaks.</description><pubDate>Thu, 23 Jul 2026 00:00:00 GMT</pubDate><content:encoded>
Trusted Execution Environments keep a secret the opposite way to the first four parts of this series. Instead of making the computation unreadable with mathematics, they decrypt it *inside* a hardware boundary that the operating system, the hypervisor, the cloud operator, and a person with a screwdriver are all locked out of -- and they prove which chip you are talking to with remote attestation.&lt;p&gt;That is what makes confidential AI real in 2026: encrypted model plus encrypted data, attested inference on an NVIDIA H100 at under nine percent overhead, where fully homomorphic encryption is orders of magnitude too slow. But the trust did not vanish; it &lt;em&gt;moved&lt;/em&gt; -- to a vendor, a die, and an unprovable &quot;no side channel&quot; assumption that a fifty-dollar memory interposer broke in 2025. The silicon and math anchors are complements, not rivals: choose per workload, or go hybrid.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;1. Run the Model in a Cloud That Cannot Read It&lt;/h2&gt;
&lt;p&gt;A hospital wants to run a proprietary 70-billion-parameter model on patient scans it is legally forbidden to expose. The datacenter belongs to a company neither the hospital nor the model&apos;s maker will trust with the plaintext. The model&apos;s owner will not ship the weights in the clear. &lt;a href=&quot;https://paragmali.com/blog/never-decrypted-how-fully-homomorphic-encryption-computes-on/&quot; rel=&quot;noopener&quot;&gt;Fully homomorphic encryption&lt;/a&gt; -- the mathematics of Part 1, which computes without ever decrypting -- is, as that part measured, three to six orders of magnitude too slow to answer in real time.&lt;/p&gt;
&lt;p&gt;And yet, in 2026, this runs at under ten percent overhead, because the weights and the scans are decrypted &lt;em&gt;only&lt;/em&gt; inside a GPU that the cloud operator, the hypervisor, and a technician with a screwdriver are all locked out of [@zhu-hopper-benchmark-2024] [@nvidia-h100-cc-ga-2024].&lt;/p&gt;
&lt;p&gt;Stop and notice how strange that is. A machine is computing on a model &lt;em&gt;and&lt;/em&gt; data its own owner may not read -- at GPU speed. For four installments, this series asked one question: how do you compute on data the machine&apos;s owner cannot see? Every previous answer was mathematical. Fully homomorphic encryption evaluates a circuit on ciphertext. &lt;a href=&quot;https://paragmali.com/blog/never-decrypted-proving-you-ran-the-computation-without-reve/&quot; rel=&quot;noopener&quot;&gt;Zero-knowledge proofs&lt;/a&gt; convince without revealing. &lt;a href=&quot;https://paragmali.com/blog/the-trusted-party-nobody-has-to-be-secure-multiparty-computa/&quot; rel=&quot;noopener&quot;&gt;Secure multi-party computation&lt;/a&gt; splits a secret so no single party holds it. &lt;a href=&quot;https://paragmali.com/blog/never-decrypted-reading-the-row-without-revealing-which-row/&quot; rel=&quot;noopener&quot;&gt;Private information retrieval&lt;/a&gt; reads a row without disclosing which row. All four buy confidentiality with a hardness assumption and, often, orders of magnitude of overhead.&lt;/p&gt;
&lt;p&gt;This capstone follows the field&apos;s &lt;em&gt;other&lt;/em&gt; answer, and it is almost rude in its simplicity: do not make the computation unreadable at all. Make the &lt;strong&gt;hardware itself&lt;/strong&gt; refuse to reveal it to anyone but an authorized party you can cryptographically identify.&lt;/p&gt;

The protection of data *in use* -- during computation -- in a hardware-based, attested Trusted Execution Environment, against an adversary that explicitly includes privileged system software (the operating system, the hypervisor, the firmware) and the owner of the physical machine. It is the third leg of a stool whose other two legs, encryption at rest and encryption in transit, have existed for decades [@ccc-technical-analysis-v1-3].
&lt;p&gt;Encryption at rest protects the disk. Encryption in transit protects the wire. Neither helps the instant the processor has to &lt;em&gt;compute&lt;/em&gt;, because a CPU or GPU operates on plaintext -- values must be decrypted into registers and memory to be added, multiplied, or matrix-multiplied. That plaintext sits in DRAM, where the machine&apos;s owner can read it: a cloud operator, a compromised hypervisor, a malicious insider, or an attacker on the memory bus. That gap -- data in use -- is the entire reason this field exists.&lt;/p&gt;

A hardware-enforced environment that keeps the code and data running inside it *confidential and integrity-protected while executing*, even from privileged software and the physical machine owner. A TEE does not hide the computation the way homomorphic encryption does; it decrypts the data inside a boundary and relies on the silicon to refuse to leak it.
&lt;p&gt;Here is the thesis of this final part, stated as a claim you should doubt until it is earned: &lt;strong&gt;the first four parts keep the secret with mathematics; a TEE keeps it with hardware plus attestation, trading a cryptographic trust model for a silicon one.&lt;/strong&gt; Raluca Ada Popa named these two options exactly -- confidential computing or cryptographic computing -- and the honest version of the contrast is not &quot;math versus no math,&quot; because a TEE is saturated with cryptography (AES memory encryption, digital-signature attestation). The difference is where trust is &lt;em&gt;anchored&lt;/em&gt; [@popa-cc-vs-cryptographic-2024].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; A TEE moves the secret from a mathematical assumption to a silicon one -- and remote attestation is what makes that silicon trust &lt;em&gt;verifiable&lt;/em&gt; instead of merely &lt;em&gt;assumed&lt;/em&gt;. Read the entire field through one question: if this breaks, who or what did you have to trust? For the mathematics of Parts 1 to 4, the answer is a hardness assumption. For a TEE, the answer is a vendor, a die, and the assumption that no one has exploited a side channel.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That lens is the spine of everything that follows. Every mechanism in the story -- memory encryption, process enclaves, confidential VMs, GPU confidential computing -- exists to keep your data and model confidential from the machine&apos;s owner &lt;em&gt;because you trust the chip and can prove which chip you are talking to&lt;/em&gt;. The rest of the article earns that generation by generation, and the conclusion sets it beside the math model and crowns no winner.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Carry three things from the earlier parts into this one. First, that &quot;compute on data the owner cannot read&quot; is a real, recurring need, not a thought experiment. Second, that the mathematical schemes buy confidentiality with a hardness assumption and pay in overhead -- FHE most of all. Third, that a proof of correct computation (Part 2&apos;s zero-knowledge proofs) is a close cousin of what a TEE calls attestation. Those threads all reconverge here.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So if the answer is not mathematics, what is it -- and where, exactly, did the trust go? To answer that, we have to go back to a heretical question someone asked in the year 2000.&lt;/p&gt;
&lt;h2&gt;2. Trust Only the Chip&lt;/h2&gt;
&lt;p&gt;In 2000, most security architecture rested on a comfortable assumption: the operating system is on your side. Antivirus ran as a privileged process. Disk encryption trusted the kernel with the key. The threat was &lt;em&gt;other users&lt;/em&gt;, or malware the OS had not yet caught. Then David Lie, Mark Horowitz, and their collaborators at Stanford and SRI asked a question that sounded almost paranoid: what if the operating system &lt;em&gt;itself&lt;/em&gt; is the enemy? What if the person who owns the machine is exactly who you are hiding from?&lt;/p&gt;
&lt;p&gt;Their answer, presented at ASPLOS 2000, was &lt;strong&gt;XOM&lt;/strong&gt; -- eXecute-Only Memory. XOM declared the CPU package the sole trust boundary and treated all off-chip memory and every bus as hostile territory. Code and data lived encrypted in DRAM and were decrypted only inside the processor; the operating system was modeled explicitly as the adversary [@xom-asplos-2000]. This is the intellectual birth of the silicon trust anchor. Everything in this article is a descendant of that one move: shrink the circle of trust until it contains nothing but the chip.&lt;/p&gt;

The component a system trusts *by assumption*, because nothing else vouches for it -- the place where the regress of &quot;but who verifies the verifier?&quot; finally stops. For a TEE, the trust anchor is a key placed inside the silicon by the manufacturer. The remote-attestation standard RFC 9334 names this exactly: a verifier trusts &quot;a manufacturer or the manufacturer&apos;s hardware&quot; by storing the endorser&apos;s key as a trust anchor [@rfc-9334].
&lt;p&gt;Three years later, G. Edward Suh, Srinivas Devadas, and colleagues at MIT built the design that every later TEE quietly inherits. &lt;strong&gt;AEGIS&lt;/strong&gt;, presented at ICS 2003, was a single-chip secure processor that added the rigor XOM had only sketched. It gave &lt;em&gt;tamper-evident&lt;/em&gt; execution by verifying off-chip memory with Merkle-style hash trees, &lt;em&gt;private tamper-resistant&lt;/em&gt; execution through memory encryption, anti-replay &lt;strong&gt;freshness&lt;/strong&gt;, and a secret rooted in a Physical Unclonable Function that even the manufacturer could not clone -- all while tolerating an untrusted operating system [@aegis-ics-2003].&lt;/p&gt;
&lt;p&gt;Pay attention to that word &lt;strong&gt;freshness&lt;/strong&gt;, because it seeds the irony that runs the length of this article. AEGIS insisted that memory protection needs three properties, not one: confidentiality (an attacker cannot read it), integrity (an attacker cannot silently alter it), and freshness (an attacker cannot replay a stale-but-valid value). Two decades later, the commercial TEEs that conquered the cloud would keep the first and quietly drop the third for speed -- and in 2025, a fifty-dollar device would pry open the exact gap AEGIS had closed in 2003.&lt;/p&gt;
&lt;p&gt;AEGIS paid a real, quantifiable price for freshness: a hash or integrity tree costs $O(\log N)$ hash verifications on every protected memory access, where $N$ scales with the size of the protected region. That logarithmic tax on every load and store is precisely the overhead later server TEEs refused to pay at whole-VM scale -- the design decision that made them fast and made them breakable.&lt;/p&gt;

timeline
    title The silicon trust anchor moves outward, 2000 to 2025
    2000 : XOM, the chip is the only trust boundary
    2003 : AEGIS, memory encryption plus integrity and freshness
    2004 : ARM TrustZone secure world : Direct Anonymous Attestation in the TPM
    2013 : Intel SGX process enclaves plus remote attestation
    2016 : AMD SEV, encrypt the whole VM
    2020 : AMD SEV-SNP adds integrity and VCEK attestation
    2021 : Intel TDX trust domains
    2023 : RFC 9334 standardizes attestation : NVIDIA H100 GPU CC preview
    2024 : H100 GPU CC general availability, confidential AI ships
    2025 : Battering RAM, WireTap, TEE.Fail break attestation physically
&lt;p&gt;AEGIS and XOM proved the model sound -- and, commercially, a dead letter in its original form. Both required new, non-commodity silicon; both imposed that logarithmic integrity-tree overhead on general workloads; and, most damning, neither shipped a usable software model or a way for a &lt;em&gt;remote&lt;/em&gt; party to check that a genuine secure processor was running the expected code. They were a correct architecture with no product [@aegis-retrospective]. The chip-only boundary was right, but it had to reach mass-market silicon, with a workable programming model and a way to prove itself across the internet.&lt;/p&gt;
&lt;p&gt;The last of those requirements was quietly being invented in parallel. In 2003 and 2004, the Trusted Computing Group standardized &lt;strong&gt;measured boot&lt;/strong&gt; -- hashing each stage of the boot process into a tamper-resistant TPM register, so a machine could later attest &quot;these are the exact bits that booted&quot; [@tcg-tpm-main-1-2].&lt;/p&gt;
&lt;p&gt;And in 2004, Ernie Brickell, Jan Camenisch, and Liqun Chen published &lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/direct-anonymous-attestation-the-zero-knowledge-proof-alread/&quot; rel=&quot;noopener&quot;&gt;Direct Anonymous Attestation&lt;/a&gt;&lt;/strong&gt;, letting a TPM prove it was genuine to a remote verifier &lt;em&gt;without revealing which&lt;/em&gt; TPM -- a zero-knowledge-style protocol adopted into TPM 1.2 [@daa-eprint-2004] [@daa-ibm-listing]. That is the seed of remote attestation: proving which code is running to someone who cannot see your datacenter.&lt;/p&gt;
&lt;p&gt;Direct Anonymous Attestation put a zero-knowledge proof inside every compliant TPM two decades ago. The companion article in this series on DAA traces that lineage in full; the point to hold here is that &quot;prove which chip and which code, without over-revealing&quot; is old, and it is the exact primitive a TEE needs to convert local isolation into remote trust.&lt;/p&gt;
&lt;p&gt;The same year measured boot and DAA were maturing, ARM shipped the first hardware isolation that would reach billions of devices [@genode-trustzone]. It answered &quot;trust only the chip&quot; for a phone. It would turn out to be the wrong shape for a cloud -- which is where the anchor has to move next.&lt;/p&gt;
&lt;h2&gt;3. Dual Worlds, Process Enclaves, and the First Cracks&lt;/h2&gt;
&lt;p&gt;The model shipped twice, in two very different shapes, and both started to crack.&lt;/p&gt;
&lt;p&gt;ARM&apos;s &lt;strong&gt;TrustZone&lt;/strong&gt;, introduced around 2003 to 2004, split the system-on-chip into two worlds -- a &lt;strong&gt;Secure World&lt;/strong&gt; and a &lt;strong&gt;Normal World&lt;/strong&gt; -- separated by a single processor-state bit propagated across the bus, so every memory and peripheral access is tagged secure or non-secure. One privileged Secure World, a small trusted OS and its apps, runs beside the rich Normal World, with a Secure Monitor Call the only gate [@genode-trustzone]. It was the first hardware isolation to ship in commodity silicon at scale, and it still guards the keys, biometrics, and payment secrets in billions of phones.&lt;/p&gt;
&lt;p&gt;But a phone has one owner. A cloud has thousands of mutually distrusting tenants, and TrustZone offers &lt;em&gt;exactly one&lt;/em&gt; coarse Secure World, owned by the platform operator [@trustzone-survey-2019]. You cannot hand each cloud customer an environment the provider itself cannot read, because the provider owns that single Secure World and holds its keys. There is no per-tenant confidential VM, and originally no per-tenant memory encryption at all -- isolation came from address-space partitioning, not an encryption engine.&lt;/p&gt;
&lt;p&gt;ARM later admitted the gap, adding a separate confidential-VM world in its Confidential Compute Architecture to give each tenant an isolated domain [@sok-tz-cca-2024]. TrustZone was the right model for a device and the wrong one for a cloud.&lt;/p&gt;
&lt;p&gt;Intel&apos;s &lt;strong&gt;SGX&lt;/strong&gt;, defined in two companion papers at HASP 2013, answered with the opposite granularity: not one big world but many tiny ones.&lt;/p&gt;

A per-process, hardware-encrypted region of memory whose contents are protected from the operating system, the hypervisor, and the BIOS. Code and data inside an SGX enclave are decrypted only on-die; an enclave can be *remotely attested* (it can prove to a third party which code it is running) and can *seal* secrets to a CPU-derived key for storage. The trust base is minimal: your enclave and the CPU, and explicitly not the operating system.
&lt;p&gt;SGX made &quot;run a piece of code the OS cannot read&quot; real at mass-market scale, and it shipped the first production remote attestation of application-enclave code, originally using EPID group signatures [@sgx-hasp-2013]. For one kind of workload -- a small, well-defined secret kernel -- it was exactly right. Signal&apos;s contact-discovery service, examined in this series&apos; secure-multiparty-computation installment, still runs inside SGX enclaves [@signal-cdsi]. It is the natural bridge between the two trust models: a reminder that a TEE is often the practical way to deploy a cryptographic protocol.&lt;/p&gt;
&lt;p&gt;Then the cracks. The first was a performance cliff. On client parts, the Enclave Page Cache was reserved at 128 MB with only about 90 to 96 MB usable; exceed it and SGX pages enclave memory out to normal RAM with encryption and integrity checks, at a &lt;strong&gt;5 to 100 times slowdown&lt;/strong&gt; once the working set spills over [@vault-asplos-2018]. The second was ergonomic: you had to refactor an application into trusted and untrusted halves, a punishing model compared with &quot;run my existing program, but private.&quot;&lt;/p&gt;
&lt;p&gt;The third crack was the one that mattered, and it kept widening. Starting in 2018, a stacking parade of attacks showed that both an enclave&apos;s contents &lt;em&gt;and its attestation root&lt;/em&gt; were extractable.&lt;/p&gt;

An attack that recovers secrets not by breaking the cryptography but by observing a physical or microarchitectural byproduct of the computation -- timing, cache state, speculative execution, power, or the electrical signals on a memory bus. Two sub-classes recur throughout this article and must be kept distinct: *microarchitectural* side channels (speculative-execution and cache attacks such as Foreshadow, SgxPectre, and AEPIC) that need only code on the machine, and *physical* side channels (memory-bus interposers such as the 2025 attacks) that need a device between the chip and its DRAM.
&lt;p&gt;&lt;strong&gt;Foreshadow&lt;/strong&gt;, in 2018, used the L1 Terminal Fault speculative-execution flaw to transiently read SGX enclave memory out of the L1 cache -- including, critically, the machine&apos;s private attestation key [@foreshadow-l1tf]. &lt;strong&gt;SgxPectre&lt;/strong&gt; brought Spectre-style speculative gadgets inside the enclave to leak its secrets [@sgxpectre-2018].&lt;/p&gt;
&lt;p&gt;Then the attacks reached the root. &lt;strong&gt;SGAxe&lt;/strong&gt;, in 2020, extracted the machine&apos;s SGX attestation key from the architectural enclaves, letting an attacker forge quotes indistinguishable from genuine ones and impersonate any SGX machine to a verifier [@sgaxe-2020]. &lt;strong&gt;AEPIC Leak&lt;/strong&gt;, in 2022, was the first &lt;em&gt;architectural&lt;/em&gt; (non-speculative) x86 data leak: an uninitialized read of APIC MMIO registers dumped stale physical-memory contents -- including enclave secrets -- bypassing every speculative-execution mitigation [@aepic-leak-2022].&lt;/p&gt;

Foreshadow demonstrated how speculative execution can be exploited for reading the contents of SGX-protected memory as well as extracting the machine&apos;s private attestation key.
&lt;p&gt;That last clause is the whole game. Reading one enclave&apos;s data is a local break. Extracting the &lt;em&gt;attestation key&lt;/em&gt; is a systemic one: it lets you forge the proof that any enclave is genuine. Hold that distinction; it returns in 2025 with a screwdriver instead of a speculative gadget.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A TEE does not make the computation mathematically unreadable the way FHE does. It &lt;em&gt;decrypts inside a boundary&lt;/em&gt; and depends on the chip to refuse to reveal it. The secret did not become unreadable; the &lt;strong&gt;trust moved&lt;/strong&gt; -- from a hardness assumption to &quot;trust this silicon, and prove which silicon.&quot; Once you feel that click, every remaining section is just a question of where the anchor moves next, and where it can be pried loose.&lt;/p&gt;
&lt;/blockquote&gt;

Two forces pushed the industry off the process-enclave model. The first was engineering cost: rewriting a large application into enclave-shaped trusted and untrusted halves, and living inside a tight encrypted page cache, was too expensive for general workloads. The second was operational: enterprises wanted to lift an *existing* virtual machine -- operating system, drivers, application, unchanged -- into a confidential environment for compliance, without touching the code. Process enclaves could not offer that. Whole-VM confidential computing could, and that is where the anchor went next.
&lt;p&gt;If a process enclave is too small, too hard to port, and its attestation root is extractable, where does the anchor move? Outward again -- this time around the entire virtual machine.&lt;/p&gt;
&lt;h2&gt;4. The Anchor Moves Outward, Generation by Generation&lt;/h2&gt;
&lt;p&gt;Line up the five generations and one motion becomes visible: the trust anchor marches outward -- chip, to one world, to many enclaves, to a whole VM, to a whole VM plus its GPU -- and every step is forced by the previous generation&apos;s concrete failure.&lt;/p&gt;

flowchart LR
    G0[&quot;Gen 0: the chip (XOM, AEGIS)&quot;] --&amp;gt;|&quot;no product, no remote attestation&quot;| G1[&quot;Gen 1: one secure world (TrustZone)&quot;]
    G1 --&amp;gt;|&quot;single operator-owned world, not multi-tenant&quot;| G2[&quot;Gen 2: many enclaves (SGX)&quot;]
    G2 --&amp;gt;|&quot;tiny page cache, app rewrite, attestation-key leaks&quot;| G3[&quot;Gen 3: whole VM (SEV-SNP, TDX)&quot;]
    G3 --&amp;gt;|&quot;the GPU where AI runs is outside the boundary&quot;| G4[&quot;Gen 4: whole VM plus GPU (H100 CC)&quot;]
&lt;p&gt;Generations 0, 1, and 2 we have met: the academic secure processors that proved the model, TrustZone&apos;s single operator-owned world, and SGX&apos;s fragile fleet of enclaves. The generation that actually conquered the cloud is the third, and it has an internal story worth telling because it re-enacts, in miniature, the whole arc of the field.&lt;/p&gt;

A virtual machine whose entire memory is encrypted with a key held by an on-die security processor, and whose isolation is enforced against the hypervisor and the cloud operator -- so an *unmodified* guest operating system and its applications can be &quot;lifted and shifted&quot; into a confidential environment with no code changes. AMD SEV-SNP and Intel TDX are the two cloud-dominant confidential-VM technologies.
&lt;p&gt;AMD&apos;s line began in 2016 with &lt;strong&gt;SME&lt;/strong&gt; (whole-DRAM encryption via an inline AES engine in the memory controller) and &lt;strong&gt;SEV&lt;/strong&gt; (Secure Encrypted Virtualization), which gave each VM a distinct key so a compromised hypervisor could not read guest memory. David Kaplan presented the architecture at USENIX Security that year [@amd-sme-sev-wp-2016] [@kaplan-usenixsec16]. It was the anchor jumping from a process to a whole machine.&lt;/p&gt;
&lt;p&gt;But the first version leaked. Plain SEV left the guest&apos;s CPU registers in plaintext: on every VMEXIT, the hypervisor saved the register state -- the VMCB -- in the clear, exposing in-use secrets and permitting tampering. &lt;strong&gt;SEV-ES&lt;/strong&gt; (&quot;Encrypted State&quot;), in 2017, closed that by encrypting the register state at VMEXIT [@amd-sev-overview] [@suse-sev-es-guide]. One leak found, one leak patched.&lt;/p&gt;
&lt;p&gt;The deeper problem was structural, and it is the one AEGIS had warned about in 2003. SEV and SEV-ES encrypted memory &lt;em&gt;deterministically and without authentication&lt;/em&gt; -- no integrity, no freshness.&lt;/p&gt;

The encryption of DRAM contents so that data is ciphertext outside the processor. Server TEEs key it on the physical address and make it *deterministic*: the same plaintext at the same location always yields the same ciphertext. Intel TDX uses AES-XTS; AMD SEV uses an XEX-mode tweak (XTS without the ciphertext-stealing step). Either way it is fast and free of per-write bookkeeping, but provides confidentiality only -- it leaks whether two ciphertexts are equal, and it cannot detect an attacker who records and later replays a valid ciphertext.
&lt;p&gt;Deterministic, unauthenticated encryption is a seam, and researchers pried at it. &lt;strong&gt;CrossLine&lt;/strong&gt; (2020) broke SEV&apos;s &quot;security-by-crash&quot; memory isolation [@crossline-2020]. &lt;strong&gt;CipherLeaks&lt;/strong&gt; (2021) recovered secrets straight out of the deterministic ciphertext of the register-save area, through what its authors named the ciphertext side channel -- no speculation required [@cipherleaks-2021].&lt;/p&gt;
&lt;p&gt;The vendors answered with integrity. AMD&apos;s &lt;strong&gt;SEV-SNP&lt;/strong&gt; (2020) added rollback protection through the &lt;strong&gt;Reverse Map Table&lt;/strong&gt;, which gives every physical page a validated owner, plus firmware-signed attestation rooted in a per-chip key, the VCEK [@amd-sev-snp-wp-2020]. Intel&apos;s &lt;strong&gt;TDX&lt;/strong&gt; (2021) followed: Trust Domains isolated from the hypervisor by a CPU-attested TDX module in a new SEAM mode, with per-domain AES-XTS memory encryption and Intel-signed attestation [@intel-tdx-overview]. Both deliver near-native speed -- typically single-digit-percent overhead -- across a whole multi-gigabyte VM, with no tiny-cache cliff and no application rewrite [@kaplan-cacm-2023].&lt;/p&gt;

The internal mechanics of confidential VMs -- the Reverse Map Table&apos;s page-state machine, the full VCEK certificate chain up to AMD&apos;s Key Distribution Service, Intel&apos;s DCAP quoting flow, and the paravisor that lets an unmodified Windows or Linux guest run under SEV-SNP or TDX -- are dissected in the companion post on Azure Confidential VMs.&lt;p&gt;This article references that substrate rather than repeating it, because the capstone&apos;s budget belongs to the trust-anchor argument, the GPU frontier, and the honest contrast. Read that post for the CPU-VM plumbing; read this one for what the plumbing is &lt;em&gt;for&lt;/em&gt; and where it breaks.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Notice what SEV-SNP restored and what it did not. It restored &lt;em&gt;integrity&lt;/em&gt; through the Reverse Map Table. But the underlying memory &lt;em&gt;encryption&lt;/em&gt; stayed deterministic and unauthenticated at the DRAM bus -- the freshness gap AEGIS closed in 2003 remained open, a design decision traded for whole-server speed. Remember that; Section 9 collects the bill.&lt;/p&gt;
&lt;p&gt;The third generation was mature, deployed, and, for the workload that now defines the decade, insufficient. A CPU confidential VM protects data in &lt;em&gt;CPU&lt;/em&gt; DRAM. But the moment a tensor crosses the PCIe bus to a GPU, it is plaintext in GPU VRAM -- readable by the operator, the hypervisor, or a DMA attack. And modern AI does not run on the CPU. It runs on the GPU. The whole-VM anchor, however polished, could not deliver confidential AI by itself, because the accelerator where the computation actually happens sat &lt;em&gt;outside&lt;/em&gt; the boundary [@nvidia-h100-cc-preview-2023].&lt;/p&gt;
&lt;p&gt;So the anchor took its final step. NVIDIA&apos;s &lt;strong&gt;H100&lt;/strong&gt;, the Hopper generation, became the first GPU to support confidential computing -- private preview in July 2023, general availability with the CUDA 12.4 data-center driver in early 2024, in single-GPU passthrough mode [@nvidia-h100-cc-ga-2024]. It extends the encrypted, attested boundary across PCIe and into the GPU. VRAM is encrypted with keys held in an on-die root of trust and never exposed to host software; the only CPU-to-GPU data path is an AES-GCM-protected bounce buffer; and the link itself is established and protected with the SPDM device-security protocol [@nvidia-hcc-whitepaper] [@dmtf-spdm-dsp0274].&lt;/p&gt;
&lt;p&gt;Composed with a CPU confidential VM, this keeps a proprietary model&apos;s weights and a user&apos;s data confidential &lt;em&gt;through inference and training on the GPU&lt;/em&gt;. Blackwell extends it again, bringing GPU-to-GPU NVLink traffic inside the boundary through Protected PCIe and TEE-I/O, so an eight-GPU or rack-scale job runs as one confidential domain [@nvidia-secure-ai-blackwell-wp].&lt;/p&gt;
&lt;p&gt;Here is the whole lineage on one axis.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Generation&lt;/th&gt;
&lt;th&gt;Era&lt;/th&gt;
&lt;th&gt;Trust boundary&lt;/th&gt;
&lt;th&gt;Integrity or freshness at the DRAM bus&lt;/th&gt;
&lt;th&gt;Attestation root&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Gen 0: XOM, AEGIS&lt;/td&gt;
&lt;td&gt;2000, 2003&lt;/td&gt;
&lt;td&gt;The chip package&lt;/td&gt;
&lt;td&gt;Full integrity plus freshness trees&lt;/td&gt;
&lt;td&gt;None (research)&lt;/td&gt;
&lt;td&gt;Never shipped at scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gen 1: ARM TrustZone&lt;/td&gt;
&lt;td&gt;2003 to 2004&lt;/td&gt;
&lt;td&gt;One secure world&lt;/td&gt;
&lt;td&gt;None originally&lt;/td&gt;
&lt;td&gt;Platform-owner keys&lt;/td&gt;
&lt;td&gt;Active in mobile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gen 2: Intel SGX&lt;/td&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;Process enclave&lt;/td&gt;
&lt;td&gt;Integrity tree over a small cache&lt;/td&gt;
&lt;td&gt;Intel EPID, later DCAP&lt;/td&gt;
&lt;td&gt;Niche, minimal-TCB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gen 3: SEV-SNP, TDX&lt;/td&gt;
&lt;td&gt;2020, 2021&lt;/td&gt;
&lt;td&gt;Whole VM&lt;/td&gt;
&lt;td&gt;Integrity (RMP); deterministic, unauthenticated&lt;/td&gt;
&lt;td&gt;AMD VCEK, Intel PCS&lt;/td&gt;
&lt;td&gt;Active, cloud default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gen 4: H100 Hopper CC&lt;/td&gt;
&lt;td&gt;2023 to 2024&lt;/td&gt;
&lt;td&gt;Whole VM plus GPU&lt;/td&gt;
&lt;td&gt;AES-GCM on the link, vendor-protected VRAM&lt;/td&gt;
&lt;td&gt;NVIDIA NRAS plus CPU root&lt;/td&gt;
&lt;td&gt;Active, confidential AI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Read down the &quot;attestation root&quot; column and you can see the entire trust model at a glance: every generation, no matter how far outward the boundary moves, ultimately trusts a key placed in the silicon by a vendor. That invariant is the article&apos;s quiet drumbeat. But isolation inside the box is worthless to someone on the other side of the planet unless they can &lt;em&gt;prove&lt;/em&gt; which box they are talking to. How?&lt;/p&gt;
&lt;h2&gt;5. Remote Attestation: The Linchpin&lt;/h2&gt;
&lt;p&gt;Everything so far is local. A chip encrypts its memory and isolates a workload from the operator. But picture yourself as the hospital in the opening scene, about to send an encrypted model key into a datacenter you do not control. From where you stand, a genuine confidential VM and an ordinary VM &lt;em&gt;lying about being one&lt;/em&gt; look identical. Both accept your connection. Both claim to be secure. Isolation you cannot verify is worth nothing, because you cannot tell it apart from its absence.&lt;/p&gt;
&lt;p&gt;The single idea that converts &quot;trust me&quot; into &quot;verify me&quot; is hardware-rooted remote attestation. It is the load-bearing move of the entire field, and it is what discharges the &quot;plus attestation&quot; in this article&apos;s thesis.&lt;/p&gt;

A procedure by which a TEE proves to a remote party what code and configuration it is running, rooted in a hardware-held key. The flow is always the same shape: the environment is *measured* (hashed), the measurement is packaged into a hardware-signed *quote*, a *verifier* checks that signature against a trusted vendor root, and only an environment that matches the expected measurement is treated as trustworthy [@rfc-9334].
&lt;p&gt;The modern vocabulary is standardized by IETF &lt;strong&gt;RFC 9334&lt;/strong&gt;, the Remote Attestation Procedures (RATS) architecture, which defines three roles: the &lt;strong&gt;Attester&lt;/strong&gt; produces Evidence, the &lt;strong&gt;Verifier&lt;/strong&gt; appraises that Evidence and produces Attestation Results, and the &lt;strong&gt;Relying Party&lt;/strong&gt; acts on the results. Tellingly, RFC 9334 frames the whole model in the language this article has been using: the Verifier trusts &quot;a manufacturer or the manufacturer&apos;s hardware&quot; by storing the endorser&apos;s key as a &lt;strong&gt;trust anchor&lt;/strong&gt; (Section 7.4). The standard itself names the thing that moves [@rfc-9334].&lt;/p&gt;

The hardware-signed report a TEE emits as proof of its state -- the measurement of its code and configuration, signed by a key that chains to the silicon vendor&apos;s root. In RATS terms it is *Evidence*; in AMD, Intel, and NVIDIA tooling it is usually called a *quote*. Its security rests entirely on the signing key staying secret: a quote is only as trustworthy as the key that signed it.

sequenceDiagram
    participant A as Attester (the TEE)
    participant V as Verifier
    participant R as Relying Party (key service)
    A-&amp;gt;&amp;gt;A: Measure code and configuration
    A-&amp;gt;&amp;gt;V: Send signed Evidence (the quote)
    V-&amp;gt;&amp;gt;V: Check signature against the vendor root
    V--&amp;gt;&amp;gt;R: Return Attestation Result, trustworthy or not
    R-&amp;gt;&amp;gt;R: Compare the measurement to the expected value
    R--&amp;gt;&amp;gt;A: Release the secret only on a match
&lt;p&gt;The final step -- release the secret only on a match -- has a name in production systems.&lt;/p&gt;

A policy that gates the release of a secret (for example, the key that decrypts model weights or patient data) on a *verified* attestation. The key-management service hands over the key only when the presented quote verifies against the correct vendor root and the measurement equals the expected, approved value. It is what turns an abstract &quot;the environment is trustworthy&quot; into a concrete &quot;and therefore you may now have the key.&quot;
&lt;p&gt;For ordinary confidential computing, one attestation suffices: the CPU confidential VM proves itself against its vendor root (AMD&apos;s VCEK for SEV-SNP, Intel&apos;s PCS/DCAP for TDX), and Secure Key Release hands over the key [@amd-sev-snp-wp-2020] [@intel-tdx-overview]. Confidential AI needs a decisive twist, because there are now &lt;em&gt;two&lt;/em&gt; pieces of silicon in the boundary -- the CPU and the GPU -- provisioned by &lt;em&gt;two different vendors&lt;/em&gt;, and each must prove itself against its &lt;em&gt;own&lt;/em&gt; root.&lt;/p&gt;

flowchart TD
    CPU[&quot;CPU confidential VM&quot;] --&amp;gt;|&quot;CVM evidence&quot;| MAA[&quot;Verifier composes both (Azure MAA)&quot;]
    GPU[&quot;NVIDIA H100 GPU&quot;] --&amp;gt;|&quot;GPU evidence&quot;| MAA
    VCEK[&quot;AMD VCEK root&quot;] -.-&amp;gt;|&quot;verifies CPU&quot;| MAA
    NRAS[&quot;NVIDIA NRAS root&quot;] -.-&amp;gt;|&quot;verifies GPU&quot;| MAA
    MAA --&amp;gt;|&quot;one combined token&quot;| SKR[&quot;Secure Key Release&quot;]
    SKR --&amp;gt;|&quot;model and data keys&quot;| APP[&quot;Attested workload&quot;]
&lt;p&gt;In Azure&apos;s deployed confidential-AI pipeline, Microsoft Azure Attestation &lt;strong&gt;composes&lt;/strong&gt; the AMD confidential-VM evidence and the NVIDIA GPU evidence into a single token -- but the GPU attestation is signed by &lt;strong&gt;NVIDIA&apos;s Remote Attestation Service (NRAS)&lt;/strong&gt;, not by Azure [@azure-attestation-overview] [@nvidia-nvtrust-docs]. Two signatures, two roots, one composed result.&lt;/p&gt;
&lt;p&gt;The procurement-critical mistake -- and it is a real one -- is to verify the CPU VM and &lt;em&gt;assume&lt;/em&gt; the GPU is covered. The trust boundary &quot;spans confidential VM on the CPU and attached GPU,&quot; and each half has its own chain of custody back to a different manufacturer [@azure-gpu-options]. The NCCadsH100v5 virtual machine size, an AMD SEV-SNP EPYC Genoa VM with an in-boundary H100, is the reference implementation of exactly this pattern [@azure-nccadsh100v5].&lt;/p&gt;
&lt;p&gt;{`
// Illustrative logic, not a real crypto library.
function verifyQuote(quote, expectedRoot, expectedMeasurement) {
  const rootOk = quote.signedBy === expectedRoot;
  const measurementOk = quote.measurement === expectedMeasurement;
  return rootOk &amp;amp;&amp;amp; measurementOk;
}&lt;/p&gt;
&lt;p&gt;const cpuQuote = { signedBy: &quot;AMD-VCEK&quot;, measurement: &quot;cvm-image-v1&quot; };
const gpuQuote = { signedBy: &quot;NVIDIA-NRAS&quot;, measurement: &quot;h100-cc-enabled&quot; };&lt;/p&gt;
&lt;p&gt;const cpuOk = verifyQuote(cpuQuote, &quot;AMD-VCEK&quot;, &quot;cvm-image-v1&quot;);
const gpuOk = verifyQuote(gpuQuote, &quot;NVIDIA-NRAS&quot;, &quot;h100-cc-enabled&quot;);&lt;/p&gt;
&lt;p&gt;// Cardinal rule: release the secret ONLY when both roots verify.
console.log(cpuOk &amp;amp;&amp;amp; gpuOk
  ? &quot;Both attestations valid -- releasing model and data keys&quot;
  : &quot;Attestation failed -- refusing to release keys&quot;);&lt;/p&gt;
&lt;p&gt;// A quote signed by the wrong key must be rejected, even with a valid measurement:
const forged = { signedBy: &quot;attacker-key&quot;, measurement: &quot;h100-cc-enabled&quot; };
console.log(&quot;Forged GPU quote accepted? &quot; + verifyQuote(forged, &quot;NVIDIA-NRAS&quot;, &quot;h100-cc-enabled&quot;));
`}&lt;/p&gt;
&lt;p&gt;There is a family resemblance to Part 2 of this series. A zero-knowledge proof lets a prover convince a verifier a computation was done correctly without revealing the inputs; an attestation quote lets a chip convince a verifier the expected code is running without the verifier seeing the datacenter. Attestation is the silicon analogue of a verifiable claim -- a proof about &lt;em&gt;which machine and which code&lt;/em&gt;, not &lt;em&gt;which computation&lt;/em&gt;. The companion post on &lt;a href=&quot;https://paragmali.com/blog/verify-me-dont-trust-me-apple-pcc-azure-confidential-ai-and-/&quot; rel=&quot;noopener&quot;&gt;Apple Private Cloud Compute versus Azure confidential AI&lt;/a&gt; pushes this further, to attestation against a &lt;em&gt;publicly logged&lt;/em&gt; build, which Section 6 reaches.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Attestation, not encryption, is the load-bearing move. A remote party cannot distinguish a real confidential VM from an ordinary VM lying about it -- unless the hardware proves itself with a signed quote checked against a vendor root, and the secret is released only on success. And confidential AI needs &lt;em&gt;two&lt;/em&gt; such proofs, against &lt;em&gt;two&lt;/em&gt; roots. Without attestation, silicon isolation is unverifiable and you are back to trusting the operator&apos;s word.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you procure confidential AI, verify both halves. Check the CPU VM&apos;s quote against the correct CPU vendor root, check the GPU&apos;s quote against NVIDIA&apos;s root, and gate Secure Key Release on &lt;em&gt;both&lt;/em&gt;. A pipeline that attests the CPU and trusts the GPU by assumption has a plaintext hole exactly where the model runs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the silicon works, and we can prove it works, to someone who cannot see the building. Is &lt;em&gt;this&lt;/em&gt; the thing that finally makes confidential AI real at GPU speed? What does the state of the art actually ship in 2026?&lt;/p&gt;
&lt;h2&gt;6. Confidential AI in 2026&lt;/h2&gt;
&lt;p&gt;Return to the hospital. The model owner encrypts the weights; the hospital encrypts the scans; both keys are held by a key-management service that will release them only to an attested environment. A confidential VM boots on an AMD SEV-SNP host, an H100 in confidential-computing mode is attached to its trust boundary, and both halves attest -- the CPU against AMD&apos;s root, the GPU against NVIDIA&apos;s -- before either key is released. Now trace the data.&lt;/p&gt;

The single permitted data path between a CPU confidential VM and a GPU in confidential-computing mode. Because host software must never see plaintext, the CPU VM encrypts each transfer with AES-GCM into a shared buffer, and the GPU decrypts it only inside its own boundary (and vice versa on the way back). Data is never plaintext on the PCIe bus or in host memory [@nvidia-hcc-whitepaper].

A DMTF standard (DSP0274) for authenticating a hardware device and establishing an encrypted, integrity-protected session with it over a bus such as PCIe. NVIDIA H100 confidential computing uses SPDM to authenticate the GPU to the CPU confidential VM and secure the link between them [@nvidia-hcc-whitepaper] [@dmtf-spdm-dsp0274].

flowchart LR
    A[&quot;Tensors inside the CPU confidential VM&quot;] --&amp;gt;|&quot;AES-GCM encrypt&quot;| BB[&quot;Encrypted bounce buffer on the PCIe bus&quot;]
    BB --&amp;gt;|&quot;SPDM-secured session&quot;| G[&quot;Decrypt only inside the GPU TEE&quot;]
    G --&amp;gt; VRAM[&quot;Compute on encrypted VRAM&quot;]
    ROT[&quot;On-die GPU root of trust holds the keys&quot;] --&amp;gt; G
&lt;p&gt;The plaintext model and the plaintext scans exist in exactly two places: inside the CPU confidential VM&apos;s encrypted memory, and inside the H100&apos;s encrypted VRAM. On the wire between them they are AES-GCM ciphertext; to the operator, the hypervisor, and anyone with a bus analyzer, the whole pipeline is opaque. That is confidential AI, and the reason it matters is the number attached to it.&lt;/p&gt;
&lt;p&gt;An empirical benchmark by Zhu and colleagues measured H100 confidential computing across many models and input sizes: the average throughput overhead is &lt;strong&gt;under nine percent&lt;/strong&gt; versus the TEE disabled [@zhu-hopper-benchmark-2024]. This is the headline homomorphic encryption cannot touch. FHE on a 70-billion-parameter forward pass is orders of magnitude too slow for real time; a GPU TEE runs the same inference within a tenth of native speed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The counterintuitive finding is that the &lt;em&gt;smallest&lt;/em&gt; model carries the highest overhead and the &lt;em&gt;largest&lt;/em&gt; carries almost none: the study reports the overhead for Llama-3.1-70B on the H100 is negligible, close to zero. The residual cost is dominated by the encrypted CPU-to-GPU transfer, not by GPU computation -- so as a model gets bigger and compute-bound, the fixed encryption cost is amortized toward nothing [@zhu-hopper-benchmark-2024].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A consequence that surprises people: a &lt;em&gt;faster&lt;/em&gt; GPU can show &lt;em&gt;more&lt;/em&gt; relative confidential-computing overhead. The benchmark finds the H200 -- the same Hopper confidential-computing family as the H100, with faster HBM3e memory [@nvidia-hopper-arch-hub] -- exhibits a larger overhead percentage for the same model, because its quicker compute makes the fixed PCIe-encryption cost a bigger share of a smaller total [@zhu-hopper-benchmark-2024].&lt;/p&gt;
&lt;p&gt;Set the shipping methods side by side. The axes are the ones a practitioner actually chooses between: how big is the protected boundary, how much does it cost, whose root do you trust, does it fit AI, and how has it been broken.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Intel SGX&lt;/th&gt;
&lt;th&gt;AMD SEV-SNP&lt;/th&gt;
&lt;th&gt;Intel TDX&lt;/th&gt;
&lt;th&gt;NVIDIA H100/H200 CC&lt;/th&gt;
&lt;th&gt;Blackwell multi-GPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Granularity&lt;/td&gt;
&lt;td&gt;Process enclave&lt;/td&gt;
&lt;td&gt;Whole VM&lt;/td&gt;
&lt;td&gt;Whole VM&lt;/td&gt;
&lt;td&gt;GPU plus CPU VM&lt;/td&gt;
&lt;td&gt;Multi-GPU plus CPU VM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First shipped&lt;/td&gt;
&lt;td&gt;2015&lt;/td&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;2023&lt;/td&gt;
&lt;td&gt;2024 GA&lt;/td&gt;
&lt;td&gt;2024 to 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overhead&lt;/td&gt;
&lt;td&gt;Near-native in cache; 5 to 100 times on paging [@vault-asplos-2018]&lt;/td&gt;
&lt;td&gt;Near-native (design)&lt;/td&gt;
&lt;td&gt;Near-native (design)&lt;/td&gt;
&lt;td&gt;Under 9% avg; near-zero for 70B [@zhu-hopper-benchmark-2024]&lt;/td&gt;
&lt;td&gt;Vendor near-native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boundary&lt;/td&gt;
&lt;td&gt;About 90 to 96 MB usable cache&lt;/td&gt;
&lt;td&gt;Whole VM&lt;/td&gt;
&lt;td&gt;Whole VM&lt;/td&gt;
&lt;td&gt;Full VRAM, single-GPU&lt;/td&gt;
&lt;td&gt;8-GPU or rack domain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attestation root&lt;/td&gt;
&lt;td&gt;Intel EPID then DCAP&lt;/td&gt;
&lt;td&gt;AMD VCEK&lt;/td&gt;
&lt;td&gt;Intel PCS/DCAP&lt;/td&gt;
&lt;td&gt;NVIDIA NRAS&lt;/td&gt;
&lt;td&gt;NVIDIA NRAS plus CPU root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI fit&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;td&gt;CPU-only&lt;/td&gt;
&lt;td&gt;CPU-only&lt;/td&gt;
&lt;td&gt;Native, single-GPU&lt;/td&gt;
&lt;td&gt;Native, multi-GPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Representative break&lt;/td&gt;
&lt;td&gt;WireTap, SGAxe, Foreshadow&lt;/td&gt;
&lt;td&gt;Battering RAM, TEE.Fail&lt;/td&gt;
&lt;td&gt;TEE.Fail forged quote&lt;/td&gt;
&lt;td&gt;TEE.Fail keys reach GPU CC&lt;/td&gt;
&lt;td&gt;Inherits the ceiling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status&lt;/td&gt;
&lt;td&gt;Niche&lt;/td&gt;
&lt;td&gt;Cloud default&lt;/td&gt;
&lt;td&gt;Intel lift-and-shift&lt;/td&gt;
&lt;td&gt;Confidential AI&lt;/td&gt;
&lt;td&gt;Emerging, frontier scale&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Two more methods complete the 2026 picture. NVIDIA&apos;s &lt;strong&gt;Blackwell&lt;/strong&gt; generation extends confidential computing across multiple GPUs -- bringing NVLink traffic inside the boundary via Protected PCIe and TEE-I/O, up to a 72-GPU rack as a single confidential domain -- which is the emerging answer for frontier-model training and inference that a single GPU cannot hold [@nvidia-secure-ai-blackwell-wp]. And &lt;strong&gt;Apple Private Cloud Compute&lt;/strong&gt;, announced in 2024 for Apple Intelligence, raises a different bar entirely.&lt;/p&gt;
&lt;p&gt;Apple PCC&apos;s distinguishing move is not the enclave but the &lt;em&gt;verifiability of the entire fleet&lt;/em&gt;. Apple publishes every production server image to an append-only transparency log with a signed measurement, and a user&apos;s device sends data &lt;strong&gt;only&lt;/strong&gt; to a node whose attestation matches a &lt;em&gt;publicly logged&lt;/em&gt; build [@apple-pcc-blog] [@apple-pcc-source]. Plain attestation proves you are talking to an approved build; PCC&apos;s transparency proves that build is one the whole world can inspect -- closing the &quot;the provider quietly changed the software and you could not tell&quot; gap. The companion post on Apple PCC versus Azure confidential AI develops that contrast.&lt;/p&gt;
&lt;p&gt;A 2025 systematic security analysis reverse-engineered the internals of NVIDIA GPU confidential computing -- the SEC2 bootstrap channel and the paired work-launch and launch-confirmation channels that carry signed, encrypted work into the protected region -- mapping exactly where the trusted and untrusted seams lie [@gpu-cc-security-analysis-2025].&lt;/p&gt;
&lt;p&gt;One myth to retire while we are here. There was no &quot;Confidential GPT-4&quot; general-availability release in 2024, however often the phrase circulates; the publicly demonstrated confidential-inferencing workload was a speech-to-text model [@nvidia-azure-h100-cvm-ga-2024], and the shipping CPU-plus-GPU pipeline anyone can rent is NCCadsH100v5 [@azure-nccadsh100v5]. The reality is more impressive than the folklore, because it is real.&lt;/p&gt;
&lt;p&gt;This is real, it ships, and it is fast. So is the silicon trust model simply &lt;em&gt;better&lt;/em&gt; than the mathematics of Parts 1 to 4? Time for the honest accounting.&lt;/p&gt;
&lt;h2&gt;7. Two Trust Models, Side by Side&lt;/h2&gt;
&lt;p&gt;Raluca Ada Popa put the fork in the road into four words. The question a system designer faces when they must compute on sensitive data is: &lt;strong&gt;confidential computing or cryptographic computing?&lt;/strong&gt; Hardware enclaves on one side, cryptography on the other -- and the honest framing of the choice is the intellectual core of this capstone [@popa-cc-vs-cryptographic-2024].&lt;/p&gt;

The field offers two options for computing on data you are not allowed to read: confidential computing, which anchors trust in hardware, or cryptographic computing, which anchors it in mathematics. -- after Raluca Ada Popa, Communications of the ACM, 2024
&lt;p&gt;Start with the precision that everything else depends on, because it is the single most common error people make about TEEs. &lt;strong&gt;A TEE is not &quot;math-free.&quot;&lt;/strong&gt; It is saturated with cryptography: AES memory encryption on the DRAM bus, AES-GCM on the CPU-to-GPU link, and ECDSA or EPID digital signatures on every attestation quote [@amd-sev-snp-wp-2020] [@nvidia-hcc-whitepaper].&lt;/p&gt;
&lt;p&gt;So the thesis is &lt;em&gt;not&lt;/em&gt; &quot;mathematics versus no mathematics.&quot; It is about where trust is &lt;em&gt;anchored&lt;/em&gt;. In the mathematical schemes of Parts 1 to 4, confidentiality rests on a computational-hardness assumption -- breaking it means solving a problem believed to be intractable. In a TEE, confidentiality rests on a vendor, a die, and the assumption that no exploitable side channel exists. Both use math. They differ in what you trust when you rely on them.&lt;/p&gt;
&lt;p&gt;Lay the two anchors on one axis.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Silicon (TEEs, this article)&lt;/th&gt;
&lt;th&gt;Mathematics (FHE, ZK, MPC, PIR -- Parts 1 to 4)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Trust anchored in&lt;/td&gt;
&lt;td&gt;A vendor, a die, and &quot;no exploitable side channel&quot;&lt;/td&gt;
&lt;td&gt;A computational-hardness assumption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vendor in the trust base?&lt;/td&gt;
&lt;td&gt;Yes -- attestation chains to a vendor-provisioned root key&lt;/td&gt;
&lt;td&gt;No vendor root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uses cryptography?&lt;/td&gt;
&lt;td&gt;Yes (AES memory encryption plus signed attestation)&lt;/td&gt;
&lt;td&gt;Yes (the computation itself is cryptography)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overhead&lt;/td&gt;
&lt;td&gt;Near-native to under 9% on a GPU&lt;/td&gt;
&lt;td&gt;Roughly $10^3$ to $10^6$ times for FHE; scheme-dependent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-time large-model inference&lt;/td&gt;
&lt;td&gt;Yes (H100/H200 CC)&lt;/td&gt;
&lt;td&gt;No (too slow today)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Breakable by a physical adversary?&lt;/td&gt;
&lt;td&gt;Yes -- a memory interposer (2025)&lt;/td&gt;
&lt;td&gt;No hardware to interpose on an assumption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standing weakness&lt;/td&gt;
&lt;td&gt;Vendor plus side-channel plus physical bus&lt;/td&gt;
&lt;td&gt;Cost; FHE gives confidentiality, not integrity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Native speed on an untrusted operator you can accept a vendor for&lt;/td&gt;
&lt;td&gt;No-vendor-trust, high-assurance, or regulatory workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Read the table as two lists of virtues that are also two lists of costs. The silicon model runs unmodified workloads at near-native speed and is the only thing on this page that makes confidential AI real at GPU scale [@zhu-hopper-benchmark-2024] -- but you must trust the vendor, the silicon, and the unprovable premise that no side channel is being exploited.&lt;/p&gt;
&lt;p&gt;The mathematical model removes the vendor from the trust base entirely -- no die to trust, no fab to audit -- but pays in orders of magnitude of overhead and, for FHE, in sharp workload limits and confidentiality without integrity.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The two ceilings are mirror images. The silicon model cannot remove the vendor from the trust base and cannot prove the absence of side channels. The mathematical model has no vendor root but cannot yet reach real-time large-model speed. Neither anchor dominates the other; each one&apos;s floor is the other&apos;s ceiling. That symmetry is why this capstone crowns no winner.&lt;/p&gt;
&lt;/blockquote&gt;

The four earlier parts are the mathematical trust model in four flavors. Part 1, fully homomorphic encryption, computes on ciphertext and never decrypts -- maximum confidentiality, maximum cost. Part 2, zero-knowledge proofs, proves a computation was done correctly without revealing its inputs -- the integrity cousin of a TEE&apos;s attestation.&lt;p&gt;Part 3, secure multi-party computation, splits a secret so no single party ever holds it. Part 4, private information retrieval, reads a record without revealing which one. Every one anchors trust in mathematics rather than a vendor. This fifth part is their foil, not their successor -- the hardware answer to the same twenty-five-year question, with a different bill.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Because the anchors are complementary rather than competitive, the mature answer is often to use &lt;em&gt;both&lt;/em&gt;. A &lt;strong&gt;hybrid&lt;/strong&gt; places each part of a workload where its trust costs least and delivers most: a TEE for the high-throughput bulk and the orchestration around it, and a cryptographic kernel -- an MPC step, an FHE evaluation, a zero-knowledge proof -- for the single most sensitive operation where you refuse to trust any vendor.&lt;/p&gt;
&lt;p&gt;Signal&apos;s contact discovery is a small, real instance of the two models meeting: a privacy protocol deployed inside an SGX enclave, hardware isolation carrying a cryptographic design [@signal-cdsi]. You do not have to pick a side for the whole system. You pick an anchor per workload.&lt;/p&gt;
&lt;p&gt;And if neither anchor dominates, the interesting question is no longer &quot;which is better.&quot; It is &quot;where does each one &lt;em&gt;fail&lt;/em&gt;?&quot; What, precisely, can no TEE ever promise -- not as a bug to be patched, but as a matter of structure?&lt;/p&gt;
&lt;h2&gt;8. What No TEE Can Promise&lt;/h2&gt;
&lt;p&gt;The limits of the silicon model are not a list of unpatched bugs. They are structural, and the field states them about itself. There are two, and they are mirror images of each other.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;lower bound&lt;/strong&gt; is that you cannot remove the vendor from the trust base. Remote attestation &lt;em&gt;requires&lt;/em&gt; a root that some manufacturer vouches for; there is no attestation without an endorser. RFC 9334 says this in as many words: the Verifier trusts &quot;a manufacturer or the manufacturer&apos;s hardware&quot; by storing that endorser&apos;s key as a trust anchor, and the components vouched for this way -- because no evidence is generated about them -- are the roots of trust (Section 7.4) [@rfc-9334].&lt;/p&gt;
&lt;p&gt;Follow any TEE&apos;s trust chain to its end and it terminates at a key provisioned by a vendor, in a fabrication process you did not audit, running microcode you cannot read. Trusting the silicon &lt;em&gt;entails&lt;/em&gt; trusting the vendor&apos;s supply chain. That is a floor the mathematical model simply does not have -- there is no vendor in the trust base of a lattice assumption.&lt;/p&gt;
&lt;p&gt;The remote-attestation standard does not merely permit a vendor root; it names it. RFC 9334 calls the manufacturer&apos;s endorsement key a &quot;trust anchor.&quot; The specification that makes silicon trust verifiable is also the specification that documents its irreducible dependence on the vendor -- the very thing this article argues moves.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;upper bound&lt;/strong&gt; is that a TEE&apos;s confidentiality is only as strong as two things: the secrecy of its attestation key, and the integrity of its memory encryption. This is not a theoretical ceiling; both conditions have been violated in practice, which turns &quot;upper bound&quot; from a claim into a demonstration.&lt;/p&gt;
&lt;p&gt;Extract the attestation signing key -- as SGAxe did with EPID, as WireTap did by recording a memory bus, as TEE.Fail did with Intel&apos;s provisioning key -- and a forged quote becomes cryptographically indistinguishable from a genuine one; the entire chain of trust collapses at once, not one machine at a time [@sgaxe-2020] [@wiretap-2025] [@tee-fail-2025]. Break the memory encryption&apos;s integrity -- as the 2025 interposers do against deterministic, unauthenticated encryption -- and the confidentiality guarantee unravels from the DRAM side [@battering-ram-2025].&lt;/p&gt;
&lt;p&gt;Between what the model &lt;em&gt;assumes&lt;/em&gt; and what it can &lt;em&gt;prove&lt;/em&gt; sits a gap the field names openly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Confidential Computing Consortium&apos;s own technical analysis lists bus and cache monitoring, cold DRAM extraction, and plugging a device into an existing port as &lt;em&gt;in-scope&lt;/em&gt; threats the model aims to defend, and places only long-term invasive attacks such as decapping and microprobing, fault injection, and power or electromagnetic side channels &lt;em&gt;out of scope&lt;/em&gt; [@ccc-technical-analysis-v1-3]. That boundary is what makes the 2025 memory-bus interposers so serious: they broke an in-scope, claimed-defended threat, not a residual risk the model had already disclaimed. Intel, AMD, and NVIDIA scope their threat models the same way. So &quot;no exploitable side channel&quot; is an assumption the model &lt;em&gt;makes&lt;/em&gt;. It is never a guarantee the model &lt;em&gt;provides&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

There is a real epistemic difference between &quot;we assume no adversary can do X&quot; and &quot;we have proven no adversary can do X.&quot; A hardness assumption in cryptography is at least a *falsifiable, studied* conjecture that the whole field attacks in the open.&lt;p&gt;&quot;No side channel exists in this microarchitecture&quot; is a weaker kind of assumption: a statement about an artifact that was never designed to make it true and that has been falsified again and again -- Foreshadow, SgxPectre, AEPIC, CipherLeaks, then the interposer wave. Treat a TEE&apos;s side-channel freedom as a hopeful default, not a load-bearing guarantee, and you will size its trust correctly.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Notice the symmetry, because it is the whole point of the capstone. The silicon model&apos;s ceiling is a vendor root it cannot remove and a side-channel assumption it cannot prove. The mathematical model&apos;s ceiling is cost -- and, for FHE, integrity it does not by itself provide -- but with &lt;em&gt;no vendor root at all&lt;/em&gt;. Each model&apos;s ceiling is exactly the other model&apos;s floor.&lt;/p&gt;
&lt;p&gt;Engineering can narrow the gaps but not close them. Authenticated, fresh memory encryption could close the interposer gap, but it costs the $O(\log N)$ integrity-tree tax AEGIS paid in 2003 and the cloud dropped for speed [@aegis-ics-2003]. Formal verification could shrink the side-channel gap. But no amount of engineering removes the vendor from the trust base of a hardware root of trust; that dimension belongs, structurally, to mathematics.&lt;/p&gt;
&lt;p&gt;These are the assumptions, stated plainly. In October 2025, three research groups put a device between the processor and its memory and turned the assumptions into demonstrations.&lt;/p&gt;
&lt;h2&gt;9. How the Silicon Model Breaks&lt;/h2&gt;
&lt;p&gt;In 2025, three groups, three interposers, one root cause. A device you can build for the price of a nice dinner forges an attestation that the vendor&apos;s own verifier rates at its highest trust level. This is the moment the article&apos;s third turn lands: attestation did not make the TEE unbreakable. It moved the whole guarantee onto the secrecy of a signing key and the integrity of memory encryption -- and both are physically reachable.&lt;/p&gt;

Producing a quote that a verifier accepts as genuine without running the genuine, expected environment. The practical route is *key extraction*: once an attacker recovers the hardware attestation signing key, the forged quote it produces is cryptographically indistinguishable from a real one, because it is signed by the real key. The break is the whole trust chain, not one machine [@tee-fail-2025].
&lt;p&gt;The root cause is the freshness gap AEGIS warned about in 2003. Server memory encryption is &lt;em&gt;deterministic and unauthenticated&lt;/em&gt; at the DRAM bus: keyed on the physical address (AES-XTS on Intel, an XEX-mode tweak on AMD), with no per-write nonce and no integrity tag. That has two consequences an attacker on the bus can use -- equal plaintext blocks produce equal ciphertext (a leak of equality), and a recorded ciphertext can be replayed later (a break of freshness).&lt;/p&gt;
&lt;p&gt;{`
// Toy deterministic keyed mapping (NOT real crypto) to show the property.
function detEncrypt(block, key) {
  let h = 0;
  for (const ch of (block + key)) h = (h * 31 + ch.charCodeAt(0)) % 100000;
  return &quot;CT&quot; + h;
}&lt;/p&gt;
&lt;p&gt;const key = &quot;vm-key&quot;;
const a = detEncrypt(&quot;balance-100&quot;, key);
const b = detEncrypt(&quot;balance-100&quot;, key);
const c = detEncrypt(&quot;balance-999&quot;, key);&lt;/p&gt;
&lt;p&gt;console.log(&quot;Equal plaintext -&amp;gt; equal ciphertext? &quot; + (a === b));      // true: leaks equality
console.log(&quot;Different plaintext -&amp;gt; different ciphertext? &quot; + (a !== c)); // true&lt;/p&gt;
&lt;p&gt;// Add per-write randomization (a nonce). This restores semantic security:
function randomizedEncrypt(block, key, nonce) {
  return detEncrypt(block + &quot;:&quot; + nonce, key);
}
const f1 = randomizedEncrypt(&quot;balance-100&quot;, key, &quot;nonce-1&quot;);
const f2 = randomizedEncrypt(&quot;balance-100&quot;, key, &quot;nonce-2&quot;);
console.log(&quot;With randomization, equal plaintext -&amp;gt; equal ciphertext? &quot; + (f1 === f2)); // false&lt;/p&gt;
&lt;p&gt;// IMPORTANT: this only hides equality. It does NOT stop replay -- an attacker
// can replay the (ciphertext, nonce) pair together. Real anti-replay freshness
// needs the nonce authenticated in an on-chip version tree, exactly as AEGIS did.
`}&lt;/p&gt;
&lt;p&gt;That toy is the whole vulnerability class in miniature. Here is what the 2025 wave did with the real thing.&lt;/p&gt;

flowchart TD
    DET[&quot;Deterministic, unauthenticated encryption on the DRAM bus&quot;] --&amp;gt; INT[&quot;Physical interposer between CPU and DIMM&quot;]
    INT --&amp;gt; ALIAS[&quot;Alias or replay physical addresses&quot;]
    INT --&amp;gt; RECORD[&quot;Record deterministic ciphertext&quot;]
    ALIAS --&amp;gt; KEY[&quot;Extract the attestation signing key&quot;]
    RECORD --&amp;gt; KEY
    KEY --&amp;gt; FORGE[&quot;Forge a quote that verifies UpToDate&quot;]
    FORGE --&amp;gt; BROKEN[&quot;The whole attestation chain collapses&quot;]
&lt;p&gt;&lt;strong&gt;WireTap&lt;/strong&gt; used a &lt;em&gt;passive&lt;/em&gt; DDR4 interposer -- it only records bus traffic -- and, exploiting the deterministic encryption, extracted an SGX attestation key from a machine in fully trusted status. It then forged quotes end to end against SGX-backed blockchains with multi-million-dollar market caps [@wiretap-2025].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Battering RAM&lt;/strong&gt; built an interposer for a total bill of materials of $47.62, invisible at boot, that aliases physical addresses to grant arbitrary plaintext access to SGX memory and to break SEV-SNP attestation on fully patched systems [@battering-ram-2025] [@kuleuven-batteringram-news].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TEE.Fail&lt;/strong&gt; was the first DDR5 memory-bus attack. It extracted Intel&apos;s provisioning-enclave ECDSA key and forged a TDX quote that verifies at Intel DCAP&apos;s highest trust level, &quot;UpToDate,&quot; carrying a deliberately impossible measurement -- the value 0x1337 -- while also reaching AMD SEV-SNP and, through the extracted keys, NVIDIA GPU confidential computing [@tee-fail-2025].&lt;/p&gt;

Defending against Battering RAM would require a fundamental redesign of memory encryption itself. -- the Battering RAM disclosure, 2025
&lt;p&gt;The word &quot;patched&quot; is doing dangerous work in most people&apos;s mental models here.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Every 2025 interposer attack works on &lt;em&gt;fully patched&lt;/em&gt; silicon, because the flaw is not a bug in the firmware -- it is the deterministic, unauthenticated design of the memory encryption itself. A software or microcode update cannot close it. A fresh attestation proves the expected build booted; it does not prove that no interposer sits on the DIMM. Treat attestation as necessary, never as sufficient [@tee-fail-2025].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These are 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;microarchitectural side channels&lt;/a&gt;&apos; louder cousins, but the quieter class has not gone away either. Foreshadow, SgxPectre, AEPIC, and CipherLeaks all leak enclave or VM secrets without a screwdriver, and undervolting fault-injection attacks such as Plundervolt can corrupt an enclave&apos;s computation from software [@foreshadow-l1tf] [@sgxpectre-2018] [@aepic-leak-2022] [@cipherleaks-2021] [@plundervolt]. Two attack families, one lesson: silicon trust is breakable in ways a hardness assumption is not.&lt;/p&gt;
&lt;p&gt;The research racing to close these gaps is real, and the leading direction is a revival. &lt;strong&gt;Memory encryption with integrity and freshness&lt;/strong&gt; at server scale -- literally AEGIS&apos;s 2003 insistence, reborn -- is the fix for the interposer class, though it must somehow avoid the logarithmic integrity-tree cost the cloud dropped for speed [@aegis-ics-2003]. &lt;strong&gt;Formally verified, side-channel-resistant TEE designs&lt;/strong&gt; would move &quot;no side channel&quot; from an assumption toward a proof; the scholarly threat-model work on SGX is the starting point [@sgx-explained-2016].&lt;/p&gt;
&lt;p&gt;Two more fronts are open. &lt;strong&gt;Multi-GPU confidential AI&lt;/strong&gt; needs independent third-party benchmarking to match its rapid deployment [@nvidia-secure-ai-blackwell-wp]. And &lt;strong&gt;shrinking or de-monopolizing the vendor root&lt;/strong&gt; -- Apple&apos;s publicly logged, transparent fleet is the leading move -- can make the root &lt;em&gt;accountable&lt;/em&gt; even though it cannot be removed [@apple-pcc-blog]. The internals of GPU confidential computing are only now being independently dissected, exactly the adversarial scrutiny a 2024-era technology still needs [@gpu-cc-security-analysis-2025].&lt;/p&gt;
&lt;p&gt;Here is the whole break surface on one table.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attack (year)&lt;/th&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Primary target&lt;/th&gt;
&lt;th&gt;What it achieves&lt;/th&gt;
&lt;th&gt;Works on patched systems?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Foreshadow (2018)&lt;/td&gt;
&lt;td&gt;Microarchitectural&lt;/td&gt;
&lt;td&gt;SGX&lt;/td&gt;
&lt;td&gt;Reads enclave memory and the attestation key&lt;/td&gt;
&lt;td&gt;Mitigated by microcode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SgxPectre (2018)&lt;/td&gt;
&lt;td&gt;Microarchitectural&lt;/td&gt;
&lt;td&gt;SGX&lt;/td&gt;
&lt;td&gt;Leaks enclave secrets via speculation&lt;/td&gt;
&lt;td&gt;Mitigated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CipherLeaks (2021)&lt;/td&gt;
&lt;td&gt;Ciphertext side channel&lt;/td&gt;
&lt;td&gt;SEV-ES, SEV-SNP&lt;/td&gt;
&lt;td&gt;Recovers secrets from deterministic ciphertext&lt;/td&gt;
&lt;td&gt;Forced the RMP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEPIC (2022)&lt;/td&gt;
&lt;td&gt;Architectural MMIO&lt;/td&gt;
&lt;td&gt;SGX&lt;/td&gt;
&lt;td&gt;Dumps stale enclave data, no speculation&lt;/td&gt;
&lt;td&gt;Mitigated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WireTap (2025)&lt;/td&gt;
&lt;td&gt;Physical, DDR4 (passive)&lt;/td&gt;
&lt;td&gt;SGX&lt;/td&gt;
&lt;td&gt;Extracts the attestation key, forges quotes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Battering RAM (2025)&lt;/td&gt;
&lt;td&gt;Physical, DDR4&lt;/td&gt;
&lt;td&gt;SGX and SEV-SNP&lt;/td&gt;
&lt;td&gt;Arbitrary plaintext, breaks attestation&lt;/td&gt;
&lt;td&gt;Yes, fully patched&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TEE.Fail (2025)&lt;/td&gt;
&lt;td&gt;Physical, DDR5&lt;/td&gt;
&lt;td&gt;SGX, TDX, SEV-SNP, reaches GPU CC&lt;/td&gt;
&lt;td&gt;Extracts keys, forges an &quot;UpToDate&quot; quote&lt;/td&gt;
&lt;td&gt;Yes, fully patched&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The capstone resolves here. Because the silicon anchor is undone by a physical or microarchitectural adversary, the mathematical trust model of Parts 1 to 4 remains the higher-assurance floor for any workload that cannot accept a vendor in its trust base or an unprovable &quot;no side channel&quot; assumption. The two models are complements, not rivals -- which is exactly why neither made the other obsolete.&lt;/p&gt;
&lt;p&gt;So what should &lt;em&gt;you&lt;/em&gt; actually do on Monday morning -- reach for silicon, for mathematics, or for both?&lt;/p&gt;
&lt;h2&gt;10. Choose Your Anchor by Workload&lt;/h2&gt;
&lt;p&gt;The practitioner&apos;s question is not &quot;which technology wins.&quot; It is &quot;which anchor fits &lt;em&gt;this&lt;/em&gt; workload and &lt;em&gt;this&lt;/em&gt; threat model.&quot; Popa&apos;s framing is the north star: confidential computing or cryptographic computing, chosen deliberately, not by default [@popa-cc-vs-cryptographic-2024].&lt;/p&gt;

flowchart TD
    START[&quot;Choose your trust anchor&quot;] --&amp;gt; Q1{&quot;GPU needed for confidential AI?&quot;}
    Q1 --&amp;gt;|&quot;Yes&quot;| GPU[&quot;H100 or H200 CC plus a CPU CVM, and enforce double attestation&quot;]
    Q1 --&amp;gt;|&quot;No&quot;| Q2{&quot;Lift-and-shift a whole VM?&quot;}
    Q2 --&amp;gt;|&quot;Yes&quot;| VM[&quot;SEV-SNP or TDX confidential VM&quot;]
    Q2 --&amp;gt;|&quot;No&quot;| ENC[&quot;SGX minimal-TCB enclave&quot;]
    GPU --&amp;gt; VERIFY[&quot;Verify every quote against the correct vendor root, then gate key release&quot;]
    VM --&amp;gt; VERIFY
    ENC --&amp;gt; VERIFY
    VERIFY --&amp;gt; Q3{&quot;Accept a vendor in your TCB and the no-side-channel assumption?&quot;}
    Q3 --&amp;gt;|&quot;Yes&quot;| SHIP[&quot;Ship on the TEE&quot;]
    Q3 --&amp;gt;|&quot;No&quot;| MATH[&quot;Reach for the mathematics of Parts 1 to 4, or a hybrid&quot;]
&lt;p&gt;Walk the flow. First: do you need the GPU inside the boundary? If you are running confidential AI, the answer is yes, and the shape is an H100 or H200 in confidential-computing mode composed with a CPU confidential VM (single-GPU today), or a Blackwell multi-GPU domain for frontier scale [@azure-gpu-options].&lt;/p&gt;
&lt;p&gt;If the GPU is not in play, choose between VM-level and process-level isolation: SEV-SNP or TDX to lift an existing OS and application into a confidential VM with no code changes, and SGX when the sensitive kernel is small enough to justify the minimal trust base and the porting effort.&lt;/p&gt;
&lt;p&gt;Second, the step no path skips: &lt;strong&gt;actually verify the attestation.&lt;/strong&gt; A TEE that is never attested is just a virtual machine that claims to be private. Gate secret release on a quote checked against the &lt;em&gt;correct&lt;/em&gt; vendor root or roots, enforce double attestation for CPU-plus-GPU pipelines, and release the model and data keys only on the expected measurement [@azure-attestation-overview]. The single most common and most damaging misconfiguration is to verify one half of a two-vendor pipeline and assume the other is covered.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If your key-release policy ever hands a secret to an endpoint whose quote you did not verify against the right root and the right measurement, you have built confidential computing with the confidentiality switched off. Everything else in this article is downstream of getting this one control right.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Third, know when &lt;em&gt;not&lt;/em&gt; to reach for a TEE. If you cannot accept a silicon vendor in your trust base, cannot accept the standing &quot;no exploitable side channel&quot; assumption, or face an adversary with physical access to the memory bus, the silicon anchor is the wrong tool. The right one is the mathematics of the earlier parts, or a hybrid that uses a TEE for throughput and a cryptographic kernel for the most sensitive step.&lt;/p&gt;
&lt;p&gt;The deep mechanics of deploying the CPU confidential VMs themselves live in the companion post on &lt;a href=&quot;https://paragmali.com/blog/inside-azure-confidential-vms-sev-snp-intel-tdx-and-the-para/&quot; rel=&quot;noopener&quot;&gt;Azure Confidential VMs&lt;/a&gt;; this section stays at the level of &lt;em&gt;which anchor&lt;/em&gt;, not &lt;em&gt;which command&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The verification is not hypothetical hand-waving -- it is tooling you run. NVIDIA&apos;s nvTrust and its NRAS verifier attest the GPU; AMD&apos;s snpguest and the virtee project, plus Intel&apos;s DCAP, verify CPU quotes; Microsoft Azure Attestation composed with Secure Key Release gates the key; and Apple&apos;s security-pcc release lets anyone inspect the logged builds a device will talk to [@nvidia-nvtrust-docs] [@apple-pcc-source].&lt;/p&gt;

On an NVIDIA confidential-computing host, `nvidia-smi conf-compute -f` reports whether the GPU is in CC mode, and the nvTrust tooling runs local and remote GPU attestation against NVIDIA&apos;s verifier; on an AMD host, the `snpguest` utility fetches and validates a SEV-SNP attestation report. None of these replaces the real control -- gating key release on the verified result -- but they are how you confirm the boundary is actually on before you trust it [@nvidia-nvtrust-docs].
&lt;p&gt;The series began by asking how to compute on data you are not allowed to read. Five parts in, we can finally answer -- not with one method, but with a choice, and with the judgment to make it well.&lt;/p&gt;
&lt;h2&gt;11. Frequently Asked Questions&lt;/h2&gt;

No, and this is the most common misconception. A TEE is saturated with cryptography: AES memory encryption on the DRAM bus, AES-GCM on the CPU-to-GPU link, and digital-signature attestation on every quote [@amd-sev-snp-wp-2020]. The thesis of this series is not &quot;mathematics versus no mathematics.&quot; It is about where trust is *anchored* -- in a silicon vendor and an attestation chain, rather than in a computational-hardness assumption [@popa-cc-vs-cryptographic-2024].

No. Attestation is exactly as strong as the secrecy of the signing key. Once that key leaks -- as WireTap did by passively recording a DDR4 memory bus, and as TEE.Fail did by extracting Intel&apos;s provisioning key -- a forged quote is cryptographically indistinguishable from a genuine one, and TEE.Fail&apos;s forged quote verified at the vendor&apos;s highest trust level [@wiretap-2025] [@tee-fail-2025]. Attestation is necessary, not sufficient.

No -- that is the point of it. You move trust *off* the cloud operator and *onto* the silicon vendor, and then you verify that the operator is locked out. In Azure&apos;s confidential-AI pipeline the trust boundary spans the CPU confidential VM and the attached GPU, and the operator has no path to the plaintext inside either [@azure-gpu-options]. You are not trusting the provider; you are trusting the chip and proving the provider cannot see in.

No. GPU confidential computing reached general availability in 2024, so it has seen a fraction of the adversarial scrutiny that a decade of SGX and SEV research produced [@nvidia-h100-cc-ga-2024]. No full-boundary GPU-CC compromise has been published, but its internals are only now being independently dissected. Newer is not the same as broken -- but it is not the same as battle-hardened either.

No, and the difference is the whole series in one sentence. Fully homomorphic encryption, from Part 1, keeps the data encrypted *during* the computation and never decrypts it -- the trust is in mathematics. A TEE *decrypts inside* a hardware boundary and relies on the chip to refuse to leak it -- the trust is in silicon and attestation. Same goal, opposite trust anchors, wildly different performance.

Often, yes, though the boundary is narrower than it sounds. The confidential-computing threat model places only long-term invasive attacks (decapping, microprobing), fault injection, and power or electromagnetic side channels *out of scope*; bus monitoring, cold DRAM extraction, and port-plugging are listed as *in-scope* [@ccc-technical-analysis-v1-3]. So the 2025 breaks matter more, not less: a fifty-dollar memory interposer defeated SGX and SEV-SNP attestation on fully patched systems, an in-scope threat the model claimed to withstand [@battering-ram-2025]. That is the honest limit of the silicon anchor, and it is precisely why the mathematical schemes of the earlier parts still matter.

No. There was no general-availability release of a &quot;Confidential GPT-4&quot; in 2024, however often the phrase is repeated. The publicly demonstrated confidential-inferencing workload was a speech-to-text model [@nvidia-azure-h100-cvm-ga-2024], and the shipping CPU-plus-GPU pipeline anyone can actually rent is the NCCadsH100v5 virtual machine, an AMD SEV-SNP VM with an in-boundary H100 [@azure-nccadsh100v5].
&lt;h2&gt;Where the Trust Went&lt;/h2&gt;
&lt;p&gt;Start where we started: a hospital runs a proprietary 70-billion-parameter model on private scans, inside a cloud nobody in the room trusts, at under ten percent overhead, where fully homomorphic encryption would be three to six orders of magnitude too slow [@zhu-hopper-benchmark-2024].&lt;/p&gt;
&lt;p&gt;The paradox dissolves once you see the move. The machine is not computing on data it cannot read; it is decrypting the data &lt;em&gt;inside a boundary its owner is locked out of&lt;/em&gt;, and proving which boundary it is with a signed quote checked against a vendor root. The secret is never mathematically hidden. The &lt;em&gt;trust&lt;/em&gt; is relocated -- from a hardness assumption to a die, a vendor, and an attestation chain.&lt;/p&gt;
&lt;p&gt;That relocation is real, and it ships. Confidential AI in 2026 is not a demo; it is a rentable virtual machine with double attestation and secret release gated on a verified measurement [@azure-nccadsh100v5]. It is the one thing on the shelf that keeps a model and its inputs confidential at GPU speed, in the exact regime where mathematics is still too slow. For that class of workload, the silicon anchor is not a compromise -- it is the answer.&lt;/p&gt;
&lt;p&gt;But the trust did not vanish; it moved somewhere with a physical address. A TEE&apos;s guarantee is exactly as strong as the secrecy of one signing key and the integrity of its memory encryption, and in 2025 a device costing less than a dinner extracted the key and forged a quote the vendor&apos;s own verifier rated &quot;UpToDate&quot; [@tee-fail-2025].&lt;/p&gt;
&lt;p&gt;You cannot remove the vendor from the trust base -- the attestation standard itself says so [@rfc-9334] -- and you cannot prove the absence of side channels; the field concedes both as residual risk [@ccc-technical-analysis-v1-3]. Those are not bugs awaiting a patch. They are the shape of the silicon anchor.&lt;/p&gt;
&lt;p&gt;So the series closes where an honest capstone must: with a refusal to crown a winner. For twenty-five years the field answered one question -- how do you compute on data the machine&apos;s owner cannot read? -- two ways. Fully homomorphic encryption, zero-knowledge proofs, secure multi-party computation, and private information retrieval answered with mathematics and paid in overhead. Trusted Execution Environments answer with hardware and attestation, and pay in a vendor you must trust and an attack surface a physical adversary can reach. Each anchor&apos;s ceiling is the other&apos;s floor.&lt;/p&gt;
&lt;p&gt;The mature engineer does not ask which is better; they ask where the trust should live for &lt;em&gt;this&lt;/em&gt; workload -- and sometimes the answer is a hybrid that uses both. The secret was never decrypted where an adversary could reach it. Across all five parts, that was only ever the beginning of the question. The end of it is knowing what, and whom, you had to trust to keep it that way.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;never-decrypted-tees-confidential-computing-gpu&quot; keyTerms={[
  { term: &quot;Confidential computing&quot;, definition: &quot;Protecting data in use, during computation, inside a hardware-based attested TEE, against privileged software and the machine owner.&quot; },
  { term: &quot;Trusted Execution Environment&quot;, definition: &quot;A hardware-enforced environment that keeps code and data confidential and integrity-protected while executing.&quot; },
  { term: &quot;Trust anchor&quot;, definition: &quot;The component trusted by assumption because nothing else vouches for it; for a TEE it is a vendor-provisioned key in the silicon.&quot; },
  { term: &quot;Remote attestation&quot;, definition: &quot;A hardware-rooted proof of which code and configuration a TEE is running, checked by a verifier against a vendor root.&quot; },
  { term: &quot;Confidential VM&quot;, definition: &quot;A whole virtual machine with encrypted memory and hypervisor-resistant isolation, as in AMD SEV-SNP and Intel TDX.&quot; },
  { term: &quot;Double attestation&quot;, definition: &quot;Confidential AI verifies both the CPU VM and the GPU, against two different vendor roots, before releasing keys.&quot; },
  { term: &quot;Deterministic memory encryption&quot;, definition: &quot;Memory encryption keyed on the physical address (AES-XTS on Intel, XEX-mode on AMD); fast but leaks ciphertext equality and permits replay, the seam the 2025 interposers exploit.&quot; },
  { term: &quot;Attestation forgery&quot;, definition: &quot;Producing a quote a verifier accepts without the genuine environment, achieved by extracting the hardware signing key.&quot; }
]} questions={[
  { q: &quot;Why is a TEE described as moving the trust anchor rather than hiding the computation?&quot;, a: &quot;Because it decrypts data inside a hardware boundary and relies on the chip to refuse to reveal it, so trust shifts from a mathematical hardness assumption to a vendor, a die, and an attestation chain.&quot; },
  { q: &quot;Why does confidential AI require two attestations?&quot;, a: &quot;The CPU confidential VM and the GPU are separate silicon from different vendors; each must prove itself against its own root before keys are released.&quot; },
  { q: &quot;Why can a firmware patch not fix the 2025 interposer attacks?&quot;, a: &quot;The root cause is deterministic, unauthenticated memory encryption, a design property of the memory encryption itself, not a software bug.&quot; },
  { q: &quot;What is the structural lower bound of the silicon trust model?&quot;, a: &quot;You cannot remove the vendor from the trust base, because attestation must chain to a vendor-provisioned root of trust.&quot; },
  { q: &quot;Why do the mathematical schemes of Parts 1 to 4 remain relevant?&quot;, a: &quot;They anchor trust in a hardness assumption with no vendor root and no physical bus to interpose on, so they cover workloads a TEE cannot.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>confidential-computing</category><category>trusted-execution-environment</category><category>gpu-security</category><category>remote-attestation</category><category>confidential-ai</category><category>sev-snp</category><category>intel-tdx</category><category>side-channel-attacks</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>How Elliptic Curves and Diffie-Hellman Break in Real Life: The Discrete Log Never Fell</title><link>https://paragmali.com/blog/how-elliptic-curves-and-diffie-hellman-break-in-real-life-th/</link><guid isPermaLink="true">https://paragmali.com/blog/how-elliptic-curves-and-diffie-hellman-break-in-real-life-th/</guid><description>No one has solved the discrete log on a strong curve or a 2048-bit group -- yet PS3, Android wallets, TPMs, CurveBall, and Logjam all fell. Here is exactly how.</description><pubDate>Sat, 18 Jul 2026 00:00:00 GMT</pubDate><content:encoded>
On a strong curve or a 2048-bit group, no one has ever solved the discrete logarithm in the field -- yet PlayStation 3 consoles, Android Bitcoin wallets, tamper-resistant TPMs, Windows certificate validation, and live TLS sessions all fell. Every one of those breaks attacked a layer the discrete-log math depends on but does not control: the per-signature nonce (PS3, Android, Minerva, TPM-Fail, LadderLeak), the curve and certificate parameters (CurveBall), or the negotiated strength (Logjam). A *reused* nonce surrenders the key from just two signatures; a *biased* nonce needs a statistical attack over many. The only discrete log ever computed here was Logjam&apos;s, against a downgrade-forced, export-crippled, shared 512-bit prime -- never a strong deployed curve. The fix is never a bigger curve. It is hedged, constant-time signing, validated parameters, and retiring export and shared groups.
&lt;h2&gt;1. Seven Breaks, One Unbroken Problem&lt;/h2&gt;
&lt;p&gt;On a well-chosen elliptic curve, the best attack anyone has ever fielded against the discrete logarithm is a square-root-time random walk that has barely moved since the 1970s [@hac-ch11][@teske-2001]. No deployed P-256, Curve25519, or secp256k1 key, and no standard 2048-bit Diffie-Hellman group, has ever had its discrete log solved in public. By every measurement we can make, the mathematics is holding.&lt;/p&gt;
&lt;p&gt;And yet. PlayStation 3 consoles were jailbroken [@fail0verflow-ps3-2010]. Android Bitcoin wallets were emptied [@bitcoin-android-2013]. Tamper-resistant TPMs certified to government standards surrendered their signing keys [@tpmfail-2020]. Windows accepted forged certificates that chained to a counterfeit authority [@curveball-cve-2020-0601]. Live TLS sessions were downgraded and decrypted in transit [@logjam-weakdh-2015]. Every one of those systems ran the discrete-log math exactly as specified. The math was never where they broke.&lt;/p&gt;
&lt;p&gt;That is the paradox this article resolves, and the resolution fits in one sentence: none of these attacks solved a discrete logarithm. Each attacked a layer the math &lt;em&gt;depends on but does not control&lt;/em&gt;. There are exactly three such layers, and they organize everything that follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The per-signature nonce&lt;/strong&gt; -- the throwaway secret ECDSA needs for every signature. PS3, Android, Minerva, TPM-Fail, and LadderLeak all landed here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The curve and certificate parameters&lt;/strong&gt; -- which curve, and whose generator, you are actually talking to. CurveBall landed here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The negotiated strength&lt;/strong&gt; -- how strong a key exchange two parties agree to use before they exchange anything. Logjam landed here.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The discrete-logarithm assumption protects the private key against being &lt;em&gt;directly computed&lt;/em&gt; -- and nothing else. &quot;Nobody solved the discrete log&quot; and &quot;somebody recovered the private key&quot; are not contradictory statements, because the discrete-log &lt;em&gt;problem&lt;/em&gt; (genuinely hard) and a discrete-log &lt;em&gt;deployment&lt;/em&gt; (a nonce, some parameters, a negotiation) are different things. Every real break in this article lives in the gap between them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A note on scope. This piece treats the hardness of the elliptic-curve discrete logarithm as a black box: assume it holds, and watch everything around it fail. The structural mathematics of curve choice -- why one curve is weak and another is strong, how the number field sieve and Shor&apos;s algorithm actually work -- belongs to a companion article, &quot;How the Discrete Log Would Break: Elliptic Curves, Finite Fields, and Why Curve Choice Is the Weak Part.&quot; Here, we assume the strongbox is uncrackable and ask how the key kept getting out anyway.&lt;/p&gt;
&lt;p&gt;To see why a hard problem protects so little, you first have to see exactly what it promises -- and what it quietly leaves to the deployment.&lt;/p&gt;
&lt;h2&gt;2. What the Math Actually Promises&lt;/h2&gt;
&lt;p&gt;In 1976, Whitfield Diffie and Martin Hellman reduced the ancient problem of exchanging a secret over an open wire to a single piece of hard arithmetic: the discrete logarithm [@diffie-hellman-1976]. Two parties each pick a private exponent, exchange public powers of a shared generator, and combine them into a key that an eavesdropper cannot reconstruct without solving for one of those exponents.&lt;/p&gt;
&lt;p&gt;Nine years later, Victor Miller and, independently, Neal Koblitz moved the same hard problem onto elliptic curves [@miller-1985][@koblitz-1987]. Koblitz argued the curve version was &quot;likely to be harder than the classical discrete logarithm problem&quot; [@koblitz-1987] -- which is why a 256-bit curve buys security that a finite field needs thousands of bits to match. A clean, triumphant origin. So where did the promise leak?&lt;/p&gt;

Given a generator `G` and a public point `Q = dG` on an elliptic curve (or a base `g` and `g^d` in a finite field), recovering the secret integer `d` is the discrete logarithm problem. The security of ECDSA, ECDH, and Diffie-Hellman rests on the assumption that this recovery is computationally infeasible for well-chosen parameters. It is the one thing the math promises -- and, as we will see, the only thing.
&lt;p&gt;Signatures are where the story starts, because signatures introduce a second secret. The Elliptic Curve Digital Signature Algorithm (ECDSA) signs a message hash &lt;code&gt;z&lt;/code&gt; under a long-term private key &lt;code&gt;d&lt;/code&gt; by generating a fresh random value &lt;code&gt;k&lt;/code&gt;, computing a point &lt;code&gt;kG&lt;/code&gt;, taking its x-coordinate as &lt;code&gt;r&lt;/code&gt;, and producing:&lt;/p&gt;
&lt;p&gt;$$s = k^{-1},(z + r,d) \bmod n$$&lt;/p&gt;
&lt;p&gt;where &lt;code&gt;n&lt;/code&gt; is the order of the group. The verifier only ever sees &lt;code&gt;(r, s)&lt;/code&gt;. The private key &lt;code&gt;d&lt;/code&gt; is buried inside, protected by the discrete-log assumption -- nobody can read &lt;code&gt;d&lt;/code&gt; off the signature. But look at what else is in that equation.&lt;/p&gt;

The `k` in ECDSA is a *nonce*: a number used once. It must be secret, statistically uniform, and unique to each signature. It is not the private key, and it is thrown away the instant the signature is produced. It is also the single most load-bearing prerequisite in the whole scheme -- because `k` and `d` appear together in one linear equation, anything an attacker learns about `k` turns directly into knowledge of `d`.
&lt;p&gt;The discrete-log assumption guards &lt;code&gt;d&lt;/code&gt; against being &lt;em&gt;computed&lt;/em&gt; from the public key. It says nothing whatsoever about three things the assumption quietly depends on but does not itself enforce:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The nonce &lt;code&gt;k&lt;/code&gt; must be secret, uniform, and unique.&lt;/strong&gt; The math assumes a perfect &lt;code&gt;k&lt;/code&gt; and never checks that you supplied one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The parameters must be the standard, named ones.&lt;/strong&gt; The math assumes you are on the curve you think you are, with the generator you think you have.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The negotiated strength must not be crippled or shared.&lt;/strong&gt; The math assumes the group you agreed to use is actually strong.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each of those is the deployment&apos;s responsibility, not the primitive&apos;s. And each one became a pillar of failure.&lt;/p&gt;

flowchart TD
    DLP[&quot;(EC)DLP is hard: d cannot be computed from the public key dG&quot;]
    DLP --&amp;gt; N[&quot;Depends on the per-signature nonce k&quot;]
    DLP --&amp;gt; P[&quot;Depends on the curve and certificate parameters&quot;]
    DLP --&amp;gt; G[&quot;Depends on the negotiated group strength&quot;]
    N --&amp;gt; P1[&quot;Pillar 1 nonce: PS3, Android, Minerva, TPM-Fail, LadderLeak&quot;]
    P --&amp;gt; P2[&quot;Pillar 2 validation: CurveBall&quot;]
    G --&amp;gt; P3[&quot;Pillar 3 downgrade: Logjam&quot;]
&lt;p&gt;The curve migration itself is not our subject.Miller (1985) and Koblitz (1987) are mentioned here only to fix the primitive&apos;s birth. Whether a &lt;em&gt;particular&lt;/em&gt; curve is structurally weak -- anomalous curves, small embedding degrees, the number field sieve, Shor&apos;s algorithm -- is the structural mathematics deferred to the companion article. This article assumes the curve is strong and attacks everything around it. The math guards the key against being computed. It says nothing about the key being &lt;em&gt;handed over&lt;/em&gt;. Three contracts govern that handover, and each one broke.&lt;/p&gt;
&lt;h2&gt;3. Three Contracts the Deployment Signs and Never Reads&lt;/h2&gt;
&lt;p&gt;Every cryptographic deployment signs a contract it never reads. There are three clauses, one for each layer the math leans on, and the fine print on all three is where real products sank.&lt;/p&gt;
&lt;h3&gt;The nonce contract: k must be fresh&lt;/h3&gt;
&lt;p&gt;Take the ECDSA signing equation and ask the cruelest possible question: what if &lt;code&gt;k&lt;/code&gt; is not unique? Suppose two different messages, with hashes &lt;code&gt;z1&lt;/code&gt; and &lt;code&gt;z2&lt;/code&gt;, are signed under the &lt;em&gt;same&lt;/em&gt; nonce &lt;code&gt;k&lt;/code&gt;. Because &lt;code&gt;r&lt;/code&gt; is the x-coordinate of &lt;code&gt;kG&lt;/code&gt;, the same &lt;code&gt;k&lt;/code&gt; produces the same &lt;code&gt;r&lt;/code&gt; in both signatures. Now write them down side by side:&lt;/p&gt;
&lt;p&gt;$$s_1 = k^{-1}(z_1 + r,d), \qquad s_2 = k^{-1}(z_2 + r,d) \pmod n$$&lt;/p&gt;
&lt;p&gt;Subtract. The &lt;code&gt;rd&lt;/code&gt; term is identical in both, so it cancels, and &lt;code&gt;k&lt;/code&gt; falls straight out:&lt;/p&gt;
&lt;p&gt;$$s_1 - s_2 = k^{-1}(z_1 - z_2), \qquad k = \frac{z_1 - z_2}{s_1 - s_2} \bmod n$$&lt;/p&gt;
&lt;p&gt;Once you know &lt;code&gt;k&lt;/code&gt;, the first equation has exactly one unknown left, and you solve for the private key by hand:&lt;/p&gt;
&lt;p&gt;$$d = \frac{s_1,k - z_1}{r} \bmod n$$&lt;/p&gt;
&lt;p&gt;No lattice. No side channel. No discrete log. &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;Two signatures that share a nonce&lt;/a&gt; are two linear equations in two unknowns, and a middle-schooler with modular arithmetic can finish the job.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The discrete-logarithm assumption protects &lt;code&gt;d&lt;/code&gt; against &lt;em&gt;direct computation from the public key&lt;/em&gt; -- and nothing else. It does not protect &lt;code&gt;d&lt;/code&gt; against being algebraically extracted when the nonce misbehaves. The moment two signatures reuse &lt;code&gt;k&lt;/code&gt;, the strongbox is irrelevant, because the deployment left a second door wide open.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The contract, then, is strict: &lt;code&gt;k&lt;/code&gt; must be secret, statistically uniform, and never reused or partially leaked. Break any word of that clause and the algebra above (or its statistical cousin, later) takes your key.&lt;/p&gt;
&lt;h3&gt;The parameter contract: talk to the curve you think you are&lt;/h3&gt;
&lt;p&gt;The second clause is about identity. A &lt;em&gt;named&lt;/em&gt; curve -- &quot;P-256,&quot; &quot;secp256k1&quot; -- is an agreement to use one specific set of domain parameters, and in particular one specific generator, the base point &lt;code&gt;G&lt;/code&gt; that every public key is measured against.&lt;/p&gt;

Every named elliptic curve fixes a single public point `G` from which all key material is derived: a private key `d` corresponds to the public point `dG`. The generator is not a secret -- it is a published constant. But it is load-bearing: &quot;the public key is `dG`&quot; is only meaningful if both sides agree on which `G`.

A certificate can specify its curve two ways. A *named curve* is an object identifier pointing at standardized domain parameters (fixed `a`, `b`, `p`, `G`, `n`). *Explicit parameters* spell out all of those numbers inline, which lets the certificate carry a *custom* generator. Accepting explicit parameters without checking them against a known named curve means trusting an attacker to tell you what `G` is.
&lt;p&gt;The contract: never trust attacker-supplied explicit parameters. A validator that checks a public &lt;em&gt;point&lt;/em&gt; but not the &lt;em&gt;generator&lt;/em&gt; it was measured against has, in effect, let the attacker choose the ruler and then declared the measurement correct. That is precisely the door CurveBall walked through [@curveball-cve-2020-0601].&lt;/p&gt;
&lt;h3&gt;The negotiation contract: agree to strength, not to a museum piece&lt;/h3&gt;
&lt;p&gt;The third clause governs what two parties agree to &lt;em&gt;before&lt;/em&gt; they exchange anything. In &lt;a href=&quot;https://paragmali.com/blog/nobody-broke-the-discrete-log-a-field-guide-to-diffie-hellma/&quot; rel=&quot;noopener&quot;&gt;ephemeral Diffie-Hellman&lt;/a&gt;, each side picks a fresh secret per connection, which is supposed to guarantee that compromising one session cannot retroactively expose others.&lt;/p&gt;

In ephemeral DH, the private exponents are generated fresh for each connection and discarded afterward, so a key recovered later cannot decrypt past sessions. This property is called forward secrecy. It is the reason &quot;just use a fresh ephemeral key&quot; feels like a complete defense -- and, as Logjam showed, the reason that feeling is dangerously incomplete.

In the 1990s, US export regulations capped the strength of cryptography shipped abroad, producing deliberately weakened cipher suites such as 512-bit `DHE_EXPORT` Diffie-Hellman [@logjam-weakdh-2015]. The policy was abandoned, but the code was not: two decades later, servers and libraries still spoke these crippled suites on request.
&lt;p&gt;The contract: the negotiated group must be strong, fresh, and unshared. The fine print that sank it: many servers ship the &lt;em&gt;same&lt;/em&gt; standardized 512-bit prime, so breaking one group breaks all of them at once [@logjam-weakdh-2015]. A fresh ephemeral exponent does not save you when the prime itself is weak and shared.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Contract&lt;/th&gt;
&lt;th&gt;What it requires&lt;/th&gt;
&lt;th&gt;What violates it&lt;/th&gt;
&lt;th&gt;Field break&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Nonce&lt;/td&gt;
&lt;td&gt;&lt;code&gt;k&lt;/code&gt; secret, uniform, unique per signature&lt;/td&gt;
&lt;td&gt;a constant, repeated, or biased &lt;code&gt;k&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PS3, Android, Minerva, TPM-Fail, LadderLeak&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parameter&lt;/td&gt;
&lt;td&gt;named curve, standard generator &lt;code&gt;G&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;trusting attacker-supplied explicit parameters&lt;/td&gt;
&lt;td&gt;CurveBall&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Negotiation&lt;/td&gt;
&lt;td&gt;strong, fresh, unshared group&lt;/td&gt;
&lt;td&gt;downgrade to a crippled, shared group&lt;/td&gt;
&lt;td&gt;Logjam&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Three contracts, three clauses of fine print. Over fifteen years, every clause was breached in the field -- and the breaches fall into exactly three piles.&lt;/p&gt;
&lt;h2&gt;4. The Failure Catalog: Seven Breaks, Three Layers, One Shape&lt;/h2&gt;
&lt;p&gt;None of the seven incidents below solved a discrete logarithm. Every one of them recovered a private key or forged a trusted one. Watch where each attack actually landed -- because the landing spot, not the marquee name, is the whole lesson.&lt;/p&gt;

timeline
    title EC and DH in the field, the assumption versus the breaks
    1976 : Diffie-Hellman, the assumption is born
    1985-1987 : Miller and Koblitz, the curve migration
    2010 : PS3 constant nonce, reuse
    2013 : Android SecureRandom, reuse
    2015 : Logjam, downgrade plus shared-prime NFS
    2019-2020 : Minerva and TPM-Fail, lattice bias
    2020 : LadderLeak, Bleichenbacher-Fourier sub-bit : CurveBall, unvalidated generator
&lt;p&gt;Here is the entire corpus on one page. The rightmost column is the thesis in a single word, repeated seven times.&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;Pillar&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Effort to break&lt;/th&gt;
&lt;th&gt;What fell&lt;/th&gt;
&lt;th&gt;Discrete log solved?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;PS3&lt;/td&gt;
&lt;td&gt;2010&lt;/td&gt;
&lt;td&gt;Nonce (reuse)&lt;/td&gt;
&lt;td&gt;a constant &lt;code&gt;k&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2 signatures&lt;/td&gt;
&lt;td&gt;ECDSA firmware-signing key&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Android wallets&lt;/td&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;Nonce (reuse)&lt;/td&gt;
&lt;td&gt;repeated &lt;code&gt;k&lt;/code&gt; from a broken RNG&lt;/td&gt;
&lt;td&gt;2 reused signatures&lt;/td&gt;
&lt;td&gt;Bitcoin wallet keys&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logjam&lt;/td&gt;
&lt;td&gt;2015&lt;/td&gt;
&lt;td&gt;Downgrade&lt;/td&gt;
&lt;td&gt;forced 512-bit shared prime&lt;/td&gt;
&lt;td&gt;1 NFS precompute per prime&lt;/td&gt;
&lt;td&gt;TLS session secrecy&lt;/td&gt;
&lt;td&gt;Only a crippled, shared 512-bit export prime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TPM-Fail&lt;/td&gt;
&lt;td&gt;2019-2020&lt;/td&gt;
&lt;td&gt;Nonce (bias)&lt;/td&gt;
&lt;td&gt;timing leak of nonce bit-length&lt;/td&gt;
&lt;td&gt;many signatures + lattice&lt;/td&gt;
&lt;td&gt;256-bit TPM keys&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minerva&lt;/td&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;Nonce (bias)&lt;/td&gt;
&lt;td&gt;timing leak of nonce bit-length&lt;/td&gt;
&lt;td&gt;about 2100 signatures + lattice&lt;/td&gt;
&lt;td&gt;ECDSA key&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LadderLeak&lt;/td&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;Nonce (bias)&lt;/td&gt;
&lt;td&gt;sub-bit ladder leak&lt;/td&gt;
&lt;td&gt;many signatures + Bleichenbacher/Fourier&lt;/td&gt;
&lt;td&gt;ECDSA key&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CurveBall&lt;/td&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;Validation&lt;/td&gt;
&lt;td&gt;an unchecked generator&lt;/td&gt;
&lt;td&gt;1 forged certificate&lt;/td&gt;
&lt;td&gt;certificate trust itself&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Six &quot;No&quot;s and one heavily qualified &quot;Yes.&quot; Let us walk the three pillars in turn.&lt;/p&gt;
&lt;h3&gt;Pillar 1a: the nonce, reused (certain, from two signatures)&lt;/h3&gt;
&lt;p&gt;In December 2010, at the 27th Chaos Communication Congress, the group fail0verflow presented &quot;Console Hacking 2010&quot; and revealed that Sony had signed PlayStation 3 firmware using ECDSA with a &lt;em&gt;constant&lt;/em&gt; nonce [@fail0verflow-ps3-2010]. Not a weak random &lt;code&gt;k&lt;/code&gt;. The same &lt;code&gt;k&lt;/code&gt;, every time. Every signature Sony ever produced shared a nonce with every other, which means any two of them collapse to the algebra from Section 3.Keep two PS3 events distinct. fail0verflow&apos;s 27C3 talk exposed the constant-nonce &lt;em&gt;mechanism&lt;/em&gt;. George Hotz released a separate PS3 root key weeks later, in January 2011 [@hotz-ps3-2011]. The teaching case -- a hardcoded constant nonce -- is fail0verflow&apos;s. The console&apos;s chain of trust, the thing Sony spent years engineering, came apart because &lt;a href=&quot;https://paragmali.com/blog/predictable-or-repeated-the-only-two-ways-cryptographic-rand/&quot; rel=&quot;noopener&quot;&gt;a random number generator&lt;/a&gt; was told to always return the same number.&lt;/p&gt;

flowchart LR
    A[&quot;Sig 1: s1 = k^-1 (z1 + r d)&quot;] --&amp;gt; C[&quot;Same k means same r&quot;]
    B[&quot;Sig 2: s2 = k^-1 (z2 + r d)&quot;] --&amp;gt; C
    C --&amp;gt; D[&quot;Subtract, k cancels: k = (z1 - z2) / (s1 - s2) mod n&quot;]
    D --&amp;gt; E[&quot;Solve for d = (s1 k - z1) / r mod n&quot;]
    E --&amp;gt; F[&quot;Private key recovered, no discrete log solved&quot;]
&lt;p&gt;This is not a metaphor. Here is the recovery, executable. Two signatures share a nonce, and a dozen lines of BigInt arithmetic reproduce the private key exactly:&lt;/p&gt;
&lt;p&gt;{`
// secp256k1 group order
const n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141n;
const mod = (a, m) =&amp;gt; ((a % m) + m) % m;&lt;/p&gt;
&lt;p&gt;// Modular inverse via the extended Euclidean algorithm
function inv(a, m) {
  let [oldr, r] = [mod(a, m), m];
  let [olds, s] = [1n, 0n];
  while (r !== 0n) {
    const q = oldr / r;
    [oldr, r] = [r, oldr - q * r];
    [olds, s] = [s, olds - q * s];
  }
  return mod(olds, m);
}&lt;/p&gt;
&lt;p&gt;// A victim signs two different messages with the SAME nonce k
const d  = 0x00c0ffee1234567890abcdef00c0ffee1234567890abcdef00c0ffee12345678n; // secret
const k  = 0x0000deadbeef0000feed0000deadbeef0000feed0000deadbeef0000feed0001n; // reused nonce
const r  = mod(0x1122334455667788112233445566778811223344556677881122334455667788n, n);
const z1 = 0x1111111111111111111111111111111111111111111111111111111111111111n;
const z2 = 0x2222222222222222222222222222222222222222222222222222222222222222n;
const s1 = mod(inv(k, n) * mod(z1 + mod(r * d, n), n), n);
const s2 = mod(inv(k, n) * mod(z2 + mod(r * d, n), n), n);&lt;/p&gt;
&lt;p&gt;// The attacker sees only (r, s1, z1) and (r, s2, z2). Recover k, then d.
const kRec = mod((z1 - z2) * inv(mod(s1 - s2, n), n), n);
const dRec = mod((mod(s1 * kRec, n) - z1) * inv(r, n), n);
console.log(&apos;recovered nonce matches:  &apos; + (kRec === k));
console.log(&apos;recovered private key:    &apos; + (dRec === d));
console.log(&apos;d = 0x&apos; + dRec.toString(16));
`}&lt;/p&gt;
&lt;p&gt;Three years later, the same algebra emptied wallets. In August 2013, an advisory on bitcoin.org warned that &quot;a component of Android responsible for generating secure random numbers contains critical weaknesses&quot; that rendered &quot;all Android wallets&quot; vulnerable to theft [@bitcoin-android-2013]. The root cause, per Google&apos;s own postmortem, was that the platform&apos;s &lt;code&gt;SecureRandom&lt;/code&gt; &quot;may not receive cryptographically strong values&quot; because the underlying PRNG was improperly initialized [@android-securerandom-2013].&lt;/p&gt;
&lt;p&gt;The consequence was nonce &lt;em&gt;repetition&lt;/em&gt; across transactions. And because every Bitcoin signature is broadcast to a public ledger, anyone could scan the chain for two signatures sharing an &lt;code&gt;r&lt;/code&gt; and drain the wallet behind them.The bitcoin.org advisory names the flaw and the affected wallets but states no total loss figure [@bitcoin-android-2013]. Any &quot;coins stolen&quot; number you have seen is reported, not established -- treat it accordingly.&lt;/p&gt;
&lt;p&gt;The detector that would have caught both PS3 and Android is embarrassingly short. Group public signatures by &lt;code&gt;r&lt;/code&gt;; any collision is an exposed key:&lt;/p&gt;
&lt;p&gt;{`
const n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141n;
const mod = (a, m) =&amp;gt; ((a % m) + m) % m;
function inv(a, m) {
  let [oldr, r] = [mod(a, m), m];
  let [olds, s] = [1n, 0n];
  while (r !== 0n) { const q = oldr / r; [oldr, r] = [r, oldr - q * r]; [olds, s] = [s, olds - q * s]; }
  return mod(olds, m);
}
// Build a public feed in which one signer reused a nonce, then forget the secret
const dSecret = 777n, kReused = 424242n, rReused = 987654321n;
const mk = (z) =&amp;gt; ({ r: rReused, s: mod(inv(kReused, n) * mod(z + mod(rReused * dSecret, n), n), n), z });
const feed = [ { r: 111n, s: 22n, z: 5n }, mk(1001n), { r: 222n, s: 44n, z: 9n }, mk(2002n), { r: 333n, s: 66n, z: 12n } ];&lt;/p&gt;
&lt;p&gt;const seen = new Map();
for (const g of feed) {
  const key = g.r.toString();
  if (seen.has(key)) {
    const a = seen.get(key), b = g;
    const k = mod((a.z - b.z) * inv(mod(a.s - b.s, n), n), n);
    const d = mod((mod(a.s * k, n) - a.z) * inv(a.r, n), n);
    console.log(&apos;NONCE REUSE at r = &apos; + key + &apos;  -&amp;gt;  private key d = &apos; + d.toString());
  } else {
    seen.set(key, g);
  }
}
`}&lt;/p&gt;
&lt;p&gt;Two incidents, two different root causes -- a hardcoded constant and a starved RNG -- and one identical, certain outcome. This is the crudest form of the whole thesis: the deployment lost the key while the discrete log stood untouched.&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 is certain key recovery from just two signatures, by elementary algebra. A &lt;em&gt;biased&lt;/em&gt; nonce -- one that merely leans, statistically, toward certain values -- leaks only a partial statistic and requires a statistical attack over many signatures. &quot;One biased signature leaks your key&quot; is false. The distinction is the difference between the next two subsections, and blurring it is the single most common error in this area.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Reused 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;What leaks&lt;/td&gt;
&lt;td&gt;the whole nonce (it repeats)&lt;/td&gt;
&lt;td&gt;a partial statistic about the nonce&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signatures needed&lt;/td&gt;
&lt;td&gt;exactly 2&lt;/td&gt;
&lt;td&gt;many (Minerva about 2100; PuTTY about 60 [@putty-cve-2024-31497])&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attack&lt;/td&gt;
&lt;td&gt;elementary algebra&lt;/td&gt;
&lt;td&gt;Hidden Number Problem (lattice or Fourier)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Certainty&lt;/td&gt;
&lt;td&gt;certain&lt;/td&gt;
&lt;td&gt;statistical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Examples&lt;/td&gt;
&lt;td&gt;PS3, Android&lt;/td&gt;
&lt;td&gt;Minerva, TPM-Fail, LadderLeak, PuTTY&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Pillar 1b: the nonce, biased (statistical, over many signatures)&lt;/h3&gt;
&lt;p&gt;Reuse is loud. The subtler failure is a nonce that never repeats but is not quite uniform -- one whose top bit is a little too often zero, say. It turns out that even this surrenders the key, and the theory predicting it predates the exploits by two decades.&lt;/p&gt;

Given many samples that each leak a few of the most-significant bits of `k`, together with the public signature data, recover the fixed secret `d`. Boneh and Venkatesan defined this problem in 1996 and proved it tractable [@boneh-venkatesan-1996]. Every biased-nonce attack in this article -- Minerva, TPM-Fail, LadderLeak, PuTTY -- is an instance of it.
&lt;p&gt;Nguyen and Shparlinski turned the abstract HNP into a concrete lattice attack on (EC)DSA with partially known nonces [@nguyen-shparlinski-2003], and Brumley and Tuveri showed in 2011 that the necessary bit-leak could be harvested &lt;em&gt;remotely&lt;/em&gt;, over a network, from an OpenSSL implementation whose scalar multiplication was not constant-time [@brumley-tuveri-2011]. Then the field split into two solver regimes, and telling them apart is essential.&lt;/p&gt;
&lt;p&gt;When 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;timing channel&lt;/a&gt; leaks a &lt;em&gt;few bits&lt;/em&gt; of the nonce -- typically its exact bit-length -- the HNP is solved by &lt;strong&gt;lattice reduction&lt;/strong&gt;. Minerva (CHES 2020) demonstrated this against smartcards and libraries whose scalar multiplication ran in time correlated with the nonce&apos;s length, reporting roughly &quot;2100 signatures to recover the private key on the standard secp256r1 curve&quot; [@minerva-2020].&lt;/p&gt;
&lt;p&gt;TPM-Fail (USENIX Security 2020) carried the same idea into hardware roots of trust. A timing leak in Intel firmware TPMs (CVE-2019-11090 [@cve-2019-11090]) and STMicroelectronics ST33 chips (CVE-2019-16863 [@cve-2019-16863]) recovered a 256-bit ECDSA key from an Intel fTPM in 4 to 20 minutes, and a VPN authentication key remotely in about five hours [@tpmfail-2020].Two honesty notes. Minerva&apos;s project page retracted its original EdDSA claim; the confirmed result is ECDSA-only [@minerva-2020]. And the TPM-Fail targets were not toys -- they held Common Criteria EAL4+ and FIPS 140-2 certification, and the leak survived that scrutiny [@tpmfail-2020].&lt;/p&gt;

flowchart TD
    L[&quot;A timing channel leaks partial information about the nonce k&quot;] --&amp;gt; Q{&quot;How much leaks per signature?&quot;}
    Q --&amp;gt;|&quot;at least 2 bits&quot;| LAT[&quot;Lattice reduction of the HNP: Minerva, TPM-Fail&quot;]
    Q --&amp;gt;|&quot;under 1 bit&quot;| FFT[&quot;Bleichenbacher and Fourier HNP: LadderLeak&quot;]
    LAT --&amp;gt; R[&quot;Private key d recovered over MANY signatures&quot;]
    FFT --&amp;gt; R
&lt;p&gt;The second regime is where people get it wrong. When the leak drops &lt;em&gt;below a single bit&lt;/em&gt; -- LadderLeak revealed the most-significant bit of the nonce &quot;but with probability less than one&quot; -- lattices become intractable, and the attack instead revives a Fourier-analysis method the paper credits to Daniel Bleichenbacher [@ladderleak-2020].&lt;/p&gt;
&lt;p&gt;The LadderLeak authors note that &quot;most of the attacks so far have relied on at least two bits of nonce bias,&quot; precisely the lattice regime. Their contribution was to break below it, over curves sect163r1 and NIST P-192, using the Fourier solver rather than a lattice [@ladderleak-2020]. Calling LadderLeak a lattice attack is the field&apos;s classic mistake.&lt;/p&gt;

&quot;Breaking ECDSA With Less Than One Bit Of Nonce Leakage&quot; -- the title of the LadderLeak paper, and the most compact statement of how little a nonce must betray before the key is gone.
&lt;p&gt;Notice what happened across this subsection. Every one of these attacks beat a signer that had already removed the reuse bug. The leak had moved from how the nonce was &lt;em&gt;generated&lt;/em&gt; to how it was &lt;em&gt;used&lt;/em&gt; -- a variable-time scalar multiplication -- and the cure had to move with it. Hold that thought; it is the pivot of the entire article. But reuse or bias, lattice or Fourier, two signatures or two thousand, the outcome is the same and the discrete logarithm is never touched: the deployment hands over &lt;code&gt;d&lt;/code&gt;, and the strongbox stays locked.&lt;/p&gt;
&lt;h3&gt;Pillar 2: the parameters, unvalidated (CurveBall)&lt;/h3&gt;
&lt;p&gt;The nonce pillar is about a secret the deployment mishandles. The second pillar is about an identity the deployment fails to check. On 14 January 2020, Microsoft patched CVE-2020-0601, reported by the NSA: &quot;a spoofing vulnerability exists in the way Windows CryptoAPI (Crypt32.dll) validates Elliptic Curve Cryptography (ECC) certificates&quot; [@curveball-cve-2020-0601]. It became known as CurveBall, and it is the cleanest example in the whole corpus of a break that has nothing to do with the mathematics of ECC.&lt;/p&gt;
&lt;p&gt;Recall the parameter contract. A public key is the point &lt;code&gt;dG&lt;/code&gt; -- meaningful only if everyone agrees on &lt;code&gt;G&lt;/code&gt;. CryptoAPI, when handed a certificate that specified its curve with &lt;em&gt;explicit&lt;/em&gt; parameters, checked that the certificate&apos;s public &lt;em&gt;point&lt;/em&gt; matched a trusted root&apos;s public key. What it did not check was the &lt;em&gt;generator&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So an attacker could craft a curve with a custom generator &lt;code&gt;G&apos;&lt;/code&gt;, pick any private key &lt;code&gt;d&apos;&lt;/code&gt; they liked, and compute &lt;code&gt;G&apos;&lt;/code&gt; such that &lt;code&gt;d&apos; * G&apos;&lt;/code&gt; equals the exact public point of a &lt;a href=&quot;https://paragmali.com/blog/a-perfect-signature-for-a-certificate-that-should-never-have/&quot; rel=&quot;noopener&quot;&gt;trusted root certificate authority&lt;/a&gt;. The forged certificate then presents the right public point on the wrong curve. Windows, comparing only the point, accepts it -- while a library that pins named curves rejects it instantly, because &lt;code&gt;G&apos;&lt;/code&gt; is not the standard base point.&lt;/p&gt;

flowchart TD
    A[&quot;Attacker picks explicit curve parameters with a custom generator G-prime&quot;] --&amp;gt; B[&quot;Chooses private key d-prime so that d-prime times G-prime equals a trusted root public point Q&quot;]
    B --&amp;gt; C[&quot;Forged certificate presents point Q on the attacker curve&quot;]
    C --&amp;gt; D{&quot;Windows CryptoAPI validation&quot;}
    D --&amp;gt;|&quot;Public point matches a trusted root? YES&quot;| E[&quot;Accepted, but the generator was never checked&quot;]
    D -.-&amp;gt;|&quot;A named-curve-pinning library also checks G&quot;| F[&quot;Rejected, G-prime is not the standard base point&quot;]
    E --&amp;gt; G[&quot;Forged code-signing or TLS certificate chains to a trusted root&quot;]
&lt;p&gt;The ECDLP was never in play. The attacker chose their own private key; they never had to recover anyone&apos;s. The failure is a single missing comparison -- generator against named curve -- buried in a certificate validation stack that a billion machines trusted. CurveBall is a validation bug, not a curve break, and the fix is exactly what the missing check would have been: reject explicit parameters, or fully re-validate them against the claimed named curve.&lt;/p&gt;
&lt;h3&gt;Pillar 3: the negotiation, downgraded (Logjam)&lt;/h3&gt;
&lt;p&gt;The third pillar is the one honest exception, and handled carelessly it looks like a refutation of the whole thesis. In 2015, the Logjam team (CVE-2015-4000) showed that a man-in-the-middle could rewrite a TLS handshake -- &quot;rewriting a ClientHello with DHE replaced by DHE_EXPORT&quot; -- to force the connection onto a 512-bit export-grade Diffie-Hellman group [@cve-2015-4000]. And here, unlike everywhere else, the attacker really does compute a discrete logarithm.&lt;/p&gt;
&lt;p&gt;The trick is that the expensive part of the number field sieve has to be done only once per prime, and servers share primes.&lt;/p&gt;

The fastest known classical algorithm for the finite-field discrete logarithm (and for integer factoring). Its decisive feature here: its costly first stage depends only on the *prime* being attacked, not on any particular exchanged key. Precompute once per prime, and every session under that prime becomes cheap to break. The internals belong to the companion article; what matters here is that one structural fact.
&lt;p&gt;The Logjam researchers found that &quot;8.4% of the Top 1 Million domains were initially vulnerable,&quot; and that because so many servers reused a handful of standardized 512-bit primes, &quot;the first step in the number field sieve ... is dependent only on this prime&quot; [@logjam-weakdh-2015]. One precomputation, amortized across every server that shipped that prime.&lt;/p&gt;

&quot;The first step in the number field sieve ... is dependent only on this prime.&quot; One precomputation breaks every server that shares the group.

sequenceDiagram
    participant C as Client
    participant M as MITM
    participant S as Server
    Note over M: One-time NFS precomputation per shared 512-bit prime
    C-&amp;gt;&amp;gt;M: ClientHello offering DHE
    M-&amp;gt;&amp;gt;S: ClientHello rewritten to DHE_EXPORT
    S-&amp;gt;&amp;gt;M: 512-bit export DH parameters, a shared standardized prime
    M-&amp;gt;&amp;gt;C: forwards the weak parameters
    Note over M: Precomputation done, so this connection solves fast
    M--&amp;gt;&amp;gt;C: session decrypted in near real time

The 512-bit `DHE_EXPORT` groups existed because 1990s US export regulations forbade shipping strong cryptography abroad, mandating deliberately breakable key exchange for foreign markets [@logjam-weakdh-2015]. The policy was abandoned by the early 2000s, but the cipher suites were never removed from server software. Logjam, in 2015, exploited a legal compromise that had been dead for over a decade and a codebase that never got the memo. The math did not decay -- the deployment simply kept a museum piece plugged in.
&lt;p&gt;Read carefully, Logjam is not a counterexample; it is the thesis in its most literal form. A discrete log &lt;em&gt;was&lt;/em&gt; computed, but only against a 512-bit prime that a downgrade forced the connection onto and that policy had left crippled and shared. The deployment set the weak, shared group on the table; the number field sieve merely finished the job. No strong, standard-sized group ever fell. The fix is the same shape as the break: remove export ciphers, negotiate vetted named groups (RFC 7919 [@rfc7919]), and adopt TLS 1.3, which removes static Diffie-Hellman entirely [@rfc8446].&lt;/p&gt;
&lt;p&gt;Three pillars, seven breaks, one shape: every attack hit a layer the discrete-log math depends on but does not control. Name the shape, and you have the whole discipline.&lt;/p&gt;
&lt;h2&gt;5. The Realization: Fix the Contracts, Not the Curve&lt;/h2&gt;
&lt;p&gt;There was no single eureka here. The insight accumulated across fifteen years of incidents and then snapped into one sentence: every field break attacked a layer the discrete-log math &lt;em&gt;depends on but does not control&lt;/em&gt; -- the nonce, then the parameters, then the negotiated strength -- and every fix changed &lt;em&gt;how the primitive is generated, used, validated, or negotiated&lt;/em&gt;, never the curve and never the log.&lt;/p&gt;
&lt;p&gt;The sharpest crystallization hides inside the word &quot;bias.&quot; For years it was treated as one problem with one fix: remove the random number generator, derive the nonce deterministically (RFC 6979 [@rfc6979], later blessed by FIPS 186-5 [@fips-186-5]), and the biased-nonce class is solved. But Minerva, TPM-Fail, and LadderLeak all recovered keys from signers that had &lt;em&gt;already&lt;/em&gt; done that. The reason is that &quot;bias&quot; was concealing two distinct root causes with two distinct cures.&lt;/p&gt;

flowchart TD
    B[&quot;One word: nonce bias&quot;] --&amp;gt; G[&quot;Generation defect: the RNG returns a constant, repeated, or predictable k&quot;]
    B --&amp;gt; U[&quot;Usage defect: variable-time scalar multiplication leaks the bit-length of k&quot;]
    G --&amp;gt; GC[&quot;Cure: deterministic and hedged nonces, RFC 6979 and FIPS 186-5&quot;]
    U --&amp;gt; UC[&quot;Cure: constant-time, exception-free scalar multiplication&quot;]
    GC --&amp;gt; BOTH[&quot;You need BOTH, they are orthogonal&quot;]
    UC --&amp;gt; BOTH
&lt;p&gt;A &lt;em&gt;generation&lt;/em&gt; defect is a bad nonce coming out of the sampler -- a constant (PS3), a repeat (Android), a predictable value. Determinism and hedging cure it. A &lt;em&gt;usage&lt;/em&gt; defect is a perfectly good nonce leaking through the &lt;em&gt;timing&lt;/em&gt; of the scalar multiplication that consumes it -- the bit-length falling out through a side channel (Minerva, TPM-Fail) or a sub-bit correlation (LadderLeak). Only constant-time code cures that. The two cures are orthogonal, and you need both.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Generalize the two-cures fork and you get the entire discipline of this field: four contracts, not one curve. &lt;em&gt;Generate&lt;/em&gt; the nonce so it cannot be predicted or repeated; &lt;em&gt;use&lt;/em&gt; it in constant time so it cannot leak; &lt;em&gt;validate&lt;/em&gt; your parameters so no attacker chooses your generator; &lt;em&gt;negotiate&lt;/em&gt; only strong, unshared groups so no downgrade can strand you. Every documented break is a breach of one of those four. No break in the corpus is a break of the discrete logarithm.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This also dissolves the apparent contradiction the article opened with. &quot;Nobody solved the discrete log&quot; and &quot;somebody recovered the key&quot; only sound incompatible if you conflate the discrete-log &lt;em&gt;problem&lt;/em&gt; with a discrete-log &lt;em&gt;deployment&lt;/em&gt;. The problem is a statement about computational hardness; the deployment is a nonce, a set of parameters, and a negotiation, wrapped around that hardness. The problem stayed hard. The wrapping tore.&lt;/p&gt;

If you remember one operational thing from this article, make it this: deterministic ECDSA and constant-time scalar multiplication are not two names for the same safeguard. A team can adopt RFC 6979, check the box marked &quot;nonce,&quot; and still ship a signer that a co-located attacker times to death. Ask both questions separately -- how is the nonce generated, and how is it used -- because they have separate answers.
&lt;p&gt;If the discipline is &quot;honor the four contracts, not the curve,&quot; what does a deployment that honors all four actually look like in 2026?&lt;/p&gt;
&lt;h2&gt;6. What Correct EC/DH Deployment Looks Like in 2026&lt;/h2&gt;
&lt;p&gt;The state of the art in this field is not a better discrete-log solver -- no such thing exists. It is a &lt;em&gt;deployment discipline&lt;/em&gt; at the three layers the math never controlled. Here it is, pillar by pillar.&lt;/p&gt;
&lt;h3&gt;Nonce: two orthogonal cures, and a primitive that folds in both&lt;/h3&gt;

Derive the nonce `k` deterministically from the private key and the message hash via an HMAC-based construction, so the signer &quot;do[es] not need access to a source of high-quality randomness&quot; [@rfc6979]. Identical key-and-message pairs always yield the same `k`; distinct messages yield unrelated nonces. This closes the *generation* defect -- the PS3 and Android reuse classes cannot occur.
&lt;p&gt;RFC 6979 also quietly records the deeper lesson. It insists on comparing each candidate nonce against the group order rather than reducing it modulo the order, warning that a &quot;simple modular reduction would induce biases that would be detrimental to signature security&quot; [@rfc6979]. That is a standards document, in 2013, acknowledging that &lt;em&gt;bias&lt;/em&gt;, not just reuse, is fatal. You can watch the effect yourself:&lt;/p&gt;
&lt;p&gt;{&lt;code&gt;// A raw sampler emits values in [0, 256). We need a nonce in [0, q). const q = 200n, B = 256n, trials = 400000; const raw = () =&amp;gt; BigInt(Math.floor(Number(B) * Math.random())); let biasedHigh = 0, fairHigh = 0; const half = q / 2n; for (let i = 0; i &amp;lt; trials; i++) {   const reduced = raw() % q;              // reduce mod q -&amp;gt; BIASED   if (reduced &amp;gt;= half) biasedHigh++;   let fair; do { fair = raw(); } while (fair &amp;gt;= q);  // compare to q, retry -&amp;gt; FAIR   if (fair &amp;gt;= half) fairHigh++; } console.log(&apos;reduce mod q -&amp;gt; P(nonce in top half): &apos; + (biasedHigh / trials).toFixed(4)); console.log(&apos;compare to q -&amp;gt; P(nonce in top half): &apos; + (fairHigh / trials).toFixed(4)); console.log(&apos;That gap from 0.5 is a free bit for a Hidden Number Problem attacker.&apos;);&lt;/code&gt;}&lt;/p&gt;
&lt;p&gt;Determinism, though, fixes only generation. On hardware it also &lt;em&gt;adds&lt;/em&gt; a risk.&lt;/p&gt;

Compute the nonce from the private key, the message hash, *and* a few bytes of fresh randomness. A dead RNG falls back to the safe deterministic core; a differential fault, which needs two identical signings to differ, is defeated by the fresh input. FIPS 186-5 recommends this for hardware because bare determinism is &quot;of particular concern for ... deterministic signature schemes, as well as embedded or IoT devices and smartcards&quot; [@fips-186-5].

Compute `kG` with a data-independent trace of instructions, branches, and memory accesses, so the runtime never depends on the bit-length or value of `k`. This is the *usage* cure -- the only defense against Minerva, TPM-Fail, and LadderLeak, whose leaks all live in the multiplication, not the sampler. Its precursor is Brumley and Tuveri&apos;s 2011 remote attack on a non-constant-time OpenSSL ladder [@brumley-tuveri-2011].
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Hedged signing and constant-time multiplication are the two cures of the fork, and they do not substitute for each other. A hardware signer needs &lt;em&gt;both&lt;/em&gt;: hedge the generation, and make the usage constant-time. Checking one box leaves the other break wide open.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;New designs can sidestep the whole fork by choosing a misuse-resistant primitive. Ed25519 (RFC 8032) derives its nonce as a hash of the secret and message -- deterministic by construction, no per-signature RNG -- and signs with a single &lt;em&gt;complete&lt;/em&gt;, constant-time addition law that has no exceptional cases to mishandle [@rfc8032]. It folds both cures into the primitive and removes the dangerous choices from the caller&apos;s hands.Misuse-resistant is not misuse-proof. PuTTY derived P-521 ECDSA nonces such that &quot;the first 9 bits of each ECDSA nonce are zero,&quot; allowing &quot;full secret key recovery in roughly 60 signatures&quot; (CVE-2024-31497) [@putty-cve-2024-31497]. Determinism implemented carelessly re-introduced exactly the bias it was meant to prevent.&lt;/p&gt;
&lt;h3&gt;Validation: reject what you cannot vouch for&lt;/h3&gt;
&lt;p&gt;The CurveBall cure is direct: bind a certificate&apos;s curve to the standard parameters of its named curve, and reject explicit parameters or fully re-validate them. The January 2020 patch made &lt;code&gt;crypt32.dll&lt;/code&gt; check the generator, not merely the point [@curveball-cve-2020-0601].&lt;/p&gt;
&lt;p&gt;For key &lt;em&gt;exchange&lt;/em&gt; with static keys, the discipline is fuller. Before using a received point, confirm it is not the identity, lies on the curve, and sits in the correct prime-order subgroup -- the full public-key validation of NIST SP 800-56A, which blocks &lt;a href=&quot;https://paragmali.com/blog/the-curve-was-hard-the-gap-was-soft-a-field-guide-to-using-e/&quot; rel=&quot;noopener&quot;&gt;invalid-curve and small-subgroup attacks&lt;/a&gt; that would otherwise bleed a static key out one query at a time [@sp-800-56a-r3].&lt;/p&gt;
&lt;p&gt;The most durable answer is to make invalid inputs unrepresentable. X25519 works on a Montgomery curve chosen so that &lt;em&gt;every&lt;/em&gt; 32-byte string is an acceptable public key; the RFC even instructs implementations to &quot;accept non-canonical values,&quot; and to run the conditional swap &quot;in constant time&quot; [@rfc7748]. There is no explicit-parameter path to abuse and no on-curve check to forget.This is the &quot;make invalid states unrepresentable&quot; principle applied to cryptography: the safest validation code is the code you deleted because the type system already guarantees the property. But note the boundary carefully.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; X25519&apos;s scalar &quot;clamping&quot; fixes the cofactor and twist problems for ephemeral key exchange. It does &lt;em&gt;not&lt;/em&gt; replace named-curve pinning in the X.509 world, and some protocols still need a contributory-behavior check on the shared secret. Twist-secure curves solve the problems they were designed for -- not every parameter problem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Negotiation: remove the weak option entirely&lt;/h3&gt;
&lt;p&gt;The downgrade pillar&apos;s fix is structural. RFC 7919 replaced ad-hoc, shared Diffie-Hellman primes with a menu of vetted named groups negotiated like curves [@rfc7919]. TLS 1.3 went further and deleted the weak options outright, so there is nothing to downgrade &lt;em&gt;to&lt;/em&gt;.&lt;/p&gt;

&quot;Static RSA and Diffie-Hellman cipher suites have been removed; all public-key based key exchange mechanisms now provide forward secrecy.&quot; -- RFC 8446, the TLS 1.3 specification [@rfc8446].
&lt;p&gt;Because TLS 1.3 permits only strong ephemeral groups and binds the negotiation into the handshake transcript, the Logjam rewrite is not merely discouraged -- it is structurally impossible [@rfc8446]. The end state of the negotiation pillar is a protocol in which the crippled, shared 512-bit group Logjam relied on simply cannot be selected.&lt;/p&gt;
&lt;p&gt;Each of these is a choice, and where there is a choice, engineers argue. Which discipline actually wins in which threat model?&lt;/p&gt;
&lt;h2&gt;7. Competing Approaches: Which Defense Answers Which Adversary&lt;/h2&gt;
&lt;p&gt;These defenses are not rungs on one ladder. They are answers to different adversaries, and the honest way to compare them is one pillar at a time.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A constant-time multiplier and a named-curve pin do not compete -- they defend different layers, and a real system needs one from each pillar. The comparisons below rank options &lt;em&gt;within&lt;/em&gt; a pillar. Picking the best nonce discipline does nothing for your parameter validation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Nonce: which signing discipline stops which adversary&lt;/h3&gt;
&lt;p&gt;The load-bearing insight is that no single column stops every row. Generation cures (deterministic [@rfc6979], hedged [@fips-186-5]) and the usage cure (constant-time) are orthogonal, which is why hedged-plus-constant-time became the practitioner default and why Ed25519 [@rfc8032] folds most of both into the primitive.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Adversary / failure&lt;/th&gt;
&lt;th&gt;Randomized (bare RNG)&lt;/th&gt;
&lt;th&gt;Deterministic (RFC 6979)&lt;/th&gt;
&lt;th&gt;Hedged (FIPS 186-5)&lt;/th&gt;
&lt;th&gt;Constant-time mult&lt;/th&gt;
&lt;th&gt;Ed25519&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;RNG returns constant or repeat (PS3, Android)&lt;/td&gt;
&lt;td&gt;fails&lt;/td&gt;
&lt;td&gt;stops&lt;/td&gt;
&lt;td&gt;stops&lt;/td&gt;
&lt;td&gt;orthogonal&lt;/td&gt;
&lt;td&gt;stops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Differential fault on a deterministic signer&lt;/td&gt;
&lt;td&gt;randomness helps&lt;/td&gt;
&lt;td&gt;fails&lt;/td&gt;
&lt;td&gt;stops&lt;/td&gt;
&lt;td&gt;orthogonal&lt;/td&gt;
&lt;td&gt;inherits the caveat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timing leak of nonce bit-length (Minerva, TPM-Fail)&lt;/td&gt;
&lt;td&gt;fails&lt;/td&gt;
&lt;td&gt;fails&lt;/td&gt;
&lt;td&gt;fails&lt;/td&gt;
&lt;td&gt;stops&lt;/td&gt;
&lt;td&gt;stops (uniform ladder)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sub-bit ladder leak (LadderLeak)&lt;/td&gt;
&lt;td&gt;fails&lt;/td&gt;
&lt;td&gt;fails&lt;/td&gt;
&lt;td&gt;fails&lt;/td&gt;
&lt;td&gt;stops&lt;/td&gt;
&lt;td&gt;stops (uniform ladder)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Read the rows, not the columns: reuse fails only the first row and is certain from two signatures; the timing leaks fail three of the five columns and are cured on a different axis entirely. That is the two-cures fork, rendered as a matrix.&lt;/p&gt;
&lt;h3&gt;Validation: three philosophies of not trusting your input&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Named-curve pinning&lt;/th&gt;
&lt;th&gt;Full validation (SP 800-56A)&lt;/th&gt;
&lt;th&gt;All-inputs-valid (X25519)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Philosophy&lt;/td&gt;
&lt;td&gt;reject non-standard parameters&lt;/td&gt;
&lt;td&gt;validate every received input&lt;/td&gt;
&lt;td&gt;make invalid inputs unrepresentable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stops CurveBall (unvalidated generator)&lt;/td&gt;
&lt;td&gt;yes, its exact fix&lt;/td&gt;
&lt;td&gt;yes, re-derives the generator&lt;/td&gt;
&lt;td&gt;yes, no explicit-parameter path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stops invalid-curve / small-subgroup&lt;/td&gt;
&lt;td&gt;partial&lt;/td&gt;
&lt;td&gt;yes, on-curve plus subgroup&lt;/td&gt;
&lt;td&gt;yes, twist-secure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-operation cost&lt;/td&gt;
&lt;td&gt;O(1) table compare&lt;/td&gt;
&lt;td&gt;O(1) up to one scalar mult&lt;/td&gt;
&lt;td&gt;one constant-time ladder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best suited for&lt;/td&gt;
&lt;td&gt;X.509, code-signing, PKI&lt;/td&gt;
&lt;td&gt;static-key ECDH, HSMs&lt;/td&gt;
&lt;td&gt;ephemeral ECDH&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Named-curve pinning is the precise CurveBall fix [@curveball-cve-2020-0601]; SP 800-56A validation is the belt-and-suspenders choice for static keys [@sp-800-56a-r3]; X25519 deletes the problem by construction [@rfc7748]. They converge on stopping CurveBall and diverge on everything else.&lt;/p&gt;
&lt;h3&gt;Downgrade: hardening, deletion, or hedging against tomorrow&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Config hardening + FFDHE&lt;/th&gt;
&lt;th&gt;TLS 1.3&lt;/th&gt;
&lt;th&gt;Hybrid post-quantum&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Removes the 512-bit export rung&lt;/td&gt;
&lt;td&gt;yes, within FFDHE&lt;/td&gt;
&lt;td&gt;yes, structurally&lt;/td&gt;
&lt;td&gt;yes, inherits 1.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Removes shared or unknown primes&lt;/td&gt;
&lt;td&gt;yes, named menu&lt;/td&gt;
&lt;td&gt;yes, fixed groups&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Downgrade protection in the handshake&lt;/td&gt;
&lt;td&gt;no, still in-band&lt;/td&gt;
&lt;td&gt;yes, transcript-bound&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Defends against a future Shor adversary&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;yes, if ML-KEM holds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Residual weakness&lt;/td&gt;
&lt;td&gt;the legacy long tail&lt;/td&gt;
&lt;td&gt;non-TLS 1024-bit primes&lt;/td&gt;
&lt;td&gt;a KEM is not a NIKE, young PQC&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;RFC 7919 named groups [@rfc7919] are the transitional hardening for TLS 1.2; TLS 1.3 is the structural end state [@rfc8446]; hybrid X25519 with &lt;a href=&quot;https://paragmali.com/blog/one-event-three-assumptions-five-answers-a-field-guide-to-th/&quot; rel=&quot;noopener&quot;&gt;ML-KEM&lt;/a&gt; (RFC 9954 [@rfc9954], ML-KEM standardized as FIPS 203 [@fips-203]) is the forward hedge against a quantum adversary. Only the last column defends against a break that would be genuine mathematics rather than a deployment slip.&lt;/p&gt;
&lt;p&gt;Every column in every table changed the deployment, not the curve. So is the discrete log itself simply unbreakable? Almost -- and the &quot;almost&quot; is the most honest paragraph in this article.&lt;/p&gt;
&lt;h2&gt;8. Theoretical Limits: What Is Provably True on Both Sides&lt;/h2&gt;
&lt;p&gt;This is the honest concession the thesis has been earning the right to make. There are two provable sides here, and the argument needs both.&lt;/p&gt;
&lt;h3&gt;The hardness side: no room for a strong curve to fall&lt;/h3&gt;
&lt;p&gt;On a well-chosen group, the discrete logarithm is genuinely hard, and we can say so with unusual precision. The best classical attack is Pollard&apos;s rho, a square-root-time random walk that needs negligible memory [@teske-2001]. In the strict generic model its expected cost is about $\sqrt{\pi n/2}$, roughly 1.25 times $\sqrt{n}$ group operations; on an elliptic curve, the negation map (where $P$ and $-P$ share an x-coordinate) trims that to about 0.886 times $\sqrt{n}$. Either way the exponent is the same, matching baby-step giant-step&apos;s $O(\sqrt{n})$ time [@hac-ch11].&lt;/p&gt;
&lt;p&gt;Against that upper bound, Shoup proved a generic &lt;em&gt;lower&lt;/em&gt; bound of $\Omega(\sqrt{p})$: no algorithm restricted to the group operation can do better [@shoup-1997]. The two meet at $\Theta(\sqrt{n})$. The generic gap is essentially closed -- which is exactly why a 256-bit curve delivers around 128-bit security, and why no strong deployed curve&apos;s discrete log has fallen.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Best classical DL attack&lt;/td&gt;
&lt;td&gt;Pollard&apos;s rho, about 1.25 times sqrt(n) generic; 0.886 times sqrt(n) on curves&lt;/td&gt;
&lt;td&gt;negligible space&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Baby-step giant-step&lt;/td&gt;
&lt;td&gt;O(sqrt(n)) time and O(sqrt(n)) space&lt;/td&gt;
&lt;td&gt;the space-heavy twin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generic lower bound&lt;/td&gt;
&lt;td&gt;Omega(sqrt(p)), provably no faster generic algorithm&lt;/td&gt;
&lt;td&gt;Shoup 1997&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finite-field DH (non-generic)&lt;/td&gt;
&lt;td&gt;sub-exponential via the number field sieve&lt;/td&gt;
&lt;td&gt;why DH needs about 3072-bit primes (2048-bit minimum)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strong deployed curve or standard group ever solved&lt;/td&gt;
&lt;td&gt;none, only Logjam&apos;s crippled shared 512-bit prime&lt;/td&gt;
&lt;td&gt;the thesis in one row&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The last two rows carry the concession. Finite-field Diffie-Hellman is &lt;em&gt;not&lt;/em&gt; generic: the number field sieve solves it in sub-exponential time, which is why finite-field DH needs primes of about 3072 bits to match the security a 256-bit curve gives (2048 bits is the absolute minimum), and why Logjam&apos;s downgrade to 512 bits was finishable at all [@logjam-weakdh-2015]. The number-field-sieve mathematics belongs to the companion article.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Logjam is the only break in this corpus that reached the mathematics, and the reason is structural, not accidental. A finite field carries extra arithmetic structure that a generic group lacks, which lets the number field sieve run in sub-exponential time, faster than the square-root barrier that protects a strong elliptic curve. That structural gap is the sole opening the discrete log ever offered, and even it was not enough alone: the computation became feasible only after the prime was cut to 512 export-grade bits. Raise the group back to a standard 2048-bit prime, or move to a curve where no such shortcut exists, and the opening closes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;The leakage side: no room to hide a little bias&lt;/h3&gt;
&lt;p&gt;The other provable side indicts the deployment just as sharply. The Hidden Number Problem makes partial leakage fatal by construction: Boneh and Venkatesan proved that recovering a secret from many small most-significant-bit leaks is tractable [@boneh-venkatesan-1996], and Nguyen and Shparlinski turned that into a working lattice attack on (EC)DSA with partial nonces [@nguyen-shparlinski-2003].&lt;/p&gt;
&lt;p&gt;There is no &quot;a little bias is tolerable&quot; regime: any &lt;em&gt;consistent&lt;/em&gt; partial leak of &lt;code&gt;k&lt;/code&gt;, integrated over enough signatures, provably recovers &lt;code&gt;d&lt;/code&gt;. Two or more leaked bits fall to a lattice; a sub-bit leak falls to Bleichenbacher&apos;s Fourier method [@ladderleak-2020]. &quot;&lt;code&gt;k&lt;/code&gt; is secret, uniform, and unique&quot; is not a best practice -- it is a hard boundary.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The math is safe at the sizes we deploy (the generic gap is closed), and leakage is fatal at any size (the HNP admits no safe margin). Both proofs point the same way: the primitive is not the weak part. The nonce, the parameters, and the negotiation are.&lt;/p&gt;
&lt;/blockquote&gt;

Two clouds sit on the horizon. First, the shared-prime structure Logjam exploited at 512 bits revives at 1024. The Logjam team estimated that precomputing the single most common 1024-bit prime would expose roughly 18% of the top HTTPS sites; a second common prime would reach about 66% of IPsec VPNs and around 26% of SSH servers [@logjam-weakdh-2015] -- the same trick, resized, and a resourced adversary&apos;s project. Second, a large fault-tolerant quantum computer running Shor&apos;s algorithm would break the discrete logarithm outright, curve and finite field alike. That is the one future break that *is* the mathematics, and it is the subject of the companion article, not this one. The deployment answer, already shipping, is hybrid key exchange.
&lt;p&gt;So where, concretely, does EC and DH still break tomorrow?&lt;/p&gt;
&lt;h2&gt;9. Where EC and DH Still Break in the Field&lt;/h2&gt;
&lt;p&gt;The incidents are settled. The &lt;em&gt;classes&lt;/em&gt; are not. Every open problem below is a documented pattern waiting for its next instance, and each one maps to a pillar you have already met.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The next SecureRandom (nonce generation, Pillar 1).&lt;/strong&gt; A signer needs a unique, secret nonce at the exact moment its entropy is weakest: first boot, a headless IoT device with no entropy events, or a freshly cloned virtual machine carrying a duplicated seed. This is the mechanism behind Android 2013 [@android-securerandom-2013], and it recurs whenever hardware is provisioned faster than it can gather randomness.Cloned-VM state duplication is an especially nasty modern form: two hosts that never coordinated can emit the &lt;em&gt;same&lt;/em&gt; &quot;random&quot; nonce because they booted from one snapshot. The signing path can be hedged [@fips-186-5], but key generation and ephemeral key exchange still need a live, well-seeded source.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The next Minerva or LadderLeak (nonce usage, Pillar 1).&lt;/strong&gt; Constant-time scalar multiplication must be re-established against every new microarchitecture -- caches, execution ports, prefetchers, simultaneous multithreading -- and on every fragile incomplete-addition curve. The bit-length leak of Minerva [@minerva-2020] and the sub-bit leak of LadderLeak [@ladderleak-2020] both post-date deterministic nonces precisely because the leak had moved to usage. Formally verified primitives close the &lt;em&gt;known&lt;/em&gt; channels on the &lt;em&gt;chosen&lt;/em&gt; curve; FIPS-mandated P-curves and secp256k1 keep hand-written code in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The long tail of shared primes (downgrade, Pillar 3).&lt;/strong&gt; TLS 1.3 closes the web protocol layer, but export-grade and shared standardized primes outlived their policy elsewhere. IKEv1 VPNs and older SSH still ship shared 1024-bit Diffie-Hellman groups, and a single precomputation per shared prime amortizes across every server using it [@logjam-weakdh-2015]. The consensus recommendation is blunt: retire 1024-bit DH now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The next CurveBall (validation, Pillar 2).&lt;/strong&gt; CurveBall was one unchecked generator in one library [@curveball-cve-2020-0601]; the class is &quot;somewhere in a large validation stack, attacker-supplied parameters are trusted.&quot; Every new parser, certificate profile, or post-quantum key format reopens the class, and a single such bug in a widely embedded validator forges trust across everything that depends on it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Post-quantum migration ahead of Shor (cross-pillar).&lt;/strong&gt; Hybrid key exchange -- running X25519 alongside ML-KEM so the session stays secure if either component holds -- is standardized (RFC 9954 [@rfc9954]; concrete groups such as X25519MLKEM768 in the ongoing ECDHE-MLKEM work [@draft-ietf-tls-ecdhe-mlkem]; ML-KEM standardized as FIPS 203 [@fips-203]) and is already deployed at scale: it protected a majority of the human web traffic Cloudflare measured by late 2025 [@cloudflare-pq-radar]. But the migration carries a trap that has nothing to do with the discrete log.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; ML-KEM is a key-&lt;em&gt;encapsulation&lt;/em&gt; mechanism, not a non-interactive key agreement. It does not reproduce X25519&apos;s static Diffie-Hellman semantics, where two long-term public keys combine without any live exchange. Systems that quietly assume &quot;post-quantum DH&quot; is a drop-in replacement for classical DH will find the shape of the primitive has changed underneath them. Migrate deliberately, not by search-and-replace.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;None of these needs new mathematics to break you. Each needs exactly one deployment mistake. Here is how not to make it.&lt;/p&gt;
&lt;h2&gt;10. What to Do on Monday&lt;/h2&gt;
&lt;p&gt;Every item below maps to a specific incident in this article. Do these, and you do not ship the next one.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Never put a bare runtime RNG in the signing path.&lt;/strong&gt; Use deterministic (RFC 6979 [@rfc6979]) or, on hardware, hedged (FIPS 186-5 [@fips-186-5]) nonces. &lt;em&gt;Prevents:&lt;/em&gt; PS3, Android.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Demand constant-time, exception-free scalar multiplication.&lt;/strong&gt; This is a separate control from the nonce discipline, not a duplicate of it. &lt;em&gt;Prevents:&lt;/em&gt; Minerva, TPM-Fail, LadderLeak.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefer misuse-resistant primitives.&lt;/strong&gt; Ed25519 for new signing [@rfc8032], X25519 for ephemeral key exchange [@rfc7748]; for static-key ECDH, run full public-key validation per SP 800-56A [@sp-800-56a-r3]. &lt;em&gt;Prevents:&lt;/em&gt; whole classes of implementer error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reject explicit curve parameters; require named curves.&lt;/strong&gt; Pin the curve, and the generator with it. &lt;em&gt;Prevents:&lt;/em&gt; CurveBall [@curveball-cve-2020-0601].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disable export ciphers and use vetted groups.&lt;/strong&gt; RFC 7919 named groups [@rfc7919] for residual TLS 1.2 DHE, or move to TLS 1.3 [@rfc8446]. &lt;em&gt;Prevents:&lt;/em&gt; Logjam.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never assume a fresh ephemeral rescues a shared prime.&lt;/strong&gt; The number-field-sieve precomputation is per-prime, not per-connection [@logjam-weakdh-2015]. &lt;em&gt;Prevents:&lt;/em&gt; the subtle half of Logjam.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plan the post-quantum migration as hybrid, not pure.&lt;/strong&gt; Run a classical curve alongside ML-KEM (RFC 9954 [@rfc9954]); remember a KEM is not a NIKE. &lt;em&gt;Prevents:&lt;/em&gt; harvest-now-decrypt-later exposure.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; New signing design, free to pick the curve: Ed25519. Must use ECDSA on a NIST or secp256k1 curve: hedged RFC 6979 &lt;em&gt;and&lt;/em&gt; a vetted constant-time multiply. Hardware or embedded signer: hedged, never bare-deterministic. Ephemeral key exchange: X25519. Static-key ECDH: full SP 800-56A validation. Certificate or PKI validation: pin named curves. Any TLS: version 1.3, and if you are stuck on 1.2 DHE, RFC 7919 groups with export ciphers off. Long-lived confidentiality: hybrid X25519 with ML-KEM.&lt;/p&gt;
&lt;/blockquote&gt;

1. **Nonce:** For every signature, can you show the nonce is both unpredictable (hedged or deterministic) *and* consumed in constant time? If you can only answer one half, you are exposed to the other.
2. **Parameters:** Does your certificate and key-exchange path reject attacker-supplied explicit parameters and validate every received point against the named curve?
3. **Negotiation:** Can a man-in-the-middle force any weaker group or version than you intend? If you cannot prove &quot;no,&quot; assume &quot;yes.&quot;
&lt;p&gt;Notice that not one item on this list is &quot;use a bigger curve.&quot; For every break except Logjam&apos;s downgrade, key size is irrelevant -- a 384-bit curve reuses a nonce exactly as fatally as a 256-bit one. The controls are about generation, usage, validation, and negotiation, because those are the four contracts, and the contracts are where reality broke.&lt;/p&gt;
&lt;p&gt;Two questions decide whether you got this right, and they happen to be the two most-repeated errors in the field.&lt;/p&gt;
&lt;h2&gt;11. FAQ: Misconceptions, Precisely Corrected&lt;/h2&gt;

Once, and only against a deliberately crippled target. Logjam computed discrete logarithms against a 512-bit export-grade Diffie-Hellman prime -- one that a man-in-the-middle downgrade could select and that many servers had in common [@logjam-weakdh-2015][@cve-2015-4000]. No strong deployed curve -- P-256, Curve25519, secp256k1 -- and no standard-sized group of 2048 bits or more has ever had its discrete log solved in public. The ceiling of the entire corpus is a 512-bit prime that policy left broken.

No, and this is the most common error. A *repeated* nonce recovers the key with certainty from exactly two signatures, by elementary algebra. A merely *biased* nonce emits only a faint statistical signal per signature, so recovery takes many of them plus a dedicated lattice or Fourier attack -- about 2100 for Minerva on secp256r1 [@minerva-2020], roughly 60 for PuTTY&apos;s nine-zero-bit bias [@putty-cve-2024-31497]. One biased signature leaks almost nothing.

No. LadderLeak&apos;s leak is under a single bit per signature, which lattice methods cannot exploit; it revives Bleichenbacher&apos;s Fourier-analysis solver instead [@ladderleak-2020]. The lattice regime is Minerva and TPM-Fail, whose leaks are two bits or more [@minerva-2020][@tpmfail-2020]. Calling all three &quot;lattice attacks&quot; collapses a distinction the attacks themselves are built on.

No. Padding oracles are an RSA and CBC-mode phenomenon; there is no elliptic-curve or Diffie-Hellman padding-oracle exemplar, and you should not go looking to manufacture one. The EC and DH attack surface is exactly the three pillars here -- the nonce, parameter validation, and downgrade. RSA&apos;s padding oracles, and the fact that RSA signing has no per-signature secret nonce to reuse, are covered in the companion piece &quot;How RSA Breaks in Real Life.&quot;

Only against half the problem. RFC 6979 removes the random number generator from the signing path and eliminates the reuse class [@rfc6979], but it does nothing about a timing leak during nonce *usage* -- which is exactly how Minerva, TPM-Fail, and LadderLeak recovered keys from deterministic signers. The complete answer is hedged signing plus constant-time scalar multiplication [@fips-186-5], the two orthogonal cures.

Almost never. The nonce, validation, and downgrade defects are all indifferent to key size: a forged CurveBall certificate is accepted no matter how large the curve is, because the flaw is a skipped generator check rather than a hard curve [@curveball-cve-2020-0601], and a reused or leaked nonce surrenders the private key whether that key is 256 or 384 bits. The one place size mattered was the export-group downgrade, and there the fix was to stop negotiating the 512-bit group at all [@logjam-weakdh-2015], not to enlarge it.

The primitive, no. The discrete logarithm on a strong group remains as hard as it was in the 1970s. What broke, repeatedly, was the deployment around it. Fix the nonce path, validate your parameters against named curves, and retire export and shared groups, and you have closed every break in this article. CurveBall was a validation bug, not a curve break [@curveball-cve-2020-0601] -- and that distinction is the whole point.
&lt;p&gt;Half a century after Diffie and Hellman reduced key exchange to one hard problem, the scoreboard is unambiguous: seven documented field breaks across three deployment layers, and a discrete-log ceiling that only ever reached a deliberately crippled, shared 512-bit export group -- never a strong deployed curve, never a standard-sized group. The mathematics kept its promise. The deployments did not.&lt;/p&gt;

The discrete log never fell. The nonce did, the parameters did, and the negotiation did -- and every one of those is the deployment&apos;s job, not the curve&apos;s.
&lt;p&gt;For the other half of the story -- how a curve itself could be structurally weak, how the number field sieve and Shor&apos;s algorithm actually break the math -- see the structural companion, &quot;How the Discrete Log Would Break.&quot; For the primitive that has no per-signature nonce to reuse and its own &lt;a href=&quot;https://paragmali.com/blog/rsa-is-a-trapdoor-not-a-cryptosystem-oaep-pss-and-the-25-yea/&quot; rel=&quot;noopener&quot;&gt;padding-oracle history&lt;/a&gt;, see the series sibling, &quot;How RSA Breaks in Real Life.&quot; This article was about the gap between a hard problem and a shipped product. That gap is where the keys keep getting out.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;how-ecc-and-dh-break-in-real-life&quot; keyTerms={[
  { term: &quot;Per-signature nonce (k)&quot;, definition: &quot;The once-used secret in ECDSA that must be secret, uniform, and unique per signature; the load-bearing prerequisite behind PS3, Android, Minerva, TPM-Fail, and LadderLeak.&quot; },
  { term: &quot;Nonce reuse vs. bias&quot;, definition: &quot;A repeated nonce recovers the key with certainty from two signatures; a biased nonce needs a statistical Hidden Number Problem attack over many signatures.&quot; },
  { term: &quot;Hidden Number Problem&quot;, definition: &quot;Recovering a fixed secret from many samples that each leak a few most-significant bits; the framework behind every biased-nonce attack.&quot; },
  { term: &quot;Two-cures fork&quot;, definition: &quot;Determinism and hedging fix nonce generation; constant-time scalar multiplication fixes nonce usage. The two are orthogonal and both are required.&quot; },
  { term: &quot;CurveBall (CVE-2020-0601)&quot;, definition: &quot;A Windows CryptoAPI bug that matched a certificate public point but never checked the generator against the named curve; a validation bug, not a curve break.&quot; },
  { term: &quot;Logjam (CVE-2015-4000)&quot;, definition: &quot;A TLS downgrade to a shared 512-bit export Diffie-Hellman prime, breakable because the number field sieve precomputes once per prime; the only discrete log in the corpus.&quot; },
  { term: &quot;Named curve vs. explicit parameters&quot;, definition: &quot;Referencing standardized domain parameters by identifier versus trusting attacker-supplied inline parameters, including a custom generator.&quot; }
]} questions={[
  { q: &quot;Why does a reused nonce recover the key from only two signatures?&quot;, a: &quot;Two signatures with the same nonce share r; subtracting the signing equations cancels the private-key term, yielding the nonce, and one equation then solves for the key.&quot; },
  { q: &quot;Why is LadderLeak not a lattice attack?&quot;, a: &quot;Its leak is under one bit per signature, which lattices cannot exploit, so it uses Bleichenbacher&apos;s Fourier method instead. Lattices are the Minerva and TPM-Fail regime.&quot; },
  { q: &quot;Is Logjam a counterexample to the thesis?&quot;, a: &quot;No. The only discrete log computed landed on a downgrade-forced, crippled, shared 512-bit prime; no strong or standard-sized group ever fell.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>elliptic-curve-cryptography</category><category>ecdsa</category><category>diffie-hellman</category><category>nonce-reuse</category><category>side-channel-attacks</category><category>tls-security</category><category>post-quantum</category><category>applied-cryptography</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>How ML-KEM Breaks in Real Life: The Machine Leaked While the Math Held</title><link>https://paragmali.com/blog/how-ml-kem-breaks-in-real-life-the-machine-leaked-while-the-/</link><guid isPermaLink="true">https://paragmali.com/blog/how-ml-kem-breaks-in-real-life-the-machine-leaked-while-the-/</guid><description>ML-KEM shipped with a machine-checked security proof, yet its reference code leaked secret keys through a division instruction. Why every break missed the math.</description><pubDate>Sat, 18 Jul 2026 00:00:00 GMT</pubDate><content:encoded>
ML-KEM (FIPS 203) is the first standardized post-quantum KEM, and as of publication its Module-LWE mathematics is unbroken -- the IND-CCA2 security of its Fujisaki-Okamoto construction is even machine-checked [@fvk], and the two headline quantum &quot;breaks&quot; both failed to withstand expert scrutiny -- Chen withdrew his own claim, and Luo&apos;s was refuted by named experts [@chen2024][@postquantum-luo]. Yet every real attack on it has recovered secret keys anyway: KyberSlash through a variable-time division instruction disclosed in December 2023 [@kyber-commit][@kyberslash-paper], Clangover through a compiler that reintroduced a secret branch [@clangover], and fault attacks like Carry Your Fault straight through the masking meant to stop them [@carry-fault]. The through-line is a law two decades old, first seen when AES was attacked at the implementation and never at the cipher [@bernstein2005]: a security proof constrains values, not execution, so the attacker&apos;s frontier moves outward -- instruction, compiler, construction, countermeasure -- and never has to reach the lattice. This article catalogs each documented break from its primary source and shows you how to choose an ML-KEM implementation that does not leak.
&lt;h2&gt;1. A fortress breached at the doorknob&lt;/h2&gt;
&lt;p&gt;On 13 August 2024, the U.S. National Institute of Standards and Technology published FIPS 203 and gave the world its first standardized post-quantum key-encapsulation mechanism: ML-KEM [@fips203]. It arrived with something almost no cipher in history has had at birth -- a machine-checked mathematical proof that the construction is secure [@fvk]. Eight months earlier, on 1 December 2023, the maintainers of its reference code had quietly committed a patch to stop that same code from handing an attacker the full secret key [@kyber-commit]. Not through any weakness in the lattice mathematics. Through a single division instruction.&lt;/p&gt;
&lt;p&gt;The proof was about the numbers. The attack was about the machine. This article is about the gap between them.&lt;/p&gt;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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


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


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


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


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


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

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

The machine leaked while the math held. That is not a footnote to ML-KEM&apos;s security -- as of publication, it is the entire story of how it breaks.
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;how-ml-kem-breaks-in-real-life&quot; keyTerms={[
  { term: &quot;Key Encapsulation Mechanism (KEM)&quot;, definition: &quot;A protocol for agreeing on a shared secret; ML-KEM is the FIPS 203 standard.&quot; },
  { term: &quot;Module-LWE&quot;, definition: &quot;The lattice problem ML-KEM&apos;s security rests on; unbroken as of publication.&quot; },
  { term: &quot;Fujisaki-Okamoto transform&quot;, definition: &quot;The re-encrypt-and-compare construction that makes ML-KEM CCA-secure.&quot; },
  { term: &quot;Implicit rejection&quot;, definition: &quot;On a re-encryption mismatch, decapsulation returns a pseudorandom secret, not an error.&quot; },
  { term: &quot;KyberSlash&quot;, definition: &quot;A December 2023 secret-dependent division-timing leak in reference Kyber code.&quot; },
  { term: &quot;Clangover&quot;, definition: &quot;A compiler-introduced secret branch that defeats source-level constant-time code.&quot; },
  { term: &quot;Plaintext-checking oracle&quot;, definition: &quot;A pass-or-fail side-channel leak that reconstructs a reused secret key.&quot; },
  { term: &quot;Constant-time execution&quot;, definition: &quot;Behavior independent of secret data; a property of the shipped binary, not the source.&quot; },
  { term: &quot;Masking&quot;, definition: &quot;Splitting secrets into t+1 shares to resist power and electromagnetic analysis.&quot; },
  { term: &quot;Carry Your Fault&quot;, definition: &quot;A fault on the A2B carry chain that defeats masking of arbitrary order.&quot; }
]} questions={[
  { q: &quot;Why does a machine-checked security proof not prevent key recovery?&quot;, a: &quot;The proof constrains values, not execution; keys leak through timing, compiler output, power, or faults.&quot; },
  { q: &quot;What single surface underlies KyberSlash, Clangover, and the PC-oracle attacks?&quot;, a: &quot;The Fujisaki-Okamoto re-encrypt-and-compare step, which must run on secret-derived data.&quot; },
  { q: &quot;Does masking alone protect an embedded device?&quot;, a: &quot;No; it stops power and EM analysis but not faults, so fault countermeasures are also required.&quot; },
  { q: &quot;What deployment hedges both a math break and an implementation bug?&quot;, a: &quot;A hybrid handshake such as X25519MLKEM768, which stays secure if either component holds.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>post-quantum-cryptography</category><category>ml-kem</category><category>kyber</category><category>side-channel-attacks</category><category>constant-time</category><category>kyberslash</category><category>fujisaki-okamoto</category><category>implementation-security</category><author>noreply@paragmali.com (Parag Mali)</author></item></channel></rss>