use crate::{
integer::PolyOverZ,
integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
macros::seeded::seedable_function,
};
impl PolynomialRingZq {
seedable_function!(
#[unseeded]
#[seeded]
#[optionally_seeded]
#[optionally_seeded]
#[seeded]
#[optionally_seeded]
#[optionally_seeded]
#[unseeded]
#[seeded]
pub(crate) fn sample_uniform(
modulus: impl Into<ModulusPolynomialRingZq>,
seed: Option<[u8; 32]>,
) -> 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_optionally_seeded(
modulus.get_degree() - 1,
0,
modulus.get_q(),
seed,
)
.unwrap();
PolynomialRingZq {
poly: poly_z,
modulus,
}
}
);
}
#[cfg(test)]
mod test_sample_uniform {
use crate::utils::sample::test_seed;
use crate::{
integer::Z,
integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq},
traits::{GetCoefficient, SetCoefficient},
};
use std::str::FromStr;
#[test]
fn boundaries_kept_small() {
for seeded in [false, true] {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
for _ in 0..32 {
let poly = PolynomialRingZq::sample_uniform_optionally_seeded(
&modulus,
seeded.then(test_seed),
);
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() {
for seeded in [false, true] {
let modulus =
ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX)).unwrap();
for _ in 0..256 {
let poly = PolynomialRingZq::sample_uniform_optionally_seeded(
&modulus,
seeded.then(test_seed),
);
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() {
for seeded in [false, true] {
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_optionally_seeded(
&modulus,
seeded.then(test_seed),
);
assert_eq!(
res.get_degree() + 1,
modulus.get_degree(),
"Could fail with probability 1/{}.",
u64::MAX
);
}
}
}
#[test]
fn invalid_modulus() {
for seeded in [false, true] {
let result = std::panic::catch_unwind(|| {
let modulus = ModulusPolynomialRingZq::from_str("1 1 mod 17").unwrap();
let _ = PolynomialRingZq::sample_uniform_optionally_seeded(
&modulus,
seeded.then(test_seed),
);
});
assert!(result.is_err());
}
}
#[test]
fn same_seed_same_sample() {
use crate::integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq};
use std::str::FromStr;
let modulus = ModulusPolynomialRingZq::from_str("3 1 2 1 mod 17").unwrap();
let sample_0 = PolynomialRingZq::sample_uniform_seeded(&modulus, [42; 32]);
let sample_1 = PolynomialRingZq::sample_uniform_seeded(&modulus, [42; 32]);
assert_eq!(sample_0, sample_1);
}
#[test]
fn known_answer() {
use crate::integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq};
use std::str::FromStr;
let modulus = ModulusPolynomialRingZq::from_str("3 1 2 1 mod 17").unwrap();
let sample = PolynomialRingZq::sample_uniform_seeded(&modulus, [42; 32]);
assert_eq!("2 2 16 / 3 1 2 1 mod 17", sample.to_string());
}
#[test]
fn availability() {
use crate::integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq};
use std::str::FromStr;
let modulus = ModulusPolynomialRingZq::from_str("3 1 2 1 mod 17").unwrap();
let _ = PolynomialRingZq::sample_uniform(&modulus);
let _ = PolynomialRingZq::sample_uniform_seeded(&modulus, test_seed());
}
}