1use polynomial_ring::Polynomial;
2use rand_distr::{Uniform, Normal, Distribution};
3use ntt::polymul_ntt;
4use rand::SeedableRng;
5use rand::rngs::StdRng;
6
7#[derive(Debug)]
9pub struct Parameters {
10 pub n: usize, pub q: i64, pub t: i64, pub omega: i64, pub f: Polynomial<i64>, pub sigma: f64, }
17
18impl Default for Parameters {
20 fn default() -> Self {
21 let n = 512;
22 let q = 12289;
23 let t = 2;
24 let omega = 10302;
25 let mut poly_vec = vec![0i64;n+1];
26 poly_vec[0] = 1;
27 poly_vec[n] = 1;
28 let f = Polynomial::new(poly_vec);
29 let sigma = 8.0;
30 Parameters {n, q, t, omega, f, sigma}
31 }
32}
33
34pub fn mod_coeffs(x : Polynomial<i64>, modulus : i64) -> Polynomial<i64> {
41
42 let coeffs = x.coeffs();
43 let mut newcoeffs = vec![];
44 let mut c;
45 if coeffs.len() == 0 {
46 x
48 } else {
49 for i in 0..coeffs.len() {
50 c = coeffs[i].rem_euclid(modulus);
51 if c > modulus/2 {
52 c = c-modulus;
53 }
54 newcoeffs.push(c);
55 }
56 Polynomial::new(newcoeffs)
57 }
58}
59
60pub fn polyrem(x: Polynomial<i64>, f: &Polynomial<i64>) -> Polynomial<i64> {
67 let n = f.coeffs().len()-1;
68 let mut coeffs = x.coeffs().to_vec();
69 if coeffs.len() < n+1 {
70 return Polynomial::new(coeffs)
71 } else{
72 for i in n..coeffs.len() {
73 coeffs[i % n] = coeffs[i % n]+(-1 as i64).pow((i/n).try_into().unwrap())*coeffs[i];
74 }
75 coeffs.resize(n,0);
76 Polynomial::new(coeffs)
77 }
78}
79
80pub fn polymul(x : &Polynomial<i64>, y : &Polynomial<i64>, q : i64, f : &Polynomial<i64>) -> Polynomial<i64> {
89 let mut r = x*y;
90 r = polyrem(r,f);
91 if q != 0 {
92 mod_coeffs(r, q)
93 }
94 else{
95 r
96 }
97}
98
99pub fn polymul_fast(
123 x: &Polynomial<i64>,
124 y: &Polynomial<i64>,
125 q: i64,
126 f: &Polynomial<i64>,
127 omega: i64
128) -> Polynomial<i64> {
129 let n = 2 * (x.deg().unwrap() + 1);
131 let x_pad = {
132 let mut coeffs = x.coeffs().to_vec();
133 coeffs.resize(n, 0);
134 coeffs
135 };
136 let y_pad = {
137 let mut coeffs = y.coeffs().to_vec();
138 coeffs.resize(n, 0);
139 coeffs
140 };
141
142 let r_coeffs = polymul_ntt(&x_pad, &y_pad, n, q, omega);
144
145 let mut r = Polynomial::new(r_coeffs);
147 r = polyrem(r,f);
148 mod_coeffs(r, q)
149}
150
151
152pub fn polyadd(x : &Polynomial<i64>, y : &Polynomial<i64>, modulus : i64, f : &Polynomial<i64>) -> Polynomial<i64> {
161 let mut r = x+y;
162 r = polyrem(r,f);
163 if modulus != 0 {
164 mod_coeffs(r, modulus)
165 }
166 else{
167 r
168 }
169}
170
171pub fn polyinv(x : &Polynomial<i64>, modulus: i64) -> Polynomial<i64> {
178 let y = -x;
180 if modulus != 0{
181 mod_coeffs(y, modulus)
182 }
183 else {
184 y
185 }
186 }
187
188pub fn polysub(x : &Polynomial<i64>, y : &Polynomial<i64>, modulus : i64, f : &Polynomial<i64>) -> Polynomial<i64> {
197 polyadd(x, &polyinv(y, modulus), modulus, f)
198}
199
200pub fn gen_binary_poly(size : usize, seed: Option<u64>) -> Polynomial<i64> {
207 let between = Uniform::new(0,2);
208 let mut rng = match seed {
209 Some(seed) => StdRng::seed_from_u64(seed),
210 None => StdRng::from_entropy(),
211 };
212 let mut coeffs = vec![0i64;size];
213 for i in 0..size {
214 coeffs[i] = between.sample(&mut rng);
215 }
216 Polynomial::new(coeffs)
217}
218
219pub fn gen_ternary_poly(size : usize, seed: Option<u64>) -> Polynomial<i64> {
226 let between = Uniform::new(-1,2);
227 let mut rng = match seed {
228 Some(seed) => StdRng::seed_from_u64(seed),
229 None => StdRng::from_entropy(),
230 };
231 let mut coeffs = vec![0i64;size];
232 for i in 0..size {
233 coeffs[i] = between.sample(&mut rng);
234 }
235 Polynomial::new(coeffs)
236}
237
238pub fn gen_uniform_poly(size: usize, q: i64, seed: Option<u64>) -> Polynomial<i64> {
246 let between = Uniform::new(0,q);
247 let mut rng = match seed {
248 Some(seed) => StdRng::seed_from_u64(seed),
249 None => StdRng::from_entropy(),
250 };
251 let mut coeffs = vec![0i64;size];
252 for i in 0..size {
253 coeffs[i] = between.sample(&mut rng);
254 }
255 mod_coeffs(Polynomial::new(coeffs),q)
256}
257
258pub fn gen_normal_poly(size: usize, sigma: f64, seed: Option<u64>) -> Polynomial<i64> {
266 let normal = Normal::new(0.0 as f64, sigma).unwrap();
267 let mut rng = match seed {
268 Some(seed) => StdRng::seed_from_u64(seed),
269 None => StdRng::from_entropy(),
270 };
271 let mut coeffs = vec![0i64;size];
272 for i in 0..size {
273 coeffs[i] = normal.sample(&mut rng).round() as i64;
274 }
275 Polynomial::new(coeffs)
276}
277
278pub fn nearest_int(a: i64, b: i64) -> i64 {
285 if a > 0 {
286 (a + b / 2) / b
287 }else {
288 -((-a + b / 2) / b)
289 }
290}