use crate::{
integer::PolyOverZ,
integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
};
impl PolynomialRingZq {
pub fn sample_uniform(modulus: impl Into<ModulusPolynomialRingZq>) -> Self {
let modulus = modulus.into();
assert!(
modulus.get_degree() > 0,
"ModulusPolynomial of degree 0 is insufficient to sample over."
);
let poly_z =
PolyOverZ::sample_uniform(modulus.get_degree() - 1, 0, modulus.get_q()).unwrap();
PolynomialRingZq {
poly: poly_z,
modulus,
}
}
}
#[cfg(test)]
mod test_sample_uniform {
use crate::{
integer::Z,
integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq},
traits::{GetCoefficient, SetCoefficient},
};
use std::str::FromStr;
#[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_uniform(&modulus);
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_uniform(&modulus);
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_uniform(&modulus);
assert_eq!(
res.get_degree() + 1,
modulus.get_degree(),
"Could fail with probability 1/{}.",
u64::MAX
);
}
}
#[test]
#[should_panic]
fn invalid_modulus() {
let modulus = ModulusPolynomialRingZq::from_str("1 1 mod 17").unwrap();
let _ = PolynomialRingZq::sample_uniform(&modulus);
}
}