|
| 1 | +theory Common |
| 2 | + imports MLKEM_Poly_Definitions "Micro_C_Examples.C_While_Examples" |
| 3 | +begin |
| 4 | + |
| 5 | +section \<open>Abstract polynomial arithmetic\<close> |
| 6 | + |
| 7 | +text \<open>We model mlkem-native polynomials abstractly as fixed-size coefficient |
| 8 | + lists over the integers. This gives a clean mathematical specification |
| 9 | + independent of machine word sizes.\<close> |
| 10 | + |
| 11 | +abbreviation MLKEM_N :: nat where |
| 12 | + \<open>MLKEM_N \<equiv> 256\<close> |
| 13 | + |
| 14 | +type_synonym int_poly = \<open>int list\<close> |
| 15 | + |
| 16 | +definition poly_add_int :: \<open>int_poly \<Rightarrow> int_poly \<Rightarrow> int_poly\<close> where |
| 17 | + \<open>poly_add_int ps qs = map2 (+) ps qs\<close> |
| 18 | + |
| 19 | +definition poly_sub_int :: \<open>int_poly \<Rightarrow> int_poly \<Rightarrow> int_poly\<close> where |
| 20 | + \<open>poly_sub_int ps qs = map2 (-) ps qs\<close> |
| 21 | + |
| 22 | +subsection \<open>Barrett reduction\<close> |
| 23 | + |
| 24 | +abbreviation MLKEM_Q :: int where |
| 25 | + \<open>MLKEM_Q \<equiv> 3329\<close> |
| 26 | + |
| 27 | +definition barrett_reduce_int :: \<open>int \<Rightarrow> int\<close> where |
| 28 | + \<open>barrett_reduce_int a = a - ((20159 * a + 2^25) div 2^26) * MLKEM_Q\<close> |
| 29 | + |
| 30 | +lemma barrett_reduce_mod: |
| 31 | + shows \<open>barrett_reduce_int a mod MLKEM_Q = a mod MLKEM_Q\<close> |
| 32 | +unfolding barrett_reduce_int_def by algebra |
| 33 | + |
| 34 | +section \<open>Concrete types and refinement\<close> |
| 35 | + |
| 36 | +text \<open> |
| 37 | + Refinement relation: a concrete @{typ c_mlk_poly} refines an abstract |
| 38 | + @{typ int_poly} when its coefficient list has the correct length and its |
| 39 | + signed interpretation matches the abstract polynomial. |
| 40 | +\<close> |
| 41 | +definition refines_mlk_poly :: \<open>c_mlk_poly \<Rightarrow> int_poly \<Rightarrow> bool\<close> where |
| 42 | + \<open>refines_mlk_poly cp ap \<longleftrightarrow> |
| 43 | + length (c_mlk_poly_coeffs cp) = MLKEM_N \<and> |
| 44 | + List.map sint (c_mlk_poly_coeffs cp) = ap\<close> |
| 45 | + |
| 46 | +text \<open> |
| 47 | + No-overflow condition: the mathematical sum of each coefficient pair |
| 48 | + fits in a signed 16-bit integer. This is required both for the C code |
| 49 | + to not abort (since @{const c_signed_add} checks for overflow) and for |
| 50 | + the refinement to integer arithmetic to hold. |
| 51 | +\<close> |
| 52 | +definition no_overflow_add :: \<open>int_poly \<Rightarrow> int_poly \<Rightarrow> bool\<close> where |
| 53 | + \<open>no_overflow_add ps qs \<longleftrightarrow> |
| 54 | + (\<forall>i < min (length ps) (length qs). |
| 55 | + ps ! i + qs ! i \<in> {-(2^15) ..< 2^15})\<close> |
| 56 | + |
| 57 | +definition no_overflow_sub :: \<open>int_poly \<Rightarrow> int_poly \<Rightarrow> bool\<close> where |
| 58 | + \<open>no_overflow_sub ps qs \<longleftrightarrow> |
| 59 | + (\<forall>i < min (length ps) (length qs). |
| 60 | + ps ! i - qs ! i \<in> {-(2^15) ..< 2^15})\<close> |
| 61 | + |
| 62 | +text \<open> |
| 63 | + The concrete (word-level) result of polynomial addition — internal helper |
| 64 | + for proofs. |
| 65 | +\<close> |
| 66 | +definition poly_add_c :: \<open>c_mlk_poly \<Rightarrow> c_mlk_poly \<Rightarrow> c_mlk_poly\<close> where |
| 67 | + \<open>poly_add_c p q = update_c_mlk_poly_coeffs |
| 68 | + (\<lambda>_. map2 (+) (c_mlk_poly_coeffs p) (c_mlk_poly_coeffs q)) p\<close> |
| 69 | + |
| 70 | +subsection \<open>Refinement lemmas\<close> |
| 71 | + |
| 72 | +lemma sint_plus_no_overflow: |
| 73 | + fixes a b :: \<open>'l::{len} sword\<close> |
| 74 | + assumes \<open>sint a + sint b \<in> {-(2^(LENGTH('l) - 1)) ..< 2^(LENGTH('l) - 1)}\<close> |
| 75 | + shows \<open>sint (a + b) = sint a + sint b\<close> |
| 76 | +using assms by (intro signed_arith_sint) (auto simp: word_size) |
| 77 | + |
| 78 | +lemma sint_minus_no_overflow: |
| 79 | + fixes a b :: \<open>'l::{len} sword\<close> |
| 80 | + assumes \<open>sint a - sint b \<in> {-(2^(LENGTH('l) - 1)) ..< 2^(LENGTH('l) - 1)}\<close> |
| 81 | + shows \<open>sint (a - b) = sint a - sint b\<close> |
| 82 | +using assms by (intro signed_arith_sint) (auto simp: word_size) |
| 83 | + |
| 84 | +text \<open> |
| 85 | + The key refinement theorem: under the no-overflow condition, the concrete |
| 86 | + word-level addition produces a result that refines the abstract integer sum. |
| 87 | +\<close> |
| 88 | +lemma poly_add_c_refines: |
| 89 | + assumes \<open>refines_mlk_poly p ap\<close> |
| 90 | + and \<open>refines_mlk_poly q aq\<close> |
| 91 | + and \<open>no_overflow_add ap aq\<close> |
| 92 | + shows \<open>refines_mlk_poly (poly_add_c p q) (poly_add_int ap aq)\<close> |
| 93 | +using assms by (auto simp add: c_mlk_poly.record_simps map2_map_map word_size refines_mlk_poly_def |
| 94 | + poly_add_c_def poly_add_int_def no_overflow_add_def intro!: nth_equalityI sint_plus_no_overflow) |
| 95 | + |
| 96 | +subsection \<open>Auxiliary Lemmas\<close> |
| 97 | + |
| 98 | +lemma nth_map2: |
| 99 | + assumes \<open>i < length xs\<close> |
| 100 | + and \<open>i < length ys\<close> |
| 101 | + shows \<open>map2 f xs ys ! i = f (xs ! i) (ys ! i)\<close> |
| 102 | +using assms by (induction xs arbitrary: i ys) (auto simp: less_Suc_eq_0_disj split: list.splits) |
| 103 | + |
| 104 | +lemma inv_list_step: |
| 105 | + assumes \<open>n < length xs\<close> |
| 106 | + and \<open>n < length ys\<close> |
| 107 | + and \<open>length xs = length ys\<close> |
| 108 | + shows \<open>(take n (map2 f xs ys) @ drop n xs)[n := f (xs ! n) (ys ! n)] = |
| 109 | + take (Suc n) (map2 f xs ys) @ drop (Suc n) xs\<close> |
| 110 | +proof - |
| 111 | + let ?zs = \<open>map2 f xs ys\<close> |
| 112 | + from assms have ln: \<open>n < length ?zs\<close> |
| 113 | + by simp |
| 114 | + from assms have zn: \<open>?zs ! n = f (xs ! n) (ys ! n)\<close> |
| 115 | + by (simp add: nth_map2) |
| 116 | + from assms have drop_eq: \<open>drop n xs = xs ! n # drop (Suc n) xs\<close> |
| 117 | + by (metis Cons_nth_drop_Suc) |
| 118 | + have \<open>(take n ?zs @ drop n xs)[n := ?zs ! n] = take n ?zs @ (drop n xs)[0 := ?zs ! n]\<close> |
| 119 | + using ln by (simp add: list_update_append) |
| 120 | + also have \<open>\<dots> = take n ?zs @ ?zs ! n # drop (Suc n) xs\<close> |
| 121 | + using drop_eq by simp |
| 122 | + also have \<open>\<dots> = take (Suc n) ?zs @ drop (Suc n) xs\<close> |
| 123 | + using ln by (simp add: take_Suc_conv_app_nth) |
| 124 | + finally show ?thesis |
| 125 | + using zn by simp |
| 126 | +qed |
| 127 | + |
| 128 | +lemma no_overflow_add_bounds: |
| 129 | + assumes \<open>refines_mlk_poly vr ar\<close> |
| 130 | + and \<open>refines_mlk_poly vb ab\<close> |
| 131 | + and \<open>no_overflow_add ar ab\<close> \<open>i < MLKEM_N\<close> |
| 132 | + shows \<open>sint (c_mlk_poly_coeffs vr ! i) + sint (c_mlk_poly_coeffs vb ! i) < 2 ^ 15\<close> |
| 133 | + and \<open>- (2 ^ 15) \<le> sint (c_mlk_poly_coeffs vr ! i) + sint (c_mlk_poly_coeffs vb ! i)\<close> |
| 134 | +proof - |
| 135 | + from assms(1) have lr: \<open>length (c_mlk_poly_coeffs vr) = MLKEM_N\<close> |
| 136 | + and mr: \<open>List.map sint (c_mlk_poly_coeffs vr) = ar\<close> |
| 137 | + unfolding refines_mlk_poly_def by auto |
| 138 | + from assms(2) have lb: \<open>length (c_mlk_poly_coeffs vb) = MLKEM_N\<close> |
| 139 | + and mb: \<open>List.map sint (c_mlk_poly_coeffs vb) = ab\<close> |
| 140 | + unfolding refines_mlk_poly_def by auto |
| 141 | + have \<open>ar ! i + ab ! i \<in> {-(2^15) ..< 2^15}\<close> |
| 142 | + using assms(3,4) lr lb mr mb unfolding no_overflow_add_def by auto |
| 143 | + moreover have \<open>ar ! i = sint (c_mlk_poly_coeffs vr ! i)\<close> |
| 144 | + using mr lr assms(4) by (simp add: nth_map[symmetric]) |
| 145 | + moreover have \<open>ab ! i = sint (c_mlk_poly_coeffs vb ! i)\<close> |
| 146 | + using mb lb assms(4) by (simp add: nth_map[symmetric]) |
| 147 | + ultimately show \<open>sint (c_mlk_poly_coeffs vr ! i) + sint (c_mlk_poly_coeffs vb ! i) < 2 ^ 15\<close> |
| 148 | + and \<open>- (2 ^ 15) \<le> sint (c_mlk_poly_coeffs vr ! i) + sint (c_mlk_poly_coeffs vb ! i)\<close> |
| 149 | + by auto |
| 150 | +qed |
| 151 | + |
| 152 | +lemma no_overflow_sub_bounds: |
| 153 | + assumes \<open>refines_mlk_poly vr ar\<close> |
| 154 | + and \<open>refines_mlk_poly vb ab\<close> |
| 155 | + and \<open>no_overflow_sub ar ab\<close> \<open>i < MLKEM_N\<close> |
| 156 | + shows \<open>sint (c_mlk_poly_coeffs vr ! i) - sint (c_mlk_poly_coeffs vb ! i) < 2 ^ 15\<close> |
| 157 | + and \<open>- (2 ^ 15) \<le> sint (c_mlk_poly_coeffs vr ! i) - sint (c_mlk_poly_coeffs vb ! i)\<close> |
| 158 | +proof - |
| 159 | + from assms(1) have lr: \<open>length (c_mlk_poly_coeffs vr) = MLKEM_N\<close> |
| 160 | + and mr: \<open>List.map sint (c_mlk_poly_coeffs vr) = ar\<close> |
| 161 | + unfolding refines_mlk_poly_def by auto |
| 162 | + from assms(2) have lb: \<open>length (c_mlk_poly_coeffs vb) = MLKEM_N\<close> |
| 163 | + and mb: \<open>List.map sint (c_mlk_poly_coeffs vb) = ab\<close> |
| 164 | + unfolding refines_mlk_poly_def by auto |
| 165 | + have \<open>ar ! i - ab ! i \<in> {-(2^15) ..< 2^15}\<close> |
| 166 | + using assms(3,4) lr lb mr mb unfolding no_overflow_sub_def by auto |
| 167 | + moreover have \<open>ar ! i = sint (c_mlk_poly_coeffs vr ! i)\<close> |
| 168 | + using mr lr assms(4) by (simp add: nth_map[symmetric]) |
| 169 | + moreover have \<open>ab ! i = sint (c_mlk_poly_coeffs vb ! i)\<close> |
| 170 | + using mb lb assms(4) by (simp add: nth_map[symmetric]) |
| 171 | + ultimately show \<open>sint (c_mlk_poly_coeffs vr ! i) - sint (c_mlk_poly_coeffs vb ! i) < 2 ^ 15\<close> |
| 172 | + and \<open>- (2 ^ 15) \<le> sint (c_mlk_poly_coeffs vr ! i) - sint (c_mlk_poly_coeffs vb ! i)\<close> |
| 173 | + by auto |
| 174 | +qed |
| 175 | + |
| 176 | +lemma MLKEM_N_sub_step [simp]: |
| 177 | + assumes \<open>k < MLKEM_N\<close> |
| 178 | + shows \<open>MLKEM_N - k = Suc (255 - k)\<close> |
| 179 | +using assms by simp |
| 180 | + |
| 181 | +lemma mlkem_rev_index_bound [simp]: |
| 182 | + shows \<open>255 - k < MLKEM_N\<close> |
| 183 | +by simp |
| 184 | + |
| 185 | +end |
0 commit comments