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