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::{Add, AddAssign};
impl AddAssign<&PolynomialRingZq> for PolynomialRingZq {
fn add_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 AddAssign<&PolyOverZ> for PolynomialRingZq {
fn add_assign(&mut self, other: &PolyOverZ) {
self.poly += other;
self.reduce();
}
}
impl AddAssign<&PolyOverZq> for PolynomialRingZq {
fn add_assign(&mut self, other: &PolyOverZq) {
if !self.compare_base(other) {
panic!("{}", self.call_compare_base_error(other).unwrap())
}
self.poly += &other.get_representative_least_nonnegative_residue();
self.reduce();
}
}
arithmetic_assign_trait_borrowed_to_owned!(
AddAssign,
add_assign,
PolynomialRingZq,
PolynomialRingZq
);
arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, PolynomialRingZq, PolyOverZ);
arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, PolynomialRingZq, PolyOverZq);
impl Add for &PolynomialRingZq {
type Output = PolynomialRingZq;
fn add(self, other: Self) -> Self::Output {
self.add_safe(other).unwrap()
}
}
impl Add<&PolyOverZ> for &PolynomialRingZq {
type Output = PolynomialRingZq;
fn add(self, other: &PolyOverZ) -> Self::Output {
let mut out = self.clone();
out += other;
out
}
}
arithmetic_trait_reverse!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
arithmetic_trait_borrowed_to_owned!(Add, add, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
arithmetic_trait_mixed_borrowed_owned!(Add, add, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
impl Add<&PolyOverZq> for &PolynomialRingZq {
type Output = PolynomialRingZq;
fn add(self, other: &PolyOverZq) -> Self::Output {
if !self.compare_base(other) {
panic!("{}", self.call_compare_base_error(other).unwrap())
}
let mut out = self.clone();
out.poly += &other.get_representative_least_nonnegative_residue();
out
}
}
arithmetic_trait_reverse!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
arithmetic_trait_borrowed_to_owned!(Add, add, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
arithmetic_trait_mixed_borrowed_owned!(Add, add, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
impl PolynomialRingZq {
pub fn add_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 += other;
Ok(out)
}
}
arithmetic_trait_borrowed_to_owned!(
Add,
add,
PolynomialRingZq,
PolynomialRingZq,
PolynomialRingZq
);
arithmetic_trait_mixed_borrowed_owned!(
Add,
add,
PolynomialRingZq,
PolynomialRingZq,
PolynomialRingZq
);
#[cfg(test)]
mod test_add_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));
let cmp = PolynomialRingZq::from((&PolyOverZ::from_str("3 1 0 4").unwrap(), &modulus));
a += b;
assert_eq!(cmp, a);
}
#[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!("4 {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
let mut a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from_str(&format!("4 {} 0 -1 {}", i64::MAX, i64::MAX)).unwrap();
let b = PolynomialRingZq::from((&poly_2, &modulus));
let cmp = PolynomialRingZq::from((
&PolyOverZ::from_str(&format!("4 {} 0 0 {}", (u64::MAX - 1) / 2 + 58, -1)).unwrap(),
&modulus,
));
a += b;
assert_eq!(cmp, a);
}
#[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 2 0 0 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_add {
use crate::integer::PolyOverZ;
use crate::integer_mod_q::ModulusPolynomialRingZq;
use crate::integer_mod_q::PolynomialRingZq;
use std::str::FromStr;
#[test]
fn add() {
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("4 1 0 4 2").unwrap(), &modulus))
);
}
#[test]
fn add_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("4 1 0 4 2").unwrap(), &modulus))
);
}
#[test]
fn add_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("4 1 0 4 2").unwrap(), &modulus))
);
}
#[test]
fn add_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("4 1 0 4 2").unwrap(), &modulus))
);
}
#[test]
fn add_reduce() {
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 1 0 4").unwrap(), &modulus))
);
}
#[test]
fn add_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!("4 {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
let a = PolynomialRingZq::from((&poly_1, &modulus));
let poly_2 = PolyOverZ::from_str(&format!("4 {} 0 -1 {}", 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!("4 {} 0 0 {}", (u64::MAX - 1) / 2 + 58, -1))
.unwrap(),
&modulus
))
);
}
#[test]
#[should_panic]
fn add_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 2 0 0 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 add_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 2 0 0 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.add_safe(&b).is_err());
}
}
#[cfg(test)]
mod test_add_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!(
"2 3 {} / 4 1 2 3 1 mod {}",
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_add_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!(
"2 3 {} / 4 1 2 3 1 mod {}",
i64::MAX as u64 + 1,
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;
}
}