mirror of
https://github.com/saymrwulf/verifying-crypto-with-lean.git
synced 2026-09-03 19:53:45 +00:00
book overhaul move 6: the Second Summit chapter + the book ends once
New Chapter 13, 'The Second Summit: A Hash-Based Pyramid' — SLH-DSA
(FIPS 205) as the transfer experiment for the whole method:
- opens on leaf 18 as the anomaly; correctness-vs-security across the
quantum divide ('a correct implementation of a broken lock is still a
broken lock')
- Lamport -> Winternitz chains with the checksum see-saw run twice on
real w=16 numbers, including a concrete failed forgery (480 -> 479,
digit 14 -> 13)
- FORS worked at napkin scale (k=2, a=2, one reuse = one forgery) and
real scale (28 of 57,344, exponent 14)
- the virtual hypertree: digest split 21/7/2 to the bit, the 54-bit
meter peeled 9 bits per layer, verification priced exactly (254 fixed
oracle calls; the see-saw itself caps a layer at 510, so worst case
3,824 — the naive 525*35 bound is unreachable, and the chapter says
why); ~2^72 to build vs ~2^12 to check
- the eleven certificates, the loop-to-fold bridges, the honest
'visible, not correct' boundary (no second semantics — and why the
natural move fails), the cone-growth table, the t_l/t_len naming
inversion told as the war story it was, the apex as an audit
invitation with the verbatim theorem named
- 'The leaf, live': leaf-vs-head precision ('plausible, and wrong
twice'), the three-clause self-reference ledger (attested machinery /
attested scheme / honest gap), one-command tryit
- six exercises with pathway'd solutions; checkpoint hands the
who-checks-them question to the finale
Structural: attestation renamed ch14 and now carries the book's single
ending (where-to-go, further reading, final reframe, prospective
checkpoint — moved from ch12); its two interior checkpoints demoted to
bigidea/tryit so the terminal checkpoint stands alone; opening now
receives ch13's baton. ch12 ends as a chapter. Front matter: three-summit
arc, fourteen-week plan, honest discussion-exercise count; ch01 promise
ladder extended to Chapters 13/14; glossary +5 entries (and the
pre-existing Hasse-bound misordering fixed); README fourteen chapters +
build.sh recipe.
Every constant verified against fips205-slhdsa-verified and
lean-transparency-log by four adversarial checkers; arithmetic
independently recomputed; didactic panel scored the chapter 9/8 —
the book's high-water mark. Build: 128 pages, zero unresolved refs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
adbcdd6bde
commit
63a809dd2c
9 changed files with 809 additions and 120 deletions
34
README.md
34
README.md
|
|
@ -22,13 +22,10 @@ Lean 4 against models extracted from the actual Rust sources:
|
|||
|
||||
## The book
|
||||
|
||||
**[`main.pdf`](main.pdf)** — thirteen chapters + interlude + three
|
||||
**[`main.pdf`](main.pdf)** — fourteen chapters + interlude + three
|
||||
appendices, full color, built with LaTeX/TikZ from the sources in this
|
||||
repo. **Honesty note:** the committed PDF (109 pages) was built 2026-07-06,
|
||||
before chapter 13 was committed (2026-07-28) — rebuild with the command
|
||||
below to get the current book; the committed PDF lags the committed
|
||||
sources until the next rebuild on a LaTeX-equipped machine. No prior Lean or formal methods assumed; high-school algebra
|
||||
and a little programming suffice.
|
||||
repo (`./build.sh`, tectonic, no root needed). No prior Lean or formal
|
||||
methods assumed; high-school algebra and a little programming suffice.
|
||||
|
||||
1. **Why Verify?** — the carry bug testing cannot find
|
||||
2. **Meet Lean** — programs, types, inductive data
|
||||
|
|
@ -43,11 +40,12 @@ and a little programming suffice.
|
|||
10. **Verifying a Field** — the full campaign, told honestly (including the crash)
|
||||
11. **Honesty and Axioms** — `#print axioms`, hollow certificates, trusted bases
|
||||
12. **The Pyramid** — group law, scalars, signatures, and where you come in
|
||||
13. **The Attestation Protocol** — what it takes to make "it is proven" checkable by a stranger; closes with *Go and touch the real thing*: a guided reading of the estate's **live transparency log** (ltl.zkdefi.org — 19 leaves, the four ed25519 pyramids at 44 certificates, the log's own Merkle proofs as leaf 17, and the first post-quantum leaf, SLH-DSA, as leaf 18), including the fifteen-minute verify-it-yourself exercise
|
||||
13. **The Second Summit** — a hash-based pyramid for the quantum era: SLH-DSA (FIPS 205), Winternitz chains and the checksum see-saw, the virtual hypertree, the eleven certificates and their cone-growth table, and leaf 18 live
|
||||
14. **The Attestation Protocol** — what it takes to make "it is proven" checkable by a stranger; closes with *Go and touch the real thing*: a guided reading of the estate's **live transparency log** (ltl.zkdefi.org — 19 leaves, the four ed25519 pyramids at 44 certificates, the log's own Merkle proofs as leaf 17, and the first post-quantum leaf, SLH-DSA, as leaf 18), including the fifteen-minute verify-it-yourself exercise
|
||||
|
||||
Appendices: **A** — the pen-and-paper toolkit (recipe cards with drills);
|
||||
**B** — guided walkthroughs of every exercise-file hole; **C** — a tour of
|
||||
the real repositories. Plus a glossary and a thirteen-week course plan.
|
||||
the real repositories. Plus a glossary and a fourteen-week course plan.
|
||||
|
||||
The didactic machinery, deliberately heavy:
|
||||
|
||||
|
|
@ -91,7 +89,14 @@ install while the cache downloads.
|
|||
|
||||
## Building the book
|
||||
|
||||
Any TeX Live ≥ 2023 with `tikz`, `tcolorbox`, `listings`, `lmodern`:
|
||||
The repo's own recipe (tectonic, user-space, no root — installs itself on
|
||||
first run):
|
||||
|
||||
```bash
|
||||
./build.sh
|
||||
```
|
||||
|
||||
Or any TeX Live ≥ 2023 with `tikz`, `tcolorbox`, `listings`, `lmodern`:
|
||||
|
||||
```bash
|
||||
pdflatex main.tex && pdflatex main.tex # twice for the TOC
|
||||
|
|
@ -122,12 +127,11 @@ In the spirit of Chapter 11:
|
|||
twice (mod-13 sign-bit walk, then the real compressed base point:
|
||||
byte-31 sign bit, and the full-size hand verification 5·y_B − 4 = 4·p,
|
||||
every digit printed), plus a new paper exercise (12.4). Every printed
|
||||
constant was machine-verified before typesetting; the PDF (109 pages,
|
||||
2026-07-06 build — predates ch13) is rebuilt from these sources.
|
||||
- The PDF in the repo is built from the committed sources by the command
|
||||
above — but the committed build currently predates chapter 13 (see the
|
||||
honesty note at the top); rebuild it yourself if you don't trust binaries
|
||||
(good instinct), and you will get the thirteen-chapter book.
|
||||
constant was machine-verified before typesetting.
|
||||
- The PDF in the repo is built from the committed sources by `./build.sh`
|
||||
and recommitted alongside source changes; rebuild it yourself if you
|
||||
don't trust binaries (good instinct), and you should get the same
|
||||
fourteen-chapter book.
|
||||
- The three named solution certificates were kernel-audited
|
||||
(coherence pass 2, 2026-07-03): `Ch09.add_spec` depends on
|
||||
`[propext, Classical.choice, Quot.sound]`; `Ch09.mulVal_spec` and
|
||||
|
|
|
|||
|
|
@ -178,6 +178,6 @@ actually wrote.
|
|||
all: the scalar layer that was open when this appendix was first written is
|
||||
now complete on all four companion forks (thirteen certificates each ---
|
||||
lemmas shaped exactly like 9.B, bigger constants, same bones). The open
|
||||
frontier today is the paused Pasta curve layer, and chapter 12's ``Extend
|
||||
the pyramid'' item points at it; the \code{CONTRIBUTING} notes there will
|
||||
treat you as what you now are: someone who has done this before.
|
||||
frontier today is the paused Pasta curve layer, and chapter 12's ``Where
|
||||
you come in'' subsection points at it; the \code{CONTRIBUTING} notes there
|
||||
will treat you as what you now are: someone who has done this before.
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ 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
|
||||
in the log. You cannot read the proofs yet --- that is what the next thirteen
|
||||
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.
|
||||
|
|
@ -184,9 +184,12 @@ prime, and watched it agree; by Chapter~9 you will read real Rust translated
|
|||
into Lean and understand the one idea (the \emph{denotation function}) that
|
||||
makes the translation trustworthy; by Chapter~12 you will stand on the apex
|
||||
and read the signature-verification theorem for the actual code in your SSH
|
||||
client. The chapters between here and there earn each of those, in order ---
|
||||
Lean itself first, then the mathematics, then the bridge from real code, then
|
||||
the climb.
|
||||
client; by Chapter~13 you will climb a \emph{second} pyramid --- the
|
||||
post-quantum entry you just saw in the log, built from hashes alone --- and
|
||||
by Chapter~14 you will verify the log itself, so that nothing in this story
|
||||
asks for your trust. The chapters between here and there earn each of those,
|
||||
in order --- Lean itself first, then the mathematics, then the bridge from
|
||||
real code, then the climb.
|
||||
|
||||
\begin{bigidea}
|
||||
\textbf{The ratchet rule of this book.} Every load-bearing idea is worked
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ falls: \textbf{apex --- done, accept $\Leftrightarrow$
|
|||
decompress$(R) = [k](-A)+[s]B$, hash an opaque oracle by design.} The
|
||||
opening figure is now all theorems, floor to peak, on all four forks.
|
||||
|
||||
\section{What you now know, and where to take it}
|
||||
\section{What you now know}
|
||||
|
||||
Take inventory. You can read a goal state and drive a proof; you know which
|
||||
decision procedure owns which arithmetic fragment; you can build a
|
||||
|
|
@ -385,23 +385,8 @@ denotation bridge and state a two-clause spec; you can certify a prime with
|
|||
a witness tree; you can audit anyone's certificate in one command and four
|
||||
questions. That skill set is not Ed25519-specific --- it is the working
|
||||
method of machine-checked mathematics applied to systems, and elliptic
|
||||
curves were merely your first campaign.
|
||||
|
||||
Where to go from here, in increasing order of ambition:
|
||||
|
||||
\begin{itemize}[leftmargin=1.4em]
|
||||
\item \textbf{Read a real proof end-to-end.} \code{FieldSpec.lean} in
|
||||
\code{dalek-ed25519-verified}, top to bottom, with this book as the
|
||||
decoder ring. Budget an afternoon; expect the odd hour of humility.
|
||||
\item \textbf{Verify something of yours.} Pick a 200-line pure function you
|
||||
actually use --- a parser, a checksum, a data structure --- write its
|
||||
denotation (what does it \emph{mean}?), state the square, prove it.
|
||||
The first solo bridge is the moment this stops being a course.
|
||||
\item \textbf{Go deeper into the theory.} \emph{Theorem Proving in Lean 4}
|
||||
(the official text), \emph{Mathematics in Lean} (Mathlib's course), and
|
||||
the Lean Zulip --- an unusually welcoming expert community --- are the
|
||||
standard next doors.
|
||||
\end{itemize}
|
||||
curves were merely your first campaign. The next chapter takes that claim
|
||||
literally: same method, a second summit, and not one line of algebra on it.
|
||||
|
||||
\subsection*{Where you come in}
|
||||
|
||||
|
|
@ -418,49 +403,6 @@ saving this for an expert. Frontier work in machine-checked cryptography
|
|||
is, right now, undergraduate-accessible, and every chapter before this
|
||||
one was the access.
|
||||
|
||||
\subsection*{Further reading, annotated}
|
||||
|
||||
\begin{itemize}[leftmargin=1.4em]
|
||||
\item \emph{Theorem Proving in Lean 4} (Avigad, de Moura, et al.; free
|
||||
online) --- the official text. Read it \emph{after} this book's
|
||||
Chapters 2--5 and it will feel like meeting the extended family of
|
||||
ideas you already know; its dependent-type chapters go far beyond our
|
||||
needs and are worth the trip.
|
||||
\item \emph{Mathematics in Lean} (the Mathlib community course) ---
|
||||
hands-on Mathlib fluency: naming conventions, search strategies, the
|
||||
algebra hierarchy. The fastest cure for ``I know the fact exists but
|
||||
not its name,'' which will be your main bottleneck after this book.
|
||||
\item \emph{The Lean Zulip} (\code{leanprover.zulipchat.com}) --- where
|
||||
the community lives. Unusually welcoming to beginners; search before
|
||||
asking, then ask well: a minimal example plus the goal state gets
|
||||
expert answers in hours.
|
||||
\item Bernstein \& Lange, \emph{Faster addition and doubling on
|
||||
elliptic curves} (2007) --- the completeness proof this chapter's
|
||||
worked example walked; readable with this book's preparation, and a
|
||||
model of what ``designed for implementers'' mathematics looks like.
|
||||
\item The RFC for EdDSA (RFC 8032) --- the signature scheme as
|
||||
deployed, cofactor-$8$s and encoding details included. Read the
|
||||
verification equation section against this chapter and notice how much
|
||||
sharper your questions have become.
|
||||
\item Project Everest / HACL$^{*}$ and Fiat Crypto --- the two other
|
||||
major verified-crypto lineages (F$^{*}$-based and Coq-based
|
||||
respectively), both shipping in real TLS stacks and browsers. Reading
|
||||
their claims with your Chapter~\ref{ch:honesty} toolkit is instructive
|
||||
in both directions: the methods differ, the honest-boundary discipline
|
||||
rhymes.
|
||||
\end{itemize}
|
||||
|
||||
\begin{aha}
|
||||
One last reframe, the one this book was secretly about. ``Formal
|
||||
verification'' sounds like bureaucracy --- forms, stamps, compliance. What
|
||||
you actually practiced is closer to \emph{engineering's version of the
|
||||
scientific method}: make the claim precise enough to be falsifiable, then
|
||||
let an incorruptible referee try to falsify it, then publish the referee's
|
||||
report with the assumptions itemized. Cryptography needed that discipline
|
||||
first because its failures are silent and adversarial. It will not need it
|
||||
last.
|
||||
\end{aha}
|
||||
|
||||
\begin{tryit}
|
||||
The graduation exercise. In the mini-system from
|
||||
\code{exercises/Ch09.lean}, the file \code{exercises/Ch12.lean} plants a
|
||||
|
|
@ -570,8 +512,8 @@ returns true \emph{iff} the signature's $R$ decompresses to a valid
|
|||
on-curve point equal to $[k](-A) + [s]B$ --- with field arithmetic,
|
||||
group law, scalar arithmetic, encoding, and decompression each carried
|
||||
by its own kernel-checked layer below. If your two columns match this,
|
||||
you can audit a verification paper's abstract in ninety seconds ---
|
||||
which was the promise on the book's cover, kept.
|
||||
you can audit a verification paper's abstract in ninety seconds --- the
|
||||
skill the last two chapters of this book will aim at a live public log.
|
||||
|
||||
\solhead{12.4}
|
||||
\pathway Mirror the worked example's run 1 with $y = 10$.
|
||||
|
|
@ -586,11 +528,12 @@ put you on the curve at the WRONG point $(7,10) = -3P$ --- the sign bit
|
|||
is one bit of information doing real cryptographic work.
|
||||
|
||||
\begin{checkpoint}
|
||||
The book's ending is a beginning, so the final checkpoint is prospective:
|
||||
you should be able to (1) state what each pyramid layer claims and which
|
||||
You should be able to: (1) state what each pyramid layer claims and which
|
||||
denotation it rides on; (2) explain to a security engineer why completeness
|
||||
of the Edwards law matters to \emph{code}; (3) locate the current frontier
|
||||
and say precisely why it is hard; and (4) name the next proof \emph{you}
|
||||
intend to write. The authors of the companion repositories left the
|
||||
scaffolding up on purpose.
|
||||
and say precisely why it is hard. The first pyramid is finished --- every
|
||||
question mark from the opening figure resolved into a theorem. But its
|
||||
entire security story rests on one algebraic assumption, and there is a
|
||||
kind of computer, not yet built, that erases it. The next chapter climbs
|
||||
the pyramid that was built for that day.
|
||||
\end{checkpoint}
|
||||
|
|
|
|||
620
chapters/ch13-second-summit.tex
Normal file
620
chapters/ch13-second-summit.tex
Normal file
|
|
@ -0,0 +1,620 @@
|
|||
\chapter{The Second Summit: A Hash-Based Pyramid}
|
||||
\label{ch:secondsummit}
|
||||
|
||||
\section{The theorem that survives, and the reason that doesn't}
|
||||
|
||||
One leaf in the log does not belong to the pyramid you just climbed. Its
|
||||
subject kind says \code{slh\_dsa} where eighteen others say
|
||||
\code{ed25519} or \code{merkle\_accumulator}; it carries eleven
|
||||
certificates where its neighbors carry sixteen, forty-four, or sixty-one;
|
||||
and the scheme it attests contains no curve, no field, no scalar --- not
|
||||
one line of the algebra this book spent twelve chapters verifying. Leaf~18
|
||||
attests the log's first \emph{post-quantum signature scheme}, and this
|
||||
chapter is the climb that earns it.
|
||||
|
||||
First, the honest reason such a thing exists. Every certificate in the
|
||||
Ed25519 pyramid will still be \emph{true} the day a large quantum computer
|
||||
boots --- whether that day is a decade out or never; what dies that day is
|
||||
the reason anyone cared. Read that carefully,
|
||||
because it separates two ideas this book has been keeping distinct all
|
||||
along. The certificates say the code \emph{computes the right function} ---
|
||||
that the extracted verifier accepts exactly the signatures the mathematics
|
||||
accepts. Whether accepting those signatures keeps anyone \emph{safe} rests
|
||||
on an assumption no proof in this book touches: that computing discrete
|
||||
logarithms on the curve is infeasible. Shor's algorithm, on a big enough
|
||||
quantum computer, computes them efficiently. Correctness certificate:
|
||||
intact. Scheme: forgeable. A correct implementation of a broken lock is
|
||||
still a broken lock.
|
||||
|
||||
Hash functions are the part of the cryptographic toolbox that takes this
|
||||
future best. The strongest known quantum attack on preimage search is
|
||||
Grover's algorithm, a \emph{quadratic} speedup --- the kind of erosion you
|
||||
answer with modestly larger parameters, not the kind that dissolves the
|
||||
problem. So in August 2024, NIST standardized FIPS~205: \textbf{SLH-DSA},
|
||||
the \emph{stateless hash-based digital signature algorithm} (descended
|
||||
from SPHINCS\textsuperscript{+}) --- a signature scheme built from hash
|
||||
functions and \emph{nothing else}. No group. No field. Nothing for Shor
|
||||
to eat.
|
||||
|
||||
\begin{bigidea}
|
||||
The second summit asks the question the first one could not: does the
|
||||
\emph{method} --- extract the real code, build a bridge, prove the
|
||||
certificates, audit the cones, attest the result --- transfer to terrain
|
||||
with entirely different mathematics? Signature chains and Merkle trees
|
||||
instead of limbs and group laws. If the method only worked on the terrain
|
||||
it was invented for, it was a trick. If it transfers, it is a discipline.
|
||||
This chapter is the experiment, run for real, on the parameter set
|
||||
\textbf{SLH-DSA-SHA2-128s}.
|
||||
\end{bigidea}
|
||||
|
||||
The whole parameter set fits on an index card, and you should copy it out
|
||||
now, because every number in this chapter comes from it: hash output
|
||||
$n = 16$ bytes; total tree height $h = 63$, split into $d = 7$ layers of
|
||||
height $h' = 9$ (check the joint: $63 = 7 \cdot 9$); FORS forest of
|
||||
$k = 14$ trees of height $a = 12$; Winternitz parameter $w = 16$ (digits
|
||||
are hex nibbles, $\log_2 w = 4$), giving $\mathit{len} = 35$ chains
|
||||
($32$ message nibbles $+$ $3$ checksum digits; check: $35 = 2n + 3$ ---
|
||||
two nibbles per byte of the $n = 16$-byte value, plus three);
|
||||
message digest $m = 30$ bytes. In the verified repository these are not
|
||||
documentation --- they are the const-generic arguments baked into the one
|
||||
extracted entry point, \code{slh\_verify\_128s}, in
|
||||
\code{gen/SlhVerify/Funs.lean} (except $w$ and $\log_2 w$, which ride
|
||||
along as the crate constants \code{W} and \code{LGW} in the same file).
|
||||
|
||||
\section{Signatures with nothing but a hash}
|
||||
|
||||
Strip the idea to one bit. Pick a hash function $F$. Choose two secret
|
||||
random values $s_0, s_1$; publish $F(s_0)$ and $F(s_1)$ as your public
|
||||
key. To sign the bit $0$, reveal $s_0$; to sign $1$, reveal $s_1$. A
|
||||
verifier hashes what you revealed and compares against your public key.
|
||||
A forger must produce a preimage of a published hash --- the exact thing
|
||||
hash functions exist to prevent. That is Lamport's 1979 scheme, and it
|
||||
already contains the whole species: \emph{a signature is a controlled
|
||||
leak of preimages; verification is re-hashing the leak}.
|
||||
|
||||
Two problems, and their fixes build the entire pyramid. First, one bit
|
||||
per key pair is absurd; the fix is \emph{chains}. Second, every key is
|
||||
one-time --- reveal twice and a forger can mix and match; the fix is
|
||||
\emph{trees}. Chains first.
|
||||
|
||||
\textbf{Winternitz chains (WOTS\textsuperscript{+}).} Instead of two
|
||||
secrets per bit, keep one secret per hex \emph{nibble} and define a chain:
|
||||
$c_0 = \text{secret}$, $c_{i+1} = F(c_i)$, sixteen positions
|
||||
$c_0 \dots c_{15}$. Publish the chain \emph{end} $c_{15}$ (all
|
||||
thirty-five chain ends will later be compressed to one value; the
|
||||
compressor is the $T$ of the pricing box to come). To sign the nibble
|
||||
value $v \in \{0,\dots,15\}$, reveal $c_v$
|
||||
--- the chain value $v$ steps up. The verifier takes what you revealed
|
||||
and \emph{walks the remaining steps}: $15 - v$ more applications of $F$
|
||||
must land exactly on the published end.
|
||||
|
||||
\begin{worked}{one chain, resumed --- and the checksum see-saw}
|
||||
Real parameters ($w = 16$), no napkin scaling needed. Say message nibble
|
||||
$v = 11$ ($\mathtt{0xB}$). The signature reveals $c_{11}$. The verifier
|
||||
computes $15 - 11 = 4$ applications of $F$ --- in the verified code the
|
||||
hash \emph{address} is set to $11, 12, 13, 14$ in turn, one per step ---
|
||||
and compares the result against the chain end. Four hashes; no secrets;
|
||||
done.
|
||||
|
||||
Now attack it. $F$ is public, so anyone holding $c_{11}$ can compute
|
||||
$c_{12} = F(c_{11})$ --- a valid signature for the nibble $12$! Walking
|
||||
\emph{forward} is free; only walking \emph{backward} needs a preimage.
|
||||
Forging ``11 $\to$ 12'' costs nothing... for that one chain. The fix is
|
||||
bookkeeping, and you can run all of it by hand. Alongside the $32$
|
||||
message nibbles, WOTS signs a \textbf{checksum}:
|
||||
\[
|
||||
\mathit{csum} \;=\; \sum_{i=0}^{31} \,(15 - \mathit{msg}_i),
|
||||
\]
|
||||
the total of all \emph{remaining} steps. Take the extreme case, all
|
||||
nibbles zero: $\mathit{csum} = 32 \cdot 15 = 480 = \mathtt{0x1E0}$. The
|
||||
code shifts left by $4$, flush against the top of two bytes, because the
|
||||
digit extractor reads nibbles most-significant-first:
|
||||
$\mathtt{0x1E00}$, bytes $[\mathtt{1E}, \mathtt{00}]$, whose
|
||||
first three nibbles are the checksum digits $(1, 14, 0)$ --- signed with
|
||||
three more chains, walked $15{-}1$, $15{-}14$, $15{-}0$ steps by the
|
||||
verifier.
|
||||
|
||||
Now run the see-saw, on these numbers. A forger bumps one message nibble
|
||||
$0 \to 1$ (walking that chain forward one step, free). The checksum
|
||||
follows: $\mathit{csum} = 479 = \mathtt{0x1DF}$, shifted
|
||||
$\mathtt{0x1DF0}$, digits $(1, 13, 15)$. Compare against $(1, 14, 0)$:
|
||||
the \emph{third} digit rose $0 \to 15$ --- forward walk, free --- but
|
||||
the \emph{second} fell $14 \to 13$, and the signature only revealed that
|
||||
chain's value at position $14$. The forger needs position $13$: one step
|
||||
\emph{earlier}. Walking backward. Inverting $F$. (In general: a strictly
|
||||
smaller checksum must have a strictly smaller digit at the most
|
||||
significant position where the two differ --- some chain always falls.)
|
||||
The thirty-five chains hold each other hostage, and the
|
||||
hostage-taking is pure arithmetic --- the kind a certificate can pin.
|
||||
\end{worked}
|
||||
|
||||
In the verified repository that arithmetic \emph{is} pinned:
|
||||
\lean{fips205.wots\_csum\_loop\_eq} certifies that the extracted checksum
|
||||
loop computes exactly the fold
|
||||
$\mathit{csum} \leftarrow \mathit{csum} + (W{-}1 - \mathit{msg}_i)$ ---
|
||||
and its axiom cone is the bare kernel three, because summing nibbles
|
||||
needs no hash at all. Keep that observation; it becomes a pattern.
|
||||
|
||||
\section{One virtual tree of $2^{63}$ keys}
|
||||
|
||||
Chains sign one message per key pair. The tree fix: make $2^{63}$
|
||||
one-time WOTS key pairs, hash each down to a leaf, and build a Merkle
|
||||
tree; the public key is the single root. A signature then contains the
|
||||
one-time signature \emph{plus the authentication path} --- the $\log_2$
|
||||
chain of sibling hashes from that leaf to the root. The verifier
|
||||
recomputes the leaf from the WOTS signature, hashes its way up the path
|
||||
--- at each level the current bit of the leaf index says whether the
|
||||
running node is a left or right child, i.e.\ whether to compute
|
||||
$H(\text{node} \,\Vert\, \text{sibling})$ or
|
||||
$H(\text{sibling} \,\Vert\, \text{node})$ --- and compares the result to
|
||||
the published root. You met this exact structure in
|
||||
Chapter~\ref{ch:why}'s pyramid diagrams and will meet it once more in the
|
||||
final chapter, holding this book's own proofs; here it holds signature
|
||||
keys.
|
||||
|
||||
Except nobody can build that tree. Count it: $2^{63}$ leaves, each
|
||||
requiring a full WOTS key generation ($35$ chains $\times$ $15$ steps
|
||||
$+$ compression), plus the internal hashes --- on the order of $10^{21}$
|
||||
hash evaluations --- roughly $5 \times 10^{21}$, about $2^{72}$ --- to
|
||||
materialize once. The resolution is two-fold:
|
||||
|
||||
\begin{itemize}[leftmargin=1.4em]
|
||||
\item \textbf{Hypertree}: don't build one tree of height $63$; build
|
||||
$7$ layers of trees of height $9$, where each tree's root is signed by
|
||||
a WOTS key of the tree \emph{above} it --- so nobody, signer included,
|
||||
ever materializes more than a height-$9$ tree at a time. A signature
|
||||
carries $7$ small WOTS signatures, one per layer.
|
||||
\item \textbf{Virtuality}: secrets are generated pseudorandomly from a
|
||||
seed, so any leaf can be \emph{recomputed on demand}. The full
|
||||
structure exists only potentially. The signer touches one path of it
|
||||
per signature; the verifier re-hashes exactly that path.
|
||||
\end{itemize}
|
||||
|
||||
\begin{aha}
|
||||
The hypertree is never built. A structure of $2^{63}$ keys --- more
|
||||
one-time keys than there are seconds in two hundred billion years ---
|
||||
exists only as the \emph{promise} that any requested piece can be
|
||||
recomputed from a $16$-byte seed, and the root pins every piece of it at
|
||||
once. This is the find/check asymmetry of Chapter~\ref{ch:prime} scaled
|
||||
to its logical extreme: the object is astronomically too large to ever
|
||||
exist, and verifying one path through it costs a few thousand hashes on
|
||||
your laptop.
|
||||
\end{aha}
|
||||
|
||||
One piece is missing: the hypertree's leaves are \emph{one-time} keys,
|
||||
and the signer is stateless --- it cannot remember which leaves it has
|
||||
used. The scheme picks the leaf pseudorandomly per message, and to
|
||||
survive the rare event that two messages draw the same leaf, it does not
|
||||
put the message directly under a WOTS key. Instead the message digest is
|
||||
signed by \textbf{FORS} (Forest Of Random Subsets): $k = 14$ little
|
||||
Merkle trees of height $a = 12$. Each tree hides $2^{12}$ secrets in its
|
||||
leaves; the message digest names one leaf per tree; signing reveals
|
||||
those $14$ secrets with their authentication paths, and the $14$
|
||||
recomputed roots are compressed into one value which the hypertree then
|
||||
certifies.
|
||||
|
||||
\begin{worked}{FORS on a napkin --- two trees, height two}
|
||||
Shrink to $k = 2$, $a = 2$: two trees of four secrets each, eight
|
||||
secrets total, digest length $k \cdot a = 4$ bits. Say the digest is
|
||||
$\mathtt{1001}$. Split into $2$-bit indices: tree $0$ opens leaf
|
||||
$\mathtt{10} = 2$, tree $1$ opens leaf $\mathtt{01} = 1$. The signature
|
||||
reveals secret $2$ of tree $0$ with its two path siblings, and secret
|
||||
$1$ of tree $1$ with its two; the verifier hashes each secret to a leaf,
|
||||
climbs both paths, and compresses the two roots. Now reuse the key on a
|
||||
second digest, $\mathtt{0111}$: it opens leaves $1$ and $3$ --- two
|
||||
\emph{more} secrets leaked, four of eight now public. A forger wanting
|
||||
to sign digest $\mathtt{1011}$ needs leaves $2$ and $3$: both already
|
||||
leaked --- forgery! At napkin scale reuse is fatal in one collision. At
|
||||
real scale the same arithmetic is the defense: two signatures leak at
|
||||
most $28$ of $57{,}344$ secrets, and a target digest needs its
|
||||
\emph{fourteen} indices --- each $12$ bits --- to land entirely inside
|
||||
the leaked sliver: probability about $(28/57{,}344)^{14}$ per key, and
|
||||
the pseudorandom leaf choice means the attacker cannot steer which
|
||||
key pair collides. Graceful degradation is not a slogan; it is this
|
||||
exponent.
|
||||
\end{worked}
|
||||
|
||||
That degradation arithmetic --- a \emph{few} secrets out of
|
||||
$14 \cdot 2^{12} = 57{,}344$, and fourteen simultaneous hits needed ---
|
||||
is the reason the scheme can afford statelessness.
|
||||
|
||||
\begin{worked}{the digest split, to the bit --- and the price of everything}
|
||||
The verifier's first act is one call to the message-digest oracle
|
||||
$H_{\mathit{msg}}$, producing $m = 30$ bytes. Those $30$ bytes are then
|
||||
split three ways by live arithmetic you can audit on paper:
|
||||
\[
|
||||
\Big\lceil \tfrac{k \cdot a}{8} \Big\rceil
|
||||
= \Big\lceil \tfrac{14 \cdot 12}{8} \Big\rceil = 21 \text{ bytes}
|
||||
\qquad
|
||||
\Big\lceil \tfrac{h - h/d}{8} \Big\rceil
|
||||
= \Big\lceil \tfrac{63 - 9}{8} \Big\rceil = 7 \text{ bytes}
|
||||
\qquad
|
||||
\Big\lceil \tfrac{h}{8d} \Big\rceil
|
||||
= \Big\lceil \tfrac{63}{56} \Big\rceil = 2 \text{ bytes}
|
||||
\]
|
||||
--- and $21 + 7 + 2 = 30$ exactly, no slack byte anywhere. The first
|
||||
$21$ bytes are the $14 \times 12 = 168$ bits of FORS leaf indices; the
|
||||
next $7$ bytes, masked to $54$ bits, choose \emph{which} bottom-layer
|
||||
tree of the $2^{54}$ signs this message; the last $2$ bytes, masked to
|
||||
$9$ bits, choose the leaf within it. (The masks in the extracted code
|
||||
are $\mathtt{U64.MAX} \ggg (64{-}54)$ and $\mathtt{U64.MAX} \ggg
|
||||
(64{-}9)$, the shift amounts computed from $h$ and $d$ --- keep $54$,
|
||||
keep $9$. And the hypertree spends the $54$ tree-index bits like a
|
||||
meter: the bottom layer takes the $9$-bit leaf index directly, then each
|
||||
of the six upper layers peels
|
||||
$\mathit{idx\_leaf} = \mathit{idx\_tree} \bmod 2^9$ off the bottom and
|
||||
shifts right by $9$; after the sixth peel, $54 - 6 \cdot 9 = 0$ bits
|
||||
remain --- the budget is spent exactly at the top layer.)
|
||||
|
||||
Now price the whole verification, from the parameter card. Five oracles
|
||||
do all the work --- $F$ steps chains and hashes leaves, $H$ hashes tree
|
||||
nodes, two compressors $T$ squeeze the $35$ WOTS chain ends and the $14$
|
||||
FORS roots down to single values, and $H_{\mathit{msg}}$ digests the
|
||||
message --- and every one of them is countable. Input-independent first:
|
||||
FORS paths $k \cdot a = 168$ calls to $H$, XMSS paths
|
||||
$d \cdot h' = 63$ more --- $231$ exactly; compressions, one $T$ per WOTS
|
||||
public key per layer ($7$) plus one for the FORS roots; the single
|
||||
$H_{\mathit{msg}}$; and the $14$ $F$-calls hashing the revealed FORS
|
||||
secrets to leaves: a fixed overhead of $254$ oracle calls. The chains
|
||||
add the input-dependent part, and here the see-saw earns its keep a
|
||||
second time: each chain walks at most $15$ steps, suggesting a cap of
|
||||
$35 \cdot 15 = 525$ per layer --- but that cap is \emph{unreachable},
|
||||
because message walks total exactly $\mathit{csum}$ while long message
|
||||
walks force short checksum digits and vice versa. Run the numbers over
|
||||
every possible checksum and the true per-layer maximum is $510$,
|
||||
achieved precisely at the all-zero message you worked above. So: at
|
||||
worst $7 \cdot 510 = 3{,}570$ chain steps, a grand total of $3{,}824$
|
||||
oracle calls --- just under four thousand, typically nearer $2{,}000$.
|
||||
Set the two numbers side by side: $\sim 2^{72}$ hash calls to
|
||||
materialize the structure, $\sim 2^{12}$ to check one path through it.
|
||||
The verifier touches a $2^{-60}$ sliver and trusts the rest to
|
||||
arithmetic.
|
||||
|
||||
And the signature that steers those two thousand hashes? Its size is an
|
||||
exercise in reading types: $n \cdot \big(1 + k(1+a) + d(\mathit{len} +
|
||||
h')\big) = 16 \cdot (1 + 182 + 308) = \mathbf{7{,}856}$ bytes, against a
|
||||
$32$-byte public key. (An Ed25519 signature is $64$ bytes. Post-quantum
|
||||
insurance is not free; it is merely \emph{possible}.)
|
||||
\end{worked}
|
||||
|
||||
\section{The same method, on alien terrain}
|
||||
|
||||
Now the experiment this chapter exists to report. The repository
|
||||
\code{fips205-slhdsa-verified} runs the exact pipeline you learned in
|
||||
Chapters~\ref{ch:rust}--\ref{ch:field}: pin a Rust source (a pure-Rust,
|
||||
no-unsafe FIPS~205 implementation, pinned by commit), extract through
|
||||
Charon and Aeneas into Lean --- starting from the one entry point
|
||||
\code{slh\_verify\_128s}, with the five hash primitives marked
|
||||
\emph{opaque} at the extraction boundary --- and prove certificates
|
||||
about the extracted model under a memory-guarded button. Same tools,
|
||||
same discipline, same \code{check.sh} skeleton with the same fail-closed
|
||||
phases. What comes out the other side is \textbf{eleven certificates}:
|
||||
ten loop theorems and one apex.
|
||||
|
||||
The ten are old friends wearing new clothes. Every one has the shape of
|
||||
Chapter~\ref{ch:denotation}'s bridge: on the left, the loop the
|
||||
extraction produced (chain walking, checksum accumulation, Merkle
|
||||
ascent, hypertree layering); on the right, a hand-written structural
|
||||
fold; between them, an equality theorem proved by unfolding one loop
|
||||
turn and inducting on the trip count. You have met every one of these
|
||||
folds already, as arithmetic. \lean{wots\_csum\_loop\_eq} pins the
|
||||
see-saw sum. \lean{chain\_free\_loop\_eq} pins the resume-the-chain
|
||||
walk, address sequence $v, v{+}1, \dots$ included.
|
||||
\lean{xmss\_loop\_eq} pins the even-bit/odd-bit sibling order of the
|
||||
Merkle ascent. And \lean{ht\_loop\_eq} pins the layer walk --- the
|
||||
peel-nine-bits-and-shift meter you just ran on the digest split, as a
|
||||
theorem.
|
||||
|
||||
But this terrain withholds something the first pyramid gave freely, and
|
||||
the repository says so in bold type. In the field proofs, the right-hand
|
||||
side of the bridge was \emph{independent mathematics} --- $\Zmod{p}$,
|
||||
which Mathlib understands without ever seeing dalek's code --- so each
|
||||
commuting square landed in a second semantics and meant something on its
|
||||
own. The natural move here would be the same: restate SLH-DSA
|
||||
verification as free-standing mathematics and prove the code equal to
|
||||
\emph{that}. But what would the restatement be made of? Hash chains and
|
||||
Merkle nodes --- the same oracles, the same folds; there is no
|
||||
Mathlib theory of SLH-DSA waiting on the other side of the bridge the
|
||||
way $\Zmod{p}$ was waiting for dalek. So the reference folds are built
|
||||
from \emph{the same extracted hash oracles} the loops call, and each
|
||||
certificate buys visibility rather than independent meaning: the
|
||||
extracted chain loop is some forty lines of monadic, generated Lean; the
|
||||
fold standing beside it in \lean{chain\_free\_loop\_eq} is fourteen you
|
||||
can hold against the standard's algorithm over a coffee. That last
|
||||
reading --- fold against FIPS~205 --- is a human step, named as such in
|
||||
the trusted base. The repository's own phrase is the one to memorize:
|
||||
read each loop certificate as \emph{``visible,'' not ``correct.''}
|
||||
|
||||
\begin{pitfall}
|
||||
Chapter~\ref{ch:honesty} trained you to ask what a certificate does
|
||||
\emph{not} say; this repository answers before you ask, and its ledger
|
||||
is worth reading twice. The five hash oracles are \emph{axioms} ---
|
||||
nothing relates them to FIPS~180-4's SHA-256, the same standing boundary
|
||||
as SHA-512 in the Ed25519 apex. One inner loop (\code{base\_2b}, the
|
||||
digit extractor that feeds both FORS indices and WOTS nibbles) is
|
||||
threaded opaquely with \emph{no certificate} --- a defect there would
|
||||
change the recomputed root while all eleven theorems held. The proved
|
||||
subject is a monomorphic facade; its bridge to the deployed generic
|
||||
verifier is a $137$-case differential test, \emph{evidence, not proof}.
|
||||
Signing and key generation were never extracted at all. And everything
|
||||
\emph{above} the extraction root is trusted base too --- the assembly of
|
||||
the domain-separated message $M'$, including the single separator byte
|
||||
that is all that distinguishes pure from prehash verification; get that
|
||||
byte wrong and you have a cross-variant forgery primitive that no
|
||||
certificate in the repository would notice. A trusted
|
||||
base is not a weakness; an \emph{unstated} one is.
|
||||
\end{pitfall}
|
||||
|
||||
The apex closes the pyramid the same way the Ed25519 apex did --- as an
|
||||
acceptance characterization, lightly paraphrased:
|
||||
|
||||
\begin{lstlisting}[language=Lean]
|
||||
theorem slh_verify_128s_accepts_iff (mprime sig pk) :
|
||||
slh_verify_128s mprime sig pk
|
||||
= do let root ← slhVerifyRoot mprime sig pk
|
||||
ok (decide (root.val = pk.pk_root.val))
|
||||
\end{lstlisting}
|
||||
|
||||
(The paraphrase elides only typography: the const-generic parameter
|
||||
decorations and the \lean{Result}-monad plumbing. The verbatim statement
|
||||
is theorem \lean{fips205.slh\_verify\_128s\_accepts\_iff} in
|
||||
\code{verification/Proofs/ApexSpec.lean} --- diff this prose against
|
||||
that source; the book taught you to distrust paraphrases, including its
|
||||
own.) For \emph{every} message digest, \emph{every} signature,
|
||||
\emph{every} public key at these parameters: the extracted verifier
|
||||
accepts exactly when the recomputed hypertree root byte-equals the
|
||||
public key's root. There is no other acceptance path --- no debug
|
||||
backdoor, no unchecked branch, no early \lean{true}. Both summits end in
|
||||
the same clean air: a quantified equation whose right-hand side a
|
||||
stranger can read.
|
||||
|
||||
One more object from this repository deserves a place in your permanent
|
||||
toolkit: the audit table of axiom cones, which turns
|
||||
Chapter~\ref{ch:honesty}'s discipline into a picture of the pyramid
|
||||
itself.
|
||||
|
||||
\begin{center}
|
||||
\small
|
||||
\begin{tabular}{@{}ll@{}}
|
||||
\toprule
|
||||
\textbf{Certificate layer} & \textbf{Cone beyond the kernel three} \\
|
||||
\midrule
|
||||
digit/byte plumbing (4 certs) & --- \emph{(pure arithmetic, no hash)} \\
|
||||
chain, WOTS recompute & $F$ \\
|
||||
XMSS ascent, FORS inner & $H$ \\
|
||||
FORS outer & $F, H$ \\
|
||||
hypertree walk & $F, H$, the WOTS compressor (axiom \code{t\_l}) \\
|
||||
apex & all five oracles \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
The cone \emph{grows as you climb}: bit-shuffling needs no oracles at
|
||||
all; each layer adds exactly the hash primitives it touches; the apex
|
||||
carries all five. The audit enforces every row with exact equality ---
|
||||
one axiom extra or one missing fails the build --- so this table is not
|
||||
documentation, it is a \emph{theorem about the theorems}.
|
||||
|
||||
And the table carries a war story, told here so you inherit the scar
|
||||
without the wound. During the audit, comparing what each compressor
|
||||
axiom was \emph{used as} against what it was \emph{named} turned up a
|
||||
mismatch: the axiom spelled \code{t\_l} is the one doing the standard's
|
||||
$T_{\mathit{len}}$ job (compressing WOTS chain ends), while the axiom
|
||||
spelled \code{t\_len} does the $T_k$ job (compressing FORS roots) ---
|
||||
the source's names are \emph{inverted} against FIPS~205. Worse, both
|
||||
axioms model what is a \emph{single} primitive in the Rust source. The
|
||||
repository's response was not to quietly ``fix'' the names --- renaming
|
||||
proves nothing --- but to document the inversion at the axiom
|
||||
declarations and keep the two axioms separate anyway, assuming
|
||||
\emph{less} (two possibly-different functions) rather than more. Had the
|
||||
auditor trusted spelling, the cone table above would read cleanly and
|
||||
lie. When you audit a stranger's certificate, judge every axiom by what
|
||||
it is used as, never by what it is named. Names are spelling; cones are
|
||||
property.
|
||||
|
||||
The experiment the chapter opened with can now be called. The pipeline
|
||||
re-ran end to end on terrain its designers never saw: extraction, the
|
||||
loop-to-fold bridge shape, the exact-cone audit, the fail-closed button,
|
||||
the acceptance-characterization apex --- all of it transferred without a
|
||||
structural change. Discipline, not trick. With one honest asterisk the
|
||||
ledger already made you read: this terrain offered no second semantics,
|
||||
so the bridges here are thinner than the field layer's --- visibility,
|
||||
not independent meaning. A method that transfers \emph{and tells you
|
||||
exactly how much thinner its guarantees just got} is rarer than either
|
||||
half alone.
|
||||
|
||||
\section{The leaf, live}
|
||||
|
||||
The climb ends where the chapter began, but now you can read every field.
|
||||
Leaf~18 of the log --- \code{entries/000018.json} in the mirror,
|
||||
nineteenth and newest --- binds the repository at its pinned commit to
|
||||
the eleven certificate names you now know, each with \code{status}
|
||||
proven, each with its \emph{observed} axiom cone equal to its expected
|
||||
cone: kernel-3 for the four plumbing certificates, the oracle sets of
|
||||
the table above for the rest, all five for the apex. Its scope block
|
||||
recites the trusted base you just read --- oracles assumed, signing out
|
||||
of scope, \code{base\_2b} uncertified, differential bridge not a proof
|
||||
--- because an attestation that hides its boundary is advertising, and
|
||||
this log does not accept advertising.
|
||||
|
||||
``Leaf~18 landed, so the log went post-quantum'' --- plausible, and
|
||||
wrong twice. First: leaf~18 is the first leaf \emph{about} a
|
||||
post-quantum signature scheme, but its own issuance signature --- the
|
||||
block inside \code{entries/000018.json}, like every leaf's --- is
|
||||
Ed25519 only. Second: the log's \emph{tree heads} did start carrying an
|
||||
additional SLH-DSA-SHA2-128s co-signature in the same publication batch
|
||||
--- but the first dual-signed head is the size-\emph{14} head (leaf~18
|
||||
arrives at size $19$, five appends later). Two separate facts, one lazy
|
||||
conflation avoided; append-only history keeps them distinguishable
|
||||
forever.
|
||||
|
||||
And here the estate quietly eats its own cooking --- with the books kept
|
||||
scrupulously. The head's required Ed25519 signature is produced by the
|
||||
dalek library attested at leaf~13 --- forty-four certificates,
|
||||
self-inclusion verified inside the signature block itself: machinery
|
||||
attested \emph{in the log}, signing \emph{for the log}. The additional
|
||||
co-signature closes a different, looser loop: it uses parameter set
|
||||
SHA2-128s --- \emph{exactly} the parameter set whose verification path
|
||||
leaf~18 proves --- but the OpenSSL backend that actually produces and
|
||||
checks that co-signature carries no certificate anywhere; what is
|
||||
attested is the scheme's verification path in an independent, extracted
|
||||
implementation, not the tool on duty. And for the \emph{signing}
|
||||
operations, no loop closes at all --- no signing operation is proven for
|
||||
either scheme, and the log says so. Read the three clauses again in
|
||||
order: attested machinery, attested scheme, honest gap. Even the
|
||||
self-reference keeps its books honest.
|
||||
|
||||
\begin{tryit}
|
||||
Touch the second summit yourself; it costs one command. Clone
|
||||
\code{github.com/saymrwulf/lean-transparency-log} and run
|
||||
\code{python3 verify.py --receipt
|
||||
receipts/fips205-slhdsa-verified.receipt.json} --- the receipt binds
|
||||
leaf~18 by inclusion proof to the size-$19$ signed head. Then open
|
||||
\code{entries/000018.json} and find, with your own eyes: the eleven
|
||||
certificate names, the five oracle axioms in the apex's observed cone,
|
||||
and the exclusions block naming \code{base\_2b}. You have just audited a
|
||||
post-quantum verification claim --- boundary and all --- in the time it
|
||||
takes to pour a coffee.
|
||||
\end{tryit}
|
||||
|
||||
\section*{Exercises}
|
||||
|
||||
\exercise{(Paper) All thirty-two message nibbles equal $7$. Compute the
|
||||
checksum, the shift, the two bytes, and the three checksum digits, as
|
||||
the worked example did for the all-zero message. How many steps of $F$
|
||||
does the verifier walk on each of the three checksum chains?}
|
||||
|
||||
\exercise{(Paper) Re-derive the digest split from the parameter card:
|
||||
show $\lceil 168/8 \rceil = 21$, $\lceil 54/8 \rceil = 7$,
|
||||
$\lceil 63/56 \rceil = 2$, and verify they exhaust $m = 30$. Then
|
||||
explain in one sentence why the second slice is masked to exactly $54$
|
||||
bits and what would go wrong with a $55$-bit mask.}
|
||||
|
||||
\exercise{(Paper) Derive the signature size from the types: $n$ bytes of
|
||||
randomness, $k$ revealed FORS secrets plus $k$ auth paths of $a$ nodes,
|
||||
and $d$ XMSS signatures of $\mathit{len} + h'$ hashes each. Show the
|
||||
total is $16 \cdot 491 = 7{,}856$ and locate the single largest
|
||||
contributor.}
|
||||
|
||||
\exercise{(Audit drill) State the see-saw precisely and prove it: if a
|
||||
forger changes the message so that some nibble strictly increases and
|
||||
none decreases, then the checksum strictly decreases, and at least one
|
||||
checksum digit's chain must be evaluated at a position \emph{earlier}
|
||||
than the one revealed. Why does ``earlier position'' mean ``invert
|
||||
$F$''?}
|
||||
|
||||
\exercise{(Audit drill) The audit holds five oracle axioms but the Rust
|
||||
source has four hash primitives: \code{t\_l} and \code{t\_len} both
|
||||
delegate to one function. Explain why modeling one primitive as two
|
||||
independent axioms is the \emph{conservative} choice --- what could a
|
||||
proof using ``they are equal'' conclude that the current model cannot,
|
||||
and why is refusing that conclusion safer?}
|
||||
|
||||
\exercise{(Discussion) The day a cryptographically relevant quantum
|
||||
computer exists, which statements in this book's estate become false?
|
||||
Work through: the four Ed25519 apex certificates; the Ed25519 signatures
|
||||
on the log's tree heads; leaf~18's certificates; the SLH-DSA
|
||||
co-signatures on the heads. Sort each into ``still true,'' ``true but no
|
||||
longer load-bearing,'' and ``broken'' --- and defend the sorting.}
|
||||
|
||||
\section*{Solutions and pathways}
|
||||
\solutionsintro
|
||||
|
||||
\solhead{13.1}
|
||||
\pathway Same three moves as the worked box: sum the remaining steps,
|
||||
align, extract nibbles.
|
||||
\answer $\mathit{csum} = 32 \cdot (15 - 7) = 256 = \mathtt{0x100}$.
|
||||
Shifted left $4$: $\mathtt{0x1000}$, bytes $[\mathtt{10}, \mathtt{00}]$,
|
||||
first three nibbles $(1, 0, 0)$. The verifier walks $15 - 1 = 14$,
|
||||
$15 - 0 = 15$, $15 - 0 = 15$ steps. (Sanity: middle-of-the-road message
|
||||
digits still force near-full walks on checksum chains --- the checksum
|
||||
digits are usually \emph{small}, so their remaining walks are long.)
|
||||
|
||||
\solhead{13.2}
|
||||
\pathway The three ceilings are $\lceil ka/8\rceil$,
|
||||
$\lceil (h - h/d)/8 \rceil$, $\lceil h/(8d) \rceil$ with the card's
|
||||
values substituted.
|
||||
\answer $\lceil 14 \cdot 12 / 8 \rceil = \lceil 21 \rceil = 21$;
|
||||
$\lceil (63-9)/8 \rceil = \lceil 6.75 \rceil = 7$;
|
||||
$\lceil 63/56 \rceil = 2$; and $21 + 7 + 2 = 30 = m$. The tree index
|
||||
addresses one of $2^{h - h/d} = 2^{54}$ bottom-layer trees, so the mask
|
||||
keeps exactly $54$ bits; a $55$-bit mask could name a tree that does not
|
||||
exist --- the verifier would recompute a root of an out-of-range tree
|
||||
and reject a valid signature (or, worse in a sloppier implementation,
|
||||
wrap around silently). Ranges are part of correctness; that is why the
|
||||
extracted masks are certificate-adjacent code, not comments.
|
||||
|
||||
\solhead{13.3}
|
||||
\pathway Transcribe the type structure into a sum, then factor out $n$.
|
||||
\answer $n\big(1 + k(1{+}a) + d(\mathit{len}{+}h')\big)
|
||||
= 16\,(1 + 14 \cdot 13 + 7 \cdot 44) = 16\,(1 + 182 + 308)
|
||||
= 16 \cdot 491 = 7856$. The hypertree's $308$ hash-values (seven WOTS
|
||||
signatures of $35$ plus seven auth paths of $9$) dominate: $4{,}928$ of
|
||||
the $7{,}856$ bytes --- the price of splitting one impossible tree into
|
||||
seven possible ones.
|
||||
|
||||
\solhead{13.4}
|
||||
\pathway Write the checksum as a function of the digit vector and
|
||||
difference it.
|
||||
\answer $\mathit{csum} = \sum_i (15 - \mathit{msg}_i)$, so if some
|
||||
nibbles increase by a total of $\delta > 0$ and none decrease,
|
||||
$\mathit{csum}$ drops by exactly $\delta$. The checksum digits are the
|
||||
base-$16$ representation of the (aligned) checksum; a strictly smaller
|
||||
value must have at least one strictly smaller digit at some position
|
||||
(compare digits from the most significant end; the first difference is
|
||||
a decrease). The signature revealed the chain value at the \emph{old}
|
||||
digit's position; a forgery needs the value at a strictly earlier
|
||||
position of that chain --- but the chain runs forward by $F$, so an
|
||||
earlier value is a preimage of the revealed one under iterated $F$.
|
||||
Producing it is inverting the hash --- the assumption the whole scheme
|
||||
stands on.
|
||||
|
||||
\solhead{13.5}
|
||||
\pathway Ask what each axiom is \emph{used for} in the proofs, then ask
|
||||
what merging them would license.
|
||||
\answer The model with two independent axioms proves everything the
|
||||
certificates claim while assuming only ``there exist two functions with
|
||||
these signatures.'' Adding \lean{t\_l = t\_len} would let a proof
|
||||
conclude that a WOTS compression can be replayed as a FORS compression
|
||||
(and vice versa) --- an interchangeability the standard does not grant
|
||||
(the two uses differ in domain separation via the address argument) and
|
||||
no certificate needs. Assuming less can only make the theorems
|
||||
\emph{harder} to prove, never falsely stronger; if the theorems still go
|
||||
through, the weaker assumption is strictly safer. The general habit:
|
||||
when in doubt, split the axiom --- and let the cones show exactly which
|
||||
theorem leaned on which half.
|
||||
|
||||
\solhead{13.6}
|
||||
\pathway Separate ``the theorem is true'' from ``the assumption behind
|
||||
the scheme's security is true'' for each artifact.
|
||||
\answer The four Ed25519 apex certificates: \emph{still true} ---
|
||||
kernel-checked equations about extracted code do not cite discrete-log
|
||||
hardness anywhere. The Ed25519 head signatures: \emph{true but no longer
|
||||
load-bearing} --- the signatures still verify, but a quantum forger
|
||||
could now mint alternative heads, so their evidentiary weight collapses
|
||||
(the certificates about the \emph{verifier} remain true; the
|
||||
unforgeability of \emph{signing} was never proven and is now also not
|
||||
believed). Leaf~18's certificates: \emph{still true}, and still
|
||||
load-bearing --- nothing in their cones or their scheme depends on
|
||||
Shor-vulnerable structure. The SLH-DSA head co-signatures: the reason
|
||||
the slot exists --- \emph{load-bearing by design} on that day, resting
|
||||
on hash preimage resistance, eroded only quadratically by Grover.
|
||||
Moral, worth saying aloud: proofs of correctness are
|
||||
quantum-proof; \emph{schemes} are not; and a log that dual-signs its
|
||||
heads is planning for the difference.
|
||||
|
||||
\begin{checkpoint}
|
||||
You should now be able to: explain why a correctness certificate
|
||||
survives a quantum computer while the scheme it certifies may not;
|
||||
run a WOTS chain-resume and the checksum see-saw by hand at $w = 16$;
|
||||
price an SLH-DSA-SHA2-128s verification ($254$ fixed oracle calls plus
|
||||
the chains, against $2^{72}$ to build what it checks); read the eleven
|
||||
certificates and the cone-growth table as one object; and recite what
|
||||
the second summit does \emph{not} claim --- oracles assumed,
|
||||
\code{base\_2b} uncertified, the $M'$ assembly above the extraction
|
||||
root, signing never in scope. Both pyramids now
|
||||
stand, and both end the same way: a script prints \texttt{ALL GREEN}
|
||||
and a leaf lands in a public log. Which leaves exactly one question in
|
||||
this book, and it is the deepest one: that script, and that log --- who
|
||||
checks \emph{them}? The final chapter has been waiting for you.
|
||||
\end{checkpoint}
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
\section{The second act nobody warns you about}
|
||||
|
||||
The question the last checkpoint left you holding --- that script, that
|
||||
log, who checks \emph{them}? --- has a name, and a body count.
|
||||
Chapter~\ref{ch:honesty} taught you to interrogate a certificate: ask what it
|
||||
rests on, and refuse to be impressed by a file that merely compiles. That
|
||||
chapter had a blind spot, and this one exists because a sequence of external
|
||||
|
|
@ -201,7 +203,7 @@ people who eventually caught them were strangers.
|
|||
You will not build an eighteen-attack self-test for a homework exercise, and you
|
||||
should not. What you should take away is a habit of mind and a vocabulary.
|
||||
|
||||
\begin{checkpoint}
|
||||
\begin{bigidea}
|
||||
When you next read the words ``formally verified'', ask two questions instead of
|
||||
one.
|
||||
|
||||
|
|
@ -215,7 +217,7 @@ myself?
|
|||
If a project cannot answer the second set, it has done act one and called it
|
||||
finished --- which is exactly the mistake these chapters were rewritten to
|
||||
prevent.
|
||||
\end{checkpoint}
|
||||
\end{bigidea}
|
||||
|
||||
And when it is your own project: invite someone to attack the button, early.
|
||||
Every one of the eighteen defects was found by a reviewer trying to break it.
|
||||
|
|
@ -236,14 +238,14 @@ interrogate offline. It is act two, industrialized: every failure class this
|
|||
chapter catalogued has a gate in that pipeline because a reviewer once got
|
||||
past the spot where the gate now stands.
|
||||
|
||||
\begin{checkpoint}
|
||||
\begin{tryit}
|
||||
The fifteen-minute exercise, and the best return on time in this book: clone
|
||||
the mirror and run the verifier.
|
||||
|
||||
\begin{itemize}
|
||||
\item \code{python3 verify.py --all} --- plain Python for the hashing, the
|
||||
\code{openssl} binary for signatures, and it \emph{fails closed} without
|
||||
them (Section~\ref{ch:attestation} taught you why ``couldn't check'' must
|
||||
them (this chapter taught you why ``couldn't check'' must
|
||||
never print as a pass). It recomputes every leaf hash, every historical
|
||||
tree head against its recomputed prefix root, every signature, and every
|
||||
inclusion proof --- your machine, your verdict, nobody's word.
|
||||
|
|
@ -257,7 +259,7 @@ the mirror and run the verifier.
|
|||
commit, the certificate list, the \emph{observed} axiom cones, the machine
|
||||
protection, and the stated exclusions.
|
||||
\end{itemize}
|
||||
\end{checkpoint}
|
||||
\end{tryit}
|
||||
|
||||
The log's nineteen leaves map onto this book. Leaves 13--16 attest the four
|
||||
ed25519 repositories whose pyramid you climbed in
|
||||
|
|
@ -268,11 +270,10 @@ Chapter~\ref{ch:honesty}'s lesson enforced in production. Leaf 17 is this
|
|||
chapter made literal: the log carries kernel-checked proofs of \emph{its own
|
||||
Merkle machinery} as one of its own entries --- ``who checks the checker?''
|
||||
answered by putting the checker's mathematics inside the thing it checks.
|
||||
And leaf 18 is the estate's first post-quantum subject: eleven certificates
|
||||
over the SLH-DSA-SHA2-128s \emph{verification} path (FIPS~205), whose apex
|
||||
states that the extracted verifier accepts exactly when the recomputed
|
||||
Merkle root matches --- tree recursions under a hash-oracle boundary, the
|
||||
same proof shapes you met in the pyramid, on a hash-based signature scheme.
|
||||
And leaf 18 is the second summit you climbed in
|
||||
Chapter~\ref{ch:secondsummit} --- the eleven SLH-DSA certificates, the
|
||||
cone-growth table, the see-saw: you can now read every field of that leaf
|
||||
against a chapter of your own experience.
|
||||
Since tree 14 every head also carries an \emph{additive} deterministic
|
||||
SLH-DSA signature beside the required Ed25519 one; heads published before
|
||||
then have none, and the verifier reports them as \code{ABSENT} rather than
|
||||
|
|
@ -293,7 +294,90 @@ a defect; it is what append-only means.
|
|||
|
||||
That is the whole arc of this book in one artifact: arithmetic became
|
||||
theorems (act one), theorems became certificates with named cones
|
||||
(Chapter~\ref{ch:honesty}), certificates became attestations a stranger can
|
||||
re-derive (this chapter) --- and the attestations went into a structure that
|
||||
remembers everything and lets anyone catch it lying. When you build your
|
||||
own, you now know what it costs, and where the bodies are buried.
|
||||
(Chapter~\ref{ch:honesty}), the method crossed to a second pyramid with
|
||||
different mathematics and held (Chapter~\ref{ch:secondsummit}),
|
||||
certificates became attestations a stranger can re-derive (this chapter)
|
||||
--- and the attestations went into a structure that remembers everything
|
||||
and lets anyone catch it lying. When you build your own, you now know what
|
||||
it costs, and where the bodies are buried.
|
||||
|
||||
\begin{aha}
|
||||
One last reframe, the one this book was secretly about. ``Formal
|
||||
verification'' sounds like bureaucracy --- forms, stamps, compliance. What
|
||||
you actually practiced is closer to \emph{engineering's version of the
|
||||
scientific method}: make the claim precise enough to be falsifiable, then
|
||||
let an incorruptible referee try to falsify it, then publish the referee's
|
||||
report with the assumptions itemized. Cryptography needed that discipline
|
||||
first because its failures are silent and adversarial. It will not need it
|
||||
last.
|
||||
\end{aha}
|
||||
|
||||
\section*{Where to go from here}
|
||||
|
||||
In increasing order of ambition:
|
||||
|
||||
\begin{itemize}[leftmargin=1.4em]
|
||||
\item \textbf{Read a real proof end-to-end.} \code{FieldSpec.lean} in
|
||||
\code{dalek-ed25519-verified}, top to bottom, with this book as the
|
||||
decoder ring. Budget an afternoon; expect the odd hour of humility.
|
||||
\item \textbf{Verify something of yours.} Pick a 200-line pure function you
|
||||
actually use --- a parser, a checksum, a data structure --- write its
|
||||
denotation (what does it \emph{mean}?), state the square, prove it.
|
||||
The first solo bridge is the moment this stops being a course.
|
||||
\item \textbf{Extend the estate.} Chapter~\ref{ch:pyramid}'s ``Where you
|
||||
come in'' names the open frontier --- the paused Pasta curve layer ---
|
||||
and the control repository's method files say exactly what a finished
|
||||
brick looks like. When yours is done, this chapter told you how to
|
||||
attest it, and the log is where it goes.
|
||||
\item \textbf{Go deeper into the theory.} \emph{Theorem Proving in Lean 4}
|
||||
(the official text), \emph{Mathematics in Lean} (Mathlib's course), and
|
||||
the Lean Zulip --- an unusually welcoming expert community --- are the
|
||||
standard next doors.
|
||||
\end{itemize}
|
||||
|
||||
\subsection*{Further reading, annotated}
|
||||
|
||||
\begin{itemize}[leftmargin=1.4em]
|
||||
\item \emph{Theorem Proving in Lean 4} (Avigad, de Moura, et al.; free
|
||||
online) --- the official text. Read it \emph{after} this book's
|
||||
Chapters~\ref{ch:lean}--\ref{ch:automation} and it will feel like
|
||||
meeting the extended family of
|
||||
ideas you already know; its dependent-type chapters go far beyond our
|
||||
needs and are worth the trip.
|
||||
\item \emph{Mathematics in Lean} (the Mathlib community course) ---
|
||||
hands-on Mathlib fluency: naming conventions, search strategies, the
|
||||
algebra hierarchy. The fastest cure for ``I know the fact exists but
|
||||
not its name,'' which will be your main bottleneck after this book.
|
||||
\item \emph{The Lean Zulip} (\code{leanprover.zulipchat.com}) --- where
|
||||
the community lives. Unusually welcoming to beginners; search before
|
||||
asking, then ask well: a minimal example plus the goal state gets
|
||||
expert answers in hours.
|
||||
\item Bernstein \& Lange, \emph{Faster addition and doubling on
|
||||
elliptic curves} (2007) --- the completeness proof
|
||||
Chapter~\ref{ch:pyramid}'s worked example walked; readable with this
|
||||
book's preparation, and a model of what ``designed for implementers''
|
||||
mathematics looks like.
|
||||
\item The RFC for EdDSA (RFC 8032) and FIPS 205 (SLH-DSA) --- the two
|
||||
signature schemes as deployed, cofactor-$8$s, encodings, and address
|
||||
words included. Read their verification sections against
|
||||
Chapters~\ref{ch:pyramid} and~\ref{ch:secondsummit} and notice how much
|
||||
sharper your questions have become.
|
||||
\item Project Everest / HACL$^{*}$ and Fiat Crypto --- the two other
|
||||
major verified-crypto lineages (F$^{*}$-based and Coq-based
|
||||
respectively), both shipping in real TLS stacks and browsers. Reading
|
||||
their claims with your Chapter~\ref{ch:honesty} toolkit is instructive
|
||||
in both directions: the methods differ, the honest-boundary discipline
|
||||
rhymes.
|
||||
\end{itemize}
|
||||
|
||||
\begin{checkpoint}
|
||||
The book's ending is a beginning, so the final checkpoint is prospective:
|
||||
you should be able to (1) explain the two acts of verification and why
|
||||
the second one cannot be delegated to the first; (2) audit a stranger's
|
||||
attestation --- leaf, cones, exclusions, inclusion proof --- in fifteen
|
||||
minutes with your own machine's verdict; (3) name the frontier brick
|
||||
\emph{you} could lay, and what the control repository says a finished
|
||||
one looks like; and (4) name the next proof you intend to write. The
|
||||
authors of the companion repositories left the scaffolding up on
|
||||
purpose.
|
||||
\end{checkpoint}
|
||||
|
|
@ -82,23 +82,40 @@ fact and the cost of verifying a certificate for it --- the engine of
|
|||
Pratt certificates, proof kernels, and (in disguise) the P-vs-NP
|
||||
question (Chapter~\ref{ch:prime}).
|
||||
|
||||
\gloss{Hasse bound} An elliptic curve over $\Fp$ has $p + 1 - t$ points
|
||||
with $|t| \le 2\sqrt{p}$; the thirty-second sanity check for any
|
||||
claimed group order (Chapter~\ref{ch:pyramid}).
|
||||
|
||||
\gloss{Fold} Reducing an overflow of the representation (weight
|
||||
$2^{255}$ and above) back into range using the modulus identity
|
||||
$2^{255} \equiv 19$; costs exactly one multiple of $p$ per unit folded
|
||||
(Chapter~\ref{ch:denotation}; Interlude).
|
||||
|
||||
\gloss{FORS} Forest Of Random Subsets: SLH-DSA's few-time signature ---
|
||||
$k$ small Merkle trees, one secret revealed per tree, all recomputed
|
||||
roots compressed and certified by the hypertree; reuse degrades
|
||||
gracefully instead of breaking, which is what buys statelessness
|
||||
(Chapter~\ref{ch:secondsummit}).
|
||||
|
||||
\gloss{Goal state} The proof assistant's board: hypotheses above the
|
||||
turnstile $\vdash$, obligation below. Reading it is the core tactic
|
||||
skill (Chapter~\ref{ch:tactics}).
|
||||
|
||||
\gloss{Hash oracle} A hash function entering a proof as an \emph{axiom}
|
||||
with assumed functional behavior and no proven properties; the five
|
||||
SLH-DSA verify-path oracles are the standing example, and the audit's
|
||||
cone table shows exactly which certificate leans on which
|
||||
(Chapter~\ref{ch:secondsummit}).
|
||||
|
||||
\gloss{Hasse bound} An elliptic curve over $\Fp$ has $p + 1 - t$ points
|
||||
with $|t| \le 2\sqrt{p}$; the thirty-second sanity check for any
|
||||
claimed group order (Chapter~\ref{ch:pyramid}).
|
||||
|
||||
\gloss{Headroom} Bits of slack between a limb's payload (e.g.\ 51 bits)
|
||||
and its machine word (64 bits); the budget lazy carries spend
|
||||
(Chapter~\ref{ch:why}).
|
||||
|
||||
\gloss{Hypertree} SLH-DSA's tower of $d$ Merkle-tree layers, each tree's
|
||||
root signed by a one-time key of the layer above --- a virtual structure
|
||||
of $2^h$ keys that is never materialized: any path can be recomputed
|
||||
from a seed, and one root pins it all (Chapter~\ref{ch:secondsummit}).
|
||||
|
||||
\gloss{Inductive type} A type defined by listing its constructors
|
||||
exhaustively (\lean{Nat}: \lean{zero} and \lean{succ}). Grants both
|
||||
pattern matching and the induction principle (Chapters~\ref{ch:lean},
|
||||
|
|
@ -129,6 +146,12 @@ certifies $p$ prime, given certificates for the $q$'s
|
|||
\gloss{Radix} The base of a limb representation ($2^{51}$ for the
|
||||
dalek field, $4$ for this book's toy system).
|
||||
|
||||
\gloss{SLH-DSA} The stateless hash-based digital signature algorithm of
|
||||
FIPS~205 (descended from SPHINCS\textsuperscript{+}): FORS under a
|
||||
hypertree of Winternitz chains, built from hash functions and nothing
|
||||
else --- no structure for Shor's algorithm to attack
|
||||
(Chapter~\ref{ch:secondsummit}).
|
||||
|
||||
\gloss{Specification (spec)} The precise statement a program is proven
|
||||
to satisfy. The two-clause shape for arithmetic: bounds propagation
|
||||
plus value equation. A proof is only as good as its spec
|
||||
|
|
@ -157,3 +180,9 @@ documented, and machine-visible (Chapters~\ref{ch:rust},
|
|||
theorem: \emph{(1)} the operation succeeds and its output satisfies the
|
||||
(possibly widened) bounds invariant; \emph{(2)} the output's denotation
|
||||
equals the ideal result (Chapter~\ref{ch:denotation}; Interlude).
|
||||
|
||||
\gloss{Winternitz chain (WOTS\textsuperscript{+})} A hash chain
|
||||
$c_0, F(c_0), F(F(c_0)), \dots$ signing one digit by revealing the
|
||||
chain value at the digit's position; the verifier walks the remaining
|
||||
steps to the published end. A checksum makes forward-walking forgeries
|
||||
self-defeating (Chapter~\ref{ch:secondsummit}).
|
||||
|
|
|
|||
BIN
main.pdf
BIN
main.pdf
Binary file not shown.
30
main.tex
30
main.tex
|
|
@ -45,9 +45,10 @@ claim it makes about a proof, a proof assistant has checked.\par}
|
|||
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.
|
||||
proof could make anyone else believe it; another belongs to a signature scheme
|
||||
built to survive a quantum computer. 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
|
||||
to make a computer \emph{prove} that a program is correct --- not test it on a
|
||||
|
|
@ -58,9 +59,11 @@ key a system ever generates.
|
|||
|
||||
This book assumes you can program a little and remember a little high-school
|
||||
algebra. It assumes \textbf{nothing} about formal methods, proof assistants, or
|
||||
Lean. We start from \code{1 + 1 = 2} and end at a real, published,
|
||||
machine-checked proof that the field arithmetic behind Ed25519 --- the signature
|
||||
scheme in your SSH client, your phone, and half the internet --- is correct.
|
||||
Lean. We start from \code{1 + 1 = 2} and end three summits later: real,
|
||||
published, machine-checked theorems about Ed25519 --- the signature scheme in
|
||||
your SSH client, your phone, and half the internet --- then about a hash-based
|
||||
scheme built for the quantum era, and finally about the public log that lets a
|
||||
stranger check all of it without trusting anyone.
|
||||
|
||||
\begin{itemize}[leftmargin=1.4em]
|
||||
\item \textbf{Do the exercises.} Reading a proof is like watching someone
|
||||
|
|
@ -106,8 +109,8 @@ then read --- in that order.
|
|||
The book is engineered for self-study, which makes it easy to teach
|
||||
from: every exercise carries an immediate pathway-then-answer solution,
|
||||
so contact hours can go to the parts that need a human --- discussing
|
||||
the discussion exercises (each chapter has one; they are the seminar
|
||||
seeds), pair-debugging the Lean files, and auditing real repositories
|
||||
the discussion exercises (Chapters 1, 7, 10, 11, and 13 carry one; they
|
||||
are the seminar seeds), pair-debugging the Lean files, and auditing real repositories
|
||||
together (Appendix~\ref{app:tour} is a ready-made lab session). Grading
|
||||
suggestion: collect the pen-and-paper worked examples \emph{reproduced
|
||||
from memory} rather than problem sets --- the book's bet is that a
|
||||
|
|
@ -117,11 +120,11 @@ Lean solution files compile against the pinned toolchain in the repo;
|
|||
\code{lake build Solutions} is your answer key's answer key. Prerequisites
|
||||
in practice: one programming course (any language) and comfort with
|
||||
high-school algebra; no number theory, no logic, no Rust. The
|
||||
thirteen-week plan below has been paced so the two hard climbs ---
|
||||
fourteen-week plan below has been paced so the two hard climbs ---
|
||||
Chapter~9 and the Interlude --- each get a full week with nothing else
|
||||
competing.
|
||||
|
||||
\subsection*{A thirteen-week plan}
|
||||
\subsection*{A fourteen-week plan}
|
||||
|
||||
For self-study or a seminar, the book paces naturally as a semester:
|
||||
|
||||
|
|
@ -142,7 +145,9 @@ For self-study or a seminar, the book paces naturally as a semester:
|
|||
10 & Interlude & the complete by-hand verification \\
|
||||
11 & Ch.~10--11 & audit drill on a stranger's repo \\
|
||||
12 & Ch.~12 + \code{Ch12.lean} & graduation: spec--refusal--fix--certificate \\
|
||||
13 & project & one open lemma or one solo bridge \\
|
||||
13 & Ch.~13 & the checksum see-saw + the cone table, from memory \\
|
||||
14 & Ch.~14 + project & a fifteen-minute independent log verification;\\
|
||||
& & then one open lemma or one solo bridge \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
|
@ -163,7 +168,8 @@ For self-study or a seminar, the book paces naturally as a semester:
|
|||
\input{chapters/ch10-verifying-a-field}
|
||||
\input{chapters/ch11-honesty-and-axioms}
|
||||
\input{chapters/ch12-the-pyramid}
|
||||
\input{chapters/ch13-attestation-protocol}
|
||||
\input{chapters/ch13-second-summit}
|
||||
\input{chapters/ch14-attestation-protocol}
|
||||
|
||||
\appendix
|
||||
\input{chapters/appendix-toolkit}
|
||||
|
|
|
|||
Loading…
Reference in a new issue