use super::PolyOverZq;
use crate::{
error::MathError,
integer::Z,
integer_mod_q::Zq,
macros::for_others::implement_for_owned,
traits::{CompareBase, Evaluate},
};
use flint3_sys::fmpz_mod_poly_evaluate_fmpz;
impl<Integer: Into<Z>> Evaluate<Integer, Zq> for PolyOverZq {
fn evaluate(&self, value: Integer) -> Zq {
let value: Z = value.into();
let mut res = Zq::from((0, &self.modulus));
unsafe {
fmpz_mod_poly_evaluate_fmpz(
&mut res.value.value,
&self.poly,
&value.value,
self.modulus.get_fmpz_mod_ctx_struct(),
)
};
res
}
}
impl PolyOverZq {
pub fn evaluate_safe(&self, value: &Zq) -> Result<Zq, MathError> {
if !self.compare_base(value) {
return Err(self.call_compare_base_error(value).unwrap());
}
Ok(self.evaluate(&value.value))
}
}
impl Evaluate<&Zq, Zq> for PolyOverZq {
fn evaluate(&self, value: &Zq) -> Zq {
self.evaluate_safe(value)
.expect("The moduli of the provided inputs mismatch")
}
}
implement_for_owned!(Zq, Zq, PolyOverZq, Evaluate);
#[cfg(test)]
mod test_evaluate_z {
use crate::integer::Z;
use crate::integer_mod_q::{PolyOverZq, Zq};
use crate::traits::Evaluate;
use std::str::FromStr;
#[test]
fn eval_z() {
let poly = PolyOverZq::from_str("2 1 2 mod 17").unwrap();
let res = poly.evaluate(Z::from(3));
assert_eq!(Zq::from((7, 17)), res);
}
#[test]
fn eval_z_ref() {
let poly = PolyOverZq::from_str("2 1 2 mod 17").unwrap();
let res = poly.evaluate(&Z::from(3));
assert_eq!(Zq::from((7, 17)), res);
}
#[test]
fn eval_z_negative() {
let poly = PolyOverZq::from_str("2 1 2 mod 17").unwrap();
let res = poly.evaluate(&Z::from(-5));
assert_eq!(Zq::from((8, 17)), res);
}
#[test]
fn eval_z_large() {
let poly = PolyOverZq::from_str(&format!("2 3 2 mod {}", u64::MAX)).unwrap();
let res = poly.evaluate(&Z::from(u64::MAX - 1));
assert_eq!(Zq::from((1, u64::MAX)), res);
}
#[test]
fn eval_max() {
let poly = PolyOverZq::from_str("2 1 2 mod 17").unwrap();
let _ = poly.evaluate(i64::MAX);
let _ = poly.evaluate(i32::MAX);
let _ = poly.evaluate(i16::MAX);
let _ = poly.evaluate(i8::MAX);
let _ = poly.evaluate(u64::MAX);
let _ = poly.evaluate(u32::MAX);
let _ = poly.evaluate(u16::MAX);
let _ = poly.evaluate(u8::MAX);
}
#[test]
fn eval_min() {
let poly = PolyOverZq::from_str("2 1 2 mod 17").unwrap();
let _ = poly.evaluate(i64::MIN);
let _ = poly.evaluate(i32::MIN);
let _ = poly.evaluate(i16::MIN);
let _ = poly.evaluate(i8::MIN);
let _ = poly.evaluate(u64::MIN);
let _ = poly.evaluate(u32::MIN);
let _ = poly.evaluate(u16::MIN);
let _ = poly.evaluate(u8::MIN);
}
}
#[cfg(test)]
mod test_evaluate_zq {
use crate::{
integer_mod_q::{PolyOverZq, Zq},
traits::Evaluate,
};
use std::str::FromStr;
#[test]
fn evaluate_positive() {
let poly = PolyOverZq::from_str("2 1 3 mod 17").unwrap();
let value = Zq::from((6, 17));
let res_ref = poly.evaluate(&value);
let res = poly.evaluate(value);
assert_eq!(Zq::from((2, 17)), res);
assert_eq!(res_ref, res);
}
#[test]
fn evaluate_large_positive() {
let poly =
PolyOverZq::from_str(&format!("2 {} 1 mod {}", (u64::MAX - 1) / 2 + 2, u64::MAX))
.unwrap();
let value = Zq::from(((u64::MAX - 1) / 2, u64::MAX));
let res_ref = poly.evaluate(&value);
let res = poly.evaluate(value);
assert_eq!(Zq::from((1, u64::MAX)), res);
assert_eq!(res_ref, res);
}
#[test]
#[should_panic]
fn mismatching_modulus_panic() {
let poly = PolyOverZq::from_str(&format!("2 3 1 mod {}", u64::MAX)).unwrap();
let value = Zq::from((3, u64::MAX - 1));
let _ = poly.evaluate(&value);
}
#[test]
fn mismatching_modulus_safe() {
let poly = PolyOverZq::from_str(&format!("2 3 1 mod {}", u64::MAX)).unwrap();
let value = Zq::from((3, u64::MAX - 1));
assert!(poly.evaluate_safe(&value).is_err());
}
}