arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/test_fft64/rlwe_dft.rs
core/src/test_fft64/rlwe_dft.rsRaw
  1#[cfg(test)]
  2mod tests {
  3    use crate::{
  4        elem::{FromProdBy, FromProdByScratchSpace, Infos, ProdBy, ProdByScratchSpace},
  5        grlwe::GRLWECt,
  6        keys::{SecretKey, SecretKeyDft},
  7        rgsw::RGSWCt,
  8        rlwe::{RLWECt, RLWECtDft, RLWEPt},
  9        test_fft64::{grlwe::noise_grlwe_rlwe_product, rgsw::noise_rgsw_rlwe_product},
 10    };
 11    use base2k::{
 12        FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, VecZnxToMut, ZnxViewMut,
 13    };
 14    use sampling::source::Source;
 15
 16    #[test]
 17    fn from_prod_by_grlwe() {
 18        let module: Module<FFT64> = Module::<FFT64>::new(2048);
 19        let log_base2k: usize = 12;
 20        let log_k_grlwe: usize = 60;
 21        let log_k_rlwe_in: usize = 45;
 22        let log_k_rlwe_out: usize = 60;
 23        let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k;
 24
 25        let sigma: f64 = 3.2;
 26        let bound: f64 = sigma * 6.0;
 27
 28        let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows);
 29        let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in);
 30        let mut ct_rlwe_in_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_in);
 31        let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out);
 32        let mut ct_rlwe_out_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_out);
 33        let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in);
 34        let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out);
 35
 36        let mut source_xs: Source = Source::new([0u8; 32]);
 37        let mut source_xe: Source = Source::new([0u8; 32]);
 38        let mut source_xa: Source = Source::new([0u8; 32]);
 39
 40        // Random input plaintext
 41        pt_want
 42            .data
 43            .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
 44
 45        let mut scratch: ScratchOwned = ScratchOwned::new(
 46            GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size())
 47                | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size())
 48                | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size())
 49                | RLWECtDft::from_prod_by_grlwe_scratch_space(
 50                    &module,
 51                    ct_rlwe_out.size(),
 52                    ct_rlwe_in.size(),
 53                    ct_grlwe.size(),
 54                ),
 55        );
 56
 57        let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module);
 58        sk0.fill_ternary_prob(0.5, &mut source_xs);
 59
 60        let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
 61        sk0_dft.dft(&module, &sk0);
 62
 63        let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module);
 64        sk1.fill_ternary_prob(0.5, &mut source_xs);
 65
 66        let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
 67        sk1_dft.dft(&module, &sk1);
 68
 69        ct_grlwe.encrypt_sk(
 70            &module,
 71            &sk0.data,
 72            &sk1_dft,
 73            &mut source_xa,
 74            &mut source_xe,
 75            sigma,
 76            bound,
 77            scratch.borrow(),
 78        );
 79
 80        ct_rlwe_in.encrypt_sk(
 81            &module,
 82            Some(&pt_want),
 83            &sk0_dft,
 84            &mut source_xa,
 85            &mut source_xe,
 86            sigma,
 87            bound,
 88            scratch.borrow(),
 89        );
 90
 91        ct_rlwe_in.dft(&module, &mut ct_rlwe_in_dft);
 92        ct_rlwe_out_dft.from_prod_by_grlwe(&module, &ct_rlwe_in_dft, &ct_grlwe, scratch.borrow());
 93        ct_rlwe_out_dft.idft(&module, &mut ct_rlwe_out, scratch.borrow());
 94
 95        ct_rlwe_out.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow());
 96
 97        module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
 98
 99        let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
100        let noise_want: f64 = noise_grlwe_rlwe_product(
101            module.n() as f64,
102            log_base2k,
103            0.5,
104            0.5,
105            0f64,
106            sigma * sigma,
107            0f64,
108            log_k_rlwe_in,
109            log_k_grlwe,
110        );
111
112        assert!(
113            (noise_have - noise_want).abs() <= 0.1,
114            "{} {}",
115            noise_have,
116            noise_want
117        );
118
119        module.free();
120    }
121
122    #[test]
123    fn prod_by_grlwe() {
124        let module: Module<FFT64> = Module::<FFT64>::new(2048);
125        let log_base2k: usize = 12;
126        let log_k_grlwe: usize = 60;
127        let log_k_rlwe: usize = 45;
128        let rows: usize = (log_k_rlwe + log_base2k - 1) / log_base2k;
129
130        let sigma: f64 = 3.2;
131        let bound: f64 = sigma * 6.0;
132
133        let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows);
134        let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe);
135        let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe);
136        let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe);
137        let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe);
138
139        let mut source_xs: Source = Source::new([0u8; 32]);
140        let mut source_xe: Source = Source::new([0u8; 32]);
141        let mut source_xa: Source = Source::new([0u8; 32]);
142
143        // Random input plaintext
144        pt_want
145            .data
146            .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
147
148        let mut scratch: ScratchOwned = ScratchOwned::new(
149            GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size())
150                | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size())
151                | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size())
152                | RLWECtDft::prod_by_grlwe_scratch_space(&module, ct_rlwe_dft.size(), ct_grlwe.size()),
153        );
154
155        let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module);
156        sk0.fill_ternary_prob(0.5, &mut source_xs);
157
158        let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
159        sk0_dft.dft(&module, &sk0);
160
161        let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module);
162        sk1.fill_ternary_prob(0.5, &mut source_xs);
163
164        let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
165        sk1_dft.dft(&module, &sk1);
166
167        ct_grlwe.encrypt_sk(
168            &module,
169            &sk0.data,
170            &sk1_dft,
171            &mut source_xa,
172            &mut source_xe,
173            sigma,
174            bound,
175            scratch.borrow(),
176        );
177
178        ct_rlwe.encrypt_sk(
179            &module,
180            Some(&pt_want),
181            &sk0_dft,
182            &mut source_xa,
183            &mut source_xe,
184            sigma,
185            bound,
186            scratch.borrow(),
187        );
188
189        ct_rlwe.dft(&module, &mut ct_rlwe_dft);
190        ct_rlwe_dft.prod_by_grlwe(&module, &ct_grlwe, scratch.borrow());
191        ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow());
192
193        ct_rlwe.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow());
194
195        module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
196
197        let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
198        let noise_want: f64 = noise_grlwe_rlwe_product(
199            module.n() as f64,
200            log_base2k,
201            0.5,
202            0.5,
203            0f64,
204            sigma * sigma,
205            0f64,
206            log_k_rlwe,
207            log_k_grlwe,
208        );
209
210        assert!(
211            (noise_have - noise_want).abs() <= 0.1,
212            "{} {}",
213            noise_have,
214            noise_want
215        );
216
217        module.free();
218    }
219
220    #[test]
221    fn from_prod_by_rgsw() {
222        let module: Module<FFT64> = Module::<FFT64>::new(2048);
223        let log_base2k: usize = 12;
224        let log_k_grlwe: usize = 60;
225        let log_k_rlwe_in: usize = 45;
226        let log_k_rlwe_out: usize = 60;
227        let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k;
228
229        let sigma: f64 = 3.2;
230        let bound: f64 = sigma * 6.0;
231
232        let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows);
233        let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in);
234        let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out);
235        let mut ct_rlwe_dft_in: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_in);
236        let mut ct_rlwe_dft_out: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_out);
237        let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
238        let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in);
239        let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out);
240
241        let mut source_xs: Source = Source::new([0u8; 32]);
242        let mut source_xe: Source = Source::new([0u8; 32]);
243        let mut source_xa: Source = Source::new([0u8; 32]);
244
245        // Random input plaintext
246        pt_want
247            .data
248            .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
249
250        pt_want.to_mut().at_mut(0, 0)[1] = 1;
251
252        let k: usize = 1;
253
254        pt_rgsw.raw_mut()[k] = 1; // X^{k}
255
256        let mut scratch: ScratchOwned = ScratchOwned::new(
257            RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size())
258                | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size())
259                | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size())
260                | RLWECt::from_prod_by_rgsw_scratch_space(
261                    &module,
262                    ct_rlwe_out.size(),
263                    ct_rlwe_in.size(),
264                    ct_rgsw.size(),
265                ),
266        );
267
268        let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module);
269        sk.fill_ternary_prob(0.5, &mut source_xs);
270
271        let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
272        sk_dft.dft(&module, &sk);
273
274        ct_rgsw.encrypt_sk(
275            &module,
276            &pt_rgsw,
277            &sk_dft,
278            &mut source_xa,
279            &mut source_xe,
280            sigma,
281            bound,
282            scratch.borrow(),
283        );
284
285        ct_rlwe_in.encrypt_sk(
286            &module,
287            Some(&pt_want),
288            &sk_dft,
289            &mut source_xa,
290            &mut source_xe,
291            sigma,
292            bound,
293            scratch.borrow(),
294        );
295
296        ct_rlwe_in.dft(&module, &mut ct_rlwe_dft_in);
297        ct_rlwe_dft_out.from_prod_by_rgsw(&module, &ct_rlwe_dft_in, &ct_rgsw, scratch.borrow());
298        ct_rlwe_dft_out.idft(&module, &mut ct_rlwe_out, scratch.borrow());
299
300        ct_rlwe_out.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow());
301
302        module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0);
303
304        module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
305
306        let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
307
308        let var_gct_err_lhs: f64 = sigma * sigma;
309        let var_gct_err_rhs: f64 = 0f64;
310
311        let var_msg: f64 = 1f64 / module.n() as f64; // X^{k}
312        let var_a0_err: f64 = sigma * sigma;
313        let var_a1_err: f64 = 1f64 / 12f64;
314
315        let noise_want: f64 = noise_rgsw_rlwe_product(
316            module.n() as f64,
317            log_base2k,
318            0.5,
319            var_msg,
320            var_a0_err,
321            var_a1_err,
322            var_gct_err_lhs,
323            var_gct_err_rhs,
324            log_k_rlwe_in,
325            log_k_grlwe,
326        );
327
328        assert!(
329            (noise_have - noise_want).abs() <= 0.1,
330            "{} {}",
331            noise_have,
332            noise_want
333        );
334
335        module.free();
336    }
337
338    #[test]
339    fn prod_by_rgsw() {
340        let module: Module<FFT64> = Module::<FFT64>::new(2048);
341        let log_base2k: usize = 12;
342        let log_k_grlwe: usize = 60;
343        let log_k_rlwe_in: usize = 45;
344        let log_k_rlwe_out: usize = 60;
345        let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k;
346
347        let sigma: f64 = 3.2;
348        let bound: f64 = sigma * 6.0;
349
350        let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows);
351        let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in);
352        let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_in);
353        let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
354        let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in);
355        let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out);
356
357        let mut source_xs: Source = Source::new([0u8; 32]);
358        let mut source_xe: Source = Source::new([0u8; 32]);
359        let mut source_xa: Source = Source::new([0u8; 32]);
360
361        // Random input plaintext
362        pt_want
363            .data
364            .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
365
366        pt_want.to_mut().at_mut(0, 0)[1] = 1;
367
368        let k: usize = 1;
369
370        pt_rgsw.raw_mut()[k] = 1; // X^{k}
371
372        let mut scratch: ScratchOwned = ScratchOwned::new(
373            RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size())
374                | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size())
375                | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size())
376                | RLWECt::prod_by_rgsw_scratch_space(&module, ct_rlwe.size(), ct_rgsw.size()),
377        );
378
379        let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module);
380        sk.fill_ternary_prob(0.5, &mut source_xs);
381
382        let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
383        sk_dft.dft(&module, &sk);
384
385        ct_rgsw.encrypt_sk(
386            &module,
387            &pt_rgsw,
388            &sk_dft,
389            &mut source_xa,
390            &mut source_xe,
391            sigma,
392            bound,
393            scratch.borrow(),
394        );
395
396        ct_rlwe.encrypt_sk(
397            &module,
398            Some(&pt_want),
399            &sk_dft,
400            &mut source_xa,
401            &mut source_xe,
402            sigma,
403            bound,
404            scratch.borrow(),
405        );
406
407        ct_rlwe.dft(&module, &mut ct_rlwe_dft);
408        ct_rlwe_dft.prod_by_rgsw(&module, &ct_rgsw, scratch.borrow());
409        ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow());
410
411        ct_rlwe.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow());
412
413        module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0);
414
415        module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
416
417        let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
418
419        let var_gct_err_lhs: f64 = sigma * sigma;
420        let var_gct_err_rhs: f64 = 0f64;
421
422        let var_msg: f64 = 1f64 / module.n() as f64; // X^{k}
423        let var_a0_err: f64 = sigma * sigma;
424        let var_a1_err: f64 = 1f64 / 12f64;
425
426        let noise_want: f64 = noise_rgsw_rlwe_product(
427            module.n() as f64,
428            log_base2k,
429            0.5,
430            var_msg,
431            var_a0_err,
432            var_a1_err,
433            var_gct_err_lhs,
434            var_gct_err_rhs,
435            log_k_rlwe_in,
436            log_k_grlwe,
437        );
438
439        assert!(
440            (noise_have - noise_want).abs() <= 0.1,
441            "{} {}",
442            noise_have,
443            noise_want
444        );
445
446        module.free();
447    }
448}