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