poulpy/poulpy-core/src/tests/test_suite/encryption/glwe_ct.rs
poulpy-core/src/tests/test_suite/encryption/glwe_ct.rsRaw
1use poulpy_hal::{
2 api::{
3 ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc,
4 SvpPPolBytesOf, SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxBigAddInplace, VecZnxBigAddNormal,
5 VecZnxBigAddSmallInplace, VecZnxBigBytesOf, VecZnxBigNormalize, VecZnxCopy, VecZnxDftAlloc, VecZnxDftApply,
6 VecZnxDftBytesOf, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace,
7 VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace,
8 },
9 layouts::{Backend, Module, Scratch, ScratchOwned},
10 source::Source,
11};
12
13use crate::{
14 GLWEEncryptSk, GLWESub, ScratchTakeCore,
15 decryption::GLWEDecrypt,
16 encryption::SIGMA,
17 layouts::{
18 GLWE, GLWEAlloc, GLWELayout, GLWEPlaintext, GLWEPlaintextLayout, GLWEPublicKey, GLWESecret, GLWESecretPrepare,
19 GLWESecretPreparedAlloc, LWEInfos,
20 compressed::GLWECompressed,
21 prepared::{GLWEPublicKeyPrepared, GLWESecretPrepared},
22 },
23};
24
25pub fn test_glwe_encrypt_sk<B: Backend>(module: &Module<B>)
26where
27 Module<B>: GLWEAlloc
28 + GLWEEncryptSk<B>
29 + GLWEDecrypt<B>
30 + GLWESecretPreparedAlloc<B>
31 + GLWESecretPrepare<B>
32 + VecZnxFillUniform
33 + GLWESub,
34 ScratchOwned<B>: ScratchOwnedAlloc<B> + ScratchOwnedBorrow<B>,
35 Scratch<B>: ScratchAvailable + ScratchTakeCore<B>,
36{
37 let base2k: usize = 8;
38 let k_ct: usize = 54;
39 let k_pt: usize = 30;
40
41 for rank in 1_usize..3 {
42 let n: usize = module.n();
43
44 let glwe_infos: GLWELayout = GLWELayout {
45 n: n.into(),
46 base2k: base2k.into(),
47 k: k_ct.into(),
48 rank: rank.into(),
49 };
50
51 let pt_infos: GLWEPlaintextLayout = GLWEPlaintextLayout {
52 n: n.into(),
53 base2k: base2k.into(),
54 k: k_pt.into(),
55 };
56
57 let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(module, &glwe_infos);
58 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(module, &pt_infos);
59 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(module, &pt_infos);
60
61 let mut source_xs: Source = Source::new([0u8; 32]);
62 let mut source_xe: Source = Source::new([0u8; 32]);
63 let mut source_xa: Source = Source::new([0u8; 32]);
64
65 let mut scratch: ScratchOwned<B> =
66 ScratchOwned::alloc(GLWE::encrypt_sk_tmp_bytes(module, &glwe_infos) | GLWE::decrypt_tmp_bytes(module, &glwe_infos));
67
68 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(module, &glwe_infos);
69 sk.fill_ternary_prob(0.5, &mut source_xs);
70 let mut sk_prepared: GLWESecretPrepared<Vec<u8>, B> = GLWESecretPrepared::alloc(module, rank.into());
71
72 sk_prepared.prepare(module, &sk);
73
74 module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
75
76 ct.encrypt_sk(
77 module,
78 &pt_want,
79 &sk_prepared,
80 &mut source_xa,
81 &mut source_xe,
82 scratch.borrow(),
83 );
84
85 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
86
87 module.glwe_sub_inplace(&mut pt_want, &pt_have);
88
89 let noise_have: f64 = pt_want.data.std(base2k, 0) * (ct.k().as_u32() as f64).exp2();
90 let noise_want: f64 = SIGMA;
91
92 assert!(noise_have <= noise_want + 0.2);
93 }
94}
95
96pub fn test_glwe_compressed_encrypt_sk<B>(module: &Module<B>)
97where
98 Module<B>: VecZnxDftBytesOf
99 + VecZnxBigBytesOf
100 + VecZnxDftApply<B>
101 + SvpApplyDftToDftInplace<B>
102 + VecZnxIdftApplyConsume<B>
103 + VecZnxBigAddInplace<B>
104 + VecZnxBigAddSmallInplace<B>
105 + VecZnxBigNormalize<B>
106 + VecZnxNormalizeTmpBytes
107 + SvpPrepare<B>
108 + SvpPPolBytesOf
109 + SvpPPolAlloc<B>
110 + SvpApplyDftToDft<B>
111 + VecZnxBigAddNormal<B>
112 + VecZnxFillUniform
113 + VecZnxSubInplace
114 + VecZnxAddInplace
115 + VecZnxNormalizeInplace<B>
116 + VecZnxAddNormal
117 + VecZnxNormalize<B>
118 + VecZnxSub
119 + VecZnxCopy,
120{
121 let base2k: usize = 8;
122 let k_ct: usize = 54;
123 let k_pt: usize = 30;
124
125 for rank in 1_usize..3 {
126 let n: usize = module.n();
127
128 let glwe_infos: GLWELayout = GLWELayout {
129 n: n.into(),
130 base2k: base2k.into(),
131 k: k_ct.into(),
132 rank: rank.into(),
133 };
134
135 let pt_infos: GLWEPlaintextLayout = GLWEPlaintextLayout {
136 n: n.into(),
137 base2k: base2k.into(),
138 k: k_pt.into(),
139 };
140
141 let mut ct_compressed: GLWECompressed<Vec<u8>> = GLWECompressed::alloc_from_infos(&glwe_infos);
142
143 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&pt_infos);
144 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&pt_infos);
145
146 let mut source_xs: Source = Source::new([0u8; 32]);
147 let mut source_xe: Source = Source::new([0u8; 32]);
148 let mut source_xa: Source = Source::new([0u8; 32]);
149
150 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
151 GLWECompressed::encrypt_sk_tmp_bytes(module, &glwe_infos) | GLWE::decrypt_tmp_bytes(module, &glwe_infos),
152 );
153
154 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos);
155 sk.fill_ternary_prob(0.5, &mut source_xs);
156 let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
157
158 module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
159
160 let seed_xa: [u8; 32] = [1u8; 32];
161
162 ct_compressed.encrypt_sk(
163 module,
164 &pt_want,
165 &sk_prepared,
166 seed_xa,
167 &mut source_xe,
168 scratch.borrow(),
169 );
170
171 let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos);
172 ct.decompress(module, &ct_compressed);
173
174 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
175
176 pt_want.sub_inplace_ab(module, &pt_have);
177
178 let noise_have: f64 = pt_want.data.std(base2k, 0) * (ct.k().as_u32() as f64).exp2();
179 let noise_want: f64 = SIGMA;
180
181 assert!(
182 noise_have <= noise_want + 0.2,
183 "{noise_have} <= {}",
184 noise_want + 0.2
185 );
186 }
187}
188
189pub fn test_glwe_encrypt_zero_sk<B>(module: &Module<B>)
190where
191 Module<B>: VecZnxDftBytesOf
192 + VecZnxBigBytesOf
193 + VecZnxDftApply<B>
194 + SvpApplyDftToDftInplace<B>
195 + VecZnxIdftApplyConsume<B>
196 + VecZnxBigAddInplace<B>
197 + VecZnxBigAddSmallInplace<B>
198 + VecZnxBigNormalize<B>
199 + VecZnxNormalizeTmpBytes
200 + SvpPrepare<B>
201 + SvpPPolBytesOf
202 + SvpPPolAlloc<B>
203 + SvpApplyDftToDft<B>
204 + VecZnxBigAddNormal<B>
205 + VecZnxFillUniform
206 + VecZnxSubInplace
207 + VecZnxAddInplace
208 + VecZnxNormalizeInplace<B>
209 + VecZnxAddNormal
210 + VecZnxNormalize<B>
211 + VecZnxSub,
212{
213 let base2k: usize = 8;
214 let k_ct: usize = 54;
215
216 for rank in 1_usize..3 {
217 let n: usize = module.n();
218
219 let glwe_infos: GLWELayout = GLWELayout {
220 n: n.into(),
221 base2k: base2k.into(),
222 k: k_ct.into(),
223 rank: rank.into(),
224 };
225
226 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos);
227
228 let mut source_xs: Source = Source::new([0u8; 32]);
229 let mut source_xe: Source = Source::new([1u8; 32]);
230 let mut source_xa: Source = Source::new([0u8; 32]);
231
232 let mut scratch: ScratchOwned<B> =
233 ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, &glwe_infos) | GLWE::encrypt_sk_tmp_bytes(module, &glwe_infos));
234
235 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos);
236 sk.fill_ternary_prob(0.5, &mut source_xs);
237 let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
238
239 let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos);
240
241 ct.encrypt_zero_sk(
242 module,
243 &sk_prepared,
244 &mut source_xa,
245 &mut source_xe,
246 scratch.borrow(),
247 );
248 ct.decrypt(module, &mut pt, &sk_prepared, scratch.borrow());
249
250 assert!((SIGMA - pt.data.std(base2k, 0) * (k_ct as f64).exp2()) <= 0.2);
251 }
252}
253
254pub fn test_glwe_encrypt_pk<B>(module: &Module<B>)
255where
256 Module<B>: VecZnxDftBytesOf
257 + VecZnxBigNormalize<B>
258 + VecZnxDftApply<B>
259 + SvpApplyDftToDftInplace<B>
260 + VecZnxIdftApplyConsume<B>
261 + VecZnxNormalizeTmpBytes
262 + VecZnxFillUniform
263 + VecZnxSubInplace
264 + VecZnxAddInplace
265 + VecZnxNormalizeInplace<B>
266 + VecZnxAddNormal
267 + VecZnxNormalize<B>
268 + VecZnxSub
269 + SvpPrepare<B>
270 + SvpPPolBytesOf
271 + SvpPPolAlloc<B>
272 + VecZnxBigAddSmallInplace<B>
273 + VecZnxBigBytesOf
274 + VecZnxBigAddInplace<B>
275 + VecZnxCopy
276 + VecZnxDftAlloc<B>
277 + SvpApplyDftToDft<B>
278 + VecZnxBigAddNormal<B>,
279{
280 let base2k: usize = 8;
281 let k_ct: usize = 54;
282
283 for rank in 1_usize..3 {
284 let n: usize = module.n();
285
286 let glwe_infos: GLWELayout = GLWELayout {
287 n: n.into(),
288 base2k: base2k.into(),
289 k: k_ct.into(),
290 rank: rank.into(),
291 };
292
293 let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos);
294 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos);
295 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos);
296
297 let mut source_xs: Source = Source::new([0u8; 32]);
298 let mut source_xe: Source = Source::new([0u8; 32]);
299 let mut source_xa: Source = Source::new([0u8; 32]);
300 let mut source_xu: Source = Source::new([0u8; 32]);
301
302 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
303 GLWE::encrypt_sk_tmp_bytes(module, &glwe_infos)
304 | GLWE::decrypt_tmp_bytes(module, &glwe_infos)
305 | GLWE::encrypt_pk_tmp_bytes(module, &glwe_infos),
306 );
307
308 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos);
309 sk.fill_ternary_prob(0.5, &mut source_xs);
310 let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
311
312 let mut pk: GLWEPublicKey<Vec<u8>> = GLWEPublicKey::alloc_from_infos(&glwe_infos);
313 pk.generate(module, &sk_prepared, &mut source_xa, &mut source_xe);
314
315 module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
316
317 let pk_prepared: GLWEPublicKeyPrepared<Vec<u8>, B> = pk.prepare_alloc(module, scratch.borrow());
318
319 ct.encrypt_pk(
320 module,
321 &pt_want,
322 &pk_prepared,
323 &mut source_xu,
324 &mut source_xe,
325 scratch.borrow(),
326 );
327
328 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
329
330 pt_want.sub_inplace_ab(module, &pt_have);
331
332 let noise_have: f64 = pt_want.data.std(base2k, 0).log2();
333 let noise_want: f64 = ((((rank as f64) + 1.0) * n as f64 * 0.5 * SIGMA * SIGMA).sqrt()).log2() - (k_ct as f64);
334
335 assert!(
336 noise_have <= noise_want + 0.2,
337 "{noise_have} <= {}",
338 noise_want + 0.2
339 );
340 }
341}