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