qfall_math/integer_mod_q/ntt_polynomial_ring_zq/arithmetic/
mul.rs1use crate::{
12 integer::Z,
13 integer_mod_q::NTTPolynomialRingZq,
14 macros::arithmetics::{
15 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
16 arithmetic_trait_mixed_borrowed_owned,
17 },
18 traits::CompareBase,
19};
20use flint_sys::fmpz_mod::fmpz_mod_mul;
21use std::ops::{Mul, MulAssign};
22
23impl Mul for &NTTPolynomialRingZq {
24 type Output = NTTPolynomialRingZq;
25
26 fn mul(self, other: Self) -> Self::Output {
50 if !self.compare_base(other) {
51 panic!("{}", self.call_compare_base_error(other).unwrap());
52 }
53 let mod_q = &self.modulus.get_fq_ctx().ctxp[0];
54
55 let mut res = Vec::with_capacity(self.poly.capacity());
56 for i in 0..self.poly.len() {
57 let mut z_i = Z::ZERO;
58 unsafe {
59 fmpz_mod_mul(
60 &mut z_i.value,
61 &self.poly[i].value,
62 &other.poly[i].value,
63 mod_q,
64 );
65 }
66 res.push(z_i)
67 }
68 Self::Output {
69 poly: res,
70 modulus: self.modulus.clone(),
71 }
72 }
73}
74
75arithmetic_trait_borrowed_to_owned!(
76 Mul,
77 mul,
78 NTTPolynomialRingZq,
79 NTTPolynomialRingZq,
80 NTTPolynomialRingZq
81);
82arithmetic_trait_mixed_borrowed_owned!(
83 Mul,
84 mul,
85 NTTPolynomialRingZq,
86 NTTPolynomialRingZq,
87 NTTPolynomialRingZq
88);
89
90impl MulAssign<&NTTPolynomialRingZq> for NTTPolynomialRingZq {
91 fn mul_assign(&mut self, other: &NTTPolynomialRingZq) {
114 if !self.compare_base(other) {
115 panic!("{}", self.call_compare_base_error(other).unwrap());
116 }
117 let mod_q = &self.modulus.get_fq_ctx().ctxp[0];
118
119 for i in 0..self.poly.len() {
120 unsafe {
121 fmpz_mod_mul(
122 &mut self.poly[i].value,
123 &self.poly[i].value,
124 &other.poly[i].value,
125 mod_q,
126 );
127 }
128 }
129 }
130}
131
132arithmetic_assign_trait_borrowed_to_owned!(
133 MulAssign,
134 mul_assign,
135 NTTPolynomialRingZq,
136 NTTPolynomialRingZq
137);
138
139#[cfg(test)]
140mod test_mul {
141 use crate::{
142 integer_mod_q::{
143 ModulusPolynomialRingZq, NTTPolynomialRingZq, PolyOverZq, PolynomialRingZq,
144 },
145 traits::SetCoefficient,
146 };
147 use std::{ops::Mul, str::FromStr};
148
149 #[test]
152 fn test_dilithium_params() {
153 let n = 256;
154 let modulus = 2_i64.pow(23) - 2_i64.pow(13) + 1;
155
156 let mut mod_poly = PolyOverZq::from(modulus);
157 mod_poly.set_coeff(0, 1).unwrap();
158 mod_poly.set_coeff(n, 1).unwrap();
159
160 let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
161
162 polynomial_modulus.set_ntt_unchecked(1753);
163
164 let p1 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
165 let p2 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
166
167 let ntt1 = NTTPolynomialRingZq::from(&p1);
168 let ntt2 = NTTPolynomialRingZq::from(&p2);
169
170 let ntt_res = ntt1.mul(ntt2);
171
172 assert_eq!(&p1 * &p2, PolynomialRingZq::from(ntt_res))
173 }
174
175 #[test]
178 fn test_hawk1024_params() {
179 let n = 1024;
180 let modulus = 12289;
181
182 let mut mod_poly = PolyOverZq::from(modulus);
183 mod_poly.set_coeff(0, 1).unwrap();
184 mod_poly.set_coeff(n, 1).unwrap();
185
186 let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
187
188 polynomial_modulus.set_ntt_unchecked(1945);
189
190 let p1 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
191 let p2 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
192
193 let ntt1 = NTTPolynomialRingZq::from(&p1);
194 let ntt2 = NTTPolynomialRingZq::from(&p2);
195
196 let ntt_res = ntt1.mul(&ntt2);
197
198 assert_eq!(&p1 * &p2, PolynomialRingZq::from(ntt_res))
199 }
200
201 #[test]
203 #[should_panic]
204 fn different_moduli() {
205 let mut modulus0 = ModulusPolynomialRingZq::from_str("5 1 0 0 0 1 mod 257").unwrap();
206 modulus0.set_ntt_unchecked(64);
207 let mut modulus1 = ModulusPolynomialRingZq::from_str("6 1 0 0 0 0 1 mod 257").unwrap();
208 modulus1.set_ntt_unchecked(64);
209
210 let a = NTTPolynomialRingZq::sample_uniform(&modulus0);
211 let b = NTTPolynomialRingZq::sample_uniform(&modulus1);
212
213 let _ = a * b;
214 }
215}
216
217#[cfg(test)]
218mod test_mul_assign {
219 use crate::{
220 integer_mod_q::{
221 ModulusPolynomialRingZq, NTTPolynomialRingZq, PolyOverZq, PolynomialRingZq,
222 },
223 traits::SetCoefficient,
224 };
225 use std::{ops::MulAssign, str::FromStr};
226
227 #[test]
230 fn test_dilithium_params() {
231 let n = 256;
232 let modulus = 2_i64.pow(23) - 2_i64.pow(13) + 1;
233
234 let mut mod_poly = PolyOverZq::from(modulus);
235 mod_poly.set_coeff(0, 1).unwrap();
236 mod_poly.set_coeff(n, 1).unwrap();
237
238 let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
239
240 polynomial_modulus.set_ntt_unchecked(1753);
241
242 let p1 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
243 let p2 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
244
245 let mut ntt1 = NTTPolynomialRingZq::from(&p1);
246 let ntt2 = NTTPolynomialRingZq::from(&p2);
247
248 ntt1.mul_assign(ntt2);
249
250 assert_eq!(&p1 * &p2, PolynomialRingZq::from(ntt1))
251 }
252
253 #[test]
256 fn test_hawk1024_params() {
257 let n = 1024;
258 let modulus = 12289;
259
260 let mut mod_poly = PolyOverZq::from(modulus);
261 mod_poly.set_coeff(0, 1).unwrap();
262 mod_poly.set_coeff(n, 1).unwrap();
263
264 let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
265
266 polynomial_modulus.set_ntt_unchecked(1945);
267
268 let p1 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
269 let p2 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
270
271 let mut ntt1 = NTTPolynomialRingZq::from(&p1);
272 let ntt2 = NTTPolynomialRingZq::from(&p2);
273
274 ntt1.mul_assign(ntt2);
275
276 assert_eq!(&p1 * &p2, PolynomialRingZq::from(ntt1))
277 }
278
279 #[test]
281 #[should_panic]
282 fn different_moduli() {
283 let mut modulus0 = ModulusPolynomialRingZq::from_str("5 1 0 0 0 1 mod 257").unwrap();
284 modulus0.set_ntt_unchecked(64);
285 let mut modulus1 = ModulusPolynomialRingZq::from_str("6 1 0 0 0 0 1 mod 257").unwrap();
286 modulus1.set_ntt_unchecked(64);
287
288 let mut a = NTTPolynomialRingZq::sample_uniform(&modulus0);
289 let b = NTTPolynomialRingZq::sample_uniform(&modulus1);
290
291 a *= b;
292 }
293}