\chapter{Verifying a Field: The Full Campaign} \label{ch:field} Partway through the campaign this chapter narrates, one proof step consumed twelve gigabytes of memory and took the machine down --- not a slow test, not a warning in a log: the computer proving these theorems crashed, mid-proof, because of how a proof was written. This chapter climbs toward that wall, hits it, quantifies exactly why it stands where it stands, and comes out the other side with the discipline the rest of the book runs on. The crash is the most instructive thing in the chapter. Keep it in view. \section{The summit statement} Every thread so far --- specs as types, tactics, automation, $\Fp$, primality, extraction, denotation --- was preparation for one theorem. In the companion repositories it is called the \emph{field implementation certificate}, and (lightly paraphrased) it says: \begin{lstlisting}[language=Lean] theorem fieldImplementation : -- p is prime, so ZMod p is genuinely a field Nat.Prime p -- and for all bounded limb arrays, every operation's -- commuting square closes: ∧ (∀ a b, Bnd a → Bnd b → AddSquare a b) ∧ (∀ a b, Bnd a → Bnd b → SubSquare a b) ∧ (∀ a b, Bnd a → Bnd b → MulSquare a b) ∧ (∀ a, Bnd a → SquareSquare a) ∧ (∀ a, Bnd a → InvertSquare a) -- Fermat chain: a^(p-2) ∧ ... -- reduce, negate, encode \end{lstlisting} (Vocabulary re-armed, from Chapter~\ref{ch:denotation}: \lean{Bnd a} says $a$'s limbs sit inside their envelopes; each \lean{...Square} says one operation's commuting square closes --- run the extracted code, denote the result, and you get the same field element as doing the mathematics.) One theorem, kernel-checked, quantified over \emph{every} input the representation admits: the extracted dalek field arithmetic implements $\Fp$. This chapter is the story of the campaign that proves it --- told honestly, including the two places where the terrain fought back, because the failures teach more than the victories. \section{Order of battle} You do not prove such a conjunction by heroism; you prove it by sequencing. The campaign order in the real projects, and the reason for each position: \begin{enumerate}[leftmargin=1.6em] \item \textbf{Bounds lemmas first} --- pure \lean{omega} facts about limb sizes, no denotation at all. Cheap, and everything depends on them. \item \textbf{Primality} (Chapter~\ref{ch:prime}) --- independent of the code entirely; it dignifies \lean{ZMod p} into a field. \item \textbf{add, sub, negate} --- linear operations; the commuting squares close with \lean{omega} plus the denotation unfolds. Confidence builders. \item \textbf{reduce} --- the $\times 19$ fold in isolation. Proving it alone, before mul uses it, halves the hardest proof's size. \item \textbf{mul, square} --- the boss fight of Chapter~\ref{ch:denotation}: column sums, carries, folds. Squaring is mul with algebraic shortcuts --- a separate code path in dalek, hence a separate theorem. No shortcuts in the proof: the \emph{code's} shortcut is precisely what needs checking. \item \textbf{invert} --- the 254-squaring Fermat chain, verified as a \lean{calc} of exponent bookkeeping on top of \code{mul}/\code{square} specs, ending at $a^{p-2}$; Fermat's little theorem (Mathlib's) closes the square. \end{enumerate} Notice the shape: \emph{each layer consumes only the specs of the layer below}, never reaching into implementations. By step 6 you are doing exponent arithmetic, blissfully ignorant of carries. That is the compositionality that Chapter~\ref{ch:denotation}'s two-clause specs (bounds + value) were designed to buy. \begin{worked}{why $16p$ --- auditing a design constant to the bit} Step 3's subtraction hides the field layer's most quotable design decision, and you can audit it completely. The problem: compute $a - b$ limb-wise in unsigned words, where limbs of $b$ may be as large as $2^{54} - 1$ (the invariant's edge) while limbs of $a$ may be as small as $0$. Unsigned subtraction would truncate (Chapter~\ref{ch:lean}); the fix is to compute $a + (kp - b)$ for a suitable multiple $k$ of the prime --- denotationally free, since $kp \equiv 0$ --- chosen so that every limb of $kp - b$ stays positive. How large must $k$ be? The limb constants of $kp$ scale the telescoped representation from Chapter~\ref{ch:denotation}: \[ kP = \big(k(2^{51}-19),\; k(2^{51}-1),\; k(2^{51}-1),\; k(2^{51}-1),\; k(2^{51}-1)\big), \] whose \emph{smallest} limb is $k(2^{51} - 19)$. Positivity of every limb of $kp - b$ demands \[ k\,(2^{51} - 19) \;\ge\; 2^{54} - 1 . \] Try the candidates, because powers of two are what the code wants: \[ k = 8:\quad 8(2^{51}-19) = 2^{54} - 152 \;<\; 2^{54} - 1 \qquad\text{✗ fails, by 151;} \] \[ k = 16:\quad 16(2^{51}-19) = 2^{55} - 304 \;\ge\; 2^{54} - 1 \qquad\text{✓ with } 2^{54} - 303 \text{ to spare.} \] So $16$ is the \emph{least} power of two that works --- $8$ misses by a margin of $151$, invisible to any test that doesn't drive a limb of $b$ within $151$ of the very top of its envelope. Two more checks complete the audit: the result's limbs are bounded by $2^{54} + 2^{55} < 2^{56} < 2^{64}$ (no overflow on the additive side ✓), and the denotation shifts by exactly $16p \equiv 0$ ✓. In the shipped proof this box is one lemma with three \lean{omega} obligations; in the git history of more than one real crypto library, the analogous constant is a patched CVE. Now you know how to tell which side of that line a codebase is on. \end{worked} \begin{tryit} Do not take the box's word for the margin of $151$ --- falsify the rejected design yourself: \begin{lstlisting}[language=Lean] #eval (8 * (2^51 - 19) : Int) - (2^54 - 1) -- -151 #eval (16 * (2^51 - 19) : Int) - (2^54 - 1) -- 18014398509481681 \end{lstlisting} The first line is the deficit a $k=8$ subtraction suffers when a limb of $b$ sits within $151$ of its envelope's top: in unsigned words that negative number is a silent wrap-around --- and a random test hits the triggering region with probability about $151/2^{54}$, which is to say never. The second line is the shipped design's headroom. Two \lean{\#eval}s, one CVE-class distinction. \end{tryit} \begin{worked}{verifying the inversion chain's bookkeeping --- all 265 steps} Step 6 sounds heroic --- verify a hand-crafted chain of $254$ squarings and $11$ multiplications computes $a^{p-2}$ --- until you see that the whole verification is \emph{exponent arithmetic}, and the exponents obey one identity you can check at every scale. The chain builds values $a^{e}$ for a cascade of exponents $e$; squaring doubles $e$, multiplying adds them. The dalek chain's opening moves: \[ \begin{array}{lcl} z_2 = a^2 & & e = 2\\ z_9 = (z_2)^{2^2} \cdot a & & e = 2\cdot 4 + 1 = 9\\ z_{11} = z_9 \cdot z_2 & & e = 9 + 2 = 11\\ z_{2^5-1} = (z_{11})^{2} \cdot z_9 & & e = 22 + 9 = 31 = 2^5 - 1 . \end{array} \] From $31 = 2^5 - 1$ the chain climbs by a doubling ladder whose single identity you should verify once symbolically: \[ (2^k - 1)\cdot 2^k + (2^k - 1) \;=\; 2^{2k} - 1 \qquad\text{(``shift a block of $k$ ones up by $k$ and fill'').} \] Check it at $k=5$: $31 \cdot 32 + 31 = 992 + 31 = 1023 = 2^{10}-1$ ✓. The ladder then assembles mixed blocks the same way: $2^{10}-1 \to 2^{20}-1 \to 2^{40}-1$, then $(2^{40}-1)2^{10} + (2^{10}-1) = 2^{50}-1$, then $2^{100}-1 \to 2^{200}-1$, then $(2^{200}-1)2^{50} + (2^{50}-1) = 2^{250}-1$. Final move: shift five and add the stashed $z_{11}$: \[ (2^{250}-1)\cdot 2^{5} + 11 \;=\; 2^{255} - 32 + 11 \;=\; 2^{255} - 21 \;=\; p - 2 . \qquad ✓ \] Every line above is hand-checkable, and together they \emph{are} the correctness of the inversion chain --- modulo only ``squaring squares and multiplication adds exponents,'' which is the already-proven \code{mul} and \code{square} specs feeding Fermat (Chapter~\ref{ch:modular}). Count the cost while you are here. Squarings, stage by stage: $1$ (to $z_2$) $+\,2$ (to $z_9$) $+\,1$ (to $z_{31}$) $+\,5+10+20$ (to $2^{10},2^{20},2^{40}$) $+\,10$ (to $2^{50}$) $+\,50+100$ (to $2^{100},2^{200}$) $+\,50$ (to $2^{250}$) $+\,5$ (final shift) $= 254$. Multiplications: one per block-join --- count the ``$\cdot$''s above --- exactly $11$. The advertised $254 + 11$ is not folklore; you just audited it. That is the point of this box: ``verify 265 field operations'' collapsed into ten lines of exponent algebra a patient undergraduate audits over coffee. \end{worked} \section{Dispatches from the terrain} \textbf{The wall that was really there.} This is the crash from the chapter's first sentence, and here is exactly how it was earned: a \code{mul}-scale goal, handed to a general decision procedure in one monolithic call --- the natural move, the move you would make --- generates an internal certificate with coefficients on the order of $2^{256}$, and checking it can exhaust the proof checker's memory. During the development of the Pasta field proofs that one call ate twelve gigabytes and took the machine down (Chapter~\ref{ch:automation} told you this story from the tactic side). The cure was never cleverness --- it was \emph{decomposition}: isolate each carry step as its own small lemma with a tiny context, prove the value identity with \lean{linear_combination} (a tactic that checks a \emph{stated} linear certificate rather than searching for one), and let the big theorem be an assembly of small checked parts. The same discipline, plus hard memory caps on the checker process, became house infrastructure. \begin{worked}{the wall, quantified --- why the monolithic proof dies} The memory catastrophe is not mystical; you can estimate it on one page, and the estimate teaches the cure. When a decision procedure like \lean{omega} proves a linear goal, it does not just say ``true'' --- it emits a \emph{certificate}: a linear combination of the hypotheses with explicit integer coefficients that the kernel then re-checks (Chapter~\ref{ch:prime}'s find/check split, again). Now count what a \emph{monolithic} field-multiplication goal hands it. The goal relates quantities at wildly different scales: raw limbs ($\sim 2^{51}$), column sums ($\sim 2^{111}$), folded values ($\sim 2^{116}$), and the final positional stack, whose top weight is $2^{204}$ --- so eliminating variables across the whole system produces certificate coefficients up to the \emph{products} of these scales: numbers of order $2^{256}$ to $2^{512}$, i.e.\ integers of $80$--$150$ decimal digits. Per coefficient that is only tens of bytes --- but the elimination is quadratic-ish in the hypothesis count: with $\sim 60$ hypotheses (five limbs each for two inputs, nine columns, nine carries, plus bounds for everything), the certificate and the kernel's intermediate terms multiply into \emph{millions} of big-number nodes, each participating in further products. Twelve gigabytes is not even surprising once you draw the multiplication table of scales --- and this estimate, run \emph{before} the tactic, is how the wall gets predicted rather than hit. The cure now reads directly off the arithmetic: cut the elimination range. Prove each carry step as its \emph{own} lemma with only its own few hypotheses in scope (coefficients stay near the step's own scale); where a large linear identity is genuinely needed, state it yourself and let \lean{linear_combination} \emph{check} your stated certificate instead of searching for one (checking is cheap; finding at scale was the memory bomb). The companion repos' rule --- no blanket automation in fat contexts --- is this box, written as policy. And note the shape of the lesson: it is the \emph{same} headroom discipline as the code's (bound your intermediates, spend your budget consciously), applied one level up, to the proof itself. \end{worked} \begin{aha} There is a deep symmetry in that fix worth savoring: the \emph{proof} was restructured exactly the way the \emph{code} was --- into small steps with controlled intermediate size. Delayed carries in the implementation; small lemmas in the verification. Bounded limbs; bounded contexts. Good proofs and good fast code turn out to obey the same engineering aesthetics. This is not a coincidence; both are fighting combinatorial growth with structure. \end{aha} \textbf{Four forks, one method, real divergence.} The companion projects verify not just upstream \code{curve25519-dalek} but three production forks (Solana's, RISC~Zero's, Betrusted's) --- each against \emph{its own} extraction. Worth it? The audit found the forks implement the same constant-time conditional selection three different ways (a \code{subtle} crate trait, a volatile-read \code{black_box}, a hand-rolled arithmetic mask), and one fork reorders instructions in point doubling. All correct --- \emph{provably}, now --- but the divergence is exactly the kind of thing that silently breaks when someone ``harmonizes'' code during a rebase. Per-fork verification is not pedantry; it is how you notice that ``the same library'' isn't. \begin{pitfall} A verified fork is verified \emph{at a commit}. Change one line of arithmetic and the certificate is stale --- that is a feature (the proof \emph{should} break when the code changes), but it means verification is a \emph{process wired into maintenance}, not a trophy. The companion repos ship \code{check.sh} scripts that recompile and re-audit every shipped proof from scratch (extraction replay is a separate pinned recipe, \code{verification/extract.sh}); treat those as the project's pulse, not as CI decoration. \end{pitfall} \section{Reading a certificate like a professional} Suppose a stranger hands you a repository claiming ``formally verified field arithmetic.'' Chapter~\ref{ch:honesty} gives you the full audit protocol, but the field-layer questions you can already ask are these: \begin{itemize}[leftmargin=1.4em] \item \textbf{What is denoted?} Find the denotation function. Does it map the \emph{extracted} representation (good) or a hand-written lookalike (Chapter~\ref{ch:rust}'s hole)? \item \textbf{Is the square complete?} Value equation \emph{and} bounds propagation \emph{and} the \lean{.ok} clause --- a spec that assumes success proves nothing about overflow. \item \textbf{Is the quantifier honest?} \lean{∀ a b} with bounds hypotheses, or a handful of \lean{example}s on constants dressed up as coverage? \item \textbf{Does anything say \lean{sorry}?} One \lean{sorry} anywhere in the dependency chain and the certificate is decorative. The checker will tell you; ask it. \end{itemize} \begin{tryit} Do the audit for real: open \code{dalek-ed25519-verified}, find the denotation, pick the \code{sub} spec, and check the three clauses against the list above. Then run the repo's \code{check.sh} and watch the whole pyramid rebuild. Total time: one coffee. Skill acquired: permanent. \end{tryit} \section*{Exercises} \exercise{Field subtraction in dalek computes $a - b$ as $a + (16p - b)$ limb-wise (adding a multiple of $p$ keeps limbs positive --- recall \lean{Nat} truncation!). State the commuting square for \code{sub} including the exact multiple-of-$p$ fact you would need as a lemma, and explain why $16p$ rather than $p$.} \exercise{The Fermat inversion chain computes $a^{p-2}$ via 254 squarings and 11 multiplications. Verify the exponent bookkeeping for the first three steps of dalek's actual chain: $a^2$, $a^{9} = (a^2)^{2\cdot 2} \cdot a$, $a^{11} = a^9 \cdot a^2$. (The full chain is exercise-by-induction: each step's exponent is a sum of previous ones --- addition-chain arithmetic.)} \exercise{(Discussion) Step 5 refuses to trust the squaring shortcut and verifies \code{square} separately from \code{mul}. A colleague argues ``square is just \code{mul a a}, reuse the theorem.'' What, concretely, would that argument miss about the code under verification?} \section*{Solutions and pathways} \solutionsintro \solhead{10.1} \pathway Assemble from parts you own: the two-clause spec shape (Chapter~\ref{ch:denotation}), the multiple-of-$p$ freedom (the telescope worked example), and the positivity audit (this chapter's $16p$ worked example). The exercise is really asking you to \emph{compose} them into one statement. \answer The commuting square for \code{sub}, with the lemma named: \[ \mathrm{Bnd54}(a) \to \mathrm{Bnd54}(b) \to \exists c,\; \code{sub}\,a\,b = \mathtt{.ok}\ c \;\wedge\; \mathrm{Bnd56}(c) \;\wedge\; \denote{c} = \denote{a} - \denote{b}, \] resting on the lemma $\denote{16P} = 16p \equiv 0 \pmod p$ (the telescope, scaled by $16$), which justifies $\denote{a + (16P - b)} = \denote{a} + 0 - \denote{b}$. Why $16$ and not $p$ itself (i.e.\ $k = 1$): positivity of every limb of $kP - b$ requires the \emph{smallest} limb constant, $k(2^{51}-19)$, to dominate the \emph{largest} allowed limb of $b$, $2^{54}-1$; $k = 1$ gives $2^{51}-19 \ll 2^{54}$ --- hopeless --- and even $k = 8$ falls $151$ short, as the worked example computed. First power of two that clears the bar: $16$. \solhead{10.2} \pathway Squaring doubles the exponent; multiplying adds. Track only exponents and check each claimed identity by substitution --- the field elements are irrelevant to the bookkeeping, which is the insight that makes the whole verification tractable. \answer $a^2$: exponent $2$ ✓ (one squaring). $a^9 = (a^2)^{2\cdot 2} \cdot a$: squaring $z_2$ twice gives exponent $2 \cdot 2 \cdot 2 = 8$; multiplying by $a$ adds $1$: exponent $9$ ✓ (two squarings, one multiplication). $a^{11} = a^9 \cdot a^2$: $9 + 2 = 11$ ✓ (one multiplication). The induction that carries the rest: each ladder stage claims $(2^j - 1)\cdot 2^k + (2^k - 1) = 2^{j+k} - 1$ for the block sizes $(j,k)$ it uses --- verify it once in general: $(2^j - 1)2^k + 2^k - 1 = 2^{j+k} - 2^k + 2^k - 1 = 2^{j+k} - 1$ ✓ --- and every remaining line of the chain is an instance. Addition-chain verification in full: substitute, cancel, done. \solhead{10.3} \pathway Ask what \emph{differs between the two code paths}, not between the two mathematical functions. The math of \code{square a} and \code{mul a a} agree; the \emph{instructions} do not. \answer Three concrete misses. (1) \code{square} is a \emph{different routine}: it exploits symmetry ($a_i a_j$ appears twice for $i \neq j$, so it computes $2 a_i a_j$ once), which changes the column expressions, the constant factors, and therefore the \emph{bounds} --- the doubled terms eat one extra headroom bit that \code{mul}'s proof never had to account for. (2) A bug in that symmetry trick --- the classic one is a missing factor of $2$ on exactly one cross term --- lives \emph{only} in \code{square}'s code path; a theorem about \code{mul} quantifies over \code{mul}'s instructions and says nothing about it. (3) Even the \lean{.ok} clause differs: overflow behavior depends on the actual intermediate expressions, not on the mathematical value. The one-line summary for design reviews: \emph{we verify code paths, not functions --- if the optimizer wrote a second path, the verifier owes a second theorem}. (This is also exactly why the four forks each got their own proofs: same math, four instruction streams.) One last thing, so the summit does not feel abstract: the certificate this chapter taught you to state is not a textbook artifact. It lives in four public repositories --- one per fork --- where \code{check.sh} rebuilds it from scratch on demand, and each of those repositories is attested as a leaf of the live transparency log at \code{ltl.zkdefi.org}. When you audit one with the four questions above, you are not doing an exercise; you are doing the thing. \begin{checkpoint} You should now be able to: state the field implementation certificate and every quantifier in it; recite the campaign order and justify why bounds and \code{reduce} come early; tell the memory-wall story and its decomposition moral; and audit a stranger's field-layer claim with four pointed questions. \end{checkpoint}