2026-11-01 — Stage 5: formal verification (Lean 4.35.0, core only, bv_decide)
Host: Apple M5 Max laptop, macOS 27, elan toolchain leanprover/lean4:v4.35.0
(Lean commit eb6cafb7, Lake 5.0.0). Project: formal/ (library Wp34, no Mathlib).
Command: cd formal && lake clean && lake build → exit 0, 32 s wall (log: formal/build.log).
Gate: tests/test_formal_lean.py (11 passed with WP34_LEAN_BUILD=1).
What was proven (all theorem, no sorry, no user axiom; see formal/README.md for the table)
- SHA-256 word identities (
Wp34/Sha256Words.lean, 2.5 s): optimisedCh/Majforms; GF(2)-linearity of Σ0, Σ1, σ0, σ1; injectivity of all four bybv_decide; explicit inverses (Σ0⁻¹, Σ1⁻¹ = XOR of 17 rotations each; σ0⁻¹, σ1⁻¹ = 32×32 GF(2) matrices computed byformal/scripts/gf2_rank.py), hence bijectivity of all four. Finding that contradicts the brief: σ0 and σ1 are bijective on 32 bits (rank 32, trivial kernel, no counter-example — the brief anticipated non-bijectivity and a counter-example). The controlsshr3_not_injectiveandsigma0_rotations_not_injectiveshow that each of the two summands of σ0 is singular while their sum is a unit. This is a known property of SHA-256. - Step bijection (
Wp34/Sha256Step.lean, 27 s):stepInv (step s k w) k w = sand the converse, plus the iterated version (steps_bijective: any number of rounds with known(K_t, W_t)is a bijection of the 256-bit state). - Message schedule (
Wp34/Schedule.lean):W_{t−16} = W_t − σ1(W_{t−2}) − W_{t−7} − σ0(W_{t−15})both as a one-liner onscheduleStepand on the well-foundedscheduledefinition. - 9-step linearised local collision (
Wp34/LocalCollision.lean): for two explicit linearisations of Ch/Maj (absorb: Ch = Maj = 0, Gilbert–Handschuh-style absorbing conditions;xor3: Ch = Maj = x⊕y⊕z, Chabaud–Joux-style), the full-value statementlin9 f s K W = lin9 f s K (W ⊕ corr δ)for alls, K, W, δ(864 bits), obtained from the difference-only version by the proven linearity oflin9. Correction vectors:absorb: (δ, Σ1δ⊕Σ0δ, Σ1Σ0δ, 0, δ, Σ0δ⊕Σ1δ, 0, 0, δ). The brief's sketch δW_{i+1} = Σ1(δ) is incomplete (the Σ0(δ) term coming from thearegister must be cancelled too). Negative control, machine-checked bydecide: the same corrections are not a collision of the real modular step (zero state, δ = 1);scripts/local_collision.pysees 0/20 000 random hits. - Abstract signatures (
Wp34/Group.lean): axiomatisedCyclicGroup G(all fields listed in the README); Schnorr correctnesss•G = R + e•Pfors = (k + e·d) mod n; ECDSA correctness; ECDSA malleability(r, s) ⟹ (r, n − s)with the modular inverse as an explicit witness andNatmodular arithmetic proven from core lemmas (sub_mul_sub_mod).
Trust base: Lean kernel + Lean compiler (the LRAT certificate checker runs natively; Lean 4.35
records each such use as an axiom <thm>._native.bv_decide.ax_…, listed by Wp34/Audit.lean in
build.log). CaDiCaL itself is not trusted. Non-SAT theorems (rotr_xor, all of Group.lean, the
decide counter-example) depend only on propext/Quot.sound/Classical.choice.
What failed and why
- Direct
bv_decideon every pure-parity goal timed out (10 s default; 240 s +acNfforSigma0Inv_Sigma0): inverse compositions (51 XOR terms per bit), linearity of the 17-rotation inverses, the 864-bit local-collision statements, thexor3difference version,corrXor3_xor. CDCL solvers have no XOR reasoning; these identities need Gaussian elimination, which we replaced by rewriting with proven linearity lemmas (rotr_xor,Sigma0_xor,linStep_xor_*) andac_rfl, plus SAT only on byte-restricted instances (8 free variables). - The direct 320-bit step-bijection goal timed out;
bv_omegaon the abstracted goal did not terminate (killed at 35 CPU-min). Resolution: abstract Σ0+Maj, Σ1, Ch and prove the two addition-chain lemmas (add4_sub4,sub4_add4, ~2 s each) by SAT — the "per-component split" the mandate anticipated. - 16-bit SAT splits produced ≈ 100 MB LRAT certificates each (
Sha256Words.oleanreached 1.3 GB); byte splits bring it to 31 MB..lake/is ≈ 470 MB after a clean build (certificates live in the oleans;Sha256Step.olean150 MB). - The Python→Lean handoff had no failures: every rank/inverse/correction vector computed in
Python was confirmed by
bv_decideordecideas stated.
Classification
All items: known_reproduced (none of these statements is new mathematics; the contribution is
the machine-checked status, the explicit sigma inverses, and the tractability map for bv_decide).
No conjecture is represented as a theorem: the Gilbert–Handschuh probability estimate and the
historical attributions are confined to comments and the README prose.
Artefacts
formal/ (Lake project, build.log, README.md, scripts/{gf2_rank,local_collision,aig_sizes}.py,
scripts/aig_sizes.tsv), tests/test_formal_lean.py. Note: the repository .gitignore ignores
*.log, so formal/build.log needs a !formal/build.log exception to be committed.