1use crate::aux_functions::{high_bits, low_bits, make_hint, use_hint};
4use crate::mldsa::{MLDSA44_POLY_W1_PACKED_LEN, MLDSA65_POLY_W1_PACKED_LEN, N, q, q_inv};
5use core::ops::{Index, IndexMut};
6
7#[derive(Clone, Copy)]
21pub struct Polynomial {
22 pub(crate) coeffs: [i32; N],
23}
24
25impl Index<usize> for Polynomial {
27 type Output = i32;
28
29 fn index(&self, index: usize) -> &Self::Output {
30 &self.coeffs[index]
31 }
32}
33impl IndexMut<usize> for Polynomial {
35 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
36 &mut self.coeffs[index]
37 }
38}
39
40impl Polynomial {
46 pub const fn new() -> Self {
48 Self { coeffs: [0i32; N] }
49 }
50
51 pub(crate) fn conditional_add_q(&mut self) {
52 for x in self.coeffs.iter_mut() {
53 *x = conditional_add_q(*x);
54 }
55 }
56
57 pub(crate) fn add_ntt(&mut self, w: &Self) {
61 for i in 0..N {
62 self[i] += w[i];
63 }
64 }
65
66 pub(crate) fn sub(&mut self, w: &Self) {
67 for i in 0..N {
68 self[i] -= w[i];
69 }
70 }
71
72 pub(crate) fn multiply_ntt(&mut self, b: &Polynomial) {
79 for i in 0..N {
80 self[i] = montgomery_reduce((self[i] as i64) * (b[i] as i64));
81 }
82 }
83
84 pub(crate) fn high_bits<const GAMMA2: i32>(&mut self) {
85 for i in 0..N {
86 self[i] = high_bits::<GAMMA2>(self[i]);
87 }
88 }
89
90 pub(crate) fn low_bits<const GAMMA2: i32>(&mut self) {
91 for i in 0..N {
92 self[i] = low_bits::<GAMMA2>(self[i]);
93 }
94 }
95
96 pub(crate) fn check_norm<const BOUND: i32>(&self) -> bool {
97 debug_assert!(BOUND <= (q - 1) / 8);
108
109 let mut t: i32;
110 for x in self.coeffs.iter() {
111 t = *x >> 31;
112 t = *x - (t & (2 * *x));
113
114 if t >= BOUND {
115 return true;
116 }
117 }
118 false
119 }
120
121 pub(crate) fn shift_left<const d: i32>(&mut self) {
122 for x in self.coeffs.iter_mut() {
123 *x <<= d;
124 }
125 }
126
127 pub(crate) fn make_hint_row<const GAMMA2: i32>(&self, r: &Self) -> (Self, i32) {
129 let mut out = Polynomial::new();
130 let mut count = 0i32;
131 for i in 0..N {
132 let x = make_hint::<GAMMA2>(self[i], r[i]);
133 out[i] = x;
134 count += x;
135 }
136
137 (out, count)
138 }
139
140 pub(crate) fn w1_encode<const POLY_W1_PACKED_LEN: usize>(&self) -> [u8; POLY_W1_PACKED_LEN] {
141 let mut r = [0u8; POLY_W1_PACKED_LEN];
151
152 match POLY_W1_PACKED_LEN {
153 MLDSA44_POLY_W1_PACKED_LEN => {
154 for i in 0..N / 4 {
155 r[3 * i] = ((self[4 * i]) as u8) | ((self[4 * i + 1] << 6) as u8);
156 r[3 * i + 1] = ((self[4 * i + 1] >> 2) as u8) | ((self[4 * i + 2] << 4) as u8);
157 r[3 * i + 2] = ((self[4 * i + 2] >> 4) as u8) | ((self[4 * i + 3] << 2) as u8);
158 }
159 }
160 MLDSA65_POLY_W1_PACKED_LEN => {
162 for i in 0..N / 2 {
163 r[i] = ((self[2 * i]) | (self[2 * i + 1] << 4)) as u8;
164 }
165 }
166 _ => {
167 unreachable!()
168 }
169 }
170
171 r
172 }
173
174 pub(crate) fn ntt(&mut self) {
188 let mut m: usize = 0;
189 let mut len: usize = 128;
190
191 while len >= 1 {
192 let mut start: usize = 0;
193 while start < N {
194 m += 1;
195 let z: i32 = ZETAS[m];
196
197 for j in start..start + len {
198 let t = montgomery_reduce(z as i64 * self[j + len] as i64);
199 self[j + len] = self[j] - t; self[j] = self[j] + t; }
202 start = start + 2 * len;
203 }
204 len >>= 1;
205 }
206 }
207
208 pub(crate) fn inv_ntt(&mut self) {
214 let mut m: usize = N;
215 let mut len: usize = 1;
216
217 while len < N {
218 let mut start: usize = 0;
219 while start < N {
220 m -= 1;
221 let z = (-1) * ZETAS[m];
222
223 for j in start..start + len {
226 let t: i32 = self[j];
228
229 self[j] = t + self[j + len];
231
232 self[j + len] = t - self[j + len];
234
235 self[j + len] = montgomery_reduce(z as i64 * self[j + len] as i64);
237 }
238 start = start + 2 * len; }
240 len <<= 1;
241 }
242
243 const f: i64 = 41978;
247 for j in 0..N {
248 self[j] = montgomery_reduce(f * self[j] as i64);
250 }
251 }
252
253 pub(crate) fn use_hint<const GAMMA2: i32>(&mut self, h: &Polynomial) {
254 for i in 0..N {
255 self[i] = use_hint::<GAMMA2>(self[i], h[i]);
256 }
257 }
258}
259
260pub(crate) fn montgomery_reduce(a: i64) -> i32 {
265 debug_assert!(a > -((q as i64) << 31) && a < ((q as i64) << 31));
266
267 let t: i32 = (a as i32).wrapping_mul(q_inv);
269
270 ((a - ((t as i64) * (q as i64))) >> 32) as i32
272}
273
274pub(crate) fn conditional_add_q(a: i32) -> i32 {
275 a + ((a >> 31) & q)
276}
277
278#[test]
279fn test_conditional_add_q() {
281 assert_eq!(conditional_add_q(-q - 1), -1);
282 assert_eq!(conditional_add_q(-q), 0);
283 assert_eq!(conditional_add_q(-q - 2), -2);
284 assert_eq!(conditional_add_q(-q + 1), 1);
285 assert_eq!(conditional_add_q(-1), q - 1);
286 assert_eq!(conditional_add_q(0), 0);
287 assert_eq!(conditional_add_q(1), 1);
288 assert_eq!(conditional_add_q(q - 1), q - 1);
289 assert_eq!(conditional_add_q(q), q);
290 assert_eq!(conditional_add_q(q + 1), q + 1);
291}
292
293const ZETAS: [i32; 256] = [
295 0, 25847, -2608894, -518909, 237124, -777960, -876248, 466468, 1826347, 2353451, -359251,
296 -2091905, 3119733, -2884855, 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488,
297 -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, 1757237, -19422, 4010497,
298 280005, 2706023, 95776, 3077325, 3530437, -1661693, -3592148, -2537516, 3915439, -3861115,
299 -3043716, 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, -1643818, 3505694,
300 -3821735, 3507263, -2140649, -1600420, 3699596, 811944, 531354, 954230, 3881043, 3900724,
301 -2556880, 2071892, -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950,
302 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, -3157330, -3632928, 126922,
303 3412210, -983419, 2147896, 2715295, -2967645, -3693493, -411027, -2477047, -671102, -1228525,
304 -22981, -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, 508951, 3097992,
305 44288, -1100098, 904516, 3958618, -3724342, -8578, 1653064, -3249728, 2389356, -210977, 759969,
306 -1316856, 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, 1341330, 1285669,
307 -1584928, -812732, -1439742, -3019102, -3881060, -3628969, 3839961, 2091667, 3407706, 2316500,
308 3817976, -3342478, 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, -3520352,
309 -3759364, -1197226, -3193378, 900702, 1859098, 909542, 819034, 495491, -1613174, -43260,
310 -522500, -655327, -3122442, 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297,
311 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, 2842341, 2691481, -2590150,
312 1265009, 4055324, 1247620, 2486353, 1595974, -3767016, 1250494, 2635921, -3548272, -2994039,
313 1869119, 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, 1312455, 3306115,
314 -1962642, -1279661, 1917081, -2546312, -1374803, 1500165, 777191, 2235880, 3406031, -542412,
315 -2831860, -1671176, -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, 2454455,
316 -164721, 1957272, 3369112, 185531, -1207385, -3183426, 162844, 1616392, 3014001, 810149,
317 1652634, -3694233, -1799107, -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735,
318 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, -260646, -3833893, -2939036,
319 -2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687, -554416, 3919660, -48306,
320 -1362209, 3937738, 1400424, -846154, 1976782,
321];