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