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,
  3    encryption::EncryptSkScratchSpace,
  4    external_product::{
  5        ExternalProduct, ExternalProductInplace, ExternalProductInplaceScratchSpace, ExternalProductScratchSpace,
  6    },
  7    ggsw::GGSWCiphertext,
  8    glwe::{GLWECiphertext, GLWECiphertextFourier, GLWEPlaintext},
  9    keys::{SecretKey, SecretKeyFourier},
 10    keyswitch::{KeySwitch, KeySwitchInplace, KeySwitchInplaceScratchSpace, KeySwitchScratchSpace},
 11    keyswitch_key::GLWEKeySwitchKey,
 12    test_fft64::{grlwe::noise_grlwe_rlwe_product, rgsw::noise_rgsw_product},
 13};
 14use base2k::{FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, VecZnxToMut, ZnxViewMut};
 15use sampling::source::Source;
 16
 17#[test]
 18fn keyswitch() {
 19    let module: Module<FFT64> = Module::<FFT64>::new(2048);
 20    let log_base2k: usize = 12;
 21    let log_k_grlwe: usize = 60;
 22    let log_k_rlwe_in: usize = 45;
 23    let log_k_rlwe_out: usize = 60;
 24    let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k;
 25
 26    let sigma: f64 = 3.2;
 27    let bound: f64 = sigma * 6.0;
 28
 29    let mut ct_grlwe: GLWEKeySwitchKey<Vec<u8>, FFT64> = GLWEKeySwitchKey::new(&module, log_base2k, log_k_grlwe, rows);
 30    let mut ct_rlwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe_in);
 31    let mut ct_rlwe_in_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
 32        GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe_in);
 33    let mut ct_rlwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe_out);
 34    let mut ct_rlwe_out_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
 35        GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe_out);
 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        GLWEKeySwitchKey::encrypt_sk_scratch_space(&module, ct_grlwe.size())
 50            | GLWECiphertext::decrypt_scratch_space(&module, ct_rlwe_out.size())
 51            | GLWECiphertext::encrypt_sk_scratch_space(&module, 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);
 61    sk0.fill_ternary_prob(0.5, &mut source_xs);
 62
 63    let mut sk0_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module);
 64    sk0_dft.dft(&module, &sk0);
 65
 66    let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module);
 67    sk1.fill_ternary_prob(0.5, &mut source_xs);
 68
 69    let mut sk1_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module);
 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
131    let sigma: f64 = 3.2;
132    let bound: f64 = sigma * 6.0;
133
134    let mut ct_grlwe: GLWEKeySwitchKey<Vec<u8>, FFT64> = GLWEKeySwitchKey::new(&module, log_base2k, log_k_grlwe, rows);
135    let mut ct_rlwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe);
136    let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe);
137    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe);
138    let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe);
139
140    let mut source_xs: Source = Source::new([0u8; 32]);
141    let mut source_xe: Source = Source::new([0u8; 32]);
142    let mut source_xa: Source = Source::new([0u8; 32]);
143
144    // Random input plaintext
145    pt_want
146        .data
147        .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
148
149    let mut scratch: ScratchOwned = ScratchOwned::new(
150        GLWEKeySwitchKey::encrypt_sk_scratch_space(&module, ct_grlwe.size())
151            | GLWECiphertext::decrypt_scratch_space(&module, ct_rlwe.size())
152            | GLWECiphertext::encrypt_sk_scratch_space(&module, ct_rlwe.size())
153            | GLWECiphertextFourier::keyswitch_inplace_scratch_space(&module, ct_rlwe_dft.size(), ct_grlwe.size()),
154    );
155
156    let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module);
157    sk0.fill_ternary_prob(0.5, &mut source_xs);
158
159    let mut sk0_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module);
160    sk0_dft.dft(&module, &sk0);
161
162    let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module);
163    sk1.fill_ternary_prob(0.5, &mut source_xs);
164
165    let mut sk1_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module);
166    sk1_dft.dft(&module, &sk1);
167
168    ct_grlwe.encrypt_sk(
169        &module,
170        &sk0.data,
171        &sk1_dft,
172        &mut source_xa,
173        &mut source_xe,
174        sigma,
175        bound,
176        scratch.borrow(),
177    );
178
179    ct_rlwe.encrypt_sk(
180        &module,
181        &pt_want,
182        &sk0_dft,
183        &mut source_xa,
184        &mut source_xe,
185        sigma,
186        bound,
187        scratch.borrow(),
188    );
189
190    ct_rlwe.dft(&module, &mut ct_rlwe_dft);
191    ct_rlwe_dft.keyswitch_inplace(&module, &ct_grlwe, scratch.borrow());
192    ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow());
193
194    ct_rlwe.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow());
195
196    module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
197
198    let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
199    let noise_want: f64 = noise_grlwe_rlwe_product(
200        module.n() as f64,
201        log_base2k,
202        0.5,
203        0.5,
204        0f64,
205        sigma * sigma,
206        0f64,
207        log_k_rlwe,
208        log_k_grlwe,
209    );
210
211    assert!(
212        (noise_have - noise_want).abs() <= 0.1,
213        "{} {}",
214        noise_have,
215        noise_want
216    );
217}
218
219#[test]
220fn external_product() {
221    let module: Module<FFT64> = Module::<FFT64>::new(2048);
222    let log_base2k: usize = 12;
223    let log_k_grlwe: usize = 60;
224    let log_k_rlwe_in: usize = 45;
225    let log_k_rlwe_out: usize = 60;
226    let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k;
227
228    let sigma: f64 = 3.2;
229    let bound: f64 = sigma * 6.0;
230
231    let mut ct_rgsw: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_grlwe, rows);
232    let mut ct_rlwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe_in);
233    let mut ct_rlwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe_out);
234    let mut ct_rlwe_dft_in: GLWECiphertextFourier<Vec<u8>, FFT64> =
235        GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe_in);
236    let mut ct_rlwe_dft_out: GLWECiphertextFourier<Vec<u8>, FFT64> =
237        GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe_out);
238    let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
239    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe_in);
240    let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe_out);
241
242    let mut source_xs: Source = Source::new([0u8; 32]);
243    let mut source_xe: Source = Source::new([0u8; 32]);
244    let mut source_xa: Source = Source::new([0u8; 32]);
245
246    // Random input plaintext
247    pt_want
248        .data
249        .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
250
251    pt_want.to_mut().at_mut(0, 0)[1] = 1;
252
253    let k: usize = 1;
254
255    pt_rgsw.raw_mut()[k] = 1; // X^{k}
256
257    let mut scratch: ScratchOwned = ScratchOwned::new(
258        GGSWCiphertext::encrypt_sk_scratch_space(&module, ct_rgsw.size())
259            | GLWECiphertext::decrypt_scratch_space(&module, ct_rlwe_out.size())
260            | GLWECiphertext::encrypt_sk_scratch_space(&module, ct_rlwe_in.size())
261            | GLWECiphertext::external_product_scratch_space(
262                &module,
263                ct_rlwe_out.size(),
264                ct_rlwe_in.size(),
265                ct_rgsw.size(),
266            ),
267    );
268
269    let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module);
270    sk.fill_ternary_prob(0.5, &mut source_xs);
271
272    let mut sk_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module);
273    sk_dft.dft(&module, &sk);
274
275    ct_rgsw.encrypt_sk(
276        &module,
277        &pt_rgsw,
278        &sk_dft,
279        &mut source_xa,
280        &mut source_xe,
281        sigma,
282        bound,
283        scratch.borrow(),
284    );
285
286    ct_rlwe_in.encrypt_sk(
287        &module,
288        &pt_want,
289        &sk_dft,
290        &mut source_xa,
291        &mut source_xe,
292        sigma,
293        bound,
294        scratch.borrow(),
295    );
296
297    ct_rlwe_in.dft(&module, &mut ct_rlwe_dft_in);
298    ct_rlwe_dft_out.external_product(&module, &ct_rlwe_dft_in, &ct_rgsw, scratch.borrow());
299    ct_rlwe_dft_out.idft(&module, &mut ct_rlwe_out, scratch.borrow());
300
301    ct_rlwe_out.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow());
302
303    module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0);
304
305    module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
306
307    let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
308
309    let var_gct_err_lhs: f64 = sigma * sigma;
310    let var_gct_err_rhs: f64 = 0f64;
311
312    let var_msg: f64 = 1f64 / module.n() as f64; // X^{k}
313    let var_a0_err: f64 = sigma * sigma;
314    let var_a1_err: f64 = 1f64 / 12f64;
315
316    let noise_want: f64 = noise_rgsw_product(
317        module.n() as f64,
318        log_base2k,
319        0.5,
320        var_msg,
321        var_a0_err,
322        var_a1_err,
323        var_gct_err_lhs,
324        var_gct_err_rhs,
325        log_k_rlwe_in,
326        log_k_grlwe,
327    );
328
329    assert!(
330        (noise_have - noise_want).abs() <= 0.1,
331        "{} {}",
332        noise_have,
333        noise_want
334    );
335}
336
337#[test]
338fn external_product_inplace() {
339    let module: Module<FFT64> = Module::<FFT64>::new(2048);
340    let log_base2k: usize = 12;
341    let log_k_grlwe: usize = 60;
342    let log_k_rlwe_in: usize = 45;
343    let log_k_rlwe_out: usize = 60;
344    let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k;
345
346    let sigma: f64 = 3.2;
347    let bound: f64 = sigma * 6.0;
348
349    let mut ct_rgsw: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_grlwe, rows);
350    let mut ct_rlwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::new(&module, log_base2k, log_k_rlwe_in);
351    let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::new(&module, log_base2k, log_k_rlwe_in);
352    let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
353    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe_in);
354    let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rlwe_out);
355
356    let mut source_xs: Source = Source::new([0u8; 32]);
357    let mut source_xe: Source = Source::new([0u8; 32]);
358    let mut source_xa: Source = Source::new([0u8; 32]);
359
360    // Random input plaintext
361    pt_want
362        .data
363        .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
364
365    pt_want.to_mut().at_mut(0, 0)[1] = 1;
366
367    let k: usize = 1;
368
369    pt_rgsw.raw_mut()[k] = 1; // X^{k}
370
371    let mut scratch: ScratchOwned = ScratchOwned::new(
372        GGSWCiphertext::encrypt_sk_scratch_space(&module, ct_rgsw.size())
373            | GLWECiphertext::decrypt_scratch_space(&module, ct_rlwe.size())
374            | GLWECiphertext::encrypt_sk_scratch_space(&module, ct_rlwe.size())
375            | GLWECiphertext::external_product_inplace_scratch_space(&module, ct_rlwe.size(), ct_rgsw.size()),
376    );
377
378    let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module);
379    sk.fill_ternary_prob(0.5, &mut source_xs);
380
381    let mut sk_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module);
382    sk_dft.dft(&module, &sk);
383
384    ct_rgsw.encrypt_sk(
385        &module,
386        &pt_rgsw,
387        &sk_dft,
388        &mut source_xa,
389        &mut source_xe,
390        sigma,
391        bound,
392        scratch.borrow(),
393    );
394
395    ct_rlwe.encrypt_sk(
396        &module,
397        &pt_want,
398        &sk_dft,
399        &mut source_xa,
400        &mut source_xe,
401        sigma,
402        bound,
403        scratch.borrow(),
404    );
405
406    ct_rlwe.dft(&module, &mut ct_rlwe_dft);
407    ct_rlwe_dft.external_product_inplace(&module, &ct_rgsw, scratch.borrow());
408    ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow());
409
410    ct_rlwe.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow());
411
412    module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0);
413
414    module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
415
416    let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
417
418    let var_gct_err_lhs: f64 = sigma * sigma;
419    let var_gct_err_rhs: f64 = 0f64;
420
421    let var_msg: f64 = 1f64 / module.n() as f64; // X^{k}
422    let var_a0_err: f64 = sigma * sigma;
423    let var_a1_err: f64 = 1f64 / 12f64;
424
425    let noise_want: f64 = noise_rgsw_product(
426        module.n() as f64,
427        log_base2k,
428        0.5,
429        var_msg,
430        var_a0_err,
431        var_a1_err,
432        var_gct_err_lhs,
433        var_gct_err_rhs,
434        log_k_rlwe_in,
435        log_k_grlwe,
436    );
437
438    assert!(
439        (noise_have - noise_want).abs() <= 0.1,
440        "{} {}",
441        noise_have,
442        noise_want
443    );
444}