use crate::{
error::MathError,
integer::{PolyOverZ, Z},
integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
rational::Q,
};
impl PolynomialRingZq {
pub fn sample_binomial(
modulus: &ModulusPolynomialRingZq,
n: impl Into<Z>,
p: impl Into<Q>,
) -> Result<Self, MathError> {
Self::sample_binomial_with_offset(modulus, 0, n, p)
}
pub fn sample_binomial_with_offset(
modulus: &ModulusPolynomialRingZq,
offset: impl Into<Z>,
n: impl Into<Z>,
p: impl Into<Q>,
) -> Result<Self, MathError> {
assert!(
modulus.get_degree() > 0,
"ModulusPolynomial of degree 0 is insufficient to sample over."
);
let poly_z =
PolyOverZ::sample_binomial_with_offset(modulus.get_degree() - 1, offset, n, p)?;
Ok(PolynomialRingZq {
poly: poly_z,
modulus: modulus.clone(),
})
}
}
#[cfg(test)]
mod test_sample_binomial {
use super::{PolynomialRingZq, Z};
use crate::{
integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq},
traits::{GetCoefficient, SetCoefficient},
};
use std::str::FromStr;
#[test]
fn boundaries_kept() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
for _ in 0..8 {
let poly = PolynomialRingZq::sample_binomial(&modulus, 2, 0.5).unwrap();
let sample: Z = poly.get_coeff(0).unwrap();
assert!(Z::ZERO <= sample || sample <= 2);
}
}
#[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_binomial(&modulus, 256, 0.99999).unwrap();
assert_eq!(
modulus.get_degree(),
res.get_degree() + 1,
"This test can fail with probability close to 0."
);
}
}
#[test]
#[should_panic]
fn invalid_modulus() {
let modulus = ModulusPolynomialRingZq::from_str("1 1 mod 17").unwrap();
let _ = PolynomialRingZq::sample_binomial(&modulus, 2, 0.5);
}
}
#[cfg(test)]
mod test_sample_binomial_with_offset {
use super::{PolynomialRingZq, Z};
use crate::{
integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq},
traits::{GetCoefficient, SetCoefficient},
};
use std::str::FromStr;
#[test]
fn boundaries_kept() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
for _ in 0..8 {
let poly = PolynomialRingZq::sample_binomial_with_offset(&modulus, -1, 2, 0.5).unwrap();
let sample: Z = poly.get_coeff(0).unwrap();
assert!(Z::MINUS_ONE <= sample || sample <= Z::ONE);
}
}
#[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_binomial_with_offset(&modulus, 1, 2, 0.5).unwrap();
assert_eq!(modulus.get_degree(), res.get_degree() + 1);
}
}
#[test]
#[should_panic]
fn invalid_modulus() {
let modulus = ModulusPolynomialRingZq::from_str("1 1 mod 17").unwrap();
let _ = PolynomialRingZq::sample_binomial_with_offset(&modulus, -1, 2, 0.5);
}
}