use crate::{
error::MathError,
integer::PolyOverZ,
integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
rational::Q,
};
impl PolynomialRingZq {
pub fn sample_discrete_gauss(
modulus: impl Into<ModulusPolynomialRingZq>,
center: impl Into<Q>,
s: impl Into<Q>,
) -> Result<Self, MathError> {
let modulus = modulus.into();
assert!(
modulus.get_degree() > 0,
"ModulusPolynomial of degree 0 is insufficient to sample over."
);
let poly_z = PolyOverZ::sample_discrete_gauss(modulus.get_degree() - 1, center, s)?;
let mut poly_ringzq = PolynomialRingZq {
poly: poly_z,
modulus,
};
poly_ringzq.reduce();
Ok(poly_ringzq)
}
}
#[cfg(test)]
mod test_sample_discrete_gauss {
use crate::{
integer::Z,
integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq},
rational::Q,
traits::{GetCoefficient, SetCoefficient},
};
use std::str::FromStr;
#[test]
fn availability() {
let center = Q::ZERO;
let s = Q::ONE;
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1u8);
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f64, 1u16);
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1u32);
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f64, 1u64);
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1i8);
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1i16);
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1i32);
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f64, 1i64);
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, center, s);
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1f64);
}
#[test]
fn boundaries_kept_small() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
for _ in 0..32 {
let poly = PolynomialRingZq::sample_discrete_gauss(&modulus, 15, 1).unwrap();
for i in 0..3 {
let sample: Z = poly.get_coeff(i).unwrap();
assert!(Z::ZERO <= sample);
assert!(sample < modulus.get_q());
}
}
}
#[test]
fn boundaries_kept_large() {
let modulus =
ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX)).unwrap();
for _ in 0..256 {
let poly = PolynomialRingZq::sample_discrete_gauss(&modulus, 1, 1).unwrap();
for i in 0..3 {
let sample: Z = poly.get_coeff(i).unwrap();
assert!(Z::ZERO <= sample);
assert!(sample < modulus.get_q());
}
}
}
#[test]
fn nr_coeffs() {
let degrees = [1, 3, 7, 15, 32, 120];
for degree in degrees {
let mut modulus = PolyOverZq::from((1, u64::MAX));
modulus.set_coeff(degree, 1).unwrap();
let modulus = ModulusPolynomialRingZq::from(&modulus);
let res = PolynomialRingZq::sample_discrete_gauss(&modulus, i64::MAX, 1).unwrap();
assert_eq!(
res.get_degree() + 1,
modulus.get_degree(),
"Could fail with negligible probability."
);
}
}
#[test]
#[should_panic]
fn invalid_modulus() {
let modulus = ModulusPolynomialRingZq::from_str("1 1 mod 17").unwrap();
let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0, 1).unwrap();
}
}