verifying-crypto-with-lean/chapters/ch07-primality-certificates.tex
saymrwulf 45048d4898 Verifying Cryptography with Lean 4: complete 12-chapter curriculum
- 53-page LaTeX/TikZ book (main.pdf + full sources): from zero background
  to reading the real Ed25519/Pasta verification projects
- runnable exercises with sorry-holes + complete solutions for chapters
  2-7, 9, 12; every solution file compiles clean (zero errors, no sorry)
  against Lean v4.30.0-rc2 + Mathlib 5450b53e
- lake project pinned to the same toolchain/Mathlib the solutions were
  verified with; students fetch the Mathlib cache, never build it
- honesty ledger in README: what was machine-checked and how

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 09:44:40 +02:00

174 lines
8.4 KiB
TeX

\chapter{Convincing a Paranoid Kernel That a 77-Digit Number Is Prime}
\label{ch:prime}
\section{The problem nobody warns you about}
Chapter~\ref{ch:modular} ended with a quiet dependency: everything ---
division, field structure, the whole elliptic curve --- rests on
$p = 2^{255}-19$ \emph{being prime}. In Lean, that is a proposition like any
other, and it must be \emph{proved}:
\begin{lstlisting}[language=Lean]
theorem p_prime : Nat.Prime (2^255 - 19) := ?
\end{lstlisting}
Your Chapter~\ref{ch:automation} instincts say \lean{decide}: primality is
decidable --- just try dividing. But trial division tests divisors up to
$\sqrt{p} \approx 2^{127}$. At a billion billion divisions per second, that
is about $10^{12}$ ages of the universe. The kernel, which happily
\emph{re-executes} every computation you feed it, cannot afford this one. And
mathematicians clearly believe this number is prime --- so how does
\emph{anyone} know?
\section{Certificates: the deep idea hiding here}
The answer reorganizes how you think about computation. \emph{Finding} a
fact and \emph{checking} a fact can have wildly different costs. What we need
is a \textbf{certificate}: a piece of data, possibly expensive to discover,
that makes the fact \emph{cheap to verify}.
You have met certificates before without the name. A composite number's
certificate is a factor: finding a factor of a 77-digit number may be hard,
but checking $n = a \cdot b$ is one multiplication. The beautiful surprise
--- Pratt's theorem, 1975 --- is that \emph{primality} has certificates too:
\begin{bigidea}
\textbf{Pratt certificate.} To certify that $p$ is prime, exhibit a
\emph{witness} $w$ such that
\[
w^{p-1} \equiv 1 \pmod p
\qquad\text{and}\qquad
w^{(p-1)/q} \not\equiv 1 \pmod p
\ \text{ for every prime factor } q \text{ of } p-1 .
\]
Such a $w$ generates all $p-1$ nonzero residues, which forces $\Zmod{p}$ to
have $p-1$ invertible elements --- something only a prime modulus allows.
Checking the certificate costs a handful of modular exponentiations
(milliseconds, by fast squaring), \emph{plus recursively certifying the
prime factors $q$} --- each much smaller, so the recursion collapses fast.
\end{bigidea}
Concretely for our hero: $p - 1 = 2^{255} - 20 = 2^2 \cdot 5 \cdot q_1 \cdot
q_2$ where $q_1$ (44 digits) and $q_2$ (33 digits) are themselves prime, with
their own small certificates. The full certificate for $p$ is a small tree of
witnesses and factorizations --- a few hundred bytes of data standing behind
a 77-digit claim:
\begin{center}
\begin{tikzpicture}[
lvl/.style={draw=ink2,thick,rounded corners=2pt,fill=white,align=center,font=\small},
edge/.style={-{Stealth},ink2,thick}
]
\node[lvl,fill=accentsoft] (p) at (0,2.6)
{$p = 2^{255}-19$ \quad witness $w=2$\\ $p-1 = 2^2\cdot 5\cdot q_1\cdot q_2$};
\node[lvl] (two) at (-4.4,0.6) {$2$: prime\\ \footnotesize (immediate)};
\node[lvl] (five) at (-1.9,0.6) {$5$: prime\\ \footnotesize (immediate)};
\node[lvl,fill=provensoft] (q1) at (0.9,0.6) {$q_1$ (44 digits)\\ own witness + factors};
\node[lvl,fill=provensoft] (q2) at (4.3,0.6) {$q_2$ (33 digits)\\ own witness + factors};
\draw[edge] (p) -- (two); \draw[edge] (p) -- (five);
\draw[edge] (p) -- (q1); \draw[edge] (p) -- (q2);
\node[font=\small\color{ink2},align=center] at (0,-0.6)
{each node: milliseconds to check; the whole tree: a proof};
\end{tikzpicture}
\end{center}
\begin{aha}
This find/check asymmetry is one of the great ideas of computer science ---
it is the P versus NP distinction wearing work clothes, and it is the engine
of zero-knowledge proof systems (the very technology the Pasta curves serve).
Proof assistants run on it too: Lean's whole architecture --- clever tactics
\emph{finding}, dumb kernel \emph{checking} --- is the same asymmetry. A
proof \emph{is} a certificate.
\end{aha}
\section{The tempting shortcut, and why the house declines it}
Lean offers a faster \lean{decide}: the variant \lean{native_decide}
compiles the decision procedure to native machine code, runs it at full
speed, and asserts the result. With a good primality test behind it, it can
dispatch \lean{Nat.Prime p} in seconds. Case closed?
Look at what you would be trusting. Ordinary \lean{decide} produces a
computation the \emph{kernel} replays --- the ~few-thousand-line paranoid
core remains the only thing you trust. \lean{native_decide} instead makes
the theorem's truth depend on the Lean \emph{compiler}, the C toolchain
behind it, and the runtime --- hundreds of thousands of lines promoted into
your trusted base, in exchange for convenience on one theorem. Every proof
downstream of the field --- group law, scalars, signatures --- would inherit
that enlarged trust, visible forever in its axiom report
(Chapter~\ref{ch:honesty} shows you how to read those).
\begin{pitfall}
\lean{native_decide} is not ``cheating,'' and for exploratory work it is a
fine tool. The trap is \emph{silent trust inflation}: its use is invisible at
the theorem statement --- the cost appears only when someone audits the
axioms, which is exactly what most readers never do. House rule, adopted from
the projects this book accompanies: exploratory scaffolding may use it;
\textbf{no shipped certificate depends on it}. The final Pallas-modulus
primality proof in \code{pasta-pallas-verified} is a kernel-checked
Lucas/Pratt certificate for precisely this reason.
\end{pitfall}
\section{Certificates in practice: Mathlib's toolbox}
You will not hand-roll witness trees. Mathlib provides the machinery
(\lean{Nat.Prime} decision lemmas, \lean{lucas_lehmer}-style infrastructure,
and the \lean{norm_num} extension \lean{Nat.Prime} plugin) that constructs
and checks Pratt-style certificates behind a single tactic call --- while
keeping every step kernel-checked. The shape in real code:
\begin{lstlisting}[language=Lean]
theorem p_prime : Nat.Prime (2^255 - 19) := by
norm_num -- certificate-backed primality, kernel-checked, ~seconds
\end{lstlisting}
When the built-in route struggles (very large or awkward moduli), the
fallback is explicit: state the witness data as definitions, prove the two
Pratt conditions with \lean{norm_num}-driven modular exponentiation, and
assemble. That is exactly the structure of the Pallas certificate in the
companion repository --- worth reading now with fresh eyes:
\code{pasta-pallas-verified/verification/Proofs/Primality.lean}.
\begin{tryit}
Open \code{exercises/Ch07.lean}. Ladder: certify $97$, then $65537$ (a
Fermat prime beloved of RSA), then the ten-digit Mersenne prime $2^{31}-1$,
watching what each tool costs as the numbers grow. (Amusingly, the
find/check asymmetry bites the \emph{tactic} too: \lean{norm_num} must
\emph{find} the witness tree before the kernel checks it, and at $2^{61}-1$
the finding already takes minutes.) Finale: implement square-and-multiply
modular exponentiation yourself and check the top witness condition for
$p = 2^{255}-19$ with \lean{\#eval} --- your own hands on the certificate,
at 77 digits, in milliseconds.
\end{tryit}
\section*{Exercises}
\exercise{Verify by hand that $w = 2$ is a Pratt witness for $p = 13$:
compute $2^{12} \bmod 13$ and $2^{12/q} \bmod 13$ for each prime $q \mid 12$.
Write the full certificate tree for $13$, recursing into the factors of
$12$.}
\exercise{Why does the witness condition force primality? Sketch the
argument: if $w$ has order exactly $p-1$ in $\Zmod{p}$, then the
multiplicative structure has $p-1$ elements, which fails if $p = ab$ with
$1 < a,b < p$. (Full rigor optional; the shape is the point.)}
\exercise{Estimate, in modular multiplications, the cost of checking the
certificate for $2^{255}-19$: count squarings for one exponentiation at 255
bits, times the number of conditions in the tree above. Compare with the
$2^{127}$ divisions of trial division. Write both numbers down next to each
other. Smile.}
\exercise{(Discussion) Bitcoin miners \emph{find} block hashes; nodes
\emph{check} them. GPS receivers \emph{check} satellite signals they could
never \emph{find}. Name two more systems built on the find/check asymmetry,
and one system that would collapse without it.}
\begin{checkpoint}
You should now be able to: explain why \lean{decide} cannot prove
$2^{255}-19$ prime while a certificate can; reproduce the two Pratt witness
conditions and check them on a small prime; articulate exactly what
additional trust \lean{native_decide} would introduce and why shipped
certificates decline it; and recognize the find/check asymmetry as the
common engine of certificates, proof assistants, and the P-vs-NP question.
\end{checkpoint}