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
 27    let mut ct_grlwe: GLWESwitchingKey<Vec<u8>, FFT64> =
 28        GLWESwitchingKey::new(&module, log_base2k, log_k_grlwe, rows, rank, rank);
 29    let mut ct_rlwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe_in, rank);
 30    let mut ct_rlwe_in_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
 31        GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe_in, rank);
 32    let mut ct_rlwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe_out, rank);
 33    let mut ct_rlwe_out_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
 34        GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe_out, rank);
 35    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe_in);
 36    let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe_out);
 37
 38    let mut source_xs: Source = Source::new([0u8; 32]);
 39    let mut source_xe: Source = Source::new([0u8; 32]);
 40    let mut source_xa: Source = Source::new([0u8; 32]);
 41
 42    // Random input plaintext
 43    pt_want
 44        .data
 45        .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
 46
 47    let mut scratch: ScratchOwned = ScratchOwned::new(
 48        GLWESwitchingKey::encrypt_sk_scratch_space(&module, rank, ct_grlwe.size())
 49            | GLWECiphertext::decrypt_scratch_space(&module, ct_rlwe_out.size())
 50            | GLWECiphertext::encrypt_sk_scratch_space(&module, rank, ct_rlwe_in.size())
 51            | GLWECiphertextFourier::keyswitch_scratch_space(
 52                &module,
 53                ct_rlwe_out.size(),
 54                ct_rlwe_in.size(),
 55                ct_grlwe.size(),
 56            ),
 57    );
 58
 59    let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
 60    sk0.fill_ternary_prob(0.5, &mut source_xs);
 61
 62    let mut sk0_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
 63    sk0_dft.dft(&module, &sk0);
 64
 65    let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
 66    sk1.fill_ternary_prob(0.5, &mut source_xs);
 67
 68    let mut sk1_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
 69    sk1_dft.dft(&module, &sk1);
 70
 71    ct_grlwe.encrypt_sk(
 72        &module,
 73        &sk0.data,
 74        &sk1_dft,
 75        &mut source_xa,
 76        &mut source_xe,
 77        sigma,
 78        scratch.borrow(),
 79    );
 80
 81    ct_rlwe_in.encrypt_sk(
 82        &module,
 83        &pt_want,
 84        &sk0_dft,
 85        &mut source_xa,
 86        &mut source_xe,
 87        sigma,
 88        scratch.borrow(),
 89    );
 90
 91    ct_rlwe_in.dft(&module, &mut ct_rlwe_in_dft);
 92    ct_rlwe_out_dft.keyswitch(&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
120#[test]
121fn keyswich_inplace() {
122    let module: Module<FFT64> = Module::<FFT64>::new(2048);
123    let log_base2k: usize = 12;
124    let log_k_grlwe: usize = 60;
125    let log_k_rlwe: usize = 45;
126    let rows: usize = (log_k_rlwe + log_base2k - 1) / log_base2k;
127    let rank: usize = 1;
128
129    let sigma: f64 = 3.2;
130
131    let mut ct_grlwe: GLWESwitchingKey<Vec<u8>, FFT64> =
132        GLWESwitchingKey::new(&module, log_base2k, log_k_grlwe, rows, rank, rank);
133    let mut ct_rlwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe, rank);
134    let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
135        GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe, rank);
136    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe);
137    let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::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        GLWESwitchingKey::encrypt_sk_scratch_space(&module, rank, ct_grlwe.size())
150            | GLWECiphertext::decrypt_scratch_space(&module, ct_rlwe.size())
151            | GLWECiphertext::encrypt_sk_scratch_space(&module, rank, ct_rlwe.size())
152            | GLWECiphertextFourier::keyswitch_inplace_scratch_space(&module, ct_rlwe_dft.size(), ct_grlwe.size()),
153    );
154
155    let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
156    sk0.fill_ternary_prob(0.5, &mut source_xs);
157
158    let mut sk0_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
159    sk0_dft.dft(&module, &sk0);
160
161    let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
162    sk1.fill_ternary_prob(0.5, &mut source_xs);
163
164    let mut sk1_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
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        scratch.borrow(),
175    );
176
177    ct_rlwe.encrypt_sk(
178        &module,
179        &pt_want,
180        &sk0_dft,
181        &mut source_xa,
182        &mut source_xe,
183        sigma,
184        scratch.borrow(),
185    );
186
187    ct_rlwe.dft(&module, &mut ct_rlwe_dft);
188    ct_rlwe_dft.keyswitch_inplace(&module, &ct_grlwe, scratch.borrow());
189    ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow());
190
191    ct_rlwe.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow());
192
193    module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
194
195    let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
196    let noise_want: f64 = noise_grlwe_rlwe_product(
197        module.n() as f64,
198        log_base2k,
199        0.5,
200        0.5,
201        0f64,
202        sigma * sigma,
203        0f64,
204        log_k_rlwe,
205        log_k_grlwe,
206    );
207
208    assert!(
209        (noise_have - noise_want).abs() <= 0.1,
210        "{} {}",
211        noise_have,
212        noise_want
213    );
214}
215
216#[test]
217fn external_product() {
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    let rank: usize = 1;
225
226    let sigma: f64 = 3.2;
227
228    let mut ct_rgsw: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_grlwe, rows, rank);
229    let mut ct_rlwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe_in, rank);
230    let mut ct_rlwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe_out, rank);
231    let mut ct_rlwe_dft_in: GLWECiphertextFourier<Vec<u8>, FFT64> =
232        GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe_in, rank);
233    let mut ct_rlwe_dft_out: GLWECiphertextFourier<Vec<u8>, FFT64> =
234        GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe_out, rank);
235    let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
236    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe_in);
237    let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe_out);
238
239    let mut source_xs: Source = Source::new([0u8; 32]);
240    let mut source_xe: Source = Source::new([0u8; 32]);
241    let mut source_xa: Source = Source::new([0u8; 32]);
242
243    // Random input plaintext
244    pt_want
245        .data
246        .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
247
248    pt_want.to_mut().at_mut(0, 0)[1] = 1;
249
250    let k: usize = 1;
251
252    pt_rgsw.raw_mut()[k] = 1; // X^{k}
253
254    let mut scratch: ScratchOwned = ScratchOwned::new(
255        GGSWCiphertext::encrypt_sk_scratch_space(&module, rank, ct_rgsw.size())
256            | GLWECiphertext::decrypt_scratch_space(&module, ct_rlwe_out.size())
257            | GLWECiphertext::encrypt_sk_scratch_space(&module, rank, ct_rlwe_in.size())
258            | GLWECiphertext::external_product_scratch_space(
259                &module,
260                ct_rlwe_out.size(),
261                ct_rlwe_in.size(),
262                ct_rgsw.size(),
263            ),
264    );
265
266    let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
267    sk.fill_ternary_prob(0.5, &mut source_xs);
268
269    let mut sk_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
270    sk_dft.dft(&module, &sk);
271
272    ct_rgsw.encrypt_sk(
273        &module,
274        &pt_rgsw,
275        &sk_dft,
276        &mut source_xa,
277        &mut source_xe,
278        sigma,
279        scratch.borrow(),
280    );
281
282    ct_rlwe_in.encrypt_sk(
283        &module,
284        &pt_want,
285        &sk_dft,
286        &mut source_xa,
287        &mut source_xe,
288        sigma,
289        scratch.borrow(),
290    );
291
292    ct_rlwe_in.dft(&module, &mut ct_rlwe_dft_in);
293    ct_rlwe_dft_out.external_product(&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
332#[test]
333fn external_product_inplace() {
334    let module: Module<FFT64> = Module::<FFT64>::new(2048);
335    let log_base2k: usize = 12;
336    let log_k_grlwe: usize = 60;
337    let log_k_rlwe_in: usize = 45;
338    let log_k_rlwe_out: usize = 60;
339    let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k;
340    let rank: usize = 1;
341
342    let sigma: f64 = 3.2;
343
344    let mut ct_rgsw: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_grlwe, rows, rank);
345    let mut ct_rlwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe_in, rank);
346    let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
347        GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe_in, rank);
348    let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
349    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe_in);
350    let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe_out);
351
352    let mut source_xs: Source = Source::new([0u8; 32]);
353    let mut source_xe: Source = Source::new([0u8; 32]);
354    let mut source_xa: Source = Source::new([0u8; 32]);
355
356    // Random input plaintext
357    pt_want
358        .data
359        .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
360
361    pt_want.to_mut().at_mut(0, 0)[1] = 1;
362
363    let k: usize = 1;
364
365    pt_rgsw.raw_mut()[k] = 1; // X^{k}
366
367    let mut scratch: ScratchOwned = ScratchOwned::new(
368        GGSWCiphertext::encrypt_sk_scratch_space(&module, rank, ct_rgsw.size())
369            | GLWECiphertext::decrypt_scratch_space(&module, ct_rlwe.size())
370            | GLWECiphertext::encrypt_sk_scratch_space(&module, rank, ct_rlwe.size())
371            | GLWECiphertext::external_product_inplace_scratch_space(&module, ct_rlwe.size(), ct_rgsw.size()),
372    );
373
374    let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
375    sk.fill_ternary_prob(0.5, &mut source_xs);
376
377    let mut sk_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
378    sk_dft.dft(&module, &sk);
379
380    ct_rgsw.encrypt_sk(
381        &module,
382        &pt_rgsw,
383        &sk_dft,
384        &mut source_xa,
385        &mut source_xe,
386        sigma,
387        scratch.borrow(),
388    );
389
390    ct_rlwe.encrypt_sk(
391        &module,
392        &pt_want,
393        &sk_dft,
394        &mut source_xa,
395        &mut source_xe,
396        sigma,
397        scratch.borrow(),
398    );
399
400    ct_rlwe.dft(&module, &mut ct_rlwe_dft);
401    ct_rlwe_dft.external_product_inplace(&module, &ct_rgsw, scratch.borrow());
402    ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow());
403
404    ct_rlwe.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow());
405
406    module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0);
407
408    module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
409
410    let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
411
412    let var_gct_err_lhs: f64 = sigma * sigma;
413    let var_gct_err_rhs: f64 = 0f64;
414
415    let var_msg: f64 = 1f64 / module.n() as f64; // X^{k}
416    let var_a0_err: f64 = sigma * sigma;
417    let var_a1_err: f64 = 1f64 / 12f64;
418
419    let noise_want: f64 = noise_rgsw_product(
420        module.n() as f64,
421        log_base2k,
422        0.5,
423        var_msg,
424        var_a0_err,
425        var_a1_err,
426        var_gct_err_lhs,
427        var_gct_err_rhs,
428        log_k_rlwe_in,
429        log_k_grlwe,
430    );
431
432    assert!(
433        (noise_have - noise_want).abs() <= 0.1,
434        "{} {}",
435        noise_have,
436        noise_want
437    );
438}