qfall_math/integer_mod_q/polynomial_ring_zq/arithmetic/
mul.rs1use super::super::PolynomialRingZq;
12use crate::{
13 error::MathError,
14 integer::PolyOverZ,
15 integer_mod_q::PolyOverZq,
16 macros::arithmetics::{
17 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
18 arithmetic_trait_mixed_borrowed_owned, arithmetic_trait_reverse,
19 },
20 traits::CompareBase,
21};
22use std::ops::{Mul, MulAssign};
23
24impl MulAssign<&PolynomialRingZq> for PolynomialRingZq {
25 fn mul_assign(&mut self, other: &Self) {
59 if !self.compare_base(other) {
60 panic!("{}", self.call_compare_base_error(other).unwrap());
61 }
62
63 self.poly *= &other.poly;
64 self.reduce();
65 }
66}
67impl<T> MulAssign<T> for PolynomialRingZq
68where
69 PolyOverZ: MulAssign<T>,
70{
71 fn mul_assign(&mut self, rhs: T) {
74 self.poly *= rhs;
75 self.reduce();
76 }
77}
78impl MulAssign<&PolyOverZq> for PolynomialRingZq {
79 fn mul_assign(&mut self, other: &PolyOverZq) {
84 if !self.compare_base(other) {
85 panic!("{}", self.call_compare_base_error(other).unwrap())
86 }
87 let other = other.get_representative_least_nonnegative_residue();
88
89 self.poly *= &other;
90 self.reduce();
91 }
92}
93
94arithmetic_assign_trait_borrowed_to_owned!(
95 MulAssign,
96 mul_assign,
97 PolynomialRingZq,
98 PolynomialRingZq
99);
100arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolynomialRingZq, PolyOverZq);
101
102impl Mul for &PolynomialRingZq {
103 type Output = PolynomialRingZq;
104 fn mul(self, other: Self) -> Self::Output {
134 self.mul_safe(other).unwrap()
135 }
136}
137
138impl Mul<&PolyOverZ> for &PolynomialRingZq {
139 type Output = PolynomialRingZq;
140 fn mul(self, other: &PolyOverZ) -> Self::Output {
163 let mut out = self.clone();
164 out *= other;
165 out
166 }
167}
168
169arithmetic_trait_reverse!(Mul, mul, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
170
171arithmetic_trait_borrowed_to_owned!(Mul, mul, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
172arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
173arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
174arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
175
176impl Mul<&PolyOverZq> for &PolynomialRingZq {
177 type Output = PolynomialRingZq;
178 fn mul(self, other: &PolyOverZq) -> Self::Output {
204 let mut out = self.clone();
205 out *= other;
206 out
207 }
208}
209
210arithmetic_trait_reverse!(Mul, mul, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
211
212arithmetic_trait_borrowed_to_owned!(Mul, mul, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
213arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
214arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
215arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
216
217impl PolynomialRingZq {
218 pub fn mul_safe(&self, other: &Self) -> Result<PolynomialRingZq, MathError> {
245 if !self.compare_base(other) {
246 return Err(self.call_compare_base_error(other).unwrap());
247 }
248
249 let mut out = self.clone();
250
251 out.poly *= &other.get_representative_least_nonnegative_residue();
252 out.reduce();
253 Ok(out)
254 }
255}
256
257arithmetic_trait_borrowed_to_owned!(
258 Mul,
259 mul,
260 PolynomialRingZq,
261 PolynomialRingZq,
262 PolynomialRingZq
263);
264arithmetic_trait_mixed_borrowed_owned!(
265 Mul,
266 mul,
267 PolynomialRingZq,
268 PolynomialRingZq,
269 PolynomialRingZq
270);
271
272#[cfg(test)]
273mod test_mul_assign {
274 use super::PolyOverZ;
275 use crate::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq};
276 use std::str::FromStr;
277
278 #[test]
280 fn correct_small() {
281 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
282 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
283 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
284 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
285 let b = PolynomialRingZq::from((&poly_2, &modulus));
286
287 a *= b;
288
289 assert_eq!(
290 a,
291 PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
292 );
293 }
294
295 #[test]
297 fn correct_large() {
298 let modulus = ModulusPolynomialRingZq::from_str(&format!(
299 "4 {} 0 0 1 mod {}",
300 u64::MAX,
301 u64::MAX - 58
302 ))
303 .unwrap();
304
305 let poly_1 = PolyOverZ::from_str(&format!("3 {} 0 {}", u64::MAX, i64::MIN)).unwrap();
306 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
307
308 let poly_2 = PolyOverZ::from_str(&format!("3 {} 0 {}", i64::MAX, i64::MAX)).unwrap();
309 let b = PolynomialRingZq::from((&poly_2, &modulus));
310
311 a *= b;
312
313 assert_eq!(
314 a,
315 PolynomialRingZq::from((
316 &PolyOverZ::from_str(&format!(
317 "5 {} {} {} {} {}",
318 u128::from(u64::MAX) * u128::from((u64::MAX - 1) / 2),
319 0,
320 i128::from(i64::MIN) * i128::from(i64::MAX)
321 + (i128::from(i64::MAX) - i128::from(i64::MIN)) * i128::from(i64::MAX),
322 0,
323 i128::from(i64::MAX) * i128::from(i64::MIN)
324 ))
325 .unwrap(),
326 &modulus
327 ))
328 );
329 }
330
331 #[test]
333 fn availability() {
334 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
335 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
336 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
337 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
338 let b = PolynomialRingZq::from((&poly_2, &modulus));
339 let c = PolyOverZq::from((poly_2, 17));
340
341 a *= &b;
342 a *= b;
343 a *= &poly_1;
344 a *= poly_1;
345 a *= &c;
346 a *= c;
347 }
348
349 #[test]
351 #[should_panic]
352 fn mismatching_moduli() {
353 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
354 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
355 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
356 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 2 1 mod 17").unwrap();
357 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
358 let b = PolynomialRingZq::from((&poly_2, &modulus));
359
360 a *= b;
361 }
362}
363
364#[cfg(test)]
365mod test_mul {
366 use crate::integer::PolyOverZ;
367 use crate::integer_mod_q::ModulusPolynomialRingZq;
368 use crate::integer_mod_q::PolynomialRingZq;
369 use std::str::FromStr;
370
371 #[test]
373 fn mul() {
374 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
375 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
376 let a = PolynomialRingZq::from((&poly_1, &modulus));
377 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
378 let b = PolynomialRingZq::from((&poly_2, &modulus));
379 let c = a * b;
380 assert_eq!(
381 c,
382 PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
383 );
384 }
385
386 #[test]
388 fn mul_borrow() {
389 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
390 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
391 let a = PolynomialRingZq::from((&poly_1, &modulus));
392 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
393 let b = PolynomialRingZq::from((&poly_2, &modulus));
394 let c = &a * &b;
395 assert_eq!(
396 c,
397 PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
398 );
399 }
400
401 #[test]
403 fn mul_first_borrowed() {
404 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
405 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
406 let a = PolynomialRingZq::from((&poly_1, &modulus));
407 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
408 let b = PolynomialRingZq::from((&poly_2, &modulus));
409 let c = &a * b;
410 assert_eq!(
411 c,
412 PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
413 );
414 }
415
416 #[test]
418 fn mul_second_borrowed() {
419 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
420 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
421 let a = PolynomialRingZq::from((&poly_1, &modulus));
422 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
423 let b = PolynomialRingZq::from((&poly_2, &modulus));
424 let c = a * &b;
425 assert_eq!(
426 c,
427 PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
428 );
429 }
430
431 #[test]
433 fn mul_constant() {
434 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
435 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
436 let a = PolynomialRingZq::from((&poly_1, &modulus));
437 let poly_2 = PolyOverZ::from(3);
438 let b = PolynomialRingZq::from((&poly_2, &modulus));
439 let c = &a * b;
440 assert_eq!(
441 c,
442 PolynomialRingZq::from((&PolyOverZ::from_str("4 -3 0 3 3").unwrap(), &modulus))
443 );
444 assert_eq!(
445 PolynomialRingZq::from((&PolyOverZ::default(), &modulus)),
446 a * PolynomialRingZq::from((&PolyOverZ::default(), &modulus))
447 )
448 }
449
450 #[test]
452 fn mul_large_numbers() {
453 let modulus = ModulusPolynomialRingZq::from_str(&format!(
454 "4 {} 0 0 1 mod {}",
455 u64::MAX,
456 u64::MAX - 58
457 ))
458 .unwrap();
459
460 let poly_1 = PolyOverZ::from_str(&format!("3 {} 0 {}", u64::MAX, i64::MIN)).unwrap();
461 let a = PolynomialRingZq::from((&poly_1, &modulus));
462
463 let poly_2 = PolyOverZ::from_str(&format!("3 {} 0 {}", i64::MAX, i64::MAX)).unwrap();
464 let b = PolynomialRingZq::from((&poly_2, &modulus));
465
466 let c = a * b;
467 assert_eq!(
468 c,
469 PolynomialRingZq::from((
470 &PolyOverZ::from_str(&format!(
471 "5 {} {} {} {} {}",
472 u128::from(u64::MAX) * u128::from((u64::MAX - 1) / 2),
473 0,
474 i128::from(i64::MIN) * i128::from(i64::MAX)
475 + (i128::from(i64::MAX) - i128::from(i64::MIN)) * i128::from(i64::MAX),
476 0,
477 i128::from(i64::MAX) * i128::from(i64::MIN)
478 ))
479 .unwrap(),
480 &modulus
481 ))
482 );
483 }
484
485 #[test]
487 #[should_panic]
488 fn mul_mismatching_modulus() {
489 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
490 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
491 let a = PolynomialRingZq::from((&poly_1, &modulus));
492 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 2 1 mod 17").unwrap();
493 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
494 let b = PolynomialRingZq::from((&poly_2, &modulus));
495 let _ = a * b;
496 }
497
498 #[test]
500 fn mul_safe_is_err() {
501 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
502 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
503 let a = PolynomialRingZq::from((&poly_1, &modulus));
504 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 2 1 mod 17").unwrap();
505 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
506 let b = PolynomialRingZq::from((&poly_2, &modulus));
507
508 assert!(&a.mul_safe(&b).is_err());
509 }
510}
511
512#[cfg(test)]
513mod test_mul_poly_over_z {
514 use super::PolynomialRingZq;
515 use crate::integer::PolyOverZ;
516 use std::str::FromStr;
517
518 #[test]
520 fn borrowed_correctness() {
521 let poly_1 =
522 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 1 mod {}", i64::MAX, u64::MAX))
523 .unwrap();
524 let poly_2 = PolynomialRingZq::from_str(&format!(
525 "3 2 {} {} / 4 1 2 3 1 mod {}",
526 i64::MAX as u64 + 4,
527 (i64::MAX as u64) * 2,
528 u64::MAX
529 ))
530 .unwrap();
531 let poly = PolyOverZ::from_str("2 1 2").unwrap();
532
533 let poly_1 = &poly_1 * &poly;
534
535 assert_eq!(poly_2, poly_1);
536 }
537
538 #[test]
540 fn availability() {
541 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 1 mod 17").unwrap();
542 let z = PolyOverZ::from(2);
543
544 _ = poly.clone() * z.clone();
545 _ = z.clone() * poly.clone();
546 _ = &poly * &z;
547 _ = &z * &poly;
548 _ = &poly * z.clone();
549 _ = z.clone() * &poly;
550 _ = &z * poly.clone();
551 _ = poly.clone() * &z;
552 }
553}
554
555#[cfg(test)]
556mod test_mul_poly_over_zq {
557 use super::PolynomialRingZq;
558 use crate::integer_mod_q::PolyOverZq;
559 use std::str::FromStr;
560
561 #[test]
563 fn borrowed_correctness() {
564 let poly_1 =
565 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 1 mod {}", i64::MAX, u64::MAX))
566 .unwrap();
567 let poly_2 = PolynomialRingZq::from_str(&format!(
568 "3 2 {} {} / 4 1 2 3 1 mod {}",
569 i64::MAX as u64 + 2,
570 9223372036854775807_u64,
571 u64::MAX
572 ))
573 .unwrap();
574 let poly = PolyOverZq::from_str(&format!("2 1 1 mod {}", u64::MAX)).unwrap();
575
576 let poly_1 = &poly_1 * &poly;
577
578 assert_eq!(poly_2, poly_1);
579 }
580
581 #[test]
583 fn availability() {
584 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 1 mod 17").unwrap();
585 let zq = PolyOverZq::from((2, 17));
586
587 _ = poly.clone() * zq.clone();
588 _ = zq.clone() * poly.clone();
589 _ = &poly * &zq;
590 _ = &zq * &poly;
591 _ = &poly * zq.clone();
592 _ = zq.clone() * &poly;
593 _ = &zq * poly.clone();
594 _ = poly.clone() * &zq;
595 }
596
597 #[test]
599 #[should_panic]
600 fn different_moduli_panic() {
601 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 1 mod 17").unwrap();
602 let zq = PolyOverZq::from((2, 16));
603
604 _ = &poly * &zq;
605 }
606}