1use polynomial_ring::Polynomial;
2use rand_distr::{Uniform, Normal, Distribution};
3use ntt::{omega,polymul_ntt};
4use rand::SeedableRng;
5use rand::rngs::StdRng;
6
7#[derive(Debug)]
8pub struct Parameters {
9 pub n: usize, pub q: i64, pub t: i64, pub omega: i64, pub f: Polynomial<i64>, pub sigma: f64, }
16
17impl Default for Parameters {
18 fn default() -> Self {
19 let n = 512;
20 let q = 12289;
21 let t = 2;
22 let omega = omega(q, 2*n);
23 let mut poly_vec = vec![0i64;n+1];
24 poly_vec[0] = 1;
25 poly_vec[n] = 1;
26 let f = Polynomial::new(poly_vec);
27 let sigma = 8.0;
28 Parameters {n, q, t, omega, f, sigma}
29 }
30}
31
32pub fn mod_coeffs(x : Polynomial<i64>, modulus : i64) -> Polynomial<i64> {
33 let coeffs = x.coeffs();
40 let mut newcoeffs = vec![];
41 let mut c;
42 if coeffs.len() == 0 {
43 x
45 } else {
46 for i in 0..coeffs.len() {
47 c = coeffs[i].rem_euclid(modulus);
48 if c > modulus/2 {
49 c = c-modulus;
50 }
51 newcoeffs.push(c);
52 }
53 Polynomial::new(newcoeffs)
54 }
55}
56
57pub fn polyrem(x: Polynomial<i64>, f: &Polynomial<i64>) -> Polynomial<i64> {
58 let n = f.coeffs().len()-1;
60 let mut coeffs = x.coeffs().to_vec();
61 if coeffs.len() < n+1 {
62 return Polynomial::new(coeffs)
63 } else{
64 for i in n..coeffs.len() {
65 coeffs[i % n] = coeffs[i % n]+(-1 as i64).pow((i/n).try_into().unwrap())*coeffs[i];
66 }
67 coeffs.resize(n,0);
68 Polynomial::new(coeffs)
69 }
70}
71
72pub fn polymul(x : &Polynomial<i64>, y : &Polynomial<i64>, q : i64, f : &Polynomial<i64>) -> Polynomial<i64> {
73 let mut r = x*y;
81 r = polyrem(r,f);
82 if q != 0 {
83 mod_coeffs(r, q)
84 }
85 else{
86 r
87 }
88}
89
90pub fn polymul_fast(
91 x: &Polynomial<i64>,
92 y: &Polynomial<i64>,
93 q: i64,
94 f: &Polynomial<i64>,
95 omega: i64
96) -> Polynomial<i64> {
97 let n = 2 * (x.deg().unwrap() + 1);
99 let x_pad = {
100 let mut coeffs = x.coeffs().to_vec();
101 coeffs.resize(n, 0);
102 coeffs
103 };
104 let y_pad = {
105 let mut coeffs = y.coeffs().to_vec();
106 coeffs.resize(n, 0);
107 coeffs
108 };
109
110 let r_coeffs = polymul_ntt(&x_pad, &y_pad, n, q, omega);
112
113 let mut r = Polynomial::new(r_coeffs);
115 r = polyrem(r,f);
116 mod_coeffs(r, q)
117}
118
119
120
121pub fn polyadd(x : &Polynomial<i64>, y : &Polynomial<i64>, modulus : i64, f : &Polynomial<i64>) -> Polynomial<i64> {
122 let mut r = x+y;
130 r = polyrem(r,f);
131 if modulus != 0 {
132 mod_coeffs(r, modulus)
133 }
134 else{
135 r
136 }
137}
138
139pub fn polyinv(x : &Polynomial<i64>, modulus: i64) -> Polynomial<i64> {
140 let y = -x;
142 if modulus != 0{
143 mod_coeffs(y, modulus)
144 }
145 else {
146 y
147 }
148 }
149
150pub fn polysub(x : &Polynomial<i64>, y : &Polynomial<i64>, modulus : i64, f : Polynomial<i64>) -> Polynomial<i64> {
151 polyadd(x, &polyinv(y, modulus), modulus, &f)
159}
160
161pub fn gen_binary_poly(size : usize, seed: Option<u64>) -> Polynomial<i64> {
162 let between = Uniform::new(0,2);
168 let mut rng = match seed {
169 Some(seed) => StdRng::seed_from_u64(seed),
170 None => StdRng::from_entropy(),
171 };
172 let mut coeffs = vec![0i64;size];
173 for i in 0..size {
174 coeffs[i] = between.sample(&mut rng);
175 }
176 Polynomial::new(coeffs)
177}
178
179pub fn gen_ternary_poly(size : usize, seed: Option<u64>) -> Polynomial<i64> {
180 let between = Uniform::new(-1,2);
186 let mut rng = match seed {
187 Some(seed) => StdRng::seed_from_u64(seed),
188 None => StdRng::from_entropy(),
189 };
190 let mut coeffs = vec![0i64;size];
191 for i in 0..size {
192 coeffs[i] = between.sample(&mut rng);
193 }
194 Polynomial::new(coeffs)
195}
196
197pub fn gen_uniform_poly(size: usize, q: i64, seed: Option<u64>) -> Polynomial<i64> {
198 let between = Uniform::new(0,q);
204 let mut rng = match seed {
205 Some(seed) => StdRng::seed_from_u64(seed),
206 None => StdRng::from_entropy(),
207 };
208 let mut coeffs = vec![0i64;size];
209 for i in 0..size {
210 coeffs[i] = between.sample(&mut rng);
211 }
212 mod_coeffs(Polynomial::new(coeffs),q)
213}
214
215pub fn gen_normal_poly(size: usize, sigma: f64, seed: Option<u64>) -> Polynomial<i64> {
216 let normal = Normal::new(0.0 as f64, sigma).unwrap();
223 let mut rng = match seed {
224 Some(seed) => StdRng::seed_from_u64(seed),
225 None => StdRng::from_entropy(),
226 };
227 let mut coeffs = vec![0i64;size];
228 for i in 0..size {
229 coeffs[i] = normal.sample(&mut rng).round() as i64;
230 }
231 Polynomial::new(coeffs)
232}
233
234pub fn nearest_int(a: i64, b: i64) -> i64 {
236 if a > 0 {
237 (a + b / 2) / b
238 }else {
239 -((-a + b / 2) / b)
240 }
241}