use super::ModulusPolynomialRingZq;
use crate::{
error::MathError,
integer::{PolyOverZ, Z},
integer_mod_q::{Modulus, PolyOverZq},
macros::for_others::implement_for_owned,
traits::GetCoefficient,
};
use std::{rc::Rc, str::FromStr};
impl<Mod: Into<Modulus>> From<(&PolyOverZ, Mod)> for ModulusPolynomialRingZq {
fn from((poly, modulus): (&PolyOverZ, Mod)) -> Self {
let poly_zq = PolyOverZq::from((poly, modulus));
check_poly_mod(&poly_zq).unwrap();
Self::from(poly_zq)
}
}
impl<Mod: Into<Modulus>> From<(PolyOverZ, Mod)> for ModulusPolynomialRingZq {
fn from((poly, modulus): (PolyOverZ, Mod)) -> Self {
let poly_zq = PolyOverZq::from((poly, modulus));
check_poly_mod(&poly_zq).unwrap();
Self::from(poly_zq)
}
}
impl From<&PolyOverZq> for ModulusPolynomialRingZq {
fn from(poly: &PolyOverZq) -> Self {
check_poly_mod(poly).unwrap();
let mut non_zero = Vec::new();
for i in 0..poly.get_degree() {
let coeff: Z = poly.get_coeff(i).unwrap();
if coeff != 0 {
non_zero.push(i.try_into().unwrap());
}
}
Self {
modulus: Rc::new(poly.clone()),
ntt_basis: Rc::new(None),
non_zero,
}
}
}
implement_for_owned!(PolyOverZq, ModulusPolynomialRingZq, From);
impl From<&ModulusPolynomialRingZq> for ModulusPolynomialRingZq {
fn from(value: &ModulusPolynomialRingZq) -> Self {
value.clone()
}
}
impl FromStr for ModulusPolynomialRingZq {
type Err = MathError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let poly_zq = PolyOverZq::from_str(s)?;
check_poly_mod(&poly_zq)?;
Ok(Self::from(poly_zq))
}
}
pub(crate) fn check_poly_mod(poly_zq: &PolyOverZq) -> Result<(), MathError> {
let leading_coefficient: Z = poly_zq.get_coeff(poly_zq.get_degree())?;
if poly_zq.get_degree() < 1 {
return Err(MathError::InvalidModulus(poly_zq.to_string()));
}
if leading_coefficient != 1 {
return Err(MathError::InvalidModulus(format!(
". The leading coefficient needs to be 1, but it is {leading_coefficient}"
)));
}
Ok(())
}
#[cfg(test)]
mod test_availability {
use super::*;
use crate::integer_mod_q::PolyOverZq;
use std::str::FromStr;
#[test]
fn availability() {
let poly = PolyOverZ::from_str("2 1 1").unwrap();
let poly_zq = PolyOverZq::from_str("4 1 0 0 1 mod 17").unwrap();
let _ = ModulusPolynomialRingZq::from((&poly, 5));
let _ = ModulusPolynomialRingZq::from((poly.clone(), 5));
let _ = ModulusPolynomialRingZq::from(&poly_zq);
let _ = ModulusPolynomialRingZq::from(poly_zq);
}
}
#[cfg(test)]
mod test_try_from_poly_z {
use crate::{integer::PolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
use std::str::FromStr;
#[test]
fn poly_z_primes() {
let poly_z = PolyOverZ::from_str("2 2 1").unwrap();
let _ = ModulusPolynomialRingZq::from((&poly_z, 10));
let _ = ModulusPolynomialRingZq::from((poly_z, 11));
}
#[test]
#[should_panic]
fn panic_0() {
let poly = PolyOverZ::from(0);
let _ = ModulusPolynomialRingZq::from((poly, 17));
}
}
#[cfg(test)]
mod test_try_from_integer_mod {
use std::str::FromStr;
use crate::{integer::PolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
#[test]
fn mod_primes() {
let _ = ModulusPolynomialRingZq::from_str("3 3 0 1 mod 17").unwrap();
let _ = ModulusPolynomialRingZq::from_str("3 3 0 1 mod 18").unwrap();
}
#[test]
#[should_panic]
fn panic_degree_0() {
let poly = PolyOverZ::from_str("1 1").unwrap();
let _ = ModulusPolynomialRingZq::from((poly, 17));
}
}
#[cfg(test)]
mod test_try_from_poly_zq {
use crate::{integer_mod_q::ModulusPolynomialRingZq, integer_mod_q::PolyOverZq};
use std::str::FromStr;
#[test]
fn working_large_entries() {
let poly_mod =
PolyOverZq::from_str(&format!("4 0 1 {} 1 mod {}", u64::MAX, 2_i32.pow(16) + 1))
.unwrap();
let _ = ModulusPolynomialRingZq::from(&poly_mod);
}
#[test]
fn poly_zq_primes() {
let poly_zq_1 = PolyOverZq::from_str("2 1 1 mod 10").unwrap();
let poly_zq_2 = PolyOverZq::from_str("2 1 1 mod 11").unwrap();
let _ = ModulusPolynomialRingZq::from(poly_zq_1);
let _ = ModulusPolynomialRingZq::from(poly_zq_2);
}
#[test]
#[should_panic]
fn panic_0() {
let poly = PolyOverZq::from((0, 17));
let _ = ModulusPolynomialRingZq::from(poly);
}
}
#[cfg(test)]
mod test_from_str {
use crate::integer_mod_q::ModulusPolynomialRingZq;
use std::str::FromStr;
#[test]
fn wrong_modulus_fmt() {
assert!(ModulusPolynomialRingZq::from_str("3 4 0 1 mod -17").is_err());
assert!(ModulusPolynomialRingZq::from_str("3 4 0 1 mod 17 mod 42").is_err());
assert!(ModulusPolynomialRingZq::from_str("3 4 0 1 mod 0").is_err());
assert!(ModulusPolynomialRingZq::from_str("3 4 0 1 mod 1 7").is_err());
assert!(ModulusPolynomialRingZq::from_str("3 4 0 1 mod ba").is_err());
}
#[test]
fn working_large_entries() {
assert!(
ModulusPolynomialRingZq::from_str(&format!(
"4 0 1 {} 1 mod {}",
u64::MAX,
2_i32.pow(16) + 1
))
.is_ok()
);
}
#[test]
fn poly_zq_primes() {
assert!(ModulusPolynomialRingZq::from_str("4 0 1 3 1 mod 10").is_ok());
assert!(ModulusPolynomialRingZq::from_str("4 0 1 3 1 mod 11").is_ok());
}
}