Formally prove the correctness of Sqrt.sol and Cbrt.sol#511
Open
duncancmt wants to merge 94 commits intodcmt/newton-raphson-optimizationfrom
Open
Formally prove the correctness of Sqrt.sol and Cbrt.sol#511duncancmt wants to merge 94 commits intodcmt/newton-raphson-optimizationfrom
duncancmt wants to merge 94 commits intodcmt/newton-raphson-optimizationfrom
Conversation
Machine-checked proof that _sqrt converges to within 1 ULP of isqrt(x) for
all uint256 inputs, and that the floor-correction step yields exactly isqrt(x).
Proof structure (zero sorry, no Mathlib):
- FloorBound.lean: Each truncated Babylonian step >= isqrt(x) (AM-GM +
integrality). Absorbing set {isqrt, isqrt+1} is preserved.
- StepMono.lean: Step is non-decreasing in z for overestimates (z^2 > x),
justifying the max-propagation upper-bound strategy.
- SqrtCorrect.lean: Definitions matching EVM semantics, native_decide
verification of all 256 bit-width octaves, lower bound chain through 6
steps, and floor correction proof.
Also includes verify_sqrt.py, the Python prototype that guided the Lean proof.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Proves the cubic AM-GM inequality (3m-2z)*z^2 <= m^3 and the resulting floor bound: a single truncated Newton-Raphson step for cube root never undershoots icbrt(x). This is the core mathematical lemma needed for the full cbrt convergence proof. Key technique: the witness identity m^3 - (3m-2z)*z^2 = (m-z)^2*(m+2z) is proved by expanding both sides via simp [add_mul, mul_add, mul_assoc, mul_comm, mul_left_comm] then closing with omega -- a 4-line ring-substitute that works without Mathlib. Also includes verify_cbrt.py (Python convergence prototype) and updates the formal/ README to track both sqrt (complete) and cbrt (in progress). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds CbrtCorrect.lean with full convergence and correction proofs: - native_decide verification of all 256 bit-width octaves - Lower bound chain through 6 NR iterations (icbrt(x) <= _cbrt(x)) - Floor correction proof (cbrt returns exactly icbrt(x)) - Seed and step positivity invariants Combined with the cubic AM-GM floor bound from the previous commit, this gives a complete machine-checked proof that Cbrt.sol is correct for all uint256 inputs (0 sorry, no Mathlib). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prove `innerCbrt x ≤ icbrt x + 1` unconditionally for all x < 2^256,
completing the end-to-end formal verification of Cbrt.sol.
The proof uses a per-octave finite certificate scheme (cribbed from the
sqrt proof):
- FiniteCert.lean: 248-entry lookup tables with native_decide proofs
of error bounds d1..d6 ≤ 1 for octaves 8..255
- CertifiedChain.lean: chains 6 NR steps through the error recurrence
d_{k+1} = d_k^2/lo + 1, using an analytic d1 bound derived from the
cubic identity m^3+2s^3-3ms^2 = (m-s)^2(m+2s)
- Wiring.lean: maps x to its certificate octave and produces the
unconditional theorems floorCbrt_correct_u256 and
floorCbrt_correct_u256_all
Zero sorry. Full project builds with `lake build`.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add .github/workflows/cbrt-formal.yml patterned after sqrt-formal.yml: generates FiniteCert.lean from generate_cbrt_cert.py then runs lake build - Remove FiniteCert.lean from git tracking (auto-generated, like sqrt's GeneratedSqrtModel.lean) and add to .gitignore - Add --output flag to generate_cbrt_cert.py for CI usage - Rewrite README.md with full proof architecture, end-to-end verify instructions, and file inventory Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the final layer that formally links the Solidity implementation to the proven-correct mathematical spec: - generate_cbrt_model.py: parses Cbrt.sol assembly and emits EVM-faithful and normalized Nat Lean models of _cbrt, cbrt, cbrtUp (forked from the sqrt analog) - GeneratedCbrtSpec.lean (1015 lines, 0 sorry): proves - model_cbrt_evm = model_cbrt on uint256 (no overflow) - model_cbrt = innerCbrt (Nat model matches hand-written spec) - model_cbrt_floor_evm_correct: EVM floor model = icbrt - model_cbrt_up_evm_upper_bound: EVM ceiling model rounds up correctly - Updated CI to generate model from Cbrt.sol before building - Updated README with full end-to-end verification instructions The proof is now end-to-end: from Cbrt.sol Solidity assembly through auto-generated Lean model to machine-checked correctness on uint256. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2 tasks
Prove that 6 Babylonian steps from the fixed seed (floor(sqrt(2^255))) give a 1-ULP bracket for natSqrt(x) when x ∈ [2^254, 2^256), and that floor correction gives exactly natSqrt(x). This is the mathematical foundation for bridging model_sqrt512_evm to natSqrt. The main EVM bridge theorem is stated but sorry'd pending mechanical EVM bridge sub-lemmas (normalization, Newton, Karatsuba, correction). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Factor the main theorem into model_sqrt512_evm_eq_sqrt512 (sorry'd EVM bridge showing the model matches the algebraic sqrt512 spec) composed with sqrt512_correct (already fully proved). This isolates the remaining work to showing each EVM phase (normalization, Newton, Karatsuba, correction, denormalization) matches the algebraic spec. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Split model_sqrt512_evm_eq_sqrt512 into three sorry'd pieces: - evm_normalization_bridge: EVM bit-shifts = multiply by 4^shift - evm_compute_bridge: EVM Newton+Karatsuba+correction = karatsubaFloor - composition: threading the bridge results through the model The main theorem model_sqrt512_evm_correct is fully proved assuming these bridges, via sqrt512_correct. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove failed decomposition attempts that hit kernel deep recursion (the model's shared let bindings prevent naive term decomposition). The single remaining sorry (model_sqrt512_evm_eq_sqrt512) captures the full EVM-to-algebraic bridge. The main theorem composition model_sqrt512_evm_correct is fully proved via sqrt512_correct. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restructure the 512-bit sqrt EVM bridge proof into well-defined layers: - Section 5: Norm model helpers — prove normStep_eq_bstep (Babylonian step in the unbounded norm model = bstep), normFloor_correction, and chain them to show norm_inner_sqrt_eq_natSqrt on normalized [2^254, 2^256) inputs. - Section 6: Norm→sqrt512 bridge — decomposes into normalization, inner sqrt (proved via floorSqrt_fixed_eq_natSqrt), Karatsuba quotient with carry, correction, and un-normalization. Single sorry remaining. - Section 7: EVM→norm bridge — proves individual op equivalences: evmSub_eq_of_le, evmAdd_eq_of_bounded, evmShl_eq_normShl (with v*2^s bound), evmShr_eq_of_small, plus the critical overflow cancellation lemma evmSub_evmAdd_eq_of_overflow showing EVM overflow+underflow at the combine step (r=2^256) produces the same result as unbounded Nat. Single sorry remaining for threading these through the full let-chain. Reduces total sorry count from 5 to 2 (model_sqrt512_norm_eq_sqrt512 and model_sqrt512_evm_eq_norm). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The norm model (model_sqrt512) uses unbounded normShl/normMul which don't match EVM uint256 semantics, making the old factorization (EVM → norm → sqrt512) unprovable. Restructure to prove model_sqrt512_evm = sqrt512 directly via 3 sub-lemmas: A. EVM normalization produces correct normalized words B. EVM inner sqrt gives natSqrt (reuses convergence certificate) C. EVM Karatsuba + correction + un-normalization = karatsubaFloor / 2^k Reduces from 2 false sorry's to 4 true sorry's (3 sub-lemmas + assembly). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add evm_bstep_eq showing each EVM Babylonian step equals bstep when z ∈ [2^127, 2^129) and x < 2^256 (sum doesn't overflow). Chain 6 steps to show EVM inner sqrt matches norm inner sqrt. Two sub-sorry's remain: - bstep lower bound (AM-GM: bstep ≥ sqrt(x) ≥ 2^127) - floor correction matching (evmSub/evmLt = normSub/normLt on bounded inputs) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Close the EVM inner sqrt proof by: - Using babylon_step_floor_bound for the lower bound (2^127 ≤ bstep) - Showing evmSub/evmLt/evmDiv = their Nat counterparts on bounded inputs - Chaining through correction_correct for the floor correction step Remaining 3 sorry's: normalization (A), Karatsuba+correction (C+D), assembly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix 5 build errors: - evm_bstep_eq: rewrite evmDiv before evmAdd (goal has evmDiv not x/z) - evm_bstep_eq: fix sum bound proof (avoid Nat.pow_succ, use omega) - evm_bstep_eq: fix upper bound (use omega instead of Nat.div_lt_div_right) - evm_inner_sqrt_eq_natSqrt: use set/rw instead of simp only to avoid massive term expansion; name intermediates with set, rewrite step by step - evmShl_eq': remove unused Nat.shiftLeft_eq from simp Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Build succeeds with 4 sorry's decomposing the EVM bridge: A. evm_normalization_correct — EVM normalization gives x*4^k/2^256 B. evm_inner_sqrt_eq_natSqrt — EVM Babylonian steps = natSqrt C+D. evm_karatsuba_correction_unnorm — Karatsuba + correction + unnorm main. model_sqrt512_evm_eq_sqrt512 — assembly of A+B+C+D Helper evm_bstep_eq is fully proved (no sorry). Reduced from 2 false sorry's to 4 true, well-defined sorry's. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract _innerSqrt, _karatsubaQuotient, _sqrtCorrection from _sqrt in 512Math.sol. Extend yul_to_lean.py to support multi-return functions (tuple types, __component_N projections). The pipeline now generates 4 separate Lean models instead of one monolithic ~30-binding term, making each sorry sub-lemma target ~2-10 let-bindings. All private sub-functions are inlined by solc → identical bytecode. Fuzz test (1000 runs) confirms the regenerated Lean model matches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prove model_innerSqrt_evm_correct by factoring through norm model: - model_innerSqrt_snd_def: residue = x - fst^2 (by rfl) - model_innerSqrt_snd_eq_residue: norm residue = x - natSqrt(x)^2 - model_innerSqrt_evm_correct: both components correct (uses evm_eq_norm) Add helper theorems natSqrt_lt_2_128 and natSqrt_ge_2_127 for bounds. Remaining sorry: model_innerSqrt_evm_eq_norm (EVM ops = norm ops on bounded inputs, ~10 let-bindings via evm_bstep_eq chain). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract `_bstep` as a separate Solidity function so the Lean model generator produces `model_bstep_evm` calls instead of inlining 6 copies of `evmShr(1, evmAdd(r, evmDiv(x, r)))`. This makes each Babylonian step independently provable via `model_bstep_evm_eq_bstep`. Gas unchanged (solc inlines private pure functions): μ 3549→3549. Prove `model_innerSqrt_evm_eq_norm` by: - Chaining 6 `model_bstep_evm_eq_bstep` applications (each gives equality + [2^127, 2^129) bounds for the next step) - Showing the correction `evmSub z6 (evmLt (evmDiv x z6) z6)` matches `normSub z6 (normLt (normDiv x z6) z6)` via `correction_correct` - Showing the residue `evmSub x (evmMul r r)` matches `normSub x (normMul r r)` since r = natSqrt(x) < 2^128 so r^2 < 2^256 Remaining sorry's: 3 (karatsubaQuotient, sqrtCorrection, composition) plus 1 pre-existing normalization proof broken by Lean v4.28 API changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite the normalization proof to handle Lean 4.28 breaking changes: - Nat.add_mul_mod_self → Nat.add_mul_mod_self_right - Nat.mul_div_mul_left pattern matching changed - Nat.mul_lt_mul → Nat.mul_lt_mul_of_le_of_lt - ring tactic unavailable (Mathlib-only) - set tactic unavailable (Mathlib-only) Key structural fix: avoid `intro` for let-bindings (which creates opaque defs that rw/simp can't penetrate in Lean 4.28). Instead use `show` to inline all let-bindings upfront, then `intro` only for variables that need case-splitting. Case-split on dbl_k = 0 (where evmShr 256 returns 0 since 256 ≥ 256) vs dbl_k > 0 (where evmShr (256 - dbl_k) works normally). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… 2 sorrys Close the Karatsuba quotient EVM bridge (sorry 2/4 → proved): - Handle no-carry case (res < 2^128): n_evm = n_full directly - Handle carry case (res >= 2^128): correction via WORD_MOD = d*qw + rw + 1 - Change hypothesis from res <= 2*natSqrt(...) to res <= 2*r_hi Revise model_sqrtCorrection_evm_correct spec to raw EVM bridge form: - Result = r_hi*2^128 + r_lo - cmp (where cmp is 257-bit comparison) - Add hypotheses: r_lo <= 2^128, rem < 2*r_hi, hedge condition - Scaffold EVM simplification (constant folding, all ops reduced to Nat) Add helper lemmas: - mul_mod_sq: (a*n) % (n*n) = (a%n)*n - mul_pow128_mod_word: (a*2^128) % 2^256 = (a%2^128)*2^128 - div_of_mul_add / mod_of_mul_add: Euclidean division after recomposition Remaining: 2 sorrys (sqrtCorrection comparison logic, composition proof) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4-way case split on rem/2^128 ∈ {0,1} × r_lo/2^128 ∈ {0,1}:
- (0,0): comparisons match directly, no EVM overflow
- (0,1): r_lo=2^128, cmp=1, handle evmAdd overflow via evmSub_evmAdd_eq_of_overflow
- (1,0): cmp=0, rem*2^128 ≥ 2^256 > r_lo^2
- (1,1): contradiction via hedge
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Close the last sorry by proving the EVM model of 512-bit sqrt equals the algebraic sqrt512 function. The proof decomposes into: - evm_composition_eq_karatsubaFloor: composition of the three EVM sub-models (innerSqrt, karatsubaQuotient, sqrtCorrection) equals karatsubaFloor on normalized inputs. Uses the Karatsuba algebraic identity x + q² = r² + rem·H + x_lo_lo via correction_equiv. - karatsubaFloor_lt_word: result fits in 256 bits, via karatsubaFloor_eq_natSqrt and natSqrt upper bound. - Main theorem assembly: unfold model_sqrt512_evm, rewrite the composition to karatsubaFloor, then convert evmShr to division. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace all 21 native_decide calls with decide (using maxRecDepth for deep convergence certificates and Fin 256 enumeration). Fix 6 unused variable/simp warnings. Axiom set now minimal: propext, Classical.choice, Quot.sound. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ex-prove-sqrt-cbrt
The Solidity helper functions in 512Math.sol were renamed: _bstep → _sqrt_babylonianStep _innerSqrt → _sqrt_baseCase _karatsubaQuotient → _sqrt_karatsubaQuotient _sqrtCorrection → _sqrt_correction Update generate_sqrt512_model.py to reference the new Solidity names while preserving the Lean model names (model_bstep, model_innerSqrt, etc.) so downstream proofs remain stable. Fix two proofs in GeneratedSqrt512Spec.lean to accommodate the slightly different generated model (double-AND shift wrapping and reversed operand order in addition from the new compiler output). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tructure - Add formal/sqrt/generate_sqrt_cert.py that generates FiniteCert.lean with SqrtCert (256 octaves) and Sqrt512Cert (fixed-seed certificates for octaves 254/255), replacing the hand-written FiniteCert.lean and inline certificate definitions in GeneratedSqrt512Spec.lean. - Refactor model_innerSqrt_evm_eq_norm: extract shared bstep chain and correction logic into evm_innerSqrt_pair, eliminating ~100 lines of duplicated proof code across the .1/.2 components. - Update CI: sqrt-formal.yml and sqrt512-formal.yml now generate the certificate before building, and sqrt512-formal.yml builds proofs (not just the model evaluator), matching sqrt/cbrt patterns. - Consolidate formal READMEs into a single formal/README.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Solc 0.8.33 emits `and(and(1,255),255)` type-cleanup wrappers around shift amounts and may reorder commutative operands in the Yul IR for `_sqrt_babylonianStep`. Update the `model_bstep_eq_bstep` and `model_bstep_evm_eq_bstep` proofs to constant-fold the nested AND back to 1 and handle the `add(div(x,z),z)` vs `add(z,div(x,z))` reordering. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Lake warns about a missing manifest when the SqrtProof dependency is resolved during a fresh CI checkout. Track the file in git so it is present at clone time. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.