qfall_math/integer_mod_q/mat_polynomial_ring_zq/arithmetic/
mul.rs1use super::super::MatPolynomialRingZq;
12use crate::error::MathError;
13use crate::integer::MatPolyOverZ;
14use crate::macros::arithmetics::{
15 arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
16};
17use crate::traits::{CompareBase, MatrixDimensions};
18use std::ops::Mul;
19
20impl Mul for &MatPolynomialRingZq {
21 type Output = MatPolynomialRingZq;
22
23 fn mul(self, other: Self) -> Self::Output {
54 self.mul_safe(other).unwrap()
55 }
56}
57
58arithmetic_trait_borrowed_to_owned!(
59 Mul,
60 mul,
61 MatPolynomialRingZq,
62 MatPolynomialRingZq,
63 MatPolynomialRingZq
64);
65arithmetic_trait_mixed_borrowed_owned!(
66 Mul,
67 mul,
68 MatPolynomialRingZq,
69 MatPolynomialRingZq,
70 MatPolynomialRingZq
71);
72
73impl Mul<&MatPolyOverZ> for &MatPolynomialRingZq {
74 type Output = MatPolynomialRingZq;
75 fn mul(self, other: &MatPolyOverZ) -> Self::Output {
98 self.mul_mat_poly_over_z_safe(other).unwrap()
99 }
100}
101
102arithmetic_trait_borrowed_to_owned!(
103 Mul,
104 mul,
105 MatPolynomialRingZq,
106 MatPolyOverZ,
107 MatPolynomialRingZq
108);
109arithmetic_trait_mixed_borrowed_owned!(
110 Mul,
111 mul,
112 MatPolynomialRingZq,
113 MatPolyOverZ,
114 MatPolynomialRingZq
115);
116
117impl MatPolynomialRingZq {
118 pub fn mul_safe(&self, other: &Self) -> Result<Self, MathError> {
150 if !self.compare_base(other) {
151 return Err(self.call_compare_base_error(other).unwrap());
152 }
153
154 let mut new = MatPolynomialRingZq {
157 matrix: self.matrix.mul_safe(&other.matrix)?,
158 modulus: self.modulus.clone(),
159 };
160
161 new.reduce();
162
163 Ok(new)
164 }
165
166 pub fn mul_mat_poly_over_z_safe(&self, other: &MatPolyOverZ) -> Result<Self, MathError> {
190 let mut out =
191 MatPolynomialRingZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
192
193 out.matrix = self.matrix.mul_safe(other)?;
194 out.reduce();
195
196 Ok(out)
197 }
198}
199
200#[cfg(test)]
201mod test_mul {
202 use super::MatPolynomialRingZq;
203 use crate::{integer::MatPolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
204 use std::str::FromStr;
205
206 const LARGE_PRIME: u64 = u64::MAX - 58;
207
208 #[test]
210 fn square_correctness() {
211 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
212 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
213 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
214 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
215 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
216
217 let poly_ring_mat_3 = &poly_ring_mat_1 * &poly_ring_mat_2;
218
219 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 11 16 1, 3 1 0 8],[0, 0]]").unwrap();
220 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
221
222 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
223 }
224
225 #[test]
227 fn different_dimensions_correctness() {
228 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
229 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
230 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
231 let poly_mat_2 = MatPolyOverZ::from_str("[[1 42],[1 17]]").unwrap();
232 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
233
234 let poly_ring_mat_3 = &poly_ring_mat_1 * &poly_ring_mat_2;
235
236 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 1 0 8],[0]]").unwrap();
237 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
238
239 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
240 }
241
242 #[test]
244 fn large_entries() {
245 let modulus =
246 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
247 let poly_mat_1 =
248 MatPolyOverZ::from_str(&format!("[[2 3 {}, 1 15],[1 1, 0]]", u64::MAX)).unwrap();
249 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
250 let poly_mat_2 = MatPolyOverZ::from_str(&format!("[[2 1 {}],[0]]", u64::MAX)).unwrap();
251 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
252
253 let poly_ring_mat_3 = &poly_ring_mat_1 * &poly_ring_mat_2;
254
255 let poly_mat_cmp = MatPolyOverZ::from_str(&format!(
256 "[[3 3 {} {}],[2 1 {}]]",
257 u128::from(u64::MAX) * 4,
258 u128::from(u64::MAX) * u128::from(u64::MAX),
259 u64::MAX
260 ))
261 .unwrap();
262 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
263
264 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
265 }
266
267 #[test]
270 fn errors() {
271 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
272 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
273
274 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
275 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
276 let poly_mat_2 =
277 MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17],[1 24, 0]]").unwrap();
278 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_1));
279 let poly_mat_3 = MatPolyOverZ::from_str("[[3 11 16 1, 3 1 0 8],[0, 0]]").unwrap();
280 let poly_ring_mat_3 = MatPolynomialRingZq::from((&poly_mat_3, &modulus_2));
281
282 assert!((poly_ring_mat_1.mul_safe(&poly_ring_mat_2)).is_err());
283 assert!((poly_ring_mat_1.mul_safe(&poly_ring_mat_3)).is_err());
284 }
285}
286
287#[cfg(test)]
288mod test_mul_mat_poly_over_z {
289 use super::MatPolynomialRingZq;
290 use crate::{integer::MatPolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
291 use std::str::FromStr;
292
293 const LARGE_PRIME: u64 = u64::MAX - 58;
294
295 #[test]
297 fn availability() {
298 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
299 let poly_mat = MatPolyOverZ::from_str("[[3 0 1 1, 1 3],[0, 2 1 2]]").unwrap();
300 let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
301
302 let _ = &poly_ring_mat * &poly_mat;
303 let _ = &poly_ring_mat * poly_mat.clone();
304 let _ = poly_ring_mat.clone() * &poly_mat;
305 let _ = poly_ring_mat * poly_mat;
306 }
307
308 #[test]
310 fn square_correctness() {
311 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
312 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
313 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
314 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
315
316 let poly_ring_mat_3 = &poly_ring_mat_1 * &poly_mat_2;
317
318 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 11 16 1, 3 1 0 8],[0, 0]]").unwrap();
319 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
320
321 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
322 }
323
324 #[test]
326 fn different_dimensions_correctness() {
327 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
328 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
329 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
330 let poly_mat_2 = MatPolyOverZ::from_str("[[1 42],[1 17]]").unwrap();
331
332 let poly_ring_mat_3 = &poly_ring_mat_1 * &poly_mat_2;
333
334 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 1 0 8],[0]]").unwrap();
335 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
336
337 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
338 }
339
340 #[test]
342 fn large_entries() {
343 let modulus =
344 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
345 let poly_mat_1 =
346 MatPolyOverZ::from_str(&format!("[[2 3 {}, 1 15],[1 1, 0]]", u64::MAX)).unwrap();
347 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
348 let poly_mat_2 = MatPolyOverZ::from_str(&format!("[[2 1 {}],[0]]", u64::MAX)).unwrap();
349
350 let poly_ring_mat_3 = &poly_ring_mat_1 * &poly_mat_2;
351
352 let poly_mat_cmp = MatPolyOverZ::from_str(&format!(
353 "[[3 3 {} {}],[2 1 {}]]",
354 u128::from(u64::MAX) * 4,
355 u128::from(u64::MAX) * u128::from(u64::MAX),
356 u64::MAX
357 ))
358 .unwrap();
359 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
360
361 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
362 }
363
364 #[test]
367 fn errors() {
368 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
369 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1],[2 1 2]]").unwrap();
370 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
371
372 assert!((poly_ring_mat_1.mul_mat_poly_over_z_safe(&poly_mat_1)).is_err());
373 }
374
375 #[test]
377 #[should_panic]
378 fn mul_panic() {
379 let modulus1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
380 let poly_mat1 = MatPolyOverZ::from_str("[[1 3],[2 1 2]]").unwrap();
381 let poly_ring_mat1 = MatPolynomialRingZq::from((&poly_mat1, &modulus1));
382
383 let _ = &poly_ring_mat1 * &poly_mat1;
384 }
385}