1use 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 flint_sys::fq::fq_mul;
23use std::ops::{Mul, MulAssign};
24
25impl MulAssign<&PolynomialRingZq> for PolynomialRingZq {
26 fn mul_assign(&mut self, other: &Self) {
60 if !self.compare_base(other) {
61 panic!("{}", self.call_compare_base_error(other).unwrap());
62 }
63
64 unsafe {
65 fq_mul(
66 &mut self.poly.poly,
67 &self.poly.poly,
68 &other.poly.poly,
69 self.modulus.get_fq_ctx(),
70 );
71 };
72 }
73}
74impl<T> MulAssign<T> for PolynomialRingZq
75where
76 PolyOverZ: MulAssign<T>,
77{
78 fn mul_assign(&mut self, rhs: T) {
81 self.poly *= rhs;
82 self.reduce();
83 }
84}
85impl MulAssign<&PolyOverZq> for PolynomialRingZq {
86 fn mul_assign(&mut self, other: &PolyOverZq) {
91 if !self.compare_base(other) {
92 panic!("{}", self.call_compare_base_error(other).unwrap())
93 }
94 let other = other.get_representative_least_nonnegative_residue();
96
97 unsafe {
98 fq_mul(
99 &mut self.poly.poly,
100 &self.poly.poly,
101 &other.poly,
102 self.modulus.get_fq_ctx(),
103 );
104 };
105 }
106}
107
108arithmetic_assign_trait_borrowed_to_owned!(
109 MulAssign,
110 mul_assign,
111 PolynomialRingZq,
112 PolynomialRingZq
113);
114arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolynomialRingZq, PolyOverZq);
115
116impl Mul for &PolynomialRingZq {
117 type Output = PolynomialRingZq;
118 fn mul(self, other: Self) -> Self::Output {
148 self.mul_safe(other).unwrap()
149 }
150}
151
152impl Mul<&PolyOverZ> for &PolynomialRingZq {
153 type Output = PolynomialRingZq;
154 fn mul(self, other: &PolyOverZ) -> Self::Output {
177 let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
178 unsafe {
179 fq_mul(
180 &mut out.poly.poly,
181 &self.poly.poly,
182 &other.poly,
183 self.modulus.get_fq_ctx(),
184 );
185 }
186 out
187 }
188}
189
190arithmetic_trait_reverse!(Mul, mul, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
191
192arithmetic_trait_borrowed_to_owned!(Mul, mul, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
193arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
194arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
195arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
196
197impl Mul<&PolyOverZq> for &PolynomialRingZq {
198 type Output = PolynomialRingZq;
199 fn mul(self, other: &PolyOverZq) -> Self::Output {
225 if !self.compare_base(other) {
226 panic!("{}", self.call_compare_base_error(other).unwrap())
227 }
228
229 let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
230 unsafe {
231 fq_mul(
232 &mut out.poly.poly,
233 &self.poly.poly,
234 &other.get_representative_least_nonnegative_residue().poly,
235 self.modulus.get_fq_ctx(),
236 );
237 }
238 out
239 }
240}
241
242arithmetic_trait_reverse!(Mul, mul, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
243
244arithmetic_trait_borrowed_to_owned!(Mul, mul, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
245arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
246arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
247arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
248
249impl PolynomialRingZq {
250 pub fn mul_safe(&self, other: &Self) -> Result<PolynomialRingZq, MathError> {
277 if !self.compare_base(other) {
278 return Err(self.call_compare_base_error(other).unwrap());
279 }
280 let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
281 unsafe {
282 fq_mul(
283 &mut out.poly.poly,
284 &self.poly.poly,
285 &other.poly.poly,
286 self.modulus.get_fq_ctx(),
287 );
288 }
289 Ok(out)
290 }
291}
292
293arithmetic_trait_borrowed_to_owned!(
294 Mul,
295 mul,
296 PolynomialRingZq,
297 PolynomialRingZq,
298 PolynomialRingZq
299);
300arithmetic_trait_mixed_borrowed_owned!(
301 Mul,
302 mul,
303 PolynomialRingZq,
304 PolynomialRingZq,
305 PolynomialRingZq
306);
307
308#[cfg(test)]
309mod test_mul_assign {
310 use super::PolyOverZ;
311 use crate::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq};
312 use std::str::FromStr;
313
314 #[test]
316 fn correct_small() {
317 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
318 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
319 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
320 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
321 let b = PolynomialRingZq::from((&poly_2, &modulus));
322
323 a *= b;
324
325 assert_eq!(
326 a,
327 PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
328 );
329 }
330
331 #[test]
333 fn correct_large() {
334 let modulus = ModulusPolynomialRingZq::from_str(&format!(
335 "4 {} 0 0 {} mod {}",
336 u64::MAX,
337 i64::MIN,
338 u64::MAX - 58
339 ))
340 .unwrap();
341
342 let poly_1 = PolyOverZ::from_str(&format!("3 {} 0 {}", u64::MAX, i64::MIN)).unwrap();
343 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
344
345 let poly_2 = PolyOverZ::from_str(&format!("3 {} 0 {}", i64::MAX, i64::MAX)).unwrap();
346 let b = PolynomialRingZq::from((&poly_2, &modulus));
347
348 a *= b;
349
350 assert_eq!(
351 a,
352 PolynomialRingZq::from((
353 &PolyOverZ::from_str(&format!(
354 "5 {} {} {} {} {}",
355 u128::from(u64::MAX) * u128::from((u64::MAX - 1) / 2),
356 0,
357 i128::from(i64::MIN) * i128::from(i64::MAX)
358 + (i128::from(i64::MAX) - i128::from(i64::MIN)) * i128::from(i64::MAX),
359 0,
360 i128::from(i64::MAX) * i128::from(i64::MIN)
361 ))
362 .unwrap(),
363 &modulus
364 ))
365 );
366 }
367
368 #[test]
370 fn availability() {
371 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
372 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
373 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
374 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
375 let b = PolynomialRingZq::from((&poly_2, &modulus));
376 let c = PolyOverZq::from((poly_2, 17));
377
378 a *= &b;
379 a *= b;
380 a *= &poly_1;
381 a *= poly_1;
382 a *= &c;
383 a *= c;
384 }
385
386 #[test]
388 #[should_panic]
389 fn mismatching_moduli() {
390 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
391 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
392 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
393 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
394 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
395 let b = PolynomialRingZq::from((&poly_2, &modulus));
396
397 a *= b;
398 }
399}
400
401#[cfg(test)]
402mod test_mul {
403 use crate::integer::PolyOverZ;
404 use crate::integer_mod_q::ModulusPolynomialRingZq;
405 use crate::integer_mod_q::PolynomialRingZq;
406 use std::str::FromStr;
407
408 #[test]
410 fn mul() {
411 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
412 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
413 let a = PolynomialRingZq::from((&poly_1, &modulus));
414 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
415 let b = PolynomialRingZq::from((&poly_2, &modulus));
416 let c = a * b;
417 assert_eq!(
418 c,
419 PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
420 );
421 }
422
423 #[test]
425 fn mul_borrow() {
426 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
427 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
428 let a = PolynomialRingZq::from((&poly_1, &modulus));
429 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
430 let b = PolynomialRingZq::from((&poly_2, &modulus));
431 let c = &a * &b;
432 assert_eq!(
433 c,
434 PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
435 );
436 }
437
438 #[test]
440 fn mul_first_borrowed() {
441 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
442 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
443 let a = PolynomialRingZq::from((&poly_1, &modulus));
444 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
445 let b = PolynomialRingZq::from((&poly_2, &modulus));
446 let c = &a * b;
447 assert_eq!(
448 c,
449 PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
450 );
451 }
452
453 #[test]
455 fn mul_second_borrowed() {
456 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
457 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
458 let a = PolynomialRingZq::from((&poly_1, &modulus));
459 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
460 let b = PolynomialRingZq::from((&poly_2, &modulus));
461 let c = a * &b;
462 assert_eq!(
463 c,
464 PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
465 );
466 }
467
468 #[test]
470 fn mul_constant() {
471 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
472 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
473 let a = PolynomialRingZq::from((&poly_1, &modulus));
474 let poly_2 = PolyOverZ::from(3);
475 let b = PolynomialRingZq::from((&poly_2, &modulus));
476 let c = &a * b;
477 assert_eq!(
478 c,
479 PolynomialRingZq::from((&PolyOverZ::from_str("4 -3 0 3 3").unwrap(), &modulus))
480 );
481 assert_eq!(
482 PolynomialRingZq::from((&PolyOverZ::default(), &modulus)),
483 a * PolynomialRingZq::from((&PolyOverZ::default(), &modulus))
484 )
485 }
486
487 #[test]
489 fn mul_large_numbers() {
490 let modulus = ModulusPolynomialRingZq::from_str(&format!(
491 "4 {} 0 0 {} mod {}",
492 u64::MAX,
493 i64::MIN,
494 u64::MAX - 58
495 ))
496 .unwrap();
497
498 let poly_1 = PolyOverZ::from_str(&format!("3 {} 0 {}", u64::MAX, i64::MIN)).unwrap();
499 let a = PolynomialRingZq::from((&poly_1, &modulus));
500
501 let poly_2 = PolyOverZ::from_str(&format!("3 {} 0 {}", i64::MAX, i64::MAX)).unwrap();
502 let b = PolynomialRingZq::from((&poly_2, &modulus));
503
504 let c = a * b;
505 assert_eq!(
506 c,
507 PolynomialRingZq::from((
508 &PolyOverZ::from_str(&format!(
509 "5 {} {} {} {} {}",
510 u128::from(u64::MAX) * u128::from((u64::MAX - 1) / 2),
511 0,
512 i128::from(i64::MIN) * i128::from(i64::MAX)
513 + (i128::from(i64::MAX) - i128::from(i64::MIN)) * i128::from(i64::MAX),
514 0,
515 i128::from(i64::MAX) * i128::from(i64::MIN)
516 ))
517 .unwrap(),
518 &modulus
519 ))
520 );
521 }
522
523 #[test]
525 #[should_panic]
526 fn mul_mismatching_modulus() {
527 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
528 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
529 let a = PolynomialRingZq::from((&poly_1, &modulus));
530 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
531 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
532 let b = PolynomialRingZq::from((&poly_2, &modulus));
533 let _ = a * b;
534 }
535
536 #[test]
538 fn mul_safe_is_err() {
539 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
540 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
541 let a = PolynomialRingZq::from((&poly_1, &modulus));
542 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
543 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
544 let b = PolynomialRingZq::from((&poly_2, &modulus));
545
546 assert!(&a.mul_safe(&b).is_err());
547 }
548}
549
550#[cfg(test)]
551mod test_mul_poly_over_z {
552 use super::PolynomialRingZq;
553 use crate::integer::PolyOverZ;
554 use std::str::FromStr;
555
556 #[test]
558 fn borrowed_correctness() {
559 let poly_1 =
560 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 4 mod {}", i64::MAX, u64::MAX))
561 .unwrap();
562 let poly_2 = PolynomialRingZq::from_str(&format!(
563 "3 2 {} {} / 4 1 2 3 4 mod {}",
564 i64::MAX as u64 + 4,
565 (i64::MAX as u64) * 2,
566 u64::MAX
567 ))
568 .unwrap();
569 let poly = PolyOverZ::from_str("2 1 2").unwrap();
570
571 let poly_1 = &poly_1 * &poly;
572
573 assert_eq!(poly_2, poly_1);
574 }
575
576 #[test]
578 fn availability() {
579 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
580 let z = PolyOverZ::from(2);
581
582 _ = poly.clone() * z.clone();
583 _ = z.clone() * poly.clone();
584 _ = &poly * &z;
585 _ = &z * &poly;
586 _ = &poly * z.clone();
587 _ = z.clone() * &poly;
588 _ = &z * poly.clone();
589 _ = poly.clone() * &z;
590 }
591}
592
593#[cfg(test)]
594mod test_mul_poly_over_zq {
595 use super::PolynomialRingZq;
596 use crate::integer_mod_q::PolyOverZq;
597 use std::str::FromStr;
598
599 #[test]
601 fn borrowed_correctness() {
602 let poly_1 =
603 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 4 mod {}", i64::MAX, u64::MAX))
604 .unwrap();
605 let poly_2 = PolynomialRingZq::from_str(&format!(
606 "3 2 {} {} / 4 1 2 3 4 mod {}",
607 i64::MAX as u64 + 4,
608 (i64::MAX as u64) * 2,
609 u64::MAX
610 ))
611 .unwrap();
612 let poly = PolyOverZq::from_str(&format!("2 1 2 mod {}", u64::MAX)).unwrap();
613
614 let poly_1 = &poly_1 * &poly;
615
616 assert_eq!(poly_2, poly_1);
617 }
618
619 #[test]
621 fn availability() {
622 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
623 let zq = PolyOverZq::from((2, 17));
624
625 _ = poly.clone() * zq.clone();
626 _ = zq.clone() * poly.clone();
627 _ = &poly * &zq;
628 _ = &zq * &poly;
629 _ = &poly * zq.clone();
630 _ = zq.clone() * &poly;
631 _ = &zq * poly.clone();
632 _ = poly.clone() * &zq;
633 }
634
635 #[test]
637 #[should_panic]
638 fn different_moduli_panic() {
639 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
640 let zq = PolyOverZq::from((2, 16));
641
642 _ = &poly * &zq;
643 }
644}