/- ────────────────────────────────────────────────────────────────────────────── Proofs/DsmMulSpec.lean — double-scalar-mul campaign, brick 4: the basepoint constant and the public `vartime_double_base::mul` spec. · `run_basepoint` — the transpiled ED25519_BASEPOINT_POINT is a VALID extended point ON THE CURVE denoting the standard base point B = (x_B, y_B), x_B = 15112…202, y_B = 46316…960 — kernel-checked literal arithmetic: the extended coherence X·Y = Z·T and the (121666-scaled, denominator-free) curve equation 121666·y² + 121665·x²y² ≡ 121666 + 121666·x² (mod p). A corrupted basepoint constant would be caught here. · `vartime_double_base_mul_spec` — THE PHASE-1 COMPUTATIONAL SPEC: for canonical scalars (byte values < 2^253) and a valid on-curve A, `mul a A b` returns a valid on-curve R with edPt R = dsmFold (digits of a) (digits of b) (edPt A) edBasePt edId 256 where both digit arrays are proven NAF encodings of the scalars' exact byte values (existentially exposed with their NafDigits + nafSum facts). Composes non_adjacent_form_spec ×2, dsm_top_index_spec, naf_table_spec ×2 (A and the basepoint), dsm_loop_spec, proj_as_extended_spec. Phase 2 (reading dsmFold as [a]A + [b]B in the group) requires Edwards associativity — deliberately deferred and documented; nothing here assumes it. ────────────────────────────────────────────────────────────────────────────── -/ import Proofs.DsmNafSpec open Aeneas Aeneas.Std Result ControlFlow open curve25519_dalek set_option maxHeartbeats 8000000 set_option linter.unusedSimpArgs false set_option maxRecDepth 8000 set_option exponentiation.threshold 600 namespace CurveFieldProofs open Aeneas.Std.WP /-- Generic mod-p witness → Fp product identity (abstract, no literal crunching during cast distribution). -/ theorem fp_mul_eq_of_witness (a b c : ℕ) (hmod : (a * b) % P = c % P) : (a : Fp) * (b : Fp) = (c : Fp) := by have h1 : ((a * b : ℕ) : Fp) = ((c : ℕ) : Fp) := by rw [← ZMod.natCast_mod, hmod, ZMod.natCast_mod] push_cast at h1 exact h1 /-- Generic 121666-scaled curve-equation witness → OnCurve (abstract x, y). -/ theorem onCurve_of_witness (x y : ℕ) (hmod : (121666 * (y * y) + 121665 * (x * x) * (y * y)) % P = (121666 + 121666 * (x * x)) % P) : OnCurve (x : Fp) (y : Fp) := by have h1 : ((121666 * (y * y) + 121665 * (x * x) * (y * y) : ℕ) : Fp) = ((121666 + 121666 * (x * x) : ℕ) : Fp) := by rw [← ZMod.natCast_mod, hmod, ZMod.natCast_mod] push_cast at h1 have h6 : (121666 : Fp) ≠ 0 := by have h : ((121666 : ℕ) : Fp) ≠ 0 := natCast_ne_zero_of_mod (by decide) simpa using h have hd := edD_char unfold OnCurve apply mul_left_cancel₀ h6 linear_combination h1 - (x : Fp)^2 * (y : Fp)^2 * hd /-- The standard Ed25519 base point, as ZMod literals. -/ noncomputable def edBasePt : Fp × Fp := ((15112221349535400772501151409588531511454012693041857206046113283949847762202 : Fp), (46316835694926478169428394003475163141307993866256225615783033603165251855960 : Fp)) /-- **The transpiled basepoint constant is the standard base point** — valid, on-curve, kernel-audited literal arithmetic. -/ theorem run_basepoint : ∃ B : EdPoint, backend.serial.u64.constants.ED25519_BASEPOINT_POINT = ok B ∧ ExtValid B ∧ OnCurveExt B ∧ edPt B = edBasePt := by -- the four coordinate denotations have hXv : ⟪(Array.make 5#usize [1738742601995546#u64, 1146398526822698#u64, 2070867633025821#u64, 562264141797630#u64, 587772402128613#u64] : backend.serial.u64.field.FieldElement51)⟫ = (15112221349535400772501151409588531511454012693041857206046113283949847762202 : Fp) := by simp [denote, feVal, limbsVal, Array.make] have hYv : ⟪(Array.make 5#usize [1801439850948184#u64, 1351079888211148#u64, 450359962737049#u64, 900719925474099#u64, 1801439850948198#u64] : backend.serial.u64.field.FieldElement51)⟫ = (46316835694926478169428394003475163141307993866256225615783033603165251855960 : Fp) := by simp [denote, feVal, limbsVal, Array.make] have hZv : ⟪(Array.make 5#usize [1#u64, 0#u64, 0#u64, 0#u64, 0#u64] : backend.serial.u64.field.FieldElement51)⟫ = (1 : Fp) := by simp [denote, feVal, limbsVal, Array.make] have hTv : ⟪(Array.make 5#usize [1841354044333475#u64, 16398895984059#u64, 755974180946558#u64, 900171276175154#u64, 1821297809914039#u64] : backend.serial.u64.field.FieldElement51)⟫ = (46827403850823179245072216630277197565144205554125654976674165829533817101731 : Fp) := by simp [denote, feVal, limbsVal, Array.make] -- coherence of the affine literals: x·y = t (z = 1) have hco : (15112221349535400772501151409588531511454012693041857206046113283949847762202 : Fp) * (46316835694926478169428394003475163141307993866256225615783033603165251855960 : Fp) = (46827403850823179245072216630277197565144205554125654976674165829533817101731 : Fp) := by apply fp_mul_eq_of_witness norm_num [P] -- the curve equation for the affine literals (121666-scaled witness) have hcv : OnCurve (15112221349535400772501151409588531511454012693041857206046113283949847762202 : Fp) (46316835694926478169428394003475163141307993866256225615783033603165251855960 : Fp) := by have h := onCurve_of_witness 15112221349535400772501151409588531511454012693041857206046113283949847762202 46316835694926478169428394003475163141307993866256225615783033603165251855960 (by norm_num [P]) push_cast at h exact h refine ⟨⟨Array.make 5#usize [1738742601995546#u64, 1146398526822698#u64, 2070867633025821#u64, 562264141797630#u64, 587772402128613#u64], Array.make 5#usize [1801439850948184#u64, 1351079888211148#u64, 450359962737049#u64, 900719925474099#u64, 1801439850948198#u64], Array.make 5#usize [1#u64, 0#u64, 0#u64, 0#u64, 0#u64], Array.make 5#usize [1841354044333475#u64, 16398895984059#u64, 755974180946558#u64, 900171276175154#u64, 1821297809914039#u64]⟩, ?_, ⟨?_, ?_, ?_, ?_, ?_, ?_⟩, ?_, ?_⟩ · unfold backend.serial.u64.constants.ED25519_BASEPOINT_POINT backend.serial.u64.field.FieldElement51.from_limbs rfl · simp [Bnd, Array.make] · simp [Bnd, Array.make] · simp [Bnd, Array.make] · simp [Bnd, Array.make] · show ⟪_⟫ ≠ 0 rw [hZv]; exact one_ne_zero · show ⟪_⟫ * ⟪_⟫ = ⟪_⟫ * ⟪_⟫ rw [hXv, hYv, hZv, hTv, one_mul] exact hco · show OnCurve (edX _) (edY _) unfold edX edY simp only rw [hXv, hYv, hZv, div_one, div_one] exact hcv · show (edX _, edY _) = edBasePt unfold edX edY edBasePt simp only rw [hXv, hYv, hZv, div_one, div_one] /-- **vartime_double_base::mul — the phase-1 computational specification.** For canonical scalars a, b (LE byte values Va, Vb < 2^253) and a valid on-curve A: the result is a valid on-curve point denoting the abstract double-and-add fold of the two proven NAF encodings over A and the standard base point. -/ theorem vartime_double_base_mul_spec (a b : scalar.Scalar) (A : EdPoint) (a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 a21 a22 a23 a24 a25 a26 a27 a28 a29 a30 a31 : Std.U8) (b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 b22 b23 b24 b25 b26 b27 b28 b29 b30 b31 : Std.U8) (hab : (↑a.bytes : List Std.U8) = [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31]) (hbb : (↑b.bytes : List Std.U8) = [b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31]) (Va Vb : ℕ) (hVa : Va = a0.val + a1.val * 2^8 + a2.val * 2^16 + a3.val * 2^24 + a4.val * 2^32 + a5.val * 2^40 + a6.val * 2^48 + a7.val * 2^56 + a8.val * 2^64 + a9.val * 2^72 + a10.val * 2^80 + a11.val * 2^88 + a12.val * 2^96 + a13.val * 2^104 + a14.val * 2^112 + a15.val * 2^120 + a16.val * 2^128 + a17.val * 2^136 + a18.val * 2^144 + a19.val * 2^152 + a20.val * 2^160 + a21.val * 2^168 + a22.val * 2^176 + a23.val * 2^184 + a24.val * 2^192 + a25.val * 2^200 + a26.val * 2^208 + a27.val * 2^216 + a28.val * 2^224 + a29.val * 2^232 + a30.val * 2^240 + a31.val * 2^248) (hVb : Vb = b0.val + b1.val * 2^8 + b2.val * 2^16 + b3.val * 2^24 + b4.val * 2^32 + b5.val * 2^40 + b6.val * 2^48 + b7.val * 2^56 + b8.val * 2^64 + b9.val * 2^72 + b10.val * 2^80 + b11.val * 2^88 + b12.val * 2^96 + b13.val * 2^104 + b14.val * 2^112 + b15.val * 2^120 + b16.val * 2^128 + b17.val * 2^136 + b18.val * 2^144 + b19.val * 2^152 + b20.val * 2^160 + b21.val * 2^168 + b22.val * 2^176 + b23.val * 2^184 + b24.val * 2^192 + b25.val * 2^200 + b26.val * 2^208 + b27.val * 2^216 + b28.val * 2^224 + b29.val * 2^232 + b30.val * 2^240 + b31.val * 2^248) (hValt : Va < 2^253) (hVblt : Vb < 2^253) (hAv : ExtValid A) (hAc : OnCurveExt A) : backend.serial.scalar_mul.vartime_double_base.mul a A b ⦃ R => ExtValid R ∧ OnCurveExt R ∧ ∃ (na nb : Std.Array Std.I8 256#usize), NafDigits na ∧ NafDigits nb ∧ nafSum na 256 = (Va : ℤ) ∧ nafSum nb 256 = (Vb : ℤ) ∧ edPt R = dsmFold (nafDigit na) (nafDigit nb) (edPt A) edBasePt edId 256 ⦄ := by obtain ⟨B, hBok, hBv, hBc, hBpt⟩ := run_basepoint unfold backend.serial.scalar_mul.vartime_double_base.mul -- the two NAF encodings step with (non_adjacent_form_spec a a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 a21 a22 a23 a24 a25 a26 a27 a28 a29 a30 a31 hab Va hVa hValt) as ⟨na, hnaD, hnaS⟩ step with (non_adjacent_form_spec b b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 b22 b23 b24 b25 b26 b27 b28 b29 b30 b31 hbb Vb hVb hVblt) as ⟨nb, hnbD, hnbS⟩ -- the top index (constant 255) step with (dsm_top_index_spec na nb) as ⟨i, hi⟩ -- table over A step with (naf_table_spec A hAv hAc) as ⟨eA0, eA1, eA2, eA3, eA4, eA5, eA6, eA7, ta, hlA, hA0, hA1, hA2, hA3, hA4, hA5, hA6, hA7⟩ -- the basepoint constant rw [hBok] simp only [bind_tc_ok] -- table over B step with (naf_table_spec B hBv hBc) as ⟨eB0, eB1, eB2, eB3, eB4, eB5, eB6, eB7, tb, hlB, hB0, hB1, hB2, hB3, hB4, hB5, hB6, hB7⟩ -- the 256-step Straus loop step with (dsm_loop_spec i (by rw [hi]; scalar_tac : i.val = 255) na nb ta tb A B ⟨eA0, eA1, eA2, eA3, eA4, eA5, eA6, eA7, hlA, hA0, hA1, hA2, hA3, hA4, hA5, hA6, hA7⟩ ⟨eB0, eB1, eB2, eB3, eB4, eB5, eB6, eB7, hlB, hB0, hB1, hB2, hB3, hB4, hB5, hB6, hB7⟩ hnaD hnbD) as ⟨r, hrv, hrc, hrfold⟩ -- the final projective → extended conversion apply spec_mono (proj_as_extended_spec r hrv) rintro R ⟨hRv, -, -, -, -, hRx, hRy⟩ refine ⟨hRv, ?_, na, nb, hnaD, hnbD, hnaS, hnbS, ?_⟩ · show OnCurve (edX R) (edY R) rw [hRx, hRy] exact hrc · calc edPt R = (edX R, edY R) := rfl _ = (projX r, projY r) := by rw [hRx, hRy] _ = dsmFold (nafDigit na) (nafDigit nb) (edPt A) (edPt B) edId 256 := hrfold _ = dsmFold (nafDigit na) (nafDigit nb) (edPt A) edBasePt edId 256 := by rw [hBpt] end CurveFieldProofs