poulpy/core/src/test_fft64/ggsw.rs
core/src/test_fft64/ggsw.rsRaw
1// use base2k::{
2// FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxDftOps, ScratchOwned, Stats, VecZnxBig, VecZnxBigAlloc, VecZnxBigOps,
3// VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxOps, VecZnxToMut, ZnxViewMut, ZnxZero,
4// };
5// use sampling::source::Source;
6//
7// use crate::{
8// elem::{GetRow, Infos},
9// ggsw_ciphertext::GGSWCiphertext,
10// glwe_ciphertext_fourier::GLWECiphertextFourier,
11// glwe_plaintext::GLWEPlaintext,
12// keys::{SecretKey, SecretKeyFourier},
13// keyswitch_key::GLWESwitchingKey,
14// test_fft64::gglwe::noise_grlwe_rlwe_product,
15// };
16//
17// #[test]
18// fn encrypt_sk() {
19// let module: Module<FFT64> = Module::<FFT64>::new(2048);
20// let log_base2k: usize = 8;
21// let log_k_ct: usize = 54;
22// let rows: usize = 4;
23// let rank: usize = 1;
24//
25// let sigma: f64 = 3.2;
26//
27// let mut ct: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_ct, rows, rank);
28// let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_ct);
29// let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_ct);
30// let mut pt_scalar: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
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// pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs);
37//
38// let mut scratch: ScratchOwned = ScratchOwned::new(
39// GGSWCiphertext::encrypt_sk_scratch_space(&module, rank, ct.size())
40// | GLWECiphertextFourier::decrypt_scratch_space(&module, ct.size()),
41// );
42//
43// let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
44// sk.fill_ternary_prob(0.5, &mut source_xs);
45//
46// let mut sk_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
47// sk_dft.dft(&module, &sk);
48//
49// ct.encrypt_sk(
50// &module,
51// &pt_scalar,
52// &sk_dft,
53// &mut source_xa,
54// &mut source_xe,
55// sigma,
56// scratch.borrow(),
57// );
58//
59// let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::new(&module, log_base2k, log_k_ct, rank);
60// let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct.size());
61// let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct.size());
62//
63// (0..ct.rank()).for_each(|col_j| {
64// (0..ct.rows()).for_each(|row_i| {
65// module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_scalar, 0);
66//
67// if col_j == 1 {
68// module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0);
69// module.svp_apply_inplace(&mut pt_dft, 0, &sk_dft, 0);
70// module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0);
71// module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow());
72// }
73//
74// ct.get_row(&module, row_i, col_j, &mut ct_rlwe_dft);
75//
76// ct_rlwe_dft.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow());
77//
78// module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
79//
80// let std_pt: f64 = pt_have.data.std(0, log_base2k) * (log_k_ct as f64).exp2();
81// assert!((sigma - std_pt).abs() <= 0.2, "{} {}", sigma, std_pt);
82//
83// pt_want.data.zero();
84// });
85// });
86// }
87//
88// #[test]
89// fn keyswitch() {
90// let module: Module<FFT64> = Module::<FFT64>::new(2048);
91// let log_base2k: usize = 12;
92// let log_k_grlwe: usize = 60;
93// let log_k_rgsw_in: usize = 45;
94// let log_k_rgsw_out: usize = 45;
95// let rows: usize = (log_k_rgsw_in + log_base2k - 1) / log_base2k;
96//
97// let rank: usize = 1;
98//
99// let sigma: f64 = 3.2;
100//
101// let mut ct_grlwe: GLWESwitchingKey<Vec<u8>, FFT64> =
102// GLWESwitchingKey::new(&module, log_base2k, log_k_grlwe, rows, rank, rank);
103// let mut ct_rgsw_in: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_rgsw_in, rows, rank);
104// let mut ct_rgsw_out: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_rgsw_out, rows, rank);
105// let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
106//
107// let mut source_xs: Source = Source::new([0u8; 32]);
108// let mut source_xe: Source = Source::new([0u8; 32]);
109// let mut source_xa: Source = Source::new([0u8; 32]);
110//
111// Random input plaintext
112// pt_rgsw.fill_ternary_prob(0, 0.5, &mut source_xs);
113//
114// let mut scratch: ScratchOwned = ScratchOwned::new(
115// GLWESwitchingKey::encrypt_sk_scratch_space(&module, rank, ct_grlwe.size())
116// | GLWECiphertextFourier::decrypt_scratch_space(&module, ct_rgsw_out.size())
117// | GGSWCiphertext::encrypt_sk_scratch_space(&module, rank, ct_rgsw_in.size())
118// | GGSWCiphertext::keyswitch_scratch_space(
119// &module,
120// ct_rgsw_out.size(),
121// ct_rgsw_in.size(),
122// ct_grlwe.size(),
123// ),
124// );
125//
126// let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
127// sk0.fill_ternary_prob(0.5, &mut source_xs);
128//
129// let mut sk0_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
130// sk0_dft.dft(&module, &sk0);
131//
132// let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
133// sk1.fill_ternary_prob(0.5, &mut source_xs);
134//
135// let mut sk1_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
136// sk1_dft.dft(&module, &sk1);
137//
138// ct_grlwe.encrypt_sk(
139// &module,
140// &sk0.data,
141// &sk1_dft,
142// &mut source_xa,
143// &mut source_xe,
144// sigma,
145// scratch.borrow(),
146// );
147//
148// ct_rgsw_in.encrypt_sk(
149// &module,
150// &pt_rgsw,
151// &sk0_dft,
152// &mut source_xa,
153// &mut source_xe,
154// sigma,
155// scratch.borrow(),
156// );
157//
158// ct_rgsw_out.keyswitch(&module, &ct_rgsw_in, &ct_grlwe, scratch.borrow());
159//
160// let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
161// GLWECiphertextFourier::new(&module, log_base2k, log_k_rgsw_out, rank);
162// let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rgsw_out);
163// let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_rgsw_out.size());
164// let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_rgsw_out.size());
165// let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rgsw_out);
166//
167// (0..ct_rgsw_out.rank()).for_each(|col_j| {
168// (0..ct_rgsw_out.rows()).for_each(|row_i| {
169// module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_rgsw, 0);
170//
171// if col_j == 1 {
172// module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0);
173// module.svp_apply_inplace(&mut pt_dft, 0, &sk0_dft, 0);
174// module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0);
175// module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow());
176// }
177//
178// ct_rgsw_out.get_row(&module, row_i, col_j, &mut ct_rlwe_dft);
179// ct_rlwe_dft.decrypt(&module, &mut pt, &sk1_dft, scratch.borrow());
180//
181// module.vec_znx_sub_ab_inplace(&mut pt, 0, &pt_want, 0);
182//
183// let noise_have: f64 = pt.data.std(0, log_base2k).log2();
184// let noise_want: f64 = noise_grlwe_rlwe_product(
185// module.n() as f64,
186// log_base2k,
187// 0.5,
188// 0.5,
189// 0f64,
190// sigma * sigma,
191// 0f64,
192// log_k_grlwe,
193// log_k_grlwe,
194// );
195//
196// assert!(
197// (noise_have - noise_want).abs() <= 0.2,
198// "have: {} want: {}",
199// noise_have,
200// noise_want
201// );
202//
203// pt_want.data.zero();
204// });
205// });
206// }
207//
208// #[test]
209// fn keyswitch_inplace() {
210// let module: Module<FFT64> = Module::<FFT64>::new(2048);
211// let log_base2k: usize = 12;
212// let log_k_grlwe: usize = 60;
213// let log_k_rgsw: usize = 45;
214// let rows: usize = (log_k_rgsw + log_base2k - 1) / log_base2k;
215// let rank: usize = 1;
216//
217// let sigma: f64 = 3.2;
218//
219// let mut ct_grlwe: GLWESwitchingKey<Vec<u8>, FFT64> =
220// GLWESwitchingKey::new(&module, log_base2k, log_k_grlwe, rows, rank, rank);
221// let mut ct_rgsw: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_rgsw, rows, rank);
222// let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
223//
224// let mut source_xs: Source = Source::new([0u8; 32]);
225// let mut source_xe: Source = Source::new([0u8; 32]);
226// let mut source_xa: Source = Source::new([0u8; 32]);
227//
228// Random input plaintext
229// pt_rgsw.fill_ternary_prob(0, 0.5, &mut source_xs);
230//
231// let mut scratch: ScratchOwned = ScratchOwned::new(
232// GLWESwitchingKey::encrypt_sk_scratch_space(&module, rank, ct_grlwe.size())
233// | GLWECiphertextFourier::decrypt_scratch_space(&module, ct_rgsw.size())
234// | GGSWCiphertext::encrypt_sk_scratch_space(&module, rank, ct_rgsw.size())
235// | GGSWCiphertext::keyswitch_inplace_scratch_space(&module, ct_rgsw.size(), ct_grlwe.size()),
236// );
237//
238// let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
239// sk0.fill_ternary_prob(0.5, &mut source_xs);
240//
241// let mut sk0_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
242// sk0_dft.dft(&module, &sk0);
243//
244// let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
245// sk1.fill_ternary_prob(0.5, &mut source_xs);
246//
247// let mut sk1_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
248// sk1_dft.dft(&module, &sk1);
249//
250// ct_grlwe.encrypt_sk(
251// &module,
252// &sk0.data,
253// &sk1_dft,
254// &mut source_xa,
255// &mut source_xe,
256// sigma,
257// scratch.borrow(),
258// );
259//
260// ct_rgsw.encrypt_sk(
261// &module,
262// &pt_rgsw,
263// &sk0_dft,
264// &mut source_xa,
265// &mut source_xe,
266// sigma,
267// scratch.borrow(),
268// );
269//
270// ct_rgsw.keyswitch_inplace(&module, &ct_grlwe, scratch.borrow());
271//
272// let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
273// GLWECiphertextFourier::new(&module, log_base2k, log_k_rgsw, rank);
274// let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rgsw);
275// let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_rgsw.size());
276// let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_rgsw.size());
277// let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rgsw);
278//
279// (0..ct_rgsw.rank()).for_each(|col_j| {
280// (0..ct_rgsw.rows()).for_each(|row_i| {
281// module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_rgsw, 0);
282//
283// if col_j == 1 {
284// module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0);
285// module.svp_apply_inplace(&mut pt_dft, 0, &sk0_dft, 0);
286// module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0);
287// module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow());
288// }
289//
290// ct_rgsw.get_row(&module, row_i, col_j, &mut ct_rlwe_dft);
291// ct_rlwe_dft.decrypt(&module, &mut pt, &sk1_dft, scratch.borrow());
292//
293// module.vec_znx_sub_ab_inplace(&mut pt, 0, &pt_want, 0);
294//
295// let noise_have: f64 = pt.data.std(0, log_base2k).log2();
296// let noise_want: f64 = noise_grlwe_rlwe_product(
297// module.n() as f64,
298// log_base2k,
299// 0.5,
300// 0.5,
301// 0f64,
302// sigma * sigma,
303// 0f64,
304// log_k_grlwe,
305// log_k_grlwe,
306// );
307//
308// assert!(
309// (noise_have - noise_want).abs() <= 0.2,
310// "have: {} want: {}",
311// noise_have,
312// noise_want
313// );
314//
315// pt_want.data.zero();
316// });
317// });
318// }
319//
320// #[test]
321// fn external_product() {
322// let module: Module<FFT64> = Module::<FFT64>::new(2048);
323// let log_base2k: usize = 12;
324// let log_k_rgsw_rhs: usize = 60;
325// let log_k_rgsw_lhs_in: usize = 45;
326// let log_k_rgsw_lhs_out: usize = 45;
327// let rows: usize = (log_k_rgsw_lhs_in + log_base2k - 1) / log_base2k;
328// let rank: usize = 1;
329//
330// let sigma: f64 = 3.2;
331//
332// let mut ct_rgsw_rhs: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_rgsw_rhs, rows, rank);
333// let mut ct_rgsw_lhs_in: GGSWCiphertext<Vec<u8>, FFT64> =
334// GGSWCiphertext::new(&module, log_base2k, log_k_rgsw_lhs_in, rows, rank);
335// let mut ct_rgsw_lhs_out: GGSWCiphertext<Vec<u8>, FFT64> =
336// GGSWCiphertext::new(&module, log_base2k, log_k_rgsw_lhs_out, rows, rank);
337// let mut pt_rgsw_lhs: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
338// let mut pt_rgsw_rhs: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
339//
340// let mut source_xs: Source = Source::new([0u8; 32]);
341// let mut source_xe: Source = Source::new([0u8; 32]);
342// let mut source_xa: Source = Source::new([0u8; 32]);
343//
344// Random input plaintext
345// pt_rgsw_lhs.fill_ternary_prob(0, 0.5, &mut source_xs);
346//
347// let k: usize = 1;
348//
349// pt_rgsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k}
350//
351// let mut scratch: ScratchOwned = ScratchOwned::new(
352// GLWESwitchingKey::encrypt_sk_scratch_space(&module, rank, ct_rgsw_rhs.size())
353// | GLWECiphertextFourier::decrypt_scratch_space(&module, ct_rgsw_lhs_out.size())
354// | GGSWCiphertext::encrypt_sk_scratch_space(&module, rank, ct_rgsw_lhs_in.size())
355// | GGSWCiphertext::external_product_scratch_space(
356// &module,
357// ct_rgsw_lhs_out.size(),
358// ct_rgsw_lhs_in.size(),
359// ct_rgsw_rhs.size(),
360// ),
361// );
362//
363// let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
364// sk.fill_ternary_prob(0.5, &mut source_xs);
365//
366// let mut sk_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
367// sk_dft.dft(&module, &sk);
368//
369// ct_rgsw_rhs.encrypt_sk(
370// &module,
371// &pt_rgsw_rhs,
372// &sk_dft,
373// &mut source_xa,
374// &mut source_xe,
375// sigma,
376// scratch.borrow(),
377// );
378//
379// ct_rgsw_lhs_in.encrypt_sk(
380// &module,
381// &pt_rgsw_lhs,
382// &sk_dft,
383// &mut source_xa,
384// &mut source_xe,
385// sigma,
386// scratch.borrow(),
387// );
388//
389// ct_rgsw_lhs_out.external_product(&module, &ct_rgsw_lhs_in, &ct_rgsw_rhs, scratch.borrow());
390//
391// let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
392// GLWECiphertextFourier::new(&module, log_base2k, log_k_rgsw_lhs_out, rank);
393// let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rgsw_lhs_out);
394// let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_rgsw_lhs_out.size());
395// let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_rgsw_lhs_out.size());
396// let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rgsw_lhs_out);
397//
398// module.vec_znx_rotate_inplace(k as i64, &mut pt_rgsw_lhs, 0);
399//
400// (0..ct_rgsw_lhs_out.rank()).for_each(|col_j| {
401// (0..ct_rgsw_lhs_out.rows()).for_each(|row_i| {
402// module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_rgsw_lhs, 0);
403//
404// if col_j == 1 {
405// module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0);
406// module.svp_apply_inplace(&mut pt_dft, 0, &sk_dft, 0);
407// module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0);
408// module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow());
409// }
410//
411// ct_rgsw_lhs_out.get_row(&module, row_i, col_j, &mut ct_rlwe_dft);
412// ct_rlwe_dft.decrypt(&module, &mut pt, &sk_dft, scratch.borrow());
413//
414// module.vec_znx_sub_ab_inplace(&mut pt, 0, &pt_want, 0);
415//
416// let noise_have: f64 = pt.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_rgsw_lhs_in,
435// log_k_rgsw_rhs,
436// );
437//
438// assert!(
439// (noise_have - noise_want).abs() <= 0.1,
440// "have: {} want: {}",
441// noise_have,
442// noise_want
443// );
444//
445// pt_want.data.zero();
446// });
447// });
448// }
449//
450// #[test]
451// fn external_product_inplace() {
452// let module: Module<FFT64> = Module::<FFT64>::new(2048);
453// let log_base2k: usize = 12;
454// let log_k_rgsw_rhs: usize = 60;
455// let log_k_rgsw_lhs: usize = 45;
456// let rows: usize = (log_k_rgsw_lhs + log_base2k - 1) / log_base2k;
457// let rank: usize = 1;
458//
459// let sigma: f64 = 3.2;
460//
461// let mut ct_rgsw_rhs: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_rgsw_rhs, rows, rank);
462// let mut ct_rgsw_lhs: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::new(&module, log_base2k, log_k_rgsw_lhs, rows, rank);
463// let mut pt_rgsw_lhs: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
464// let mut pt_rgsw_rhs: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
465//
466// let mut source_xs: Source = Source::new([0u8; 32]);
467// let mut source_xe: Source = Source::new([0u8; 32]);
468// let mut source_xa: Source = Source::new([0u8; 32]);
469//
470// Random input plaintext
471// pt_rgsw_lhs.fill_ternary_prob(0, 0.5, &mut source_xs);
472//
473// let k: usize = 1;
474//
475// pt_rgsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k}
476//
477// let mut scratch: ScratchOwned = ScratchOwned::new(
478// GLWESwitchingKey::encrypt_sk_scratch_space(&module, rank, ct_rgsw_rhs.size())
479// | GLWECiphertextFourier::decrypt_scratch_space(&module, ct_rgsw_lhs.size())
480// | GGSWCiphertext::encrypt_sk_scratch_space(&module, rank, ct_rgsw_lhs.size())
481// | GGSWCiphertext::external_product_inplace_scratch_space(&module, ct_rgsw_lhs.size(), ct_rgsw_rhs.size()),
482// );
483//
484// let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module, rank);
485// sk.fill_ternary_prob(0.5, &mut source_xs);
486//
487// let mut sk_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::new(&module, rank);
488// sk_dft.dft(&module, &sk);
489//
490// ct_rgsw_rhs.encrypt_sk(
491// &module,
492// &pt_rgsw_rhs,
493// &sk_dft,
494// &mut source_xa,
495// &mut source_xe,
496// sigma,
497// scratch.borrow(),
498// );
499//
500// ct_rgsw_lhs.encrypt_sk(
501// &module,
502// &pt_rgsw_lhs,
503// &sk_dft,
504// &mut source_xa,
505// &mut source_xe,
506// sigma,
507// scratch.borrow(),
508// );
509//
510// ct_rgsw_lhs.external_product_inplace(&module, &ct_rgsw_rhs, scratch.borrow());
511//
512// let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
513// GLWECiphertextFourier::new(&module, log_base2k, log_k_rgsw_lhs, rank);
514// let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rgsw_lhs);
515// let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_rgsw_lhs.size());
516// let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_rgsw_lhs.size());
517// let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::new(&module, log_base2k, log_k_rgsw_lhs);
518//
519// module.vec_znx_rotate_inplace(k as i64, &mut pt_rgsw_lhs, 0);
520//
521// (0..ct_rgsw_lhs.rank()).for_each(|col_j| {
522// (0..ct_rgsw_lhs.rows()).for_each(|row_i| {
523// module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_rgsw_lhs, 0);
524//
525// if col_j == 1 {
526// module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0);
527// module.svp_apply_inplace(&mut pt_dft, 0, &sk_dft, 0);
528// module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0);
529// module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow());
530// }
531//
532// ct_rgsw_lhs.get_row(&module, row_i, col_j, &mut ct_rlwe_dft);
533// ct_rlwe_dft.decrypt(&module, &mut pt, &sk_dft, scratch.borrow());
534//
535// module.vec_znx_sub_ab_inplace(&mut pt, 0, &pt_want, 0);
536//
537// let noise_have: f64 = pt.data.std(0, log_base2k).log2();
538//
539// let var_gct_err_lhs: f64 = sigma * sigma;
540// let var_gct_err_rhs: f64 = 0f64;
541//
542// let var_msg: f64 = 1f64 / module.n() as f64; // X^{k}
543// let var_a0_err: f64 = sigma * sigma;
544// let var_a1_err: f64 = 1f64 / 12f64;
545//
546// let noise_want: f64 = noise_rgsw_product(
547// module.n() as f64,
548// log_base2k,
549// 0.5,
550// var_msg,
551// var_a0_err,
552// var_a1_err,
553// var_gct_err_lhs,
554// var_gct_err_rhs,
555// log_k_rgsw_lhs,
556// log_k_rgsw_rhs,
557// );
558//
559// assert!(
560// (noise_have - noise_want).abs() <= 0.1,
561// "have: {} want: {}",
562// noise_have,
563// noise_want
564// );
565//
566// pt_want.data.zero();
567// });
568// });
569// }
570pub(crate) fn noise_rgsw_product(
571 n: f64,
572 log_base2k: usize,
573 var_xs: f64,
574 var_msg: f64,
575 var_a0_err: f64,
576 var_a1_err: f64,
577 var_gct_err_lhs: f64,
578 var_gct_err_rhs: f64,
579 rank: f64,
580 a_logq: usize,
581 b_logq: usize,
582) -> f64 {
583 let a_logq: usize = a_logq.min(b_logq);
584 let a_cols: usize = (a_logq + log_base2k - 1) / log_base2k;
585
586 let b_scale = 2.0f64.powi(b_logq as i32);
587 let a_scale: f64 = 2.0f64.powi((b_logq - a_logq) as i32);
588
589 let base: f64 = (1 << (log_base2k)) as f64;
590 let var_base: f64 = base * base / 12f64;
591
592 // lhs = a_cols * n * (var_base * var_gct_err_lhs + var_e_a * var_msg * p^2)
593 // rhs = a_cols * n * var_base * var_gct_err_rhs * var_xs
594 let mut noise: f64 = (rank + 1.0) * (a_cols as f64) * n * var_base * (var_gct_err_lhs + var_xs * var_gct_err_rhs);
595 noise += var_msg * var_a0_err * a_scale * a_scale * n;
596 noise += var_msg * var_a1_err * a_scale * a_scale * n * var_xs * rank;
597 noise = noise.sqrt();
598 noise /= b_scale;
599 noise.log2().min(-1.0) // max noise is [-2^{-1}, 2^{-1}]
600}