|
| 1 | +import Mathlib.Data.Nat.Bitwise |
| 2 | +import MidenLean.Proofs.U32.Common |
| 3 | +import MidenLean.Generated.U256 |
| 4 | + |
| 5 | +namespace MidenLean.Proofs |
| 6 | + |
| 7 | +open MidenLean |
| 8 | + |
| 9 | +-- ============================================================================ |
| 10 | +-- Procedure environment |
| 11 | +-- ============================================================================ |
| 12 | + |
| 13 | +/-- Procedure environment for manual u256 proofs that call other u256 procedures. -/ |
| 14 | +def u256ProcEnv : ProcEnv := fun name => |
| 15 | + match name with |
| 16 | + | "u256_le_to_be" => some Miden.Core.U256.u256_le_to_be |
| 17 | + | "u256_le_to_be_pair" => some Miden.Core.U256.u256_le_to_be_pair |
| 18 | + | "add_with_carry_be" => some Miden.Core.U256.add_with_carry_be |
| 19 | + | "sub_with_borrow_be" => some Miden.Core.U256.sub_with_borrow_be |
| 20 | + | "mulstep" => some Miden.Core.U256.mulstep |
| 21 | + | "mulstep4" => some Miden.Core.U256.mulstep4 |
| 22 | + | _ => none |
| 23 | + |
| 24 | +-- ============================================================================ |
| 25 | +-- U256 type: a 256-bit unsigned integer as eight U32 limbs |
| 26 | +-- ============================================================================ |
| 27 | + |
| 28 | +/-- A 256-bit unsigned integer represented as eight U32 limbs (little-endian). |
| 29 | + `a0` is the least significant limb, `a7` is the most significant. -/ |
| 30 | +structure U256 where |
| 31 | + a0 : U32 |
| 32 | + a1 : U32 |
| 33 | + a2 : U32 |
| 34 | + a3 : U32 |
| 35 | + a4 : U32 |
| 36 | + a5 : U32 |
| 37 | + a6 : U32 |
| 38 | + a7 : U32 |
| 39 | + |
| 40 | +namespace U256 |
| 41 | + |
| 42 | +/-- Reconstruct the natural number value: |
| 43 | + `a7 * 2^224 + a6 * 2^192 + ... + a1 * 2^32 + a0`. -/ |
| 44 | +def toNat (x : U256) : Nat := |
| 45 | + x.a7.val.val * 2^224 + x.a6.val.val * 2^192 + |
| 46 | + x.a5.val.val * 2^160 + x.a4.val.val * 2^128 + |
| 47 | + x.a3.val.val * 2^96 + x.a2.val.val * 2^64 + |
| 48 | + x.a1.val.val * 2^32 + x.a0.val.val |
| 49 | + |
| 50 | +theorem toNat_lt (x : U256) : x.toNat < 2^256 := by |
| 51 | + unfold toNat |
| 52 | + have h0 := x.a0.val_lt; have h1 := x.a1.val_lt |
| 53 | + have h2 := x.a2.val_lt; have h3 := x.a3.val_lt |
| 54 | + have h4 := x.a4.val_lt; have h5 := x.a5.val_lt |
| 55 | + have h6 := x.a6.val_lt; have h7 := x.a7.val_lt |
| 56 | + omega |
| 57 | + |
| 58 | +theorem toNat_def (x : U256) : |
| 59 | + x.toNat = x.a7.val.val * 2^224 + x.a6.val.val * 2^192 + |
| 60 | + x.a5.val.val * 2^160 + x.a4.val.val * 2^128 + |
| 61 | + x.a3.val.val * 2^96 + x.a2.val.val * 2^64 + |
| 62 | + x.a1.val.val * 2^32 + x.a0.val.val := rfl |
| 63 | + |
| 64 | +/-- Construct a U256 from a natural number (taken mod 2^256). -/ |
| 65 | +def ofNat (n : Nat) : U256 where |
| 66 | + a0 := ⟨Felt.ofNat (n % 2^32), u32_mod_isU32 n⟩ |
| 67 | + a1 := ⟨Felt.ofNat ((n / 2^32) % 2^32), u32_mod_isU32 (n / 2^32)⟩ |
| 68 | + a2 := ⟨Felt.ofNat ((n / 2^64) % 2^32), u32_mod_isU32 (n / 2^64)⟩ |
| 69 | + a3 := ⟨Felt.ofNat ((n / 2^96) % 2^32), u32_mod_isU32 (n / 2^96)⟩ |
| 70 | + a4 := ⟨Felt.ofNat ((n / 2^128) % 2^32), u32_mod_isU32 (n / 2^128)⟩ |
| 71 | + a5 := ⟨Felt.ofNat ((n / 2^160) % 2^32), u32_mod_isU32 (n / 2^160)⟩ |
| 72 | + a6 := ⟨Felt.ofNat ((n / 2^192) % 2^32), u32_mod_isU32 (n / 2^192)⟩ |
| 73 | + a7 := ⟨Felt.ofNat ((n / 2^224) % 2^32), u32_mod_isU32 (n / 2^224)⟩ |
| 74 | + |
| 75 | +@[simp] theorem ofNat_toNat (n : Nat) : (U256.ofNat n).toNat = n % 2^256 := by |
| 76 | + unfold ofNat toNat |
| 77 | + have h0 : (Felt.ofNat (n % 2^32)).val = n % 2^32 := |
| 78 | + felt_ofNat_val_lt _ (by unfold GOLDILOCKS_PRIME; omega) |
| 79 | + have h1 : (Felt.ofNat ((n / 2^32) % 2^32)).val = (n / 2^32) % 2^32 := |
| 80 | + felt_ofNat_val_lt _ (by unfold GOLDILOCKS_PRIME; omega) |
| 81 | + have h2 : (Felt.ofNat ((n / 2^64) % 2^32)).val = (n / 2^64) % 2^32 := |
| 82 | + felt_ofNat_val_lt _ (by unfold GOLDILOCKS_PRIME; omega) |
| 83 | + have h3 : (Felt.ofNat ((n / 2^96) % 2^32)).val = (n / 2^96) % 2^32 := |
| 84 | + felt_ofNat_val_lt _ (by unfold GOLDILOCKS_PRIME; omega) |
| 85 | + have h4 : (Felt.ofNat ((n / 2^128) % 2^32)).val = (n / 2^128) % 2^32 := |
| 86 | + felt_ofNat_val_lt _ (by unfold GOLDILOCKS_PRIME; omega) |
| 87 | + have h5 : (Felt.ofNat ((n / 2^160) % 2^32)).val = (n / 2^160) % 2^32 := |
| 88 | + felt_ofNat_val_lt _ (by unfold GOLDILOCKS_PRIME; omega) |
| 89 | + have h6 : (Felt.ofNat ((n / 2^192) % 2^32)).val = (n / 2^192) % 2^32 := |
| 90 | + felt_ofNat_val_lt _ (by unfold GOLDILOCKS_PRIME; omega) |
| 91 | + have h7 : (Felt.ofNat ((n / 2^224) % 2^32)).val = (n / 2^224) % 2^32 := |
| 92 | + felt_ofNat_val_lt _ (by unfold GOLDILOCKS_PRIME; omega) |
| 93 | + rw [h0, h1, h2, h3, h4, h5, h6, h7]; omega |
| 94 | + |
| 95 | +-- Limb accessors for ofNat (Felt level) |
| 96 | +@[simp] theorem ofNat_a0 (n : Nat) : (U256.ofNat n).a0.val = Felt.ofNat (n % 2^32) := rfl |
| 97 | +@[simp] theorem ofNat_a1 (n : Nat) : (U256.ofNat n).a1.val = Felt.ofNat ((n / 2^32) % 2^32) := rfl |
| 98 | +@[simp] theorem ofNat_a2 (n : Nat) : (U256.ofNat n).a2.val = Felt.ofNat ((n / 2^64) % 2^32) := rfl |
| 99 | +@[simp] theorem ofNat_a3 (n : Nat) : (U256.ofNat n).a3.val = Felt.ofNat ((n / 2^96) % 2^32) := rfl |
| 100 | +@[simp] theorem ofNat_a4 (n : Nat) : (U256.ofNat n).a4.val = Felt.ofNat ((n / 2^128) % 2^32) := rfl |
| 101 | +@[simp] theorem ofNat_a5 (n : Nat) : (U256.ofNat n).a5.val = Felt.ofNat ((n / 2^160) % 2^32) := rfl |
| 102 | +@[simp] theorem ofNat_a6 (n : Nat) : (U256.ofNat n).a6.val = Felt.ofNat ((n / 2^192) % 2^32) := rfl |
| 103 | +@[simp] theorem ofNat_a7 (n : Nat) : (U256.ofNat n).a7.val = Felt.ofNat ((n / 2^224) % 2^32) := rfl |
| 104 | + |
| 105 | +-- Limb accessors for ofNat (Nat level) |
| 106 | +@[simp] theorem ofNat_a0_toNat (n : Nat) : (U256.ofNat n).a0.toNat = n % 2^32 := |
| 107 | + felt_ofNat_val_lt _ (u32_mod_lt_prime n) |
| 108 | +@[simp] theorem ofNat_a1_toNat (n : Nat) : (U256.ofNat n).a1.toNat = (n / 2^32) % 2^32 := |
| 109 | + felt_ofNat_val_lt _ (u32_mod_lt_prime (n / 2^32)) |
| 110 | +@[simp] theorem ofNat_a2_toNat (n : Nat) : (U256.ofNat n).a2.toNat = (n / 2^64) % 2^32 := |
| 111 | + felt_ofNat_val_lt _ (u32_mod_lt_prime (n / 2^64)) |
| 112 | +@[simp] theorem ofNat_a3_toNat (n : Nat) : (U256.ofNat n).a3.toNat = (n / 2^96) % 2^32 := |
| 113 | + felt_ofNat_val_lt _ (u32_mod_lt_prime (n / 2^96)) |
| 114 | +@[simp] theorem ofNat_a4_toNat (n : Nat) : (U256.ofNat n).a4.toNat = (n / 2^128) % 2^32 := |
| 115 | + felt_ofNat_val_lt _ (u32_mod_lt_prime (n / 2^128)) |
| 116 | +@[simp] theorem ofNat_a5_toNat (n : Nat) : (U256.ofNat n).a5.toNat = (n / 2^160) % 2^32 := |
| 117 | + felt_ofNat_val_lt _ (u32_mod_lt_prime (n / 2^160)) |
| 118 | +@[simp] theorem ofNat_a6_toNat (n : Nat) : (U256.ofNat n).a6.toNat = (n / 2^192) % 2^32 := |
| 119 | + felt_ofNat_val_lt _ (u32_mod_lt_prime (n / 2^192)) |
| 120 | +@[simp] theorem ofNat_a7_toNat (n : Nat) : (U256.ofNat n).a7.toNat = (n / 2^224) % 2^32 := |
| 121 | + felt_ofNat_val_lt _ (u32_mod_lt_prime (n / 2^224)) |
| 122 | + |
| 123 | +-- Extensionality |
| 124 | +@[ext] theorem ext {a b : U256} |
| 125 | + (h0 : a.a0 = b.a0) (h1 : a.a1 = b.a1) (h2 : a.a2 = b.a2) (h3 : a.a3 = b.a3) |
| 126 | + (h4 : a.a4 = b.a4) (h5 : a.a5 = b.a5) (h6 : a.a6 = b.a6) (h7 : a.a7 = b.a7) : |
| 127 | + a = b := by |
| 128 | + cases a; cases b; simp_all |
| 129 | + |
| 130 | +theorem toNat_injective : Function.Injective U256.toNat := by |
| 131 | + intro a b hab |
| 132 | + have ha0 := a.a0.val_lt; have ha1 := a.a1.val_lt |
| 133 | + have ha2 := a.a2.val_lt; have ha3 := a.a3.val_lt |
| 134 | + have ha4 := a.a4.val_lt; have ha5 := a.a5.val_lt |
| 135 | + have ha6 := a.a6.val_lt; have ha7 := a.a7.val_lt |
| 136 | + have hb0 := b.a0.val_lt; have hb1 := b.a1.val_lt |
| 137 | + have hb2 := b.a2.val_lt; have hb3 := b.a3.val_lt |
| 138 | + have hb4 := b.a4.val_lt; have hb5 := b.a5.val_lt |
| 139 | + have hb6 := b.a6.val_lt; have hb7 := b.a7.val_lt |
| 140 | + unfold toNat at hab |
| 141 | + apply ext <;> exact U32.ext (ZMod.val_injective _ (by omega)) |
| 142 | + |
| 143 | +theorem eq_of_toNat_eq {a b : U256} (h : a.toNat = b.toNat) : a = b := |
| 144 | + toNat_injective h |
| 145 | + |
| 146 | +end U256 |
| 147 | + |
| 148 | +-- ============================================================================ |
| 149 | +-- Arithmetic instances |
| 150 | +-- ============================================================================ |
| 151 | + |
| 152 | +instance : Add U256 where add a b := U256.ofNat (a.toNat + b.toNat) |
| 153 | +instance : Sub U256 where sub a b := U256.ofNat (a.toNat + 2^256 - b.toNat) |
| 154 | +instance : Mul U256 where mul a b := U256.ofNat (a.toNat * b.toNat) |
| 155 | + |
| 156 | +-- ============================================================================ |
| 157 | +-- Comparison instances |
| 158 | +-- ============================================================================ |
| 159 | + |
| 160 | +instance : LT U256 where lt a b := a.toNat < b.toNat |
| 161 | +instance : LE U256 where le a b := a.toNat ≤ b.toNat |
| 162 | +instance (a b : U256) : Decidable (a < b) := inferInstanceAs (Decidable (a.toNat < b.toNat)) |
| 163 | +instance (a b : U256) : Decidable (a ≤ b) := inferInstanceAs (Decidable (a.toNat ≤ b.toNat)) |
| 164 | + |
| 165 | +-- ============================================================================ |
| 166 | +-- Bitwise instances (limb-wise) |
| 167 | +-- ============================================================================ |
| 168 | + |
| 169 | +instance : AndOp U256 where and a b := { |
| 170 | + a0 := ⟨Felt.ofNat (a.a0.val.val &&& b.a0.val.val), |
| 171 | + felt_ofNat_isU32_of_lt _ (Nat.lt_of_le_of_lt Nat.and_le_left a.a0.val_lt)⟩ |
| 172 | + a1 := ⟨Felt.ofNat (a.a1.val.val &&& b.a1.val.val), |
| 173 | + felt_ofNat_isU32_of_lt _ (Nat.lt_of_le_of_lt Nat.and_le_left a.a1.val_lt)⟩ |
| 174 | + a2 := ⟨Felt.ofNat (a.a2.val.val &&& b.a2.val.val), |
| 175 | + felt_ofNat_isU32_of_lt _ (Nat.lt_of_le_of_lt Nat.and_le_left a.a2.val_lt)⟩ |
| 176 | + a3 := ⟨Felt.ofNat (a.a3.val.val &&& b.a3.val.val), |
| 177 | + felt_ofNat_isU32_of_lt _ (Nat.lt_of_le_of_lt Nat.and_le_left a.a3.val_lt)⟩ |
| 178 | + a4 := ⟨Felt.ofNat (a.a4.val.val &&& b.a4.val.val), |
| 179 | + felt_ofNat_isU32_of_lt _ (Nat.lt_of_le_of_lt Nat.and_le_left a.a4.val_lt)⟩ |
| 180 | + a5 := ⟨Felt.ofNat (a.a5.val.val &&& b.a5.val.val), |
| 181 | + felt_ofNat_isU32_of_lt _ (Nat.lt_of_le_of_lt Nat.and_le_left a.a5.val_lt)⟩ |
| 182 | + a6 := ⟨Felt.ofNat (a.a6.val.val &&& b.a6.val.val), |
| 183 | + felt_ofNat_isU32_of_lt _ (Nat.lt_of_le_of_lt Nat.and_le_left a.a6.val_lt)⟩ |
| 184 | + a7 := ⟨Felt.ofNat (a.a7.val.val &&& b.a7.val.val), |
| 185 | + felt_ofNat_isU32_of_lt _ (Nat.lt_of_le_of_lt Nat.and_le_left a.a7.val_lt)⟩ |
| 186 | +} |
| 187 | + |
| 188 | +instance : OrOp U256 where or a b := { |
| 189 | + a0 := ⟨Felt.ofNat (a.a0.val.val ||| b.a0.val.val), |
| 190 | + felt_ofNat_isU32_of_lt _ (Nat.or_lt_two_pow a.a0.val_lt b.a0.val_lt)⟩ |
| 191 | + a1 := ⟨Felt.ofNat (a.a1.val.val ||| b.a1.val.val), |
| 192 | + felt_ofNat_isU32_of_lt _ (Nat.or_lt_two_pow a.a1.val_lt b.a1.val_lt)⟩ |
| 193 | + a2 := ⟨Felt.ofNat (a.a2.val.val ||| b.a2.val.val), |
| 194 | + felt_ofNat_isU32_of_lt _ (Nat.or_lt_two_pow a.a2.val_lt b.a2.val_lt)⟩ |
| 195 | + a3 := ⟨Felt.ofNat (a.a3.val.val ||| b.a3.val.val), |
| 196 | + felt_ofNat_isU32_of_lt _ (Nat.or_lt_two_pow a.a3.val_lt b.a3.val_lt)⟩ |
| 197 | + a4 := ⟨Felt.ofNat (a.a4.val.val ||| b.a4.val.val), |
| 198 | + felt_ofNat_isU32_of_lt _ (Nat.or_lt_two_pow a.a4.val_lt b.a4.val_lt)⟩ |
| 199 | + a5 := ⟨Felt.ofNat (a.a5.val.val ||| b.a5.val.val), |
| 200 | + felt_ofNat_isU32_of_lt _ (Nat.or_lt_two_pow a.a5.val_lt b.a5.val_lt)⟩ |
| 201 | + a6 := ⟨Felt.ofNat (a.a6.val.val ||| b.a6.val.val), |
| 202 | + felt_ofNat_isU32_of_lt _ (Nat.or_lt_two_pow a.a6.val_lt b.a6.val_lt)⟩ |
| 203 | + a7 := ⟨Felt.ofNat (a.a7.val.val ||| b.a7.val.val), |
| 204 | + felt_ofNat_isU32_of_lt _ (Nat.or_lt_two_pow a.a7.val_lt b.a7.val_lt)⟩ |
| 205 | +} |
| 206 | + |
| 207 | +instance : XorOp U256 where xor a b := { |
| 208 | + a0 := ⟨Felt.ofNat (a.a0.val.val ^^^ b.a0.val.val), |
| 209 | + felt_ofNat_isU32_of_lt _ (Nat.xor_lt_two_pow a.a0.val_lt b.a0.val_lt)⟩ |
| 210 | + a1 := ⟨Felt.ofNat (a.a1.val.val ^^^ b.a1.val.val), |
| 211 | + felt_ofNat_isU32_of_lt _ (Nat.xor_lt_two_pow a.a1.val_lt b.a1.val_lt)⟩ |
| 212 | + a2 := ⟨Felt.ofNat (a.a2.val.val ^^^ b.a2.val.val), |
| 213 | + felt_ofNat_isU32_of_lt _ (Nat.xor_lt_two_pow a.a2.val_lt b.a2.val_lt)⟩ |
| 214 | + a3 := ⟨Felt.ofNat (a.a3.val.val ^^^ b.a3.val.val), |
| 215 | + felt_ofNat_isU32_of_lt _ (Nat.xor_lt_two_pow a.a3.val_lt b.a3.val_lt)⟩ |
| 216 | + a4 := ⟨Felt.ofNat (a.a4.val.val ^^^ b.a4.val.val), |
| 217 | + felt_ofNat_isU32_of_lt _ (Nat.xor_lt_two_pow a.a4.val_lt b.a4.val_lt)⟩ |
| 218 | + a5 := ⟨Felt.ofNat (a.a5.val.val ^^^ b.a5.val.val), |
| 219 | + felt_ofNat_isU32_of_lt _ (Nat.xor_lt_two_pow a.a5.val_lt b.a5.val_lt)⟩ |
| 220 | + a6 := ⟨Felt.ofNat (a.a6.val.val ^^^ b.a6.val.val), |
| 221 | + felt_ofNat_isU32_of_lt _ (Nat.xor_lt_two_pow a.a6.val_lt b.a6.val_lt)⟩ |
| 222 | + a7 := ⟨Felt.ofNat (a.a7.val.val ^^^ b.a7.val.val), |
| 223 | + felt_ofNat_isU32_of_lt _ (Nat.xor_lt_two_pow a.a7.val_lt b.a7.val_lt)⟩ |
| 224 | +} |
| 225 | + |
| 226 | +-- ============================================================================ |
| 227 | +-- Equality instance |
| 228 | +-- ============================================================================ |
| 229 | + |
| 230 | +instance : BEq U256 where beq a b := |
| 231 | + (a.a0.val == b.a0.val) && (a.a1.val == b.a1.val) && |
| 232 | + (a.a2.val == b.a2.val) && (a.a3.val == b.a3.val) && |
| 233 | + (a.a4.val == b.a4.val) && (a.a5.val == b.a5.val) && |
| 234 | + (a.a6.val == b.a6.val) && (a.a7.val == b.a7.val) |
| 235 | + |
| 236 | +-- ============================================================================ |
| 237 | +-- Bridging lemmas |
| 238 | +-- ============================================================================ |
| 239 | + |
| 240 | +namespace U256 |
| 241 | + |
| 242 | +-- Comparison bridging |
| 243 | +@[simp] theorem lt_iff_toNat_lt (a b : U256) : a < b ↔ a.toNat < b.toNat := Iff.rfl |
| 244 | +@[simp] theorem le_iff_toNat_le (a b : U256) : a ≤ b ↔ a.toNat ≤ b.toNat := Iff.rfl |
| 245 | + |
| 246 | +-- Arithmetic bridging |
| 247 | +@[simp] theorem toNat_add (a b : U256) : (a + b).toNat = (a.toNat + b.toNat) % 2^256 := |
| 248 | + ofNat_toNat _ |
| 249 | +@[simp] theorem toNat_sub (a b : U256) : (a - b).toNat = (a.toNat + 2^256 - b.toNat) % 2^256 := |
| 250 | + ofNat_toNat _ |
| 251 | +@[simp] theorem toNat_mul (a b : U256) : (a * b).toNat = (a.toNat * b.toNat) % 2^256 := |
| 252 | + ofNat_toNat _ |
| 253 | + |
| 254 | +-- Bitwise bridging (Felt level) |
| 255 | +@[simp] theorem and_a0 (a b : U256) : (a &&& b).a0.val = Felt.ofNat (a.a0.val.val &&& b.a0.val.val) := rfl |
| 256 | +@[simp] theorem and_a1 (a b : U256) : (a &&& b).a1.val = Felt.ofNat (a.a1.val.val &&& b.a1.val.val) := rfl |
| 257 | +@[simp] theorem and_a2 (a b : U256) : (a &&& b).a2.val = Felt.ofNat (a.a2.val.val &&& b.a2.val.val) := rfl |
| 258 | +@[simp] theorem and_a3 (a b : U256) : (a &&& b).a3.val = Felt.ofNat (a.a3.val.val &&& b.a3.val.val) := rfl |
| 259 | +@[simp] theorem and_a4 (a b : U256) : (a &&& b).a4.val = Felt.ofNat (a.a4.val.val &&& b.a4.val.val) := rfl |
| 260 | +@[simp] theorem and_a5 (a b : U256) : (a &&& b).a5.val = Felt.ofNat (a.a5.val.val &&& b.a5.val.val) := rfl |
| 261 | +@[simp] theorem and_a6 (a b : U256) : (a &&& b).a6.val = Felt.ofNat (a.a6.val.val &&& b.a6.val.val) := rfl |
| 262 | +@[simp] theorem and_a7 (a b : U256) : (a &&& b).a7.val = Felt.ofNat (a.a7.val.val &&& b.a7.val.val) := rfl |
| 263 | + |
| 264 | +@[simp] theorem or_a0 (a b : U256) : (a ||| b).a0.val = Felt.ofNat (a.a0.val.val ||| b.a0.val.val) := rfl |
| 265 | +@[simp] theorem or_a1 (a b : U256) : (a ||| b).a1.val = Felt.ofNat (a.a1.val.val ||| b.a1.val.val) := rfl |
| 266 | +@[simp] theorem or_a2 (a b : U256) : (a ||| b).a2.val = Felt.ofNat (a.a2.val.val ||| b.a2.val.val) := rfl |
| 267 | +@[simp] theorem or_a3 (a b : U256) : (a ||| b).a3.val = Felt.ofNat (a.a3.val.val ||| b.a3.val.val) := rfl |
| 268 | +@[simp] theorem or_a4 (a b : U256) : (a ||| b).a4.val = Felt.ofNat (a.a4.val.val ||| b.a4.val.val) := rfl |
| 269 | +@[simp] theorem or_a5 (a b : U256) : (a ||| b).a5.val = Felt.ofNat (a.a5.val.val ||| b.a5.val.val) := rfl |
| 270 | +@[simp] theorem or_a6 (a b : U256) : (a ||| b).a6.val = Felt.ofNat (a.a6.val.val ||| b.a6.val.val) := rfl |
| 271 | +@[simp] theorem or_a7 (a b : U256) : (a ||| b).a7.val = Felt.ofNat (a.a7.val.val ||| b.a7.val.val) := rfl |
| 272 | + |
| 273 | +@[simp] theorem xor_a0 (a b : U256) : (a ^^^ b).a0.val = Felt.ofNat (a.a0.val.val ^^^ b.a0.val.val) := rfl |
| 274 | +@[simp] theorem xor_a1 (a b : U256) : (a ^^^ b).a1.val = Felt.ofNat (a.a1.val.val ^^^ b.a1.val.val) := rfl |
| 275 | +@[simp] theorem xor_a2 (a b : U256) : (a ^^^ b).a2.val = Felt.ofNat (a.a2.val.val ^^^ b.a2.val.val) := rfl |
| 276 | +@[simp] theorem xor_a3 (a b : U256) : (a ^^^ b).a3.val = Felt.ofNat (a.a3.val.val ^^^ b.a3.val.val) := rfl |
| 277 | +@[simp] theorem xor_a4 (a b : U256) : (a ^^^ b).a4.val = Felt.ofNat (a.a4.val.val ^^^ b.a4.val.val) := rfl |
| 278 | +@[simp] theorem xor_a5 (a b : U256) : (a ^^^ b).a5.val = Felt.ofNat (a.a5.val.val ^^^ b.a5.val.val) := rfl |
| 279 | +@[simp] theorem xor_a6 (a b : U256) : (a ^^^ b).a6.val = Felt.ofNat (a.a6.val.val ^^^ b.a6.val.val) := rfl |
| 280 | +@[simp] theorem xor_a7 (a b : U256) : (a ^^^ b).a7.val = Felt.ofNat (a.a7.val.val ^^^ b.a7.val.val) := rfl |
| 281 | + |
| 282 | +-- Equality bridging |
| 283 | +@[simp] theorem beq_iff (a b : U256) : |
| 284 | + (a == b) = ((a.a0.val == b.a0.val) && (a.a1.val == b.a1.val) && |
| 285 | + (a.a2.val == b.a2.val) && (a.a3.val == b.a3.val) && |
| 286 | + (a.a4.val == b.a4.val) && (a.a5.val == b.a5.val) && |
| 287 | + (a.a6.val == b.a6.val) && (a.a7.val == b.a7.val)) := rfl |
| 288 | + |
| 289 | +-- ============================================================================ |
| 290 | +-- isU32 lemmas for U256 limbs |
| 291 | +-- ============================================================================ |
| 292 | + |
| 293 | +theorem a0_isU32 (x : U256) : x.a0.val.isU32 = true := x.a0.isU32 |
| 294 | +theorem a1_isU32 (x : U256) : x.a1.val.isU32 = true := x.a1.isU32 |
| 295 | +theorem a2_isU32 (x : U256) : x.a2.val.isU32 = true := x.a2.isU32 |
| 296 | +theorem a3_isU32 (x : U256) : x.a3.val.isU32 = true := x.a3.isU32 |
| 297 | +theorem a4_isU32 (x : U256) : x.a4.val.isU32 = true := x.a4.isU32 |
| 298 | +theorem a5_isU32 (x : U256) : x.a5.val.isU32 = true := x.a5.isU32 |
| 299 | +theorem a6_isU32 (x : U256) : x.a6.val.isU32 = true := x.a6.isU32 |
| 300 | +theorem a7_isU32 (x : U256) : x.a7.val.isU32 = true := x.a7.isU32 |
| 301 | + |
| 302 | +-- ============================================================================ |
| 303 | +-- Eqz helper |
| 304 | +-- ============================================================================ |
| 305 | + |
| 306 | +/-- A U256 is zero iff all limbs are zero. -/ |
| 307 | +theorem eqz_iff (x : U256) : |
| 308 | + x.toNat = 0 ↔ x.a0.val.val = 0 ∧ x.a1.val.val = 0 ∧ x.a2.val.val = 0 ∧ x.a3.val.val = 0 ∧ |
| 309 | + x.a4.val.val = 0 ∧ x.a5.val.val = 0 ∧ x.a6.val.val = 0 ∧ x.a7.val.val = 0 := by |
| 310 | + unfold toNat |
| 311 | + constructor |
| 312 | + · intro h; omega |
| 313 | + · intro ⟨h0, h1, h2, h3, h4, h5, h6, h7⟩; omega |
| 314 | + |
| 315 | +end U256 |
| 316 | + |
| 317 | +end MidenLean.Proofs |
0 commit comments