1use polynomial_ring::Polynomial;
2use rand_distr::{Uniform, Normal, Distribution};
3use ntt::polymul_ntt;
4use rand::SeedableRng;
5use rand::rngs::StdRng;
6use base64::{engine::general_purpose, Engine as _};
7use bincode;
8
9#[derive(Debug)]
11pub struct Parameters {
12 pub n: usize, pub q: i64, pub t: i64, pub omega: i64, pub f: Polynomial<i64>, #[allow(dead_code)]
18 pub sigma: f64, }
20
21impl Default for Parameters {
23 fn default() -> Self {
24 let n = 1024;
25 let q = 12289;
26 let t = 2;
27 let omega = ntt::omega(q, 2*n);
28 let mut poly_vec = vec![0i64;n+1];
29 poly_vec[0] = 1;
30 poly_vec[n] = 1;
31 let f = Polynomial::new(poly_vec);
32 let sigma = 8.0;
33 Parameters {n, q, t, omega, f, sigma}
34 }
35}
36
37pub fn mod_coeffs(x : Polynomial<i64>, modulus : i64) -> Polynomial<i64> {
44
45 let coeffs = x.coeffs();
46 let mut newcoeffs = vec![];
47 let mut c;
48 if coeffs.len() == 0 {
49 x
51 } else {
52 for i in 0..coeffs.len() {
53 c = coeffs[i].rem_euclid(modulus);
54 if c > modulus/2 {
55 c = c-modulus;
56 }
57 newcoeffs.push(c);
58 }
59 Polynomial::new(newcoeffs)
60 }
61}
62
63pub fn polyrem(x: Polynomial<i64>, f: &Polynomial<i64>) -> Polynomial<i64> {
70 let n = f.coeffs().len()-1;
71 let mut coeffs = x.coeffs().to_vec();
72 if coeffs.len() < n+1 {
73 return Polynomial::new(coeffs)
74 } else{
75 for i in n..coeffs.len() {
76 coeffs[i % n] = coeffs[i % n]+(-1 as i64).pow((i/n).try_into().unwrap())*coeffs[i];
77 }
78 coeffs.resize(n,0);
79 Polynomial::new(coeffs)
80 }
81}
82
83#[allow(dead_code)]
92pub fn polymul(x : &Polynomial<i64>, y : &Polynomial<i64>, q : i64, f : &Polynomial<i64>) -> Polynomial<i64> {
93 let mut r = x*y;
94 r = polyrem(r,f);
95 if q != 0 {
96 mod_coeffs(r, q)
97 }
98 else{
99 r
100 }
101}
102
103pub fn polymul_fast(
125 x: &Polynomial<i64>,
126 y: &Polynomial<i64>,
127 q: i64,
128 f: &Polynomial<i64>,
129 omega: i64
130) -> Polynomial<i64> {
131 let n1 = x.coeffs().len();
132 let n2 = y.coeffs().len();
133 let n = 2*(std::cmp::max(n1, n2)).next_power_of_two();
135 let x_pad = {
137 let mut coeffs = x.coeffs().to_vec();
138 coeffs.resize(n, 0);
139 coeffs
140 };
141 let y_pad = {
142 let mut coeffs = y.coeffs().to_vec();
143 coeffs.resize(n, 0);
144 coeffs
145 };
146
147 let r_coeffs = polymul_ntt(&x_pad, &y_pad, n, q, omega);
149
150 let mut r = Polynomial::new(r_coeffs);
152 r = polyrem(r,f);
153 mod_coeffs(r, q)
154}
155
156
157pub fn polyadd(x : &Polynomial<i64>, y : &Polynomial<i64>, modulus : i64, f : &Polynomial<i64>) -> Polynomial<i64> {
166 let mut r = x+y;
167 r = polyrem(r,f);
168 if modulus != 0 {
169 mod_coeffs(r, modulus)
170 }
171 else{
172 r
173 }
174}
175
176pub fn polyinv(x : &Polynomial<i64>, modulus: i64) -> Polynomial<i64> {
183 let y = -x;
185 if modulus != 0{
186 mod_coeffs(y, modulus)
187 }
188 else {
189 y
190 }
191 }
192
193#[allow(dead_code)]
202pub fn polysub(x : &Polynomial<i64>, y : &Polynomial<i64>, modulus : i64, f : &Polynomial<i64>) -> Polynomial<i64> {
203 polyadd(x, &polyinv(y, modulus), modulus, f)
204}
205
206#[allow(dead_code)]
213pub fn gen_binary_poly(size : usize, seed: Option<u64>) -> Polynomial<i64> {
214 let between = Uniform::new(0,2);
215 let mut rng = match seed {
216 Some(seed) => StdRng::seed_from_u64(seed),
217 None => StdRng::from_entropy(),
218 };
219 let mut coeffs = vec![0i64;size];
220 for i in 0..size {
221 coeffs[i] = between.sample(&mut rng);
222 }
223 Polynomial::new(coeffs)
224}
225
226pub fn gen_ternary_poly(size : usize, seed: Option<u64>) -> Polynomial<i64> {
233 let between = Uniform::new(-1,2);
234 let mut rng = match seed {
235 Some(seed) => StdRng::seed_from_u64(seed),
236 None => StdRng::from_entropy(),
237 };
238 let mut coeffs = vec![0i64;size];
239 for i in 0..size {
240 coeffs[i] = between.sample(&mut rng);
241 }
242 Polynomial::new(coeffs)
243}
244
245pub fn gen_uniform_poly(size: usize, q: i64, seed: Option<u64>) -> Polynomial<i64> {
253 let between = Uniform::new(0,q);
254 let mut rng = match seed {
255 Some(seed) => StdRng::seed_from_u64(seed),
256 None => StdRng::from_entropy(),
257 };
258 let mut coeffs = vec![0i64;size];
259 for i in 0..size {
260 coeffs[i] = between.sample(&mut rng);
261 }
262 mod_coeffs(Polynomial::new(coeffs),q)
263}
264
265#[allow(dead_code)]
273pub fn gen_normal_poly(size: usize, sigma: f64, seed: Option<u64>) -> Polynomial<i64> {
274 let normal = Normal::new(0.0 as f64, sigma).unwrap();
275 let mut rng = match seed {
276 Some(seed) => StdRng::seed_from_u64(seed),
277 None => StdRng::from_entropy(),
278 };
279 let mut coeffs = vec![0i64;size];
280 for i in 0..size {
281 coeffs[i] = normal.sample(&mut rng).round() as i64;
282 }
283 Polynomial::new(coeffs)
284}
285
286pub fn nearest_int(a: i64, b: i64) -> i64 {
293 if a > 0 {
294 (a + b / 2) / b
295 }else {
296 -((-a + b / 2) / b)
297 }
298}
299
300pub fn compress(data: &Vec<i64>) -> String {
306 let serialized_data = bincode::serialize(data).expect("Failed to serialize data");
307 general_purpose::STANDARD.encode(&serialized_data)
308}
309
310pub fn decompress(base64_str: &str) -> Vec<i64> {
316 let decoded_bytes = general_purpose::STANDARD.decode(base64_str).expect("Failed to decode base64 string");
317 bincode::deserialize(&decoded_bytes).expect("Failed to deserialize data")
318}