|
| 1 | +use hax_lib as hax; |
| 2 | +use hax_lib::lean; |
| 3 | + |
| 4 | +/// Values having this type hold a representative 'x' of the Kyber field. |
| 5 | +/// We use 'fe' as a shorthand for this type. |
| 6 | +pub(crate) type FieldElement = i32; |
| 7 | + |
| 8 | +#[hax_lib::lean::before("@[simp, spec]")] |
| 9 | +const BARRETT_R: i64 = 0x400000; // is 0x4000000 in the normal barrett example |
| 10 | + |
| 11 | +#[hax_lib::lean::before("@[simp, spec]")] |
| 12 | +const BARRETT_SHIFT: i64 = 26; |
| 13 | + |
| 14 | +#[hax_lib::lean::before("@[simp, spec]")] |
| 15 | +const BARRETT_MULTIPLIER: i64 = 20159; |
| 16 | + |
| 17 | +#[hax_lib::lean::before("@[simp, spec]")] |
| 18 | +pub(crate) const FIELD_MODULUS: i32 = 3329; |
| 19 | + |
| 20 | +/// Signed Barrett Reduction |
| 21 | +/// |
| 22 | +/// Given an input `value`, `barrett_reduce` outputs a representative `result` |
| 23 | +/// such that: |
| 24 | +/// |
| 25 | +/// - result ≡ value (mod FIELD_MODULUS) |
| 26 | +/// - the absolute value of `result` is bound as follows: |
| 27 | +/// |
| 28 | +/// `|result| ≤ FIELD_MODULUS / 2 · (|value|/BARRETT_R + 1) |
| 29 | +/// |
| 30 | +/// In particular, if `|value| < BARRETT_R`, then `|result| < FIELD_MODULUS`. |
| 31 | +#[hax::requires((i64::from(value) >= -BARRETT_R && i64::from(value) <= BARRETT_R))] |
| 32 | +#[hax::ensures(|result| { |
| 33 | + let valid_result = value % FIELD_MODULUS; |
| 34 | + result > -FIELD_MODULUS |
| 35 | + && result < FIELD_MODULUS |
| 36 | + && (result == valid_result || |
| 37 | + result == valid_result + FIELD_MODULUS || |
| 38 | + result == valid_result - FIELD_MODULUS) |
| 39 | +})] |
| 40 | +#[hax_lib::lean::before("@[simp, spec]")] |
| 41 | +#[hax_lib::lean::after(" |
| 42 | +theorem barrett_spec (value: i32) : |
| 43 | + ⦃ __requires (value) = pure true ⦄ |
| 44 | + (barrett_reduce value) |
| 45 | + ⦃ ⇓ result => __ensures value result = pure true ⦄ |
| 46 | +:= by |
| 47 | + mvcgen [__requires, __ensures] |
| 48 | + hax_bv_decide |
| 49 | + simp [__requires, __ensures] at * |
| 50 | + rw [Int32.HaxRem_spec_bv_rw] ; simp ; |
| 51 | + rw [Int32.HaxAdd_spec_bv_rw] ; simp ; |
| 52 | + rw [Int32.HaxSub_spec_bv_rw] ; simp |
| 53 | + hax_bv_decide |
| 54 | + expose_names |
| 55 | + have ⟨ h1, h2 ⟩ := h; clear h |
| 56 | + simp [Int32.eq_iff_toBitVec_eq, |
| 57 | + Int32.lt_iff_toBitVec_slt, |
| 58 | + Int32.le_iff_toBitVec_sle, |
| 59 | + Int64.eq_iff_toBitVec_eq, |
| 60 | + Int64.lt_iff_toBitVec_slt, |
| 61 | + Int64.le_iff_toBitVec_sle, |
| 62 | + ] at * |
| 63 | + generalize Int32.toBitVec value = bv_value at * ; clear value |
| 64 | + bv_decide (config := {timeout := 120}) |
| 65 | +")] |
| 66 | +pub fn barrett_reduce(value: FieldElement) -> FieldElement { |
| 67 | + let t = i64::from(value) * BARRETT_MULTIPLIER; |
| 68 | + let t = t + (BARRETT_R >> 1); |
| 69 | + let quotient = t >> BARRETT_SHIFT; |
| 70 | + let quotient = quotient as i32; |
| 71 | + let sub = quotient * FIELD_MODULUS; |
| 72 | + value - sub |
| 73 | +} |
0 commit comments