Commit graph

19 commits

Author SHA1 Message Date
8e52a449dc Double-scalar-mul enters the verified model: vartime_double_base extracted transparently
extract.sh now opens crate::backend::serial::scalar_mul::vartime_double_base
(the other scalar_mul strategies stay opaque): non_adjacent_form (with its
loops), NafLookupTable5 (from/select), the curve-model helpers and
vartime_double_base::mul itself land in gen/CurveField - the same
namespace as the proven edwards operations, so the coming double-and-add
induction can consume EdDouble/EdAddProjNiels/EdConvert directly.
Zero sorries, zero external axioms (the pinned sources carry documented
compat refactors: single-assignment loop helpers, param-rooted while,
always-256-iterations, index-based LE load).

Full check.sh pressed fresh over the regenerated model: every existing
field and group-law certificate still green and axiom-clean - the scope
extension is purely additive.
2026-07-04 11:48:51 +02:00
3a10206600 Hash-to-scalar PROVEN: from_bytes_wide_spec - Scalar::from_hash's reduction is exact mod l
The apex brick of the scalar layer: for any 64 bytes (the opaque SHA-512
digest), [from_bytes_wide bytes] = (LE 512-bit value) mod l, with
canonical 52-bit-bounded output. Composition: bytes_unpack_spec (8x8
loops) -> split_words_lo/hi_spec (exact div/mod per limb, disjoint ORs
as additions) -> wide_split_telescope (isolated omega) -> montgomery_mul
by R and RR (R cancels as a unit, RR restores it) -> the canonical add.

The two kernel-capacity walls found and crossed en route (control repo
FAILURES.md updated):
- a montgomery_mul inside any walk motive replays its 400-line body at
  every kernel step (fix: named prefix functions in the pinned source);
- straight-line IndexMut closure chains make kernel defeq exponential in
  depth (fix: struct-literal construction - the split halves now build
  Scalar52([...]) directly). Full certificate: 77 s kernel-inclusive.

Regenerated gen (sources factor from_bytes_wide -> from_bytes_wide_parts
-> split_words_lo/hi; documented pure refactors, cargo-checked).
check-scalar.sh: 13 proof files, 13 kernel audits, all exactly
[propext, Classical.choice, Quot.sound]. Button pressed fresh: green.
2026-07-04 10:31:32 +02:00
e5f8982e84 chore: remove stray telescope probe file (never wired into the button) 2026-07-04 04:33:50 +02:00
6aa4f39328 Signature layer: the 64-byte unpack certificates (8x8 loops proven)
Toward Scalar::from_hash: bytes_unpack_spec proves the from_bytes_wide
word-unpack loops pack 64 little-endian bytes into 8 words exactly.

- Proofs/ScalarBytesSpec.lean (3308 lines): bytes_word_loop_spec_0..7,
  each split head/tail at j=4 (the 8-fold monolith grows exponentially
  in elaboration - METHOD 4). Disjoint-bit ORs become additions via
  core's Nat.two_pow_add_eq_or_of_lt with explicit calc bridges (the
  default simp set literalizes 2^8 -> 256 and breaks pow-form rewrites;
  simp only everywhere).
- Proofs/ScalarUnpackSpec.lean: bytes_unpack_spec composes the eight
  inner lemmas through the outer loop (iterator start needs a term-level
  equality rewrite per peel).

The from_bytes_wide main walk itself is proven at elaboration level
(fail-probe verified end to end) but its single-decl kernel certificate
replays >30min; it ships next as a phase-split (plan in the control
repo's method notes). check-scalar.sh: 12 proof files, 12 kernel audits,
all exactly [propext, Classical.choice, Quot.sound]. Button green.
2026-07-04 03:00:42 +02:00
d08a6e1890 Signature layer, first bricks: canonicity closure + hash-to-scalar foundation
Canonicity pass (the layer is now closed under its own preconditions):
- sub_val_spec post carries the exact value equation
  (exists beta <= 1, scVal r + scVal b = scVal a + ell*beta, with the
  underflow guard beta = 1 -> scVal a < scVal b)
- add/montgomery_reduce/mul/aggregate posts all carry scVal r < ell:
  canonical inputs give canonical outputs everywhere. Needed because
  from_bytes_wide (hash-to-scalar) feeds Montgomery outputs into add.

Hash-to-scalar foundation (toward Scalar::from_hash / EdDSA verify):
- extraction scope + from_bytes_wide (brings constants::R); regenerated gen
- source repos carry a documented Aeneas-compat patch: the bare
  `hi[4] = words[7] >> 20` extracts ill-typed at pin bf13c42e; masked
  (semantic no-op, words[7] >> 20 < 2^44)
- Proofs/ScalarWideSpec.lean: R constant lemmas (R = 2^260 mod ell,
  witness 2^260 = R + 255*ell) and montgomery_mul_spec, the single
  Montgomery round: [r]*2^260 = [a]*[b], canonical bounded output

check-scalar.sh: 10 proof files, 11 kernel audits, all exactly
[propext, Classical.choice, Quot.sound]. Button pressed fresh: green.
2026-07-03 23:18:29 +02:00
a6b6e86865 Scalar layer complete: Montgomery reduction + full mul proven, scalarImplementation aggregate
Phase B - montgomery_reduce (Proofs/ScalarMontSpec.lean + Proofs/ScalarReduceSpec.lean):
- mont_key: LFACTOR*L0 + 1 = 214835089243030*2^52 (the -1 inverse identity, norm_num)
- mont_cancel: (s + ((s*LFACTOR) % 2^52)*L0) % 2^52 = 0 via Nat.ModEq - every
  part1 shift is an EXACT division, nothing discarded
- part1_spec / part2_spec: per-round helpers (carry*2^52 = sum + p*L0; exact split)
- mont_head_telescope (E0-E4) and mont_tail_telescope (E5-E8): linear_combination
  certificates with weights 2^52k; mont_bound: X' < 2*ell from Z < 2^260*ell
- montgomery_reduce_spec: post `scDenote r * 2^260 = Z` in ZMod ell + 52-bit bounds.
  METHOD-4 split at the round-4/5 boundary: the 74-step monolith is
  elaboration-pathological; each half compiles in ~25s/3GB.
- The single death-spiral line: an omega for the nonce-sum bound with ~110
  hypotheses in context never returns; extracted to nonce_sum_bound (5 hypotheses,
  instant). Bisected with fail-probes; documented in control-repo FAILURES.md.

Phase C - mul (Proofs/ScalarFullMulSpec.lean):
- RR_limbs/RR_scVal/RR_lt; RR_denote: RR = 2^520 - K*ell kernel-checked, so
  ⟦RR⟧ = R^2; R_isUnit: 2^260 unit of ZMod ell (coprime oddness witness)
- mul_spec: mul_internal -> montgomery_reduce -> mul_internal(*, RR) ->
  montgomery_reduce composed; column values folded by `ring`; R cancelled via
  IsUnit.mul_right_cancel. Hypothesis scVal a * scVal b < 2^260*ell (honest
  Montgomery bound; canonical inputs satisfy it).

Aggregate (Proofs/ScalarMain.lean): scalar_add/sub/mul_correct on ScBnd
interfaces + canonical_mul_bound + scalarImplementation bundling all three.

sub_val_spec/add_val_spec posts strengthened with result-limb 52-bit bounds
(the montgomery tail feeds sub's output back into mul_internal).

check-scalar.sh: 9 proof files, 10 kernel audits (was 6), all exactly
[propext, Classical.choice, Quot.sound]. Button pressed fresh: green.
2026-07-03 21:06:15 +02:00
0120fe971a scalar layer: mul_internal proven — Montgomery frontier phase A down
Proofs/ScalarMulSpec.lean (axiom-clean, no sorry):
- m_spec: the widening 52x52->104-bit product helper — total, exact
- mul_internal_spec: all NINE schoolbook column sums proven exact
  (z_k = sum_{i+j=k} a_i*b_j) and bounded (each product < 2^104, each
  column < 2^107) through the 60-step straight-line extraction

This is the half of Scalar52::mul that the kernel-capacity frontier does
NOT touch. Phase B — montgomery_reduce (74 steps, part1/part2, the
Montgomery invariant result = input * R^{-1} mod l with R = 2^260, and
the double-round composition through RR) — remains the open frontier,
now precisely one function wide.

check-scalar.sh: ScalarMulSpec in manifest + audit (6/6 clean), green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 18:56:04 +02:00
5fade418de scalar layer: Scalar52::add FULLY proven mod l (add_val_spec)
Proofs/ScalarAddSpec.lean, axiom-clean, no sorry:
- add_loop_spec: the 5-limb carry loop unrolled (same skeleton as the
  proven conditional-add-L chain, with b's limbs in place of L's
  constants); per-limb equations r_i + 2^52*g_(i+1) = a_i + b_i + g_i.
- add_val_spec: denote(add a b) = denote a + denote b in ZMod l for
  limb-bounded canonical inputs. Composition: add_telescope lifts the
  carry equations to scLimbs sum + 2^260*g5 = scVal a + scVal b;
  canonicity (a,b < l < 2^253) forces g5 = 0; the trailing sub(sum, L)
  goes through sub_val_spec with subtrahend L — enabled by weakening
  sub_val_spec's hypothesis from scVal b < l to scVal b <= l (the
  gamma5=1 forcing argument only needs <=), since scVal L = l exactly.
  denote L = 0 in ZMod l closes it.

check-scalar.sh: ScalarAddSpec in manifest + audit (5/5 clean), button
green at the re-budgeted 300s/4096MB caps.

With sub (previous commit): the scalar layer's + and - are both fully
verified against dalek's own extraction. Remaining: x3 fork port,
Montgomery mul/reduce (kernel frontier).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 18:02:38 +02:00
9479a2bcba re-budget scalar caps post-optimization; guard 3b (headroom clamp)
check-scalar.sh proofs phase back to 300s/4096MB: the sub_val_spec
assembly's true peak is 753MB after the atomic-scLimbs fix — the 8192 cap
was inflation left over from the slow draft and caused the 2026-07-03
swap-pressure incident (see control repo FAILURES.md). lean-guard updated
to master with Guard 3b. Button green at the honest budget, 4/4 audits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 17:51:14 +02:00
1766544daf scalar layer: Scalar52::sub FULLY proven mod l (sub_val_spec)
sub_val_spec closes the top-level two-clause value spec:
  denote(Scalar52.sub a b) = denote(a) - denote(b)   in ZMod l
for limb-bounded inputs with canonical subtrahend (scVal b < l).
Axiom-clean [propext, Classical.choice, Quot.sound]; no sorry.

The assembly documented-as-remaining last session is now done. Key resolutions:
- Applied the WP "spec_bind" rule manually instead of "step", and reduced the
  resulting "let (difference,borrow) := (dw,w)" Prod-let with an explicit
  "show" — this was the destructuring friction that blocked the earlier
  attempt (step's arity heuristics mis-typed the pair result).
- Inlined the subtle "Choice::from" identity (no step-spec, like csel_step).
- PERFORMANCE: kept "scLimbs" as opaque atoms in the gamma5=1 derivation
  instead of "unfold ... at *" — the unfold exploded omega with 2^52..2^260
  coefficients and blew past 600s; atomic form proves in ~1 min (METHOD 4,
  same kernel-cost discipline as the field layer).
- The 2^260 borrow-wrap and the +l conditional-add cancel in ZMod l:
  beta5=0 direct; beta5=1 forces top carry gamma5=1 from scVal b < l, closed
  by linear_combination over the two telescopes (sub_telescope, add_telescope).

check-scalar.sh: sub_val_spec in the manifest + Phase-3 audit (4/4 clean);
proof-phase caps raised to 600s/8192MB for the assembly; full button green.
exponentiation.threshold raised to 300 for the 2^260 literal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 17:27:23 +02:00
8a37ed7273 scalar layer: prove Scalar52::sub borrow + conditional-add-L carry chains
New in Proofs/ScalarSubSpec.lean (all axiom-clean [propext, Classical.choice,
Quot.sound], no sorry, no native_decide):
- nat_and_mask52 / nat_shift52 / nat_shift63 : 52/63-bit ops -> %,/
- sub_step_arith : isolated per-limb borrow accounting (tiny ℕ context,
  correction-on-the-left so no truncated subtraction) — the METHOD-4
  discipline that keeps 2^260-scale coefficients out of any one certificate
- sub_loop_spec : the FULL 5-limb borrow chain of Scalar52::sub, unrolled
  via loop_step/range_next_*; wrapping_sub, 52-bit mask store, borrow-out
  bit. This is the loop unroll that blocked the earlier attempt.
- csel_step : step-spec for the subtle conditional_select (faithful model)
- cond_add_l_zero_spec / cond_add_l_one_spec : BOTH cases of conditional
  add-of-L, full carry chains; the condition-1 case steps the addend as a
  clean value so the index_mut write-back matches sub_loop's pattern
- sub_telescope / add_telescope : the 2^52i-weighted value telescopes to
  2^260, discharged by omega (no kernel-capacity blowup)

check-scalar.sh: ScalarSubSpec added to the compile manifest; Phase-3 axiom
audit extended to sub_loop_spec + cond_add_l_one_spec (3/3 clean). Full
button green.

Honest boundary: top-level sub_val_spec (⟦sub a b⟧ = ⟦a⟧-⟦b⟧ in ZMod ℓ)
is documented as remaining — every lemma it needs is proven; what's left is
the Aeneas binding-arity for destructuring sub_loop_spec's pair-valued
multi-existential postcondition inside the do-block, a mechanical not a
mathematical gap. No sorry shipped (Invariants H1/H4).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 16:26:24 +02:00
5f785a75a3 coherence pass 2: restore the one-button property, institutionalize audits
- check.sh: proofs memory default 6144 -> 8192 (ReduceSpec's norm_num
  step peaks above 6144; guard aborted gracefully — R3 was broken, S1
  held). Matches pasta's calibration.
- check.sh: dead-file gate now exempts Scalar* (delegated to
  check-scalar.sh); the gate had been un-passable since the scalar layer
  landed, masked by the memory failure.
- check.sh: axiom-audit phase routed through lean-guard (cgroup + flock;
  was raw lean -M), audit temp file moved into the workspace (lake env
  rejects /tmp inputs — the /tmp phase had never run green).
- check-scalar.sh: NEW Phase 3 kernel axiom audit — ScalarProofs.L_val
  must report exactly [propext, Classical.choice, Quot.sound].
- README: signature layer ' planned' (was 'in progress' with nothing
  started); planned certificate names marked as such.

Validated: full check.sh + check-scalar.sh green end-to-end in the pass-2
sweep (see formal-verification-control/COHERENCE-PASS-2.md).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:54:26 +02:00
5eeaaad74a scalar: add ScalarLoop to the check manifest
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 21:56:40 +02:00
24a9fb653a scalar: generic loop-combinator lemmas (loop_step, range_next_lt/ge_spec)
Reusable infrastructure for the scalar Range-loop reductions (sub_loop,
add_loop, conditional_add_l). Re-stated standalone so scalar proofs stay
independent of the field gen tree. Compiles axiom-clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 21:47:47 +02:00
c4fbd063bd scalar layer: clean Scalar52 extraction + denotation foundation
extract-scalar.sh: function-level roots (add/sub/mul/square/montgomery_*)
yield a 28-def Scalar52 limb-arithmetic gen with ZERO iterator/byte/wrapper
entanglement — the byte-serialization and high-level Scalar wrapper (which
pull untranslatable chunks/zip iterators) are excluded by scoping, not faked.

Proofs/ScalarDenote.lean (compiles, axiom-clean): Ell = ℓ = 2^252+..., the
Scalar52 denotation ⟦·⟧ : Scalar52 → ZMod ℓ, the ScBnd 52-bit limb invariant,
and L_val — the transpiled constants::L denotes EXACTLY the group order ℓ
(kernel-checked, no native_decide).

add/sub (Range-loop conditional reductions, tractable — field-layer pattern)
and the Montgomery mul path (shares pasta's big-coefficient kernel limit) are
in progress. check-scalar.sh is green for the foundation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 21:13:43 +02:00
c81b26d9c2 lean-guard: disable core dumps (no more apport popups on capped aborts)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 16:23:30 +02:00
67f1b11730 controls: route all compiles through lean-guard (memory-capped, single-flight)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 16:10:55 +02:00
8ce599c4aa group-law layer: complete twisted Edwards addition law proven
Extraction widened to backend::serial::curve_models + edwards (own gen/,
209 defs). Adapted the reference Ed* proof suite: namespace rename +
Curve25519TraitsIdentity -> Curve25519_dalekTraitsIdentity. New opaque
externals (scalar_mul backends, get_selected_backend, decompress, sum,
from_slice) are axioms outside both certificate cones — verified by the
Phase-3 audit. All 21 proofs compile; field certificates unchanged.

Not claimed (matching the reference solution's honest scope): edAdd
associativity, scalar multiplication, decompress/compress, AVX2 backend.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 14:50:42 +02:00
b79375600f field layer: 14 proofs pass, fieldImplementation axiom-clean
Ported from the locally verified Hermes working copy; FeQ and Square2Spec
(dead files in the published replica) now compile and are in the check
manifest. check.sh gates: source integrity, stub audit, zero axiom
declarations under Proofs/, per-certificate axiom audit.

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