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