2026-07-22 22:00:53 +00:00
|
|
|
|
/- drafts/ChainSpec.lean — WIP: Algorithm 5 (chain) fidelity.
|
|
|
|
|
|
|
|
|
|
|
|
Goal: the extracted `chain_free` loop equals the explicit s-fold
|
|
|
|
|
|
application of the (opaque) hash F, with hash-address set to
|
2026-07-23 07:38:54 +00:00
|
|
|
|
i, i+1, …, i+s−1 in turn — ruling out off-by-one loop bounds, a wrong
|
|
|
|
|
|
address field, and wrong threading. F stays opaque (oracle.f), so a
|
|
|
|
|
|
finished certificate cone here is the three kernel axioms + oracle.f.
|
|
|
|
|
|
|
|
|
|
|
|
STATUS (2026-07-23): the two mathematically-substantive increment
|
|
|
|
|
|
lemmas are PROVEN and axiom-clean:
|
|
|
|
|
|
· u32_succ — the successful u32 index increment (start+1 = ok w).
|
|
|
|
|
|
· fwd_succ — the range iterator's `forward_checked start 1` = some w.
|
|
|
|
|
|
The one open front is `chain_step` (one loop step = one fold step): the
|
|
|
|
|
|
reduction is fully mechanised EXCEPT the final let-pair exposure. After
|
|
|
|
|
|
`simp only [… fwd_succ hwok]` the loop-body scrutinee is
|
|
|
|
|
|
`let (o,iter1) := (some start, {start:=w,end:=stop}); match o with …`
|
|
|
|
|
|
which neither `simp only` nor `dsimp` iota/zeta-reduces, so
|
|
|
|
|
|
`rw [match_ok_bind]` cannot see the underlying `bind` yet. NEXT TACTIC:
|
|
|
|
|
|
force the let-pair with full `simp` (it did reduce it in probing),
|
|
|
|
|
|
producing `match (do binds; ok (cont y)) with …`, THEN
|
|
|
|
|
|
`rw [match_ok_bind]; simp only [bind_assoc, bind_ok, hwok]; rfl`. The
|
|
|
|
|
|
fallback is the WP formulation (`loop.spec_decr_nat` + `spec_mono`, the
|
|
|
|
|
|
dalek loop-spec pattern), which sidesteps the raw match/bind plumbing.
|
|
|
|
|
|
Nothing here is claimed proven: this file carries sorries and lives in
|
|
|
|
|
|
drafts/, never in Proofs/ or check.sh.
|
meta-drill over the previous drill: one false claim caught, substance held
The prior post-flip drill itself ran in the suspect window, so this
pass re-executed every check independently.
CAUGHT (drill catch): the prior drill checked only the SUBJECT of
commit a2d8e5f and declared the message intact. The full body (%B)
shows a backticked fragment was eaten by bash command substitution
inside the double-quoted -m string: the body reads "exposing the
let-pair so" where it should read: exposing the let-pair
(o,iter1) := (some start, {start:=w,end:=stop}). No knowledge lost
(the committed ChainSpec header carries the full record, and now says
so explicitly); pushed history stays unrewritten per discipline.
HELD (all re-verified fresh, under lean-guard): worktree clean;
StepProbe absent from worktree and from ALL history; sorries exist
only in drafts/ChainSpec.lean (exactly 2, lines 83/103, zero errors);
check.sh references no draft and is GREEN; u32_succ / fwd_succ are
real statements (printed) and axiom-clean; match_ok_bind depends on
no axioms; local == remote.
Standing rules from this catch: (1) never put backticks in a
double-quoted git -m string - use -F with a quoted heredoc, as this
commit does; (2) a drill that verifies a commit message verifies %B,
never %s.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 09:07:03 +00:00
|
|
|
|
|
|
|
|
|
|
RECORD NOTE: commit a2d8e5f's message body lost one backticked fragment
|
|
|
|
|
|
to shell command-substitution (it reads "the let-pair so"); the intended
|
|
|
|
|
|
text was: the let-pair (o,iter1) := (some start, {start:=w,end:=stop}).
|
|
|
|
|
|
This header is the authoritative technical record.
|
2026-07-22 22:00:53 +00:00
|
|
|
|
-/
|
|
|
|
|
|
import SlhVerify.Funs
|
|
|
|
|
|
open Aeneas Aeneas.Std Result ControlFlow
|
|
|
|
|
|
open fips205
|
|
|
|
|
|
|
2026-07-23 07:38:54 +00:00
|
|
|
|
set_option maxHeartbeats 4000000
|
2026-07-22 22:00:53 +00:00
|
|
|
|
|
|
|
|
|
|
namespace fips205
|
|
|
|
|
|
|
2026-07-23 07:38:54 +00:00
|
|
|
|
/-- The successful u32 increment as a clean equation (no overflow). PROVEN. -/
|
|
|
|
|
|
theorem u32_succ {start : Std.U32} (hb : start.val + 1 < 2 ^ 32) :
|
|
|
|
|
|
∃ w : Std.U32, start + 1#u32 = ok w ∧ w.val = start.val + 1 := by
|
|
|
|
|
|
have he := Std.UScalar.add_equiv start (1#u32)
|
|
|
|
|
|
cases hc : start + 1#u32 with
|
|
|
|
|
|
| ok w =>
|
|
|
|
|
|
refine ⟨w, rfl, ?_⟩
|
|
|
|
|
|
rw [hc] at he
|
|
|
|
|
|
have : (1#u32 : Std.U32).val = 1 := by rfl
|
|
|
|
|
|
omega
|
|
|
|
|
|
| fail e =>
|
|
|
|
|
|
exfalso; rw [hc] at he; simp [Std.UScalar.inBounds] at he
|
|
|
|
|
|
have : (1#u32 : Std.U32).val = 1 := by rfl
|
|
|
|
|
|
omega
|
|
|
|
|
|
| div => rw [hc] at he; simp at he
|
|
|
|
|
|
|
|
|
|
|
|
/-- The range iterator's forward step, when start+1 succeeds. PROVEN. -/
|
|
|
|
|
|
theorem fwd_succ {start w : Std.U32} (hw : start + 1#u32 = ok w) :
|
|
|
|
|
|
U32.Insts.CoreIterRangeStep.forward_checked start 1#usize = ok (some w) := by
|
|
|
|
|
|
unfold U32.Insts.CoreIterRangeStep.forward_checked
|
|
|
|
|
|
have h1 : (1#usize : Std.Usize).val < 2 ^ 32 := by decide
|
|
|
|
|
|
simp only [h1, dif_pos]
|
|
|
|
|
|
have hone : Std.U32.ofNatCore (1#usize : Std.Usize).val h1 = (1#u32 : Std.U32) := by
|
|
|
|
|
|
apply Std.UScalar.eq_of_val_eq; rfl
|
|
|
|
|
|
rw [hone]
|
|
|
|
|
|
unfold Std.U32.checked_add core.num.checked_add_UScalar Option.ofResult
|
|
|
|
|
|
rw [hw]
|
post-flip drill over phase-2 window: all claims held; one doc upgrade
Re-verified from primary sources:
- THE DEEP CHECK: the three discharged u32 Step defs vs the PINNED
rustc's own library/core/src/iter/range.rs (nightly-2026-06-01,
u32 = narrower arm on 64-bit): forward/backward = try_from-then-
checked_{add,sub} (try_from succeeds iff n < 2^32), steps_between =
(0, None) iff start > end else saturated diff twice. Branch-for-
branch identical to the defs in FunsExternal.lean.
- commit scopes: bde63f5 = exactly the 3 axiom->def swaps; d6e4d93 =
only the new draft file.
- fresh audits: the u32 Step INSTANCE and each of the three defs are
axiom-clean ([propext(, Classical.choice, Quot.sound)]); check.sh
green fresh; draft compiles with exactly ONE sorry (line 65, succ
branch); base case genuinely closed.
- the 'dalek u32 Step axioms are vestigial' claim: confirmed — every
IteratorRange.next call site in dalek's gen uses StepUsize.
- remote heads match local everywhere.
Drill catch (documentation, not error): the loop increments the index
BEFORE each oracle call (forward_checked inside next, .panic on
overflow), the fold AFTER (add's overflow error) — equal only under
the theorem's start.val + s < 2^32 precondition, which is exactly why
that precondition exists. Now documented on chainFoldN so the
step-case prover discharges both increments from the bound and nobody
weakens it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 07:01:06 +00:00
|
|
|
|
|
2026-07-23 07:38:54 +00:00
|
|
|
|
/-- The outer match of `loop.eq_1` IS the Result bind (definitional). PROVEN. -/
|
|
|
|
|
|
theorem match_ok_bind {α β : Type} (m : Result α) (f : α → Result β) :
|
|
|
|
|
|
(match m with | ok r => f r | fail e => fail e | div => div) = m >>= f := rfl
|
|
|
|
|
|
|
|
|
|
|
|
/-- The mathematical chaining fold, threading the address exactly as the
|
|
|
|
|
|
extracted body does. See the EFFECT-ORDER NOTE: agreement holds precisely
|
|
|
|
|
|
under `start.val + s < 2^32`, which makes every intermediate increment
|
|
|
|
|
|
succeed. -/
|
2026-07-22 22:00:53 +00:00
|
|
|
|
noncomputable def chainFoldN {N : Std.Usize} (pk_seed : Slice Std.U8) :
|
|
|
|
|
|
types.Adrs → Array Std.U8 N → Std.U32 → Nat → Result (Array Std.U8 N)
|
|
|
|
|
|
| _, tmp, _, 0 => ok tmp
|
|
|
|
|
|
| adrs, tmp, start, (k+1) => do
|
|
|
|
|
|
let adrs1 ← helpers.Adrs.set_hash_address adrs start
|
|
|
|
|
|
let s ← lift (Array.to_slice tmp)
|
|
|
|
|
|
let tmp1 ← verify_mono.oracle.f N pk_seed adrs1 s
|
|
|
|
|
|
let start1 ← start + 1#u32
|
|
|
|
|
|
chainFoldN pk_seed adrs1 tmp1 start1 k
|
|
|
|
|
|
|
2026-07-23 07:38:54 +00:00
|
|
|
|
/-- One full loop step on a non-empty range = one fold step, tail as the
|
|
|
|
|
|
continuation loop. OPEN (see file header — let-pair exposure). -/
|
|
|
|
|
|
theorem chain_step {N : Std.Usize} (pk_seed : Slice Std.U8) (start stop : Std.U32)
|
|
|
|
|
|
(adrs : types.Adrs) (tmp : Array Std.U8 N)
|
|
|
|
|
|
(hlt : start.val < stop.val) (hb : start.val + 1 < 2 ^ 32) :
|
|
|
|
|
|
verify_mono.chain_free_loop { start := start, «end» := stop } pk_seed adrs tmp
|
|
|
|
|
|
= (do
|
|
|
|
|
|
let adrs1 ← helpers.Adrs.set_hash_address adrs start
|
|
|
|
|
|
let s ← lift (Array.to_slice tmp)
|
|
|
|
|
|
let tmp1 ← verify_mono.oracle.f N pk_seed adrs1 s
|
|
|
|
|
|
let start1 ← start + 1#u32
|
|
|
|
|
|
verify_mono.chain_free_loop { start := start1, «end» := stop } pk_seed adrs1 tmp1) := by
|
|
|
|
|
|
obtain ⟨w, hwok, _⟩ := u32_succ hb
|
|
|
|
|
|
have hd : decide (start.val < stop.val) = true := by simp [hlt]
|
|
|
|
|
|
conv_lhs => rw [verify_mono.chain_free_loop, loop.eq_1]
|
|
|
|
|
|
unfold verify_mono.chain_free_loop.body core.iter.range.IteratorRange.next
|
|
|
|
|
|
simp only [core.cmp.impls.PartialOrdU32.lt, hd, if_true, bind_tc_ok, bind_ok,
|
|
|
|
|
|
core.clone.impls.CloneU32.clone, fwd_succ hwok]
|
|
|
|
|
|
sorry
|
|
|
|
|
|
|
|
|
|
|
|
/-- The loop over [start, start+s) equals the s-step fold. Base case PROVEN;
|
|
|
|
|
|
succ case reduces to `chain_step` + the IH once `chain_step` closes. -/
|
2026-07-22 22:00:53 +00:00
|
|
|
|
theorem chain_free_loop_eq {N : Std.Usize} (pk_seed : Slice Std.U8) (s : Nat) :
|
|
|
|
|
|
∀ (start : Std.U32) (adrs : types.Adrs) (tmp : Array Std.U8 N),
|
|
|
|
|
|
start.val + s < 2 ^ 32 →
|
|
|
|
|
|
∀ (stop : Std.U32), stop.val = start.val + s →
|
|
|
|
|
|
verify_mono.chain_free_loop { start := start, «end» := stop } pk_seed adrs tmp
|
|
|
|
|
|
= chainFoldN pk_seed adrs tmp start s := by
|
|
|
|
|
|
induction s with
|
|
|
|
|
|
| zero =>
|
|
|
|
|
|
intro start adrs tmp _ stop hstop
|
2026-07-23 07:38:54 +00:00
|
|
|
|
have hse : start = stop := by apply Std.UScalar.eq_of_val_eq; omega
|
2026-07-22 22:00:53 +00:00
|
|
|
|
subst hse
|
|
|
|
|
|
unfold verify_mono.chain_free_loop chainFoldN
|
|
|
|
|
|
rw [loop.eq_1]
|
|
|
|
|
|
unfold verify_mono.chain_free_loop.body core.iter.range.IteratorRange.next
|
|
|
|
|
|
simp [core.cmp.impls.PartialOrdU32.lt]
|
|
|
|
|
|
| succ k ih =>
|
|
|
|
|
|
intro start adrs tmp hb stop hstop
|
|
|
|
|
|
have hlt : start.val < stop.val := by omega
|
2026-07-23 07:38:54 +00:00
|
|
|
|
have hb1 : start.val + 1 < 2 ^ 32 := by omega
|
|
|
|
|
|
rw [chain_step pk_seed start stop adrs tmp hlt hb1]
|
|
|
|
|
|
-- push the fold's step through, then apply ih at (w, stop, k)
|
2026-07-22 22:00:53 +00:00
|
|
|
|
sorry
|
|
|
|
|
|
|
|
|
|
|
|
end fips205
|