use polynomial_ring::Polynomial;
use rand_distr::{Uniform, Normal, Distribution};
use ntt::polymul_ntt;
use rand::SeedableRng;
use rand::rngs::StdRng;
#[derive(Debug)]
pub struct Parameters {
pub n: usize, pub q: i64, pub t: i64, pub f: Polynomial<i64>, pub sigma: f64, }
impl Default for Parameters {
fn default() -> Self {
let n = 512;
let q = 1048576;
let t = 256;
let mut poly_vec = vec![0i64;n+1];
poly_vec[0] = 1;
poly_vec[n] = 1;
let f = Polynomial::new(poly_vec);
let sigma = 8.0;
Parameters { n, q, t, f, sigma}
}
}
pub fn mod_coeffs(x : Polynomial<i64>, modulus : i64) -> Polynomial<i64> {
let coeffs = x.coeffs();
let mut newcoeffs = vec![];
let mut c;
if coeffs.len() == 0 {
x
} else {
for i in 0..coeffs.len() {
c = coeffs[i].rem_euclid(modulus);
if c > modulus/2 {
c = c-modulus;
}
newcoeffs.push(c);
}
Polynomial::new(newcoeffs)
}
}
pub fn polyrem(x: Polynomial<i64>, f: &Polynomial<i64>) -> Polynomial<i64> {
let n = f.coeffs().len()-1;
let mut coeffs = x.coeffs().to_vec();
if coeffs.len() < n+1 {
return Polynomial::new(coeffs)
} else{
for i in n..coeffs.len() {
coeffs[i % n] = coeffs[i % n]+(-1 as i64).pow((i/n).try_into().unwrap())*coeffs[i];
}
coeffs.resize(n,0);
Polynomial::new(coeffs)
}
}
pub fn polymul(x : &Polynomial<i64>, y : &Polynomial<i64>, q : i64, f : &Polynomial<i64>) -> Polynomial<i64> {
let mut r = x*y;
r = polyrem(r,f);
if q != 0 {
mod_coeffs(r, q)
}
else{
r
}
}
pub fn polymul_fast(
x: &Polynomial<i64>,
y: &Polynomial<i64>,
q: i64,
f: &Polynomial<i64>,
root: i64
) -> Polynomial<i64> {
let n = 2 * (x.deg().unwrap() + 1);
let x_pad = {
let mut coeffs = x.coeffs().to_vec();
coeffs.resize(n, 0);
coeffs
};
let y_pad = {
let mut coeffs = y.coeffs().to_vec();
coeffs.resize(n, 0);
coeffs
};
let r_coeffs = polymul_ntt(&x_pad, &y_pad, n, q, root);
let mut r = Polynomial::new(r_coeffs);
r = polyrem(r,f);
mod_coeffs(r, q)
}
pub fn polyadd(x : &Polynomial<i64>, y : &Polynomial<i64>, modulus : i64, f : &Polynomial<i64>) -> Polynomial<i64> {
let mut r = x+y;
r = polyrem(r,f);
if modulus != 0 {
mod_coeffs(r, modulus)
}
else{
r
}
}
pub fn polyinv(x : &Polynomial<i64>, modulus: i64) -> Polynomial<i64> {
let y = -x;
if modulus != 0{
mod_coeffs(y, modulus)
}
else {
y
}
}
pub fn polysub(x : &Polynomial<i64>, y : &Polynomial<i64>, modulus : i64, f : Polynomial<i64>) -> Polynomial<i64> {
polyadd(x, &polyinv(y, modulus), modulus, &f)
}
pub fn gen_binary_poly(size : usize, seed: Option<u64>) -> Polynomial<i64> {
let between = Uniform::new(0,2);
let mut rng = match seed {
Some(seed) => StdRng::seed_from_u64(seed),
None => StdRng::from_entropy(),
};
let mut coeffs = vec![0i64;size];
for i in 0..size {
coeffs[i] = between.sample(&mut rng);
}
Polynomial::new(coeffs)
}
pub fn gen_ternary_poly(size : usize, seed: Option<u64>) -> Polynomial<i64> {
let between = Uniform::new(-1,2);
let mut rng = match seed {
Some(seed) => StdRng::seed_from_u64(seed),
None => StdRng::from_entropy(),
};
let mut coeffs = vec![0i64;size];
for i in 0..size {
coeffs[i] = between.sample(&mut rng);
}
Polynomial::new(coeffs)
}
pub fn gen_uniform_poly(size: usize, q: i64, seed: Option<u64>) -> Polynomial<i64> {
let between = Uniform::new(0,q);
let mut rng = match seed {
Some(seed) => StdRng::seed_from_u64(seed),
None => StdRng::from_entropy(),
};
let mut coeffs = vec![0i64;size];
for i in 0..size {
coeffs[i] = between.sample(&mut rng);
}
mod_coeffs(Polynomial::new(coeffs),q)
}
pub fn gen_normal_poly(size: usize, sigma: f64, seed: Option<u64>) -> Polynomial<i64> {
let normal = Normal::new(0.0 as f64, sigma).unwrap();
let mut rng = match seed {
Some(seed) => StdRng::seed_from_u64(seed),
None => StdRng::from_entropy(),
};
let mut coeffs = vec![0i64;size];
for i in 0..size {
coeffs[i] = normal.sample(&mut rng).round() as i64;
}
Polynomial::new(coeffs)
}
pub fn nearest_int(a: i64, b: i64) -> i64 {
(a + b / 2) / b
}