poulpy/core/src/test_fft64/rlwe_dft.rs
core/src/test_fft64/rlwe_dft.rsRaw
1#[cfg(test)]
2mod tests {
3 use crate::{
4 elem::{FromProdBy, FromProdByScratchSpace, Infos, ProdBy, ProdByScratchSpace},
5 grlwe::GRLWECt,
6 keys::{SecretKey, SecretKeyDft},
7 rlwe::{RLWECt, RLWECtDft, RLWEPt},
8 test_fft64::grlwe::noise_grlwe_rlwe_product,
9 };
10 use base2k::{FFT64, FillUniform, Module, ScratchOwned, Stats, VecZnxOps};
11 use sampling::source::Source;
12
13 #[test]
14 fn from_prod_by_grlwe() {
15 let module: Module<FFT64> = Module::<FFT64>::new(2048);
16 let log_base2k: usize = 12;
17 let log_k_grlwe: usize = 60;
18 let log_k_rlwe_in: usize = 45;
19 let log_k_rlwe_out: usize = 60;
20 let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k;
21
22 let sigma: f64 = 3.2;
23 let bound: f64 = sigma * 6.0;
24
25 let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows);
26 let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in);
27 let mut ct_rlwe_in_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_in);
28 let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out);
29 let mut ct_rlwe_out_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_out);
30 let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in);
31 let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out);
32
33 let mut source_xs: Source = Source::new([0u8; 32]);
34 let mut source_xe: Source = Source::new([0u8; 32]);
35 let mut source_xa: Source = Source::new([0u8; 32]);
36
37 // Random input plaintext
38 pt_want
39 .data
40 .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
41
42 let mut scratch: ScratchOwned = ScratchOwned::new(
43 GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size())
44 | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size())
45 | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size())
46 | RLWECtDft::from_prod_by_grlwe_scratch_space(
47 &module,
48 ct_rlwe_out.size(),
49 ct_rlwe_in.size(),
50 ct_grlwe.size(),
51 ),
52 );
53
54 let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module);
55 sk0.fill_ternary_prob(0.5, &mut source_xs);
56
57 let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
58 sk0_dft.dft(&module, &sk0);
59
60 let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module);
61 sk1.fill_ternary_prob(0.5, &mut source_xs);
62
63 let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
64 sk1_dft.dft(&module, &sk1);
65
66 ct_grlwe.encrypt_sk(
67 &module,
68 &sk0.data,
69 &sk1_dft,
70 &mut source_xa,
71 &mut source_xe,
72 sigma,
73 bound,
74 scratch.borrow(),
75 );
76
77 ct_rlwe_in.encrypt_sk(
78 &module,
79 Some(&pt_want),
80 &sk0_dft,
81 &mut source_xa,
82 &mut source_xe,
83 sigma,
84 bound,
85 scratch.borrow(),
86 );
87
88 ct_rlwe_in.dft(&module, &mut ct_rlwe_in_dft);
89 ct_rlwe_out_dft.from_prod_by_grlwe(&module, &ct_rlwe_in_dft, &ct_grlwe, scratch.borrow());
90 ct_rlwe_out_dft.idft(&module, &mut ct_rlwe_out, scratch.borrow());
91
92 ct_rlwe_out.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow());
93
94 module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
95
96 let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
97 let noise_want: f64 = noise_grlwe_rlwe_product(
98 module.n() as f64,
99 log_base2k,
100 0.5,
101 0.5,
102 0f64,
103 sigma * sigma,
104 0f64,
105 log_k_rlwe_in,
106 log_k_grlwe,
107 );
108
109 assert!(
110 (noise_have - noise_want).abs() <= 0.1,
111 "{} {}",
112 noise_have,
113 noise_want
114 );
115
116 module.free();
117 }
118
119 #[test]
120 fn prod_by_grlwe() {
121 let module: Module<FFT64> = Module::<FFT64>::new(2048);
122 let log_base2k: usize = 12;
123 let log_k_grlwe: usize = 60;
124 let log_k_rlwe: usize = 45;
125 let rows: usize = (log_k_rlwe + log_base2k - 1) / log_base2k;
126
127 let sigma: f64 = 3.2;
128 let bound: f64 = sigma * 6.0;
129
130 let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows);
131 let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe);
132 let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe);
133 let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe);
134 let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe);
135
136 let mut source_xs: Source = Source::new([0u8; 32]);
137 let mut source_xe: Source = Source::new([0u8; 32]);
138 let mut source_xa: Source = Source::new([0u8; 32]);
139
140 // Random input plaintext
141 pt_want
142 .data
143 .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa);
144
145 let mut scratch: ScratchOwned = ScratchOwned::new(
146 GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size())
147 | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size())
148 | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size())
149 | RLWECtDft::prod_by_grlwe_scratch_space(&module, ct_rlwe_dft.size(), ct_grlwe.size()),
150 );
151
152 let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module);
153 sk0.fill_ternary_prob(0.5, &mut source_xs);
154
155 let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
156 sk0_dft.dft(&module, &sk0);
157
158 let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module);
159 sk1.fill_ternary_prob(0.5, &mut source_xs);
160
161 let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
162 sk1_dft.dft(&module, &sk1);
163
164 ct_grlwe.encrypt_sk(
165 &module,
166 &sk0.data,
167 &sk1_dft,
168 &mut source_xa,
169 &mut source_xe,
170 sigma,
171 bound,
172 scratch.borrow(),
173 );
174
175 ct_rlwe.encrypt_sk(
176 &module,
177 Some(&pt_want),
178 &sk0_dft,
179 &mut source_xa,
180 &mut source_xe,
181 sigma,
182 bound,
183 scratch.borrow(),
184 );
185
186 ct_rlwe.dft(&module, &mut ct_rlwe_dft);
187 ct_rlwe_dft.prod_by_grlwe(&module, &ct_grlwe, scratch.borrow());
188 ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow());
189
190 ct_rlwe.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow());
191
192 module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
193
194 let noise_have: f64 = pt_have.data.std(0, log_base2k).log2();
195 let noise_want: f64 = noise_grlwe_rlwe_product(
196 module.n() as f64,
197 log_base2k,
198 0.5,
199 0.5,
200 0f64,
201 sigma * sigma,
202 0f64,
203 log_k_rlwe,
204 log_k_grlwe,
205 );
206
207 assert!(
208 (noise_have - noise_want).abs() <= 0.1,
209 "{} {}",
210 noise_have,
211 noise_want
212 );
213
214 module.free();
215 }
216}