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