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 VecZnxSubABInplace,
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, GLWEPlaintext, GLWEPublicKey, GLWESecret, Infos,
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 + VecZnxDftAllocBytes
42 + VecZnxBigAllocBytes
43 + SvpPPolAllocBytes
44 + SvpPrepare<B>
45 + SvpApplyDftToDft<B>
46 + VecZnxIdftApplyConsume<B>
47 + VecZnxBigAddNormal<B>
48 + VecZnxBigAddSmallInplace<B>
49 + VecZnxBigNormalize<B>
50 + VecZnxNormalizeTmpBytes
51 + VecZnxDftAllocBytes
52 + VecZnxBigNormalize<B>
53 + VecZnxDftApply<B>
54 + SvpApplyDftToDftInplace<B>
55 + VecZnxIdftApplyConsume<B>
56 + VecZnxNormalizeTmpBytes
57 + VecZnxFillUniform
58 + VecZnxSubABInplace
59 + VecZnxAddInplace
60 + VecZnxNormalizeInplace<B>
61 + VecZnxAddNormal
62 + VecZnxNormalize<B>
63 + VecZnxSub,
64 B: Backend
65 + TakeVecZnxDftImpl<B>
66 + TakeVecZnxBigImpl<B>
67 + TakeSvpPPolImpl<B>
68 + ScratchOwnedAllocImpl<B>
69 + ScratchOwnedBorrowImpl<B>
70 + ScratchAvailableImpl<B>
71 + TakeScalarZnxImpl<B>
72 + TakeVecZnxImpl<B>,
73{
74 let basek: usize = 8;
75 let k_ct: usize = 54;
76 let k_pt: usize = 30;
77
78 for rank in 1..3 {
79 let n = module.n();
80 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
81 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
82 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
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, basek, ct.k())
90 | GLWECiphertext::decrypt_scratch_space(module, basek, ct.k()),
91 );
92
93 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
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(basek, &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(basek, 0) * (ct.k() 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 + VecZnxDftAllocBytes
134 + VecZnxBigAllocBytes
135 + SvpPPolAllocBytes
136 + SvpPrepare<B>
137 + SvpApplyDftToDft<B>
138 + VecZnxIdftApplyConsume<B>
139 + VecZnxBigAddNormal<B>
140 + VecZnxBigAddSmallInplace<B>
141 + VecZnxBigNormalize<B>
142 + VecZnxNormalizeTmpBytes
143 + VecZnxDftAllocBytes
144 + VecZnxBigNormalize<B>
145 + VecZnxDftApply<B>
146 + SvpApplyDftToDftInplace<B>
147 + VecZnxIdftApplyConsume<B>
148 + VecZnxNormalizeTmpBytes
149 + VecZnxFillUniform
150 + VecZnxSubABInplace
151 + VecZnxAddInplace
152 + VecZnxNormalizeInplace<B>
153 + VecZnxAddNormal
154 + VecZnxNormalize<B>
155 + VecZnxSub
156 + VecZnxCopy,
157 B: Backend
158 + TakeVecZnxDftImpl<B>
159 + TakeVecZnxBigImpl<B>
160 + TakeSvpPPolImpl<B>
161 + ScratchOwnedAllocImpl<B>
162 + ScratchOwnedBorrowImpl<B>
163 + ScratchAvailableImpl<B>
164 + TakeScalarZnxImpl<B>
165 + TakeVecZnxImpl<B>,
166{
167 let basek: usize = 8;
168 let k_ct: usize = 54;
169 let k_pt: usize = 30;
170
171 for rank in 1..3 {
172 let n = module.n();
173 let mut ct_compressed: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(n, basek, k_ct, rank);
174
175 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
176 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
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, basek, k_ct)
184 | GLWECiphertext::decrypt_scratch_space(module, basek, k_ct),
185 );
186
187 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
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(basek, &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(n, basek, k_ct, rank);
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(basek, 0) * (ct.k() as f64).exp2();
212 let noise_want: f64 = SIGMA;
213
214 assert!(
215 noise_have <= noise_want + 0.2,
216 "{} <= {}",
217 noise_have,
218 noise_want + 0.2
219 );
220 }
221}
222
223pub fn test_glwe_encrypt_zero_sk<B>(module: &Module<B>)
224where
225 Module<B>: VecZnxDftAllocBytes
226 + VecZnxBigAllocBytes
227 + VecZnxDftApply<B>
228 + SvpApplyDftToDftInplace<B>
229 + VecZnxIdftApplyConsume<B>
230 + VecZnxBigAddInplace<B>
231 + VecZnxBigAddSmallInplace<B>
232 + VecZnxBigNormalize<B>
233 + VecZnxNormalizeTmpBytes
234 + SvpPrepare<B>
235 + SvpPPolAllocBytes
236 + SvpPPolAlloc<B>
237 + VecZnxDftAllocBytes
238 + VecZnxBigAllocBytes
239 + SvpPPolAllocBytes
240 + SvpPrepare<B>
241 + SvpApplyDftToDft<B>
242 + VecZnxIdftApplyConsume<B>
243 + VecZnxBigAddNormal<B>
244 + VecZnxBigAddSmallInplace<B>
245 + VecZnxBigNormalize<B>
246 + VecZnxNormalizeTmpBytes
247 + VecZnxDftAllocBytes
248 + VecZnxBigNormalize<B>
249 + VecZnxDftApply<B>
250 + SvpApplyDftToDftInplace<B>
251 + VecZnxIdftApplyConsume<B>
252 + VecZnxNormalizeTmpBytes
253 + VecZnxFillUniform
254 + VecZnxSubABInplace
255 + VecZnxAddInplace
256 + VecZnxNormalizeInplace<B>
257 + VecZnxAddNormal
258 + VecZnxNormalize<B>
259 + VecZnxSub,
260 B: Backend
261 + TakeVecZnxDftImpl<B>
262 + TakeVecZnxBigImpl<B>
263 + TakeSvpPPolImpl<B>
264 + ScratchOwnedAllocImpl<B>
265 + ScratchOwnedBorrowImpl<B>
266 + ScratchAvailableImpl<B>
267 + TakeScalarZnxImpl<B>
268 + TakeVecZnxImpl<B>,
269{
270 let basek: usize = 8;
271 let k_ct: usize = 54;
272
273 for rank in 1..3 {
274 let n = module.n();
275 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
276
277 let mut source_xs: Source = Source::new([0u8; 32]);
278 let mut source_xe: Source = Source::new([1u8; 32]);
279 let mut source_xa: Source = Source::new([0u8; 32]);
280
281 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
282 GLWECiphertext::decrypt_scratch_space(module, basek, k_ct)
283 | GLWECiphertext::encrypt_sk_scratch_space(module, basek, k_ct),
284 );
285
286 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
287 sk.fill_ternary_prob(0.5, &mut source_xs);
288 let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
289
290 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
291
292 ct.encrypt_zero_sk(
293 module,
294 &sk_prepared,
295 &mut source_xa,
296 &mut source_xe,
297 scratch.borrow(),
298 );
299 ct.decrypt(module, &mut pt, &sk_prepared, scratch.borrow());
300
301 assert!((SIGMA - pt.data.std(basek, 0) * (k_ct as f64).exp2()) <= 0.2);
302 }
303}
304
305pub fn test_glwe_encrypt_pk<B>(module: &Module<B>)
306where
307 Module<B>: VecZnxDftAllocBytes
308 + VecZnxBigNormalize<B>
309 + VecZnxDftApply<B>
310 + SvpApplyDftToDftInplace<B>
311 + VecZnxIdftApplyConsume<B>
312 + VecZnxNormalizeTmpBytes
313 + VecZnxFillUniform
314 + VecZnxSubABInplace
315 + VecZnxAddInplace
316 + VecZnxNormalizeInplace<B>
317 + VecZnxAddNormal
318 + VecZnxNormalize<B>
319 + VecZnxSub
320 + SvpPrepare<B>
321 + SvpPPolAllocBytes
322 + SvpPPolAlloc<B>
323 + VecZnxBigAddSmallInplace<B>
324 + VecZnxBigAllocBytes
325 + VecZnxBigAddInplace<B>
326 + VecZnxCopy
327 + VecZnxDftAlloc<B>
328 + SvpApplyDftToDft<B>
329 + VecZnxBigAddNormal<B>,
330 B: Backend
331 + TakeVecZnxDftImpl<B>
332 + TakeVecZnxBigImpl<B>
333 + TakeSvpPPolImpl<B>
334 + ScratchOwnedAllocImpl<B>
335 + ScratchOwnedBorrowImpl<B>
336 + ScratchAvailableImpl<B>
337 + TakeScalarZnxImpl<B>
338 + TakeVecZnxImpl<B>,
339{
340 let basek: usize = 8;
341 let k_ct: usize = 54;
342 let k_pk: usize = 54;
343
344 for rank in 1..3 {
345 let n: usize = module.n();
346 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
347 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
348 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
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, basek, ct.k())
357 | GLWECiphertext::decrypt_scratch_space(module, basek, ct.k())
358 | GLWECiphertext::encrypt_pk_scratch_space(module, basek, k_pk),
359 );
360
361 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
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(n, basek, k_pk, rank);
366 pk.generate_from_sk(module, &sk_prepared, &mut source_xa, &mut source_xe);
367
368 module.vec_znx_fill_uniform(basek, &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(basek, 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 "{} {}",
391 noise_have,
392 noise_want
393 );
394 }
395}