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