Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/blockchain/state_transition/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,8 +503,8 @@ pub fn slot_is_justifiable_after(slot: u64, finalized_slot: u64) -> bool {
/// funnel votes towards only some slots, increasing finalization chances.
///
/// When the `lean-ffi` feature is enabled, this calls the formally verified
/// Lean4 implementation via FFI. The Lean implementation has been proven correct
/// for all natural numbers (see `formal/EthLambda/Justifiability/`).
/// Lean4 implementation via FFI. Its equivalence theorem covers deltas below
/// `2^62`, the range where the pronic discriminant fits in `u64`.
///
/// Without the feature, uses the native Rust implementation.
#[cfg(not(feature = "lean-ffi"))]
Expand Down
10 changes: 7 additions & 3 deletions formal/EthLambda/Justifiability.lean
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@ def isqrt (n : UInt64) : UInt64 :=
-- r+1 ≤ n/(r+1) ↔ (r+1)*(r+1) ≤ n (when r+1 > 0)
if r + 1 <= n / (r + 1) then r + 1 else r

/-- Computable justifiability check mirroring the Rust implementation. -/
/-- Computable justifiability check mirroring Rust's checked arithmetic.
The pronic discriminant is evaluated only when `4 * delta + 1` fits in
`UInt64`; otherwise that branch returns `false`. -/
def justifiable (delta : UInt64) : Bool :=
delta <= 5
|| isqrt delta ^ 2 == delta
|| (let val := 4 * delta + 1
isqrt val ^ 2 == val && val % 2 == 1)
|| if delta <= 4611686018427387903 then
let val := 4 * delta + 1
isqrt val ^ 2 == val && val % 2 == 1
else false

/-- Full slot-level function matching the Rust `slot_is_justifiable_after` API. -/
def slotIsJustifiableAfter (slot finalizedSlot : UInt64) : Bool :=
Expand Down
1 change: 1 addition & 0 deletions formal/EthLambdaProofs/Justifiability.lean
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ import EthLambdaProofs.Justifiability.Classification
import EthLambdaProofs.Justifiability.Infinite
import EthLambdaProofs.Justifiability.Density
import EthLambdaProofs.Justifiability.ImplEquivalence
import EthLambdaProofs.Justifiability.Regression
9 changes: 8 additions & 1 deletion formal/EthLambdaProofs/Justifiability/ImplEquivalence.lean
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,12 @@ private lemma uint64_sq_toNat (a : UInt64) (ha : a.toNat < 2 ^ 32) :
theorem justifiable_equiv (d : UInt64) (h : d.toNat < 2 ^ 62) :
justifiable d = true ↔ Justifiable d.toNat := by
rw [justifiable_iff]
have hguard : d ≤ 4611686018427387903 := by
apply UInt64.le_iff_toNat_le_toNat.mpr
have hlimit : (4611686018427387903 : UInt64).toNat = 2 ^ 62 - 1 := by
decide
rw [hlimit]
omega
-- Bounds for 4 * d + 1 not overflowing
have hval_nat : (4 * d + 1).toNat = 4 * d.toNat + 1 := by
have h4_eq : (4 : UInt64).toNat = 4 := by decide
Expand All @@ -427,7 +433,8 @@ theorem justifiable_equiv (d : UInt64) (h : d.toNat < 2 ^ 62) :
simp [UInt64.toNat_one]
-- Unfold justifiable and convert Bool to Prop
unfold justifiable
simp only [Bool.or_eq_true, Bool.and_eq_true, decide_eq_true_eq, beq_iff_eq]
simp only [hguard, ↓reduceIte, Bool.or_eq_true, Bool.and_eq_true,
decide_eq_true_eq, beq_iff_eq]
-- The let binding in justifiable introduces `val := 4 * d + 1`; after simp, it becomes
-- direct UInt64 expressions that we can rewrite with our bridge lemmas
constructor
Expand Down
28 changes: 28 additions & 0 deletions formal/EthLambdaProofs/Justifiability/Regression.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/-
Copyright (c) 2026 ethlambda contributors. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
-/
import EthLambda.Justifiability

/-!
# Fixed-Width Arithmetic Regression

The pronic discriminant for this value overflows UInt64. Rust uses checked
arithmetic, so the Lean FFI implementation must reject it as well.
-/

/-- `4 * delta + 1` would wrap to `9` under unchecked UInt64 arithmetic. -/
example : justifiable 4611686018427387906 = false := by
decide

/-- The largest delta whose pronic discriminant fits remains evaluable. -/
example : justifiable 4611686018427387903 = false := by
decide

/-- Perfect-square detection remains valid at the first overflowing-pronic delta. -/
example : justifiable 4611686018427387904 = true := by
decide

/-- Values above the checked-pronic range do not wrap into false positives. -/
example : justifiable 18446744073709551615 = false := by
decide