/- ────────────────────────────────────────────────────────────────────────────── Proofs/ScalarMulSpec.lean — Scalar52 multiplication, phase A: mul_internal `mul_internal a b` computes the nine schoolbook column sums z_k = Σ_(i+j=k) a_i·b_j into u128 words (scalar.rs:222-236) — no carries, no reduction; those happen in montgomery_reduce (phase B, open frontier). This file proves the columns exact and bounded: each product < 2^104 (52+52 bits), each column < 5·2^104 < 2^107. ────────────────────────────────────────────────────────────────────────────── -/ import Proofs.ScalarDenote open Aeneas Aeneas.Std Result open curve25519_dalek set_option maxHeartbeats 8000000 set_option linter.unusedSimpArgs false namespace ScalarProofs open Aeneas.Std.WP /-- The widening 52×52→104-bit product helper `m` (scalar.rs:56-58): total, value exact (u64→u128 casts cannot truncate; the product of two 64-bit values cannot overflow u128). -/ theorem m_spec (x y : U64) : backend.serial.u64.scalar.m x y ⦃ r => r.val = x.val * y.val ⦄ := by unfold backend.serial.u64.scalar.m step with UScalar.cast.step_spec as ⟨cx, hcx⟩ step with UScalar.cast.step_spec as ⟨cy, hcy⟩ have hcxv : cx.val = x.val := by simp [hcx, UScalar.cast_val_eq, U64.size, U128.size] have hcyv : cy.val = y.val := by simp [hcy, UScalar.cast_val_eq, U64.size, U128.size] have hfits : cx.val * cy.val ≤ U128.max := by rw [hcxv, hcyv] have hx := x.hBounds have hy := y.hBounds have h2 : x.val * y.val < 2^64 * 2^64 := by apply Nat.mul_lt_mul'' <;> scalar_tac scalar_tac step as ⟨r, hr⟩ try simp only [spec_ok] rw [hr, hcxv, hcyv] /-- `mul_internal`: the nine exact schoolbook columns, each bounded. For 52-bit-bounded inputs no operation can overflow. -/ theorem mul_internal_spec (a b : Sc) (a0 a1 a2 a3 a4 b0 b1 b2 b3 b4 : U64) (ha : (↑a : List U64) = [a0, a1, a2, a3, a4]) (hb : (↑b : List U64) = [b0, b1, b2, b3, b4]) (hbnd : a0.val < 2^52 ∧ a1.val < 2^52 ∧ a2.val < 2^52 ∧ a3.val < 2^52 ∧ a4.val < 2^52 ∧ b0.val < 2^52 ∧ b1.val < 2^52 ∧ b2.val < 2^52 ∧ b3.val < 2^52 ∧ b4.val < 2^52) : backend.serial.u64.scalar.Scalar52.mul_internal a b ⦃ (zz : Std.Array Std.U128 9#usize) => ∃ z0 z1 z2 z3 z4 z5 z6 z7 z8 : Std.U128, (↑zz : List Std.U128) = [z0, z1, z2, z3, z4, z5, z6, z7, z8] ∧ z0.val = (a0.val * b0.val) ∧ z1.val = ((a0.val * b1.val) + (a1.val * b0.val)) ∧ z2.val = (((a0.val * b2.val) + (a1.val * b1.val)) + (a2.val * b0.val)) ∧ z3.val = ((((a0.val * b3.val) + (a1.val * b2.val)) + (a2.val * b1.val)) + (a3.val * b0.val)) ∧ z4.val = (((((a0.val * b4.val) + (a1.val * b3.val)) + (a2.val * b2.val)) + (a3.val * b1.val)) + (a4.val * b0.val)) ∧ z5.val = ((((a1.val * b4.val) + (a2.val * b3.val)) + (a3.val * b2.val)) + (a4.val * b1.val)) ∧ z6.val = (((a2.val * b4.val) + (a3.val * b3.val)) + (a4.val * b2.val)) ∧ z7.val = ((a3.val * b4.val) + (a4.val * b3.val)) ∧ z8.val = (a4.val * b4.val) ⦄ := by obtain ⟨hA0, hA1, hA2, hA3, hA4, hB0, hB1, hB2, hB3, hB4⟩ := hbnd unfold backend.serial.u64.scalar.Scalar52.mul_internal backend.serial.u64.scalar.Scalar52.Insts.CoreOpsIndexIndexUsizeU64.index step as ⟨i, hi⟩ simp [ha] at hi have hvi : i.val = a0.val := by rw [hi] step as ⟨i1, hi1⟩ simp [hb] at hi1 have hvi1 : i1.val = b0.val := by rw [hi1] step with m_spec as ⟨i2, hi2⟩ have hvi2 : i2.val = a0.val * b0.val := by rw [hi2, hvi, hvi1] have hbi2 : a0.val * b0.val < 2^104 := by have h := Nat.mul_lt_mul'' hA0 hB0; omega step as ⟨z1, hz1⟩ step as ⟨i3, hi3⟩ simp [hb] at hi3 have hvi3 : i3.val = b1.val := by rw [hi3] step with m_spec as ⟨i4, hi4⟩ have hvi4 : i4.val = a0.val * b1.val := by rw [hi4, hvi, hvi3] have hbi4 : a0.val * b1.val < 2^104 := by have h := Nat.mul_lt_mul'' hA0 hB1; omega step as ⟨i5, hi5⟩ simp [ha] at hi5 have hvi5 : i5.val = a1.val := by rw [hi5] step with m_spec as ⟨i6, hi6⟩ have hvi6 : i6.val = a1.val * b0.val := by rw [hi6, hvi5, hvi1] have hbi6 : a1.val * b0.val < 2^104 := by have h := Nat.mul_lt_mul'' hA1 hB0; omega have hsi7 : i4.val + i6.val < 2^128 := by rw [hvi4, hvi6]; omega step as ⟨i7, hi7⟩ have hvi7 : i7.val = (a0.val * b1.val) + (a1.val * b0.val) := by rw [hi7, hvi4, hvi6] have hbi7 : (a0.val * b1.val) + (a1.val * b0.val) < 2^107 := by omega step as ⟨z2, hz2⟩ step as ⟨i8, hi8⟩ simp [hb] at hi8 have hvi8 : i8.val = b2.val := by rw [hi8] step with m_spec as ⟨i9, hi9⟩ have hvi9 : i9.val = a0.val * b2.val := by rw [hi9, hvi, hvi8] have hbi9 : a0.val * b2.val < 2^104 := by have h := Nat.mul_lt_mul'' hA0 hB2; omega step with m_spec as ⟨i10, hi10⟩ have hvi10 : i10.val = a1.val * b1.val := by rw [hi10, hvi5, hvi3] have hbi10 : a1.val * b1.val < 2^104 := by have h := Nat.mul_lt_mul'' hA1 hB1; omega have hsi11 : i9.val + i10.val < 2^128 := by rw [hvi9, hvi10]; omega step as ⟨i11, hi11⟩ have hvi11 : i11.val = (a0.val * b2.val) + (a1.val * b1.val) := by rw [hi11, hvi9, hvi10] have hbi11 : (a0.val * b2.val) + (a1.val * b1.val) < 2^107 := by omega step as ⟨i12, hi12⟩ simp [ha] at hi12 have hvi12 : i12.val = a2.val := by rw [hi12] step with m_spec as ⟨i13, hi13⟩ have hvi13 : i13.val = a2.val * b0.val := by rw [hi13, hvi12, hvi1] have hbi13 : a2.val * b0.val < 2^104 := by have h := Nat.mul_lt_mul'' hA2 hB0; omega have hsi14 : i11.val + i13.val < 2^128 := by rw [hvi11, hvi13]; omega step as ⟨i14, hi14⟩ have hvi14 : i14.val = ((a0.val * b2.val) + (a1.val * b1.val)) + (a2.val * b0.val) := by rw [hi14, hvi11, hvi13] have hbi14 : ((a0.val * b2.val) + (a1.val * b1.val)) + (a2.val * b0.val) < 2^107 := by omega step as ⟨z3, hz3⟩ step as ⟨i15, hi15⟩ simp [hb] at hi15 have hvi15 : i15.val = b3.val := by rw [hi15] step with m_spec as ⟨i16, hi16⟩ have hvi16 : i16.val = a0.val * b3.val := by rw [hi16, hvi, hvi15] have hbi16 : a0.val * b3.val < 2^104 := by have h := Nat.mul_lt_mul'' hA0 hB3; omega step with m_spec as ⟨i17, hi17⟩ have hvi17 : i17.val = a1.val * b2.val := by rw [hi17, hvi5, hvi8] have hbi17 : a1.val * b2.val < 2^104 := by have h := Nat.mul_lt_mul'' hA1 hB2; omega have hsi18 : i16.val + i17.val < 2^128 := by rw [hvi16, hvi17]; omega step as ⟨i18, hi18⟩ have hvi18 : i18.val = (a0.val * b3.val) + (a1.val * b2.val) := by rw [hi18, hvi16, hvi17] have hbi18 : (a0.val * b3.val) + (a1.val * b2.val) < 2^107 := by omega step with m_spec as ⟨i19, hi19⟩ have hvi19 : i19.val = a2.val * b1.val := by rw [hi19, hvi12, hvi3] have hbi19 : a2.val * b1.val < 2^104 := by have h := Nat.mul_lt_mul'' hA2 hB1; omega have hsi20 : i18.val + i19.val < 2^128 := by rw [hvi18, hvi19]; omega step as ⟨i20, hi20⟩ have hvi20 : i20.val = ((a0.val * b3.val) + (a1.val * b2.val)) + (a2.val * b1.val) := by rw [hi20, hvi18, hvi19] have hbi20 : ((a0.val * b3.val) + (a1.val * b2.val)) + (a2.val * b1.val) < 2^107 := by omega step as ⟨i21, hi21⟩ simp [ha] at hi21 have hvi21 : i21.val = a3.val := by rw [hi21] step with m_spec as ⟨i22, hi22⟩ have hvi22 : i22.val = a3.val * b0.val := by rw [hi22, hvi21, hvi1] have hbi22 : a3.val * b0.val < 2^104 := by have h := Nat.mul_lt_mul'' hA3 hB0; omega have hsi23 : i20.val + i22.val < 2^128 := by rw [hvi20, hvi22]; omega step as ⟨i23, hi23⟩ have hvi23 : i23.val = (((a0.val * b3.val) + (a1.val * b2.val)) + (a2.val * b1.val)) + (a3.val * b0.val) := by rw [hi23, hvi20, hvi22] have hbi23 : (((a0.val * b3.val) + (a1.val * b2.val)) + (a2.val * b1.val)) + (a3.val * b0.val) < 2^107 := by omega step as ⟨z4, hz4⟩ step as ⟨i24, hi24⟩ simp [hb] at hi24 have hvi24 : i24.val = b4.val := by rw [hi24] step with m_spec as ⟨i25, hi25⟩ have hvi25 : i25.val = a0.val * b4.val := by rw [hi25, hvi, hvi24] have hbi25 : a0.val * b4.val < 2^104 := by have h := Nat.mul_lt_mul'' hA0 hB4; omega step with m_spec as ⟨i26, hi26⟩ have hvi26 : i26.val = a1.val * b3.val := by rw [hi26, hvi5, hvi15] have hbi26 : a1.val * b3.val < 2^104 := by have h := Nat.mul_lt_mul'' hA1 hB3; omega have hsi27 : i25.val + i26.val < 2^128 := by rw [hvi25, hvi26]; omega step as ⟨i27, hi27⟩ have hvi27 : i27.val = (a0.val * b4.val) + (a1.val * b3.val) := by rw [hi27, hvi25, hvi26] have hbi27 : (a0.val * b4.val) + (a1.val * b3.val) < 2^107 := by omega step with m_spec as ⟨i28, hi28⟩ have hvi28 : i28.val = a2.val * b2.val := by rw [hi28, hvi12, hvi8] have hbi28 : a2.val * b2.val < 2^104 := by have h := Nat.mul_lt_mul'' hA2 hB2; omega have hsi29 : i27.val + i28.val < 2^128 := by rw [hvi27, hvi28]; omega step as ⟨i29, hi29⟩ have hvi29 : i29.val = ((a0.val * b4.val) + (a1.val * b3.val)) + (a2.val * b2.val) := by rw [hi29, hvi27, hvi28] have hbi29 : ((a0.val * b4.val) + (a1.val * b3.val)) + (a2.val * b2.val) < 2^107 := by omega step with m_spec as ⟨i30, hi30⟩ have hvi30 : i30.val = a3.val * b1.val := by rw [hi30, hvi21, hvi3] have hbi30 : a3.val * b1.val < 2^104 := by have h := Nat.mul_lt_mul'' hA3 hB1; omega have hsi31 : i29.val + i30.val < 2^128 := by rw [hvi29, hvi30]; omega step as ⟨i31, hi31⟩ have hvi31 : i31.val = (((a0.val * b4.val) + (a1.val * b3.val)) + (a2.val * b2.val)) + (a3.val * b1.val) := by rw [hi31, hvi29, hvi30] have hbi31 : (((a0.val * b4.val) + (a1.val * b3.val)) + (a2.val * b2.val)) + (a3.val * b1.val) < 2^107 := by omega step as ⟨i32, hi32⟩ simp [ha] at hi32 have hvi32 : i32.val = a4.val := by rw [hi32] step with m_spec as ⟨i33, hi33⟩ have hvi33 : i33.val = a4.val * b0.val := by rw [hi33, hvi32, hvi1] have hbi33 : a4.val * b0.val < 2^104 := by have h := Nat.mul_lt_mul'' hA4 hB0; omega have hsi34 : i31.val + i33.val < 2^128 := by rw [hvi31, hvi33]; omega step as ⟨i34, hi34⟩ have hvi34 : i34.val = ((((a0.val * b4.val) + (a1.val * b3.val)) + (a2.val * b2.val)) + (a3.val * b1.val)) + (a4.val * b0.val) := by rw [hi34, hvi31, hvi33] have hbi34 : ((((a0.val * b4.val) + (a1.val * b3.val)) + (a2.val * b2.val)) + (a3.val * b1.val)) + (a4.val * b0.val) < 2^107 := by omega step as ⟨z5, hz5⟩ step with m_spec as ⟨i35, hi35⟩ have hvi35 : i35.val = a1.val * b4.val := by rw [hi35, hvi5, hvi24] have hbi35 : a1.val * b4.val < 2^104 := by have h := Nat.mul_lt_mul'' hA1 hB4; omega step with m_spec as ⟨i36, hi36⟩ have hvi36 : i36.val = a2.val * b3.val := by rw [hi36, hvi12, hvi15] have hbi36 : a2.val * b3.val < 2^104 := by have h := Nat.mul_lt_mul'' hA2 hB3; omega have hsi37 : i35.val + i36.val < 2^128 := by rw [hvi35, hvi36]; omega step as ⟨i37, hi37⟩ have hvi37 : i37.val = (a1.val * b4.val) + (a2.val * b3.val) := by rw [hi37, hvi35, hvi36] have hbi37 : (a1.val * b4.val) + (a2.val * b3.val) < 2^107 := by omega step with m_spec as ⟨i38, hi38⟩ have hvi38 : i38.val = a3.val * b2.val := by rw [hi38, hvi21, hvi8] have hbi38 : a3.val * b2.val < 2^104 := by have h := Nat.mul_lt_mul'' hA3 hB2; omega have hsi39 : i37.val + i38.val < 2^128 := by rw [hvi37, hvi38]; omega step as ⟨i39, hi39⟩ have hvi39 : i39.val = ((a1.val * b4.val) + (a2.val * b3.val)) + (a3.val * b2.val) := by rw [hi39, hvi37, hvi38] have hbi39 : ((a1.val * b4.val) + (a2.val * b3.val)) + (a3.val * b2.val) < 2^107 := by omega step with m_spec as ⟨i40, hi40⟩ have hvi40 : i40.val = a4.val * b1.val := by rw [hi40, hvi32, hvi3] have hbi40 : a4.val * b1.val < 2^104 := by have h := Nat.mul_lt_mul'' hA4 hB1; omega have hsi41 : i39.val + i40.val < 2^128 := by rw [hvi39, hvi40]; omega step as ⟨i41, hi41⟩ have hvi41 : i41.val = (((a1.val * b4.val) + (a2.val * b3.val)) + (a3.val * b2.val)) + (a4.val * b1.val) := by rw [hi41, hvi39, hvi40] have hbi41 : (((a1.val * b4.val) + (a2.val * b3.val)) + (a3.val * b2.val)) + (a4.val * b1.val) < 2^107 := by omega step as ⟨z6, hz6⟩ step with m_spec as ⟨i42, hi42⟩ have hvi42 : i42.val = a2.val * b4.val := by rw [hi42, hvi12, hvi24] have hbi42 : a2.val * b4.val < 2^104 := by have h := Nat.mul_lt_mul'' hA2 hB4; omega step with m_spec as ⟨i43, hi43⟩ have hvi43 : i43.val = a3.val * b3.val := by rw [hi43, hvi21, hvi15] have hbi43 : a3.val * b3.val < 2^104 := by have h := Nat.mul_lt_mul'' hA3 hB3; omega have hsi44 : i42.val + i43.val < 2^128 := by rw [hvi42, hvi43]; omega step as ⟨i44, hi44⟩ have hvi44 : i44.val = (a2.val * b4.val) + (a3.val * b3.val) := by rw [hi44, hvi42, hvi43] have hbi44 : (a2.val * b4.val) + (a3.val * b3.val) < 2^107 := by omega step with m_spec as ⟨i45, hi45⟩ have hvi45 : i45.val = a4.val * b2.val := by rw [hi45, hvi32, hvi8] have hbi45 : a4.val * b2.val < 2^104 := by have h := Nat.mul_lt_mul'' hA4 hB2; omega have hsi46 : i44.val + i45.val < 2^128 := by rw [hvi44, hvi45]; omega step as ⟨i46, hi46⟩ have hvi46 : i46.val = ((a2.val * b4.val) + (a3.val * b3.val)) + (a4.val * b2.val) := by rw [hi46, hvi44, hvi45] have hbi46 : ((a2.val * b4.val) + (a3.val * b3.val)) + (a4.val * b2.val) < 2^107 := by omega step as ⟨z7, hz7⟩ step with m_spec as ⟨i47, hi47⟩ have hvi47 : i47.val = a3.val * b4.val := by rw [hi47, hvi21, hvi24] have hbi47 : a3.val * b4.val < 2^104 := by have h := Nat.mul_lt_mul'' hA3 hB4; omega step with m_spec as ⟨i48, hi48⟩ have hvi48 : i48.val = a4.val * b3.val := by rw [hi48, hvi32, hvi15] have hbi48 : a4.val * b3.val < 2^104 := by have h := Nat.mul_lt_mul'' hA4 hB3; omega have hsi49 : i47.val + i48.val < 2^128 := by rw [hvi47, hvi48]; omega step as ⟨i49, hi49⟩ have hvi49 : i49.val = (a3.val * b4.val) + (a4.val * b3.val) := by rw [hi49, hvi47, hvi48] have hbi49 : (a3.val * b4.val) + (a4.val * b3.val) < 2^107 := by omega step as ⟨z8, hz8⟩ step with m_spec as ⟨i50, hi50⟩ have hvi50 : i50.val = a4.val * b4.val := by rw [hi50, hvi32, hvi24] have hbi50 : a4.val * b4.val < 2^104 := by have h := Nat.mul_lt_mul'' hA4 hB4; omega step as ⟨zfin, hzfin⟩ try simp only [spec_ok] refine ⟨i2, i7, i14, i23, i34, i41, i46, i49, i50, ?_, hvi2, hvi7, hvi14, hvi23, hvi34, hvi41, hvi46, hvi49, hvi50⟩ simp [hzfin, hz1, hz2, hz3, hz4, hz5, hz6, hz7, hz8, Array.set_val_eq] end ScalarProofs