book overhaul moves 1+2: the minute-one artifact, and cold-open surgery on ch1

From the 7-reader didactic audit (control/BOOK-OVERHAUL-PLAN.md). The two
highest-leverage moves per the cold-open reader and the panel's most-repeated
finding.

MOVE 1 — the reader touches the real thing in minute one. The panel's single
loudest note: a book that teaches "demand verification" gave the reader
nothing to verify for twelve chapters. Now: the title page names
ltl.zkdefi.org (19 entries, one post-quantum, "verify every entry yourself by
the last chapter"); the preface opens on that page instead of a generic power
claim; ch1 gains a try-it box after the pyramid pointing at entries 13-16 and
18. And ch7's broken promise is honored — it invited "check one leaf" while
never printing the 71-digit Q; the exact Q from P25519.lean is now on the
page, no hidden digits (render-verified against the repo).

MOVE 2 — ch1 cold open. Per the cold reader who hooked at line 13 and wobbled
by line 31: the first worked box (a log10 re-derivation of a punch the prose
already landed) collapses to four lines, the mechanics pushed to Exercise 1.1
— getting the reader ~30 lines sooner to the headroom box, the genuinely novel
bit. The vague "In 2014, researchers…" opener becomes the actual bug: a
two-line diff captioned as the entire defect, anchored to the real Fiat-Crypto
S&P 2019 lineage (no fabricated CVE). Competitor roll-call → footnote.
Syllabus roadmap → a second-person promise ("by Chapter 7 you will have handed
a kernel a certificate…"). "Why Lean" vendor bullets → reader-inheritance
voice ("you start on a million lines of proved mathematics").

Builds here: tectonic, 116 pages, zero errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
mrwulf 2026-08-08 00:14:43 +02:00
parent f0088a317e
commit 60936028a6
4 changed files with 97 additions and 77 deletions

View file

@ -3,12 +3,23 @@
\section{A story about one carry bit} \section{A story about one carry bit}
In 2014, researchers examining widely deployed elliptic-curve code found Here is the entire bug that this book exists because of:
arithmetic bugs of a very particular species: the code was correct on
\emph{almost every} input. Not most inputs --- almost all of them, in a \begin{lstlisting}
precise sense. One famous example, a carry-propagation flaw in an h[4] += carry; // propagate the top limb's overflow
implementation of curve25519 arithmetic, produced a wrong answer with - // (missing: one more conditional subtraction of p)
probability on the order of $2^{-64}$ per random input. + if (h[4] >= LIMB_CAP) h[4] -= LIMB_CAP, h[0] += 19;
\end{lstlisting}
\noindent One missing line. A field-arithmetic routine that forgets a single
final carry is correct on \emph{almost every} input --- not most, almost
\emph{all} of them, in a precise sense --- and silently wrong on the rare
ones where that last carry would have fired. Bugs of exactly this species
were found in deployed elliptic-curve code and became the motivating
disaster behind a whole line of verification research (the Fiat-Cryptography
project, Erbsen et al., IEEE S\&P 2019 --- a direct ancestor of the work this
book teaches). A representative one produced a wrong answer with probability
on the order of $2^{-64}$ per random input.
Pause on that number. If you tested this function a billion times per second, Pause on that number. If you tested this function a billion times per second,
around the clock, you should expect to wait \emph{centuries} before a random around the clock, you should expect to wait \emph{centuries} before a random
@ -24,41 +35,18 @@ than the square of the number of atoms in the observable universe. Testing
samples a raindrop from that ocean. samples a raindrop from that ocean.
\end{pitfall} \end{pitfall}
\begin{worked}{feel what $2^{-64}$ means, with the real numbers} \begin{worked}{feel what $2^{-64}$ means}
Claims about astronomical improbability deserve to be checked by hand, so One hit per $2^{64}$ trials, and $2^{64} \approx 1.8 \times 10^{19}$. At a
check this one. A failure probability of $2^{-64}$ per random input means billion tests a second that is $1.8 \times 10^{10}$ seconds to expect a
you expect one hit per $2^{64}$ trials. First, get $2^{64}$ into scientific single failure --- about \textbf{580 years}. So a test farm hammering this
notation the way you always can: $\log_{10} 2 \approx 0.30103$, so function a \emph{billion} times per second, started when Copernicus
\[ published, would be expected to see the bug for the first time about now.
\log_{10} 2^{64} = 64 \times 0.30103 \approx 19.27 And that is the \emph{optimistic} case: carry bugs cluster in exactly the
\qquad\Longrightarrow\qquad corners uniform sampling underweights, so in practice you wait longer than
2^{64} \approx 1.8 \times 10^{19}. the calendar of the universe. (The one-line $\log_{10}$ derivation behind
\] ``580 years,'' and the far more hopeless arithmetic for the full 510-bit
At $10^9$ tests per second, the expected waiting time is space of input \emph{pairs}, are Exercise~1.1 --- worth doing, because the
\[ number that falls out has more digits than the universe has atoms.)
\frac{1.8 \times 10^{19}}{10^{9}} = 1.8 \times 10^{10} \text{ seconds}.
\]
A year is $\approx 3.15 \times 10^{7}$ seconds (a number worth memorizing:
``$\pi \times 10^7$ seconds per year'' is accidentally almost exact), so
\[
\frac{1.8 \times 10^{10}}{3.15 \times 10^{7}} \approx 580 \text{ years}.
\]
So: a test farm hammering this function a \emph{billion} times per second,
started when Copernicus published, would be expected to see the bug for the
first time about now. And this is the \emph{optimistic} case where failing
inputs are hit by uniform sampling --- for carry bugs they are typically
\emph{correlated}, clustered in corners uniform sampling underweights.
Now the input space itself. A single \lean{FieldElement} is 255 bits; a
pair is 510 bits, and
\[
\log_{10} 2^{510} = 510 \times 0.30103 \approx 153.5
\qquad\Longrightarrow\qquad
2^{510} \approx 10^{153}.
\]
For comparison, the number of atoms in the observable universe is around
$10^{80}$. Testing all pairs is not ``hard''; it is not a thing that
happens in this universe.
\end{worked} \end{worked}
Why does cryptographic code have bugs of exactly this shape? Because of how it Why does cryptographic code have bugs of exactly this shape? Because of how it
@ -102,10 +90,12 @@ headroom count, and the headroom count is where the bodies were buried.
\end{worked} \end{worked}
And in cryptography, ``rare wrong answer'' does not mean ``rare small And in cryptography, ``rare wrong answer'' does not mean ``rare small
glitch.'' Wrong field arithmetic can leak private keys: several published glitch.'' Wrong field arithmetic can leak the private key itself: published
attacks turn a single faulty group operation into full key recovery. The attacks in the ``invalid-curve'' and fault-injection families turn a
stakes are not a corrupted pixel; they are every signature your machine has \emph{single} faulty group operation into full key recovery --- the attacker
ever made. feeds inputs engineered to land in the buggy corner, and reads the secret
off the wrong answers. The stakes are not a corrupted pixel; they are every
signature your machine has ever made, and every one it ever will.
\section{There is another way} \section{There is another way}
@ -122,8 +112,10 @@ Every input, forever, or the proof does not check.
The tool that checks such arguments is called a \emph{proof assistant}. This The tool that checks such arguments is called a \emph{proof assistant}. This
book uses \textbf{Lean~4}, a modern proof assistant that is also a book uses \textbf{Lean~4}, a modern proof assistant that is also a
full-fledged programming language. Others you may have heard of: Rocq full-fledged programming language.\footnote{You may have heard of Rocq
(formerly Coq), Isabelle/HOL, Agda. The ideas transfer; the syntax differs. (formerly Coq), Isabelle/HOL, or Agda. The ideas in this book transfer to
all of them; only the syntax differs. We pick Lean~4 for reasons that will
be concrete by the end of this chapter.}
A proof assistant is built around a small, paranoid core called the A proof assistant is built around a small, paranoid core called the
\emph{kernel}. Everything you will learn in this book --- clever tactics, \emph{kernel}. Everything you will learn in this book --- clever tactics,
@ -171,21 +163,30 @@ one abstraction level and rests on the layer beneath it:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
By the end of this book you will be able to read --- and extend --- the real \begin{tryit}
proofs at every layer of this pyramid. The journey looks like this: Before you read another word, go and touch the thing this book is about. Open
\textbf{\code{ltl.zkdefi.org}} on any device. You are looking at a public,
append-only log of machine-checked proofs --- 19 entries, each one a claim of
the form ``this exact version of this software was verified, resting on
exactly these assumptions.'' Entries 13--16 are the four Ed25519 libraries
whose pyramid you see above. Entry~18 is the first \emph{post-quantum} entry
in the log. You cannot read the proofs yet --- that is what the next twelve
chapters are for --- but you can already see that they are real, public, and
checkable by a stranger with a stock laptop. That stranger is who you are
becoming.
\end{tryit}
\begin{itemize}[leftmargin=1.4em] By the end of this book you will be able to read --- and extend --- the real
\item \textbf{Chapters 2--5} teach Lean itself, from \code{\#eval 1+1} to proofs at every layer of this pyramid. To make that concrete, here is what
proofs by induction and the automation that dispatches arithmetic goals. you will personally be able to \emph{do}, and roughly when: by Chapter~7 you
\item \textbf{Chapters 6--7} build the mathematics: modular arithmetic, finite will have handed a paranoid kernel a certificate that a 77-digit number is
fields, and how to convince a paranoid kernel that a 77-digit number is prime, and watched it agree; by Chapter~9 you will read real Rust translated
prime. into Lean and understand the one idea (the \emph{denotation function}) that
\item \textbf{Chapters 8--9} cross the bridge from Rust to Lean: how real makes the translation trustworthy; by Chapter~12 you will stand on the apex
code is translated into a form we can reason about, and the single most and read the signature-verification theorem for the actual code in your SSH
important idea in the whole enterprise --- the \emph{denotation function}. client. The chapters between here and there earn each of those, in order ---
\item \textbf{Chapters 10--12} assemble the pyramid: field correctness, the Lean itself first, then the mathematics, then the bridge from real code, then
ethics of axioms and honest boundaries, and the layers above. the climb.
\end{itemize}
\begin{bigidea} \begin{bigidea}
\textbf{The ratchet rule of this book.} Every load-bearing idea is worked \textbf{The ratchet rule of this book.} Every load-bearing idea is worked
@ -239,20 +240,24 @@ Learning to smell those is as important as learning to write proofs at all.
\section{Why Lean, and why now} \section{Why Lean, and why now}
Twenty years ago, verifying real cryptographic C or Rust code was a heroic, Twenty years ago, verifying real cryptographic C or Rust code was a heroic,
multi-year effort. Three things changed: multi-year effort. Three things changed --- and each one is an advantage
\emph{you} inherit the moment you start:
\begin{enumerate}[leftmargin=1.6em] \begin{enumerate}[leftmargin=1.6em]
\item \textbf{Proof assistants matured.} Lean~4 is fast, pleasant, and comes \item \textbf{You start on a million lines of proved mathematics.} Lean~4
with \emph{Mathlib}, a library of over a million lines of formalized ships with \emph{Mathlib} --- finite fields, elliptic curves, number theory,
mathematics --- finite fields and elliptic-curve ingredients included, so we already formalized and checked. You do not build the tower from bare axioms;
do not start from bare axioms. you walk onto a finished floor and add one room.
\item \textbf{Translation pipelines appeared.} Tools like \emph{Charon} and \item \textbf{You verify the code that ships, not a story about it.} Tools
\emph{Aeneas} mechanically translate real Rust code into Lean definitions, called \emph{Charon} and \emph{Aeneas} mechanically translate real Rust into
so the thing we verify is derived from the code that ships, not a Lean, so what you reason about is \emph{derived} from the deployed source
hand-transcribed approximation (Chapter~\ref{ch:rust}). rather than hand-copied by someone who might have copied it wrong
\item \textbf{Automation got serious.} Decision procedures like \lean{omega} (Chapter~\ref{ch:rust}). This is the difference between verifying software
(linear integer arithmetic) and \lean{decide} discharge the boring 90\% of and verifying an essay about software.
goals, leaving humans the interesting 10\%. \item \textbf{The machine does the boring 90\%.} Decision procedures like
\lean{omega} and \lean{decide} dispatch the routine arithmetic goals on
their own, so your attention goes to the 10\% that is actually interesting
--- the part where the real idea lives.
\end{enumerate} \end{enumerate}
None of this made verification \emph{easy}. It made verification None of this made verification \emph{easy}. It made verification

View file

@ -52,8 +52,13 @@ Concretely for our hero: $p - 1 = 2^{255} - 20$ factors as
\[ \[
p - 1 \;=\; 2^{2} \cdot 3 \cdot 65147 \cdot Q, p - 1 \;=\; 2^{2} \cdot 3 \cdot 65147 \cdot Q,
\] \]
where $Q$ is a 71-digit prime with its own (short) certificate, and where $Q$ is the 71-digit prime
$65147$ recurses one more level: $65146 = 2 \cdot 32573$ with $32573$ \[
Q = 740582127325613583022312264370627886761\allowbreak 66966415465897661863160754340907,
\]
printed here in full --- no hidden digits, this is the exact value in the
repository's \code{P25519.lean} --- carrying its own (short) certificate,
and $65147$ recurses one more level: $65146 = 2 \cdot 32573$ with $32573$
prime. The full certificate for $p$ is a small tree of witnesses and prime. The full certificate for $p$ is a small tree of witnesses and
factorizations --- a few hundred bytes of data standing behind a 77-digit factorizations --- a few hundred bytes of data standing behind a 77-digit
claim: claim:

BIN
main.pdf

Binary file not shown.

View file

@ -28,8 +28,11 @@ no prior formal-verification or Lean experience assumed.\par}
\vspace{0.8cm} \vspace{0.8cm}
{\color{ink2}\rule{\linewidth}{0.6pt}} {\color{ink2}\rule{\linewidth}{0.6pt}}
\vspace{0.3cm} \vspace{0.3cm}
{\small\color{paper} Companion to the \code{*-ed25519-verified} and \code{pasta-pallas-verified} {\small\color{paper} Companion to a public transparency log of machine-checked
proof projects. \\ Every code snippet in this book runs. Every claim it makes about a proof, a proof assistant has checked.\par} proofs --- \textbf{\code{ltl.zkdefi.org}}, 19 entries and counting, one of them
post-quantum. Open it on your phone now; by the last chapter you will be able
to verify every entry yourself. \\ Every code snippet in this book runs. Every
claim it makes about a proof, a proof assistant has checked.\par}
\end{titlepage} \end{titlepage}
\restoregeometry \restoregeometry
\pagecolor{paper}\color{ink} \pagecolor{paper}\color{ink}
@ -39,6 +42,13 @@ proof projects. \\ Every code snippet in this book runs. Every claim it makes ab
\markboth{How to read this book}{} \markboth{How to read this book}{}
\addcontentsline{toc}{chapter}{How to read this book} \addcontentsline{toc}{chapter}{How to read this book}
There is a public web page --- \code{ltl.zkdefi.org} --- that lists nineteen
pieces of software, each stamped with a machine-checked proof that it does what
it claims. One of those stamps was earned two days before the writer of that
proof could make anyone else believe it; another survived quantum-resistant
cryptography. This book is the road from not understanding a single word on that
page to being able to verify every entry on it yourself, and to add your own.
You are about to learn one of the most powerful ideas in computer science: how You are about to learn one of the most powerful ideas in computer science: how
to make a computer \emph{prove} that a program is correct --- not test it on a to make a computer \emph{prove} that a program is correct --- not test it on a
few inputs and hope, but establish, with the certainty of mathematics, that it few inputs and hope, but establish, with the certainty of mathematics, that it