anza-ed25519-verified/verification/Proofs/ScalarLoop.lean
saymrwulf 962fa89e06 scalar layer: add+sub fully proven mod l (port from dalek, own extraction)
The solana fork's Scalar52 sub/add/conditional_add_l extract token-identical
to upstream dalek (only the crate namespace differs: curve25519 vs
curve25519_dalek), so ScalarSubSpec/ScalarAddSpec port with the namespace
adjustment and verify against THIS fork's own gen (R2). ScalarLoop
infrastructure included. check-scalar.sh at dalek parity: full manifest +
5/5 kernel axiom audit, green at 300s/4096MB.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 18:17:30 +02:00

62 lines
3.1 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/- ──────────────────────────────────────────────────────────────────────────────
Proofs/ScalarLoop.lean — generic loop-combinator lemmas for the scalar
layer's `for i in 0..5` reductions (sub_loop, add_loop, conditional_add_l).
These three lemmas are identical in statement to the field layer's
(Proofs/AddSpec.lean); they are about `Aeneas.Std.loop` and the transpiled
`core::iter::range` iterator, NOT about any field/scalar specifics, so they
are re-stated here to keep the scalar proofs independent of the field gen.
────────────────────────────────────────────────────────────────────────────── -/
import Proofs.ScalarDenote
open Aeneas Aeneas.Std Result ControlFlow
open curve25519
namespace ScalarProofs
open Aeneas.Std.WP
/-- Peel one iteration of the `Aeneas.Std.loop` fixed point under a `spec` goal. -/
theorem loop_step {α : Type u} {β : Type v}
{body : α → Result (ControlFlow α β)} {x : α} {post : β → Prop}
(h : body x ⦃ r => match r with
| .cont x' => Aeneas.Std.loop body x' ⦃ post ⦄
| .done y => post y ⦄) :
Aeneas.Std.loop body x ⦃ post ⦄ := by
obtain ⟨r, hr, hpost⟩ := spec_imp_exists h
rw [Aeneas.Std.loop.eq_def, hr]
cases r <;> simpa using hpost
/-- `Iterator::next` on a not-yet-finished `usize` range: yields `some start`
and advances `start`. -/
theorem range_next_lt_spec (r : core.ops.range.Range Usize)
(h : r.start.val < r.«end».val) :
core.iter.range.IteratorRange.next core.iter.range.StepUsize r
⦃ (o, r') => o = some r.start ∧ r'.start.val = r.start.val + 1 ∧
r'.«end» = r.«end» ⦄ := by
have hmax : r.start.val + 1 ≤ Usize.max := by scalar_tac
have hca := Usize.checked_add_bv_spec r.start 1#usize
unfold core.iter.range.IteratorRange.next
simp only [core.cmp.impls.PartialOrdUsize.lt,
core.clone.impls.CloneUsize.clone, core.iter.range.StepUsize.forward_checked,
liftFun1, liftFun2, bind_tc_ok]
simp only [h, decide_true, if_true]
cases hadd : Usize.checked_add r.start 1#usize with
| none => rw [hadd] at hca; simp at hca; scalar_tac
| some n =>
rw [hadd] at hca
simp at hca
simp [spec_ok, hca]
/-- `Iterator::next` on a finished `usize` range: yields `none`, range unchanged. -/
theorem range_next_ge_spec (r : core.ops.range.Range Usize)
(h : r.«end».val ≤ r.start.val) :
core.iter.range.IteratorRange.next core.iter.range.StepUsize r
⦃ (o, r') => o = none ∧ r' = r ⦄ := by
unfold core.iter.range.IteratorRange.next
simp only [core.cmp.impls.PartialOrdUsize.lt,
core.clone.impls.CloneUsize.clone, core.iter.range.StepUsize.forward_checked,
liftFun1, liftFun2, bind_tc_ok]
have : ¬ (r.start.val < r.«end».val) := by omega
simp [this]
end ScalarProofs