use super::super::PolynomialRingZq;
use crate::{
error::MathError,
integer::PolyOverZ,
integer_mod_q::PolyOverZq,
macros::arithmetics::{
arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
arithmetic_trait_mixed_borrowed_owned, arithmetic_trait_reverse,
},
traits::CompareBase,
};
use std::ops::{Mul, MulAssign};
impl MulAssign<&PolynomialRingZq> for PolynomialRingZq {
fn mul_assign(&mut self, other: &Self) {
if !self.compare_base(other) {
panic!("{}", self.call_compare_base_error(other).unwrap());
}
self.poly *= &other.poly;
self.reduce();
}
}
impl<T> MulAssign<T> for PolynomialRingZq
where
PolyOverZ: MulAssign<T>,
{
fn mul_assign(&mut self, rhs: T) {
self.poly *= rhs;
self.reduce();
}
}
impl MulAssign<&PolyOverZq> for PolynomialRingZq {
fn mul_assign(&mut self, other: &PolyOverZq) {
if !self.compare_base(other) {
panic!("{}", self.call_compare_base_error(other).unwrap())
}
let other = other.get_representative_least_nonnegative_residue();
self.poly *= &other;
self.reduce();
}
}
arithmetic_assign_trait_borrowed_to_owned!(
MulAssign,
mul_assign,
PolynomialRingZq,
PolynomialRingZq
);
arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolynomialRingZq, PolyOverZq);
impl Mul for &PolynomialRingZq {
type Output = PolynomialRingZq;
fn mul(self, other: Self) -> Self::Output {
self.mul_safe(other).unwrap()
}
}
impl Mul<&PolyOverZ> for &PolynomialRingZq {
type Output = PolynomialRingZq;
fn mul(self, other: &PolyOverZ) -> Self::Output {
let mut out = self.clone();
out *= other;
out
}
}
arithmetic_trait_reverse!(Mul, mul, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
arithmetic_trait_borrowed_to_owned!(Mul, mul, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
impl Mul<&PolyOverZq> for &PolynomialRingZq {
type Output = PolynomialRingZq;
fn mul(self, other: &PolyOverZq) -> Self::Output {
let mut out = self.clone();
out *= other;
out
}
}
arithmetic_trait_reverse!(Mul, mul, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
arithmetic_trait_borrowed_to_owned!(Mul, mul, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
impl PolynomialRingZq {
pub fn mul_safe(&self, other: &Self) -> Result<PolynomialRingZq, MathError> {
if !self.compare_base(other) {
return Err(self.call_compare_base_error(other).unwrap());
}
let mut out = self.clone();
out.poly *= &other.get_representative_least_nonnegative_residue();
out.reduce();
Ok(out)
}
}
arithmetic_trait_borrowed_to_owned!(
Mul,
mul,
PolynomialRingZq,
PolynomialRingZq,
PolynomialRingZq
);
arithmetic_trait_mixed_borrowed_owned!(
Mul,
mul,
PolynomialRingZq,
PolynomialRingZq,
PolynomialRingZq
);
#[cfg(test)]
mod test_mul_assign {
use super::PolyOverZ;
use crate::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq};
use std::str::FromStr;
#[test]
fn correct_small() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let mut a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
a *= b;
assert_eq!(
a,
PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
);
}
#[test]
fn correct_large() {
let modulus = ModulusPolynomialRingZq::from_str(&format!(
"4 {} 0 0 1 mod {}",
u64::MAX,
u64::MAX - 58
))
.unwrap();
let poly_1 = PolyOverZ::from_str(&format!("3 {} 0 {}", u64::MAX, i64::MIN)).unwrap();
let mut a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from_str(&format!("3 {} 0 {}", i64::MAX, i64::MAX)).unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
a *= b;
assert_eq!(
a,
PolynomialRingZq::from((
&PolyOverZ::from_str(&format!(
"5 {} {} {} {} {}",
u128::from(u64::MAX) * u128::from((u64::MAX - 1) / 2),
0,
i128::from(i64::MIN) * i128::from(i64::MAX)
+ (i128::from(i64::MAX) - i128::from(i64::MIN)) * i128::from(i64::MAX),
0,
i128::from(i64::MAX) * i128::from(i64::MIN)
))
.unwrap(),
&modulus
))
);
}
#[test]
fn availability() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let mut a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
let c = PolyOverZq::from((poly_2, 17));
a *= &b;
a *= b;
a *= &poly_1;
a *= poly_1;
a *= &c;
a *= c;
}
#[test]
#[should_panic]
fn mismatching_moduli() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let mut a = PolynomialRingZq::from((&poly_1, &modulus));
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 2 1 mod 17").unwrap();
let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
a *= b;
}
}
#[cfg(test)]
mod test_mul {
use crate::integer::PolyOverZ;
use crate::integer_mod_q::ModulusPolynomialRingZq;
use crate::integer_mod_q::PolynomialRingZq;
use std::str::FromStr;
#[test]
fn mul() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
let c = a * b;
assert_eq!(
c,
PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
);
}
#[test]
fn mul_borrow() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
let c = &a * &b;
assert_eq!(
c,
PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
);
}
#[test]
fn mul_first_borrowed() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
let c = &a * b;
assert_eq!(
c,
PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
);
}
#[test]
fn mul_second_borrowed() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
let c = a * &b;
assert_eq!(
c,
PolynomialRingZq::from((&PolyOverZ::from_str("3 15 14 12").unwrap(), &modulus))
);
}
#[test]
fn mul_constant() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from(3);
let b = PolynomialRingZq::from((&poly_2, &modulus));
let c = &a * b;
assert_eq!(
c,
PolynomialRingZq::from((&PolyOverZ::from_str("4 -3 0 3 3").unwrap(), &modulus))
);
assert_eq!(
PolynomialRingZq::from((&PolyOverZ::default(), &modulus)),
a * PolynomialRingZq::from((&PolyOverZ::default(), &modulus))
)
}
#[test]
fn mul_large_numbers() {
let modulus = ModulusPolynomialRingZq::from_str(&format!(
"4 {} 0 0 1 mod {}",
u64::MAX,
u64::MAX - 58
))
.unwrap();
let poly_1 = PolyOverZ::from_str(&format!("3 {} 0 {}", u64::MAX, i64::MIN)).unwrap();
let a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from_str(&format!("3 {} 0 {}", i64::MAX, i64::MAX)).unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
let c = a * b;
assert_eq!(
c,
PolynomialRingZq::from((
&PolyOverZ::from_str(&format!(
"5 {} {} {} {} {}",
u128::from(u64::MAX) * u128::from((u64::MAX - 1) / 2),
0,
i128::from(i64::MIN) * i128::from(i64::MAX)
+ (i128::from(i64::MAX) - i128::from(i64::MIN)) * i128::from(i64::MAX),
0,
i128::from(i64::MAX) * i128::from(i64::MIN)
))
.unwrap(),
&modulus
))
);
}
#[test]
#[should_panic]
fn mul_mismatching_modulus() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let a = PolynomialRingZq::from((&poly_1, &modulus));
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 2 1 mod 17").unwrap();
let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
let _ = a * b;
}
#[test]
fn mul_safe_is_err() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let a = PolynomialRingZq::from((&poly_1, &modulus));
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 2 1 mod 17").unwrap();
let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
assert!(&a.mul_safe(&b).is_err());
}
}
#[cfg(test)]
mod test_mul_poly_over_z {
use super::PolynomialRingZq;
use crate::integer::PolyOverZ;
use std::str::FromStr;
#[test]
fn borrowed_correctness() {
let poly_1 =
PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 1 mod {}", i64::MAX, u64::MAX))
.unwrap();
let poly_2 = PolynomialRingZq::from_str(&format!(
"3 2 {} {} / 4 1 2 3 1 mod {}",
i64::MAX as u64 + 4,
(i64::MAX as u64) * 2,
u64::MAX
))
.unwrap();
let poly = PolyOverZ::from_str("2 1 2").unwrap();
let poly_1 = &poly_1 * &poly;
assert_eq!(poly_2, poly_1);
}
#[test]
fn availability() {
let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 1 mod 17").unwrap();
let z = PolyOverZ::from(2);
_ = poly.clone() * z.clone();
_ = z.clone() * poly.clone();
_ = &poly * &z;
_ = &z * &poly;
_ = &poly * z.clone();
_ = z.clone() * &poly;
_ = &z * poly.clone();
_ = poly.clone() * &z;
}
}
#[cfg(test)]
mod test_mul_poly_over_zq {
use super::PolynomialRingZq;
use crate::integer_mod_q::PolyOverZq;
use std::str::FromStr;
#[test]
fn borrowed_correctness() {
let poly_1 =
PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 1 mod {}", i64::MAX, u64::MAX))
.unwrap();
let poly_2 = PolynomialRingZq::from_str(&format!(
"3 2 {} {} / 4 1 2 3 1 mod {}",
i64::MAX as u64 + 2,
9223372036854775807_u64,
u64::MAX
))
.unwrap();
let poly = PolyOverZq::from_str(&format!("2 1 1 mod {}", u64::MAX)).unwrap();
let poly_1 = &poly_1 * &poly;
assert_eq!(poly_2, poly_1);
}
#[test]
fn availability() {
let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 1 mod 17").unwrap();
let zq = PolyOverZq::from((2, 17));
_ = poly.clone() * zq.clone();
_ = zq.clone() * poly.clone();
_ = &poly * &zq;
_ = &zq * &poly;
_ = &poly * zq.clone();
_ = zq.clone() * &poly;
_ = &zq * poly.clone();
_ = poly.clone() * &zq;
}
#[test]
#[should_panic]
fn different_moduli_panic() {
let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 1 mod 17").unwrap();
let zq = PolyOverZq::from((2, 16));
_ = &poly * &zq;
}
}