|
| 1 | +import MidenLean.Proofs.U128.Common |
| 2 | +import MidenLean.Proofs.U128.Divmod |
| 3 | +import MidenLean.Proofs.Tactics |
| 4 | +import MidenLean.Generated.U128 |
| 5 | + |
| 6 | +namespace MidenLean.Proofs |
| 7 | + |
| 8 | +open MidenLean |
| 9 | +open MidenLean.StepLemmas |
| 10 | +open MidenLean.Tactics |
| 11 | + |
| 12 | +set_option maxHeartbeats 12000000 in |
| 13 | +set_option maxRecDepth 65536 in |
| 14 | +private theorem divmod_execWithEnv_eq_exec (fuel : Nat) (s : MidenState) |
| 15 | + (hf : 0 < fuel) : |
| 16 | + execWithEnv u128ProcEnv fuel s Miden.Core.U128.divmod = |
| 17 | + exec 163 s Miden.Core.U128.divmod := by |
| 18 | + cases fuel with |
| 19 | + | zero => cases hf |
| 20 | + | succ fuel' => |
| 21 | + simp (maxSteps := 5000000) [exec, execWithEnv, u128ProcEnv, Miden.Core.U128.divmod] |
| 22 | + |
| 23 | +set_option maxHeartbeats 12000000 in |
| 24 | +/-- `u128::div` verifies an advice-supplied quotient and remainder for u128 division, |
| 25 | + then drops the remainder word and returns the quotient limbs. |
| 26 | + Execution succeeds iff the advice-supplied q and r satisfy q * b + r = a and r < b. |
| 27 | + Input stack: [b.a0, b.a1, b.a2, b.a3, a.a0, a.a1, a.a2, a.a3] ++ rest |
| 28 | + Advice stack: [r.a0, r.a1, r.a2, r.a3, q.a0, q.a1, q.a2, q.a3] ++ adv_rest |
| 29 | + Output stack: [q.a0, q.a1, q.a2, q.a3] ++ rest -/ |
| 30 | +theorem u128_div_correct |
| 31 | + (a b q r : U128) (rest adv_rest : List Felt) (s : MidenState) |
| 32 | + (hs : s.stack = b.a0.val :: b.a1.val :: b.a2.val :: b.a3.val :: |
| 33 | + a.a0.val :: a.a1.val :: a.a2.val :: a.a3.val :: rest) |
| 34 | + (hadv : s.advice = r.a0.val :: r.a1.val :: r.a2.val :: r.a3.val :: |
| 35 | + q.a0.val :: q.a1.val :: q.a2.val :: q.a3.val :: adv_rest) : |
| 36 | + execWithEnv u128ProcEnv 31 s Miden.Core.U128.div = |
| 37 | + some { stack := q.a0.val :: q.a1.val :: q.a2.val :: q.a3.val :: rest, |
| 38 | + memory := s.memory, |
| 39 | + locals := s.locals, |
| 40 | + advice := adv_rest } |
| 41 | + ↔ (q.toNat * b.toNat + r.toNat = a.toNat ∧ r.toNat < b.toNat) := by |
| 42 | + obtain ⟨stk, mem, locs, adv⟩ := s |
| 43 | + simp only [] at hs hadv |
| 44 | + subst hs |
| 45 | + subst hadv |
| 46 | + constructor |
| 47 | + · intro hexec |
| 48 | + unfold Miden.Core.U128.div execWithEnv at hexec |
| 49 | + simp only [List.foldlM, u128ProcEnv] at hexec |
| 50 | + revert hexec |
| 51 | + cases h_dm : execWithEnv u128ProcEnv 30 |
| 52 | + { stack := b.a0.val :: b.a1.val :: b.a2.val :: b.a3.val :: |
| 53 | + a.a0.val :: a.a1.val :: a.a2.val :: a.a3.val :: rest, |
| 54 | + memory := mem, |
| 55 | + locals := locs, |
| 56 | + advice := r.a0.val :: r.a1.val :: r.a2.val :: r.a3.val :: |
| 57 | + q.a0.val :: q.a1.val :: q.a2.val :: q.a3.val :: adv_rest } |
| 58 | + Miden.Core.U128.divmod with |
| 59 | + | none => |
| 60 | + simp [bind, Bind.bind, Option.bind] |
| 61 | + | some val => |
| 62 | + intro _ |
| 63 | + have h_dm_exec : |
| 64 | + exec 163 |
| 65 | + { stack := b.a0.val :: b.a1.val :: b.a2.val :: b.a3.val :: |
| 66 | + a.a0.val :: a.a1.val :: a.a2.val :: a.a3.val :: rest, |
| 67 | + memory := mem, |
| 68 | + locals := locs, |
| 69 | + advice := r.a0.val :: r.a1.val :: r.a2.val :: r.a3.val :: |
| 70 | + q.a0.val :: q.a1.val :: q.a2.val :: q.a3.val :: adv_rest } |
| 71 | + Miden.Core.U128.divmod = some val := by |
| 72 | + rw [← divmod_execWithEnv_eq_exec 30 _ (by decide)] |
| 73 | + exact h_dm |
| 74 | + exact u128_divmod_conditions_of_exec a b q r rest adv_rest _ rfl rfl h_dm_exec |
| 75 | + · intro ⟨hdiv, hlt⟩ |
| 76 | + have h_divmod : |
| 77 | + exec 163 |
| 78 | + { stack := b.a0.val :: b.a1.val :: b.a2.val :: b.a3.val :: |
| 79 | + a.a0.val :: a.a1.val :: a.a2.val :: a.a3.val :: rest, |
| 80 | + memory := mem, |
| 81 | + locals := locs, |
| 82 | + advice := r.a0.val :: r.a1.val :: r.a2.val :: r.a3.val :: |
| 83 | + q.a0.val :: q.a1.val :: q.a2.val :: q.a3.val :: adv_rest } |
| 84 | + Miden.Core.U128.divmod = |
| 85 | + some { stack := r.a0.val :: r.a1.val :: r.a2.val :: r.a3.val :: |
| 86 | + q.a0.val :: q.a1.val :: q.a2.val :: q.a3.val :: rest, |
| 87 | + memory := mem, |
| 88 | + locals := locs, |
| 89 | + advice := adv_rest } := |
| 90 | + (u128_divmod_correct a b q r rest adv_rest |
| 91 | + { stack := b.a0.val :: b.a1.val :: b.a2.val :: b.a3.val :: |
| 92 | + a.a0.val :: a.a1.val :: a.a2.val :: a.a3.val :: rest, |
| 93 | + memory := mem, |
| 94 | + locals := locs, |
| 95 | + advice := r.a0.val :: r.a1.val :: r.a2.val :: r.a3.val :: |
| 96 | + q.a0.val :: q.a1.val :: q.a2.val :: q.a3.val :: adv_rest } |
| 97 | + rfl rfl).mpr ⟨hdiv, hlt⟩ |
| 98 | + unfold Miden.Core.U128.div execWithEnv |
| 99 | + simp only [List.foldlM, u128ProcEnv] |
| 100 | + dsimp only [bind, Bind.bind, Option.bind] |
| 101 | + rw [divmod_execWithEnv_eq_exec 30 _ (by decide)] |
| 102 | + rw [h_divmod] |
| 103 | + miden_bind |
| 104 | + rw [stepDropw] |
| 105 | + rfl |
| 106 | + |
| 107 | +end MidenLean.Proofs |
0 commit comments