poulpy/poulpy-core/src/tests/generics/encryption/glwe_ct.rs
poulpy-core/src/tests/generics/encryption/glwe_ct.rsRaw
1use poulpy_backend::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 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, sigma: f64, rank: usize)
27where
28 Module<B>: VecZnxDftAllocBytes
29 + VecZnxBigAllocBytes
30 + VecZnxDftFromVecZnx<B>
31 + SvpApplyInplace<B>
32 + VecZnxDftToVecZnxBigConsume<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 + VecZnxDftToVecZnxBigConsume<B>
46 + VecZnxBigAddNormal<B>
47 + VecZnxBigAddSmallInplace<B>
48 + VecZnxBigNormalize<B>
49 + VecZnxNormalizeTmpBytes
50 + VecZnxDftAllocBytes
51 + VecZnxBigNormalize<B>
52 + VecZnxDftFromVecZnx<B>
53 + SvpApplyInplace<B>
54 + VecZnxDftToVecZnxBigConsume<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, n, basek, ct.k())
84 | GLWECiphertext::decrypt_scratch_space(module, n, 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 sigma,
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, sigma: f64, 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 sigma,
191 scratch.borrow(),
192 );
193
194 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
195 ct.decompress(module, &ct_compressed);
196
197 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
198
199 pt_want.sub_inplace_ab(module, &pt_have);
200
201 let noise_have: f64 = pt_want.data.std(basek, 0) * (ct.k() as f64).exp2();
202 let noise_want: f64 = sigma;
203
204 assert!(
205 noise_have <= noise_want + 0.2,
206 "{} <= {}",
207 noise_have,
208 noise_want + 0.2
209 );
210}
211
212pub fn test_glwe_encrypt_zero_sk<B>(module: &Module<B>, basek: usize, k_ct: usize, sigma: f64, rank: usize)
213where
214 Module<B>: VecZnxDftAllocBytes
215 + VecZnxBigAllocBytes
216 + VecZnxDftFromVecZnx<B>
217 + SvpApplyInplace<B>
218 + VecZnxDftToVecZnxBigConsume<B>
219 + VecZnxBigAddInplace<B>
220 + VecZnxBigAddSmallInplace<B>
221 + VecZnxBigNormalize<B>
222 + VecZnxNormalizeTmpBytes
223 + SvpPrepare<B>
224 + SvpPPolAllocBytes
225 + SvpPPolAlloc<B>
226 + VecZnxDftAllocBytes
227 + VecZnxBigAllocBytes
228 + SvpPPolAllocBytes
229 + SvpPrepare<B>
230 + SvpApply<B>
231 + VecZnxDftToVecZnxBigConsume<B>
232 + VecZnxBigAddNormal<B>
233 + VecZnxBigAddSmallInplace<B>
234 + VecZnxBigNormalize<B>
235 + VecZnxNormalizeTmpBytes
236 + VecZnxDftAllocBytes
237 + VecZnxBigNormalize<B>
238 + VecZnxDftFromVecZnx<B>
239 + SvpApplyInplace<B>
240 + VecZnxDftToVecZnxBigConsume<B>
241 + VecZnxNormalizeTmpBytes
242 + VecZnxFillUniform
243 + VecZnxSubABInplace
244 + VecZnxAddInplace
245 + VecZnxNormalizeInplace<B>
246 + VecZnxAddNormal
247 + VecZnxNormalize<B>
248 + VecZnxSub,
249 B: Backend
250 + TakeVecZnxDftImpl<B>
251 + TakeVecZnxBigImpl<B>
252 + TakeSvpPPolImpl<B>
253 + ScratchOwnedAllocImpl<B>
254 + ScratchOwnedBorrowImpl<B>
255 + ScratchAvailableImpl<B>
256 + TakeScalarZnxImpl<B>
257 + TakeVecZnxImpl<B>,
258{
259 let n = module.n();
260 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
261
262 let mut source_xs: Source = Source::new([0u8; 32]);
263 let mut source_xe: Source = Source::new([1u8; 32]);
264 let mut source_xa: Source = Source::new([0u8; 32]);
265
266 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
267 GLWECiphertext::decrypt_scratch_space(module, n, basek, k_ct)
268 | GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, k_ct),
269 );
270
271 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
272 sk.fill_ternary_prob(0.5, &mut source_xs);
273 let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
274
275 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
276
277 ct.encrypt_zero_sk(
278 module,
279 &sk_prepared,
280 &mut source_xa,
281 &mut source_xe,
282 sigma,
283 scratch.borrow(),
284 );
285 ct.decrypt(module, &mut pt, &sk_prepared, scratch.borrow());
286
287 assert!((sigma - pt.data.std(basek, 0) * (k_ct as f64).exp2()) <= 0.2);
288}
289
290pub fn test_glwe_encrypt_pk<B>(module: &Module<B>, basek: usize, k_ct: usize, k_pk: usize, sigma: f64, rank: usize)
291where
292 Module<B>: VecZnxDftAllocBytes
293 + VecZnxBigNormalize<B>
294 + VecZnxDftFromVecZnx<B>
295 + SvpApplyInplace<B>
296 + VecZnxDftToVecZnxBigConsume<B>
297 + VecZnxNormalizeTmpBytes
298 + VecZnxFillUniform
299 + VecZnxSubABInplace
300 + VecZnxAddInplace
301 + VecZnxNormalizeInplace<B>
302 + VecZnxAddNormal
303 + VecZnxNormalize<B>
304 + VecZnxSub
305 + SvpPrepare<B>
306 + SvpPPolAllocBytes
307 + SvpPPolAlloc<B>
308 + VecZnxBigAddSmallInplace<B>
309 + VecZnxBigAllocBytes
310 + VecZnxBigAddInplace<B>
311 + VecZnxCopy
312 + VecZnxDftAlloc<B>
313 + SvpApply<B>
314 + VecZnxBigAddNormal<B>,
315 B: Backend
316 + TakeVecZnxDftImpl<B>
317 + TakeVecZnxBigImpl<B>
318 + TakeSvpPPolImpl<B>
319 + ScratchOwnedAllocImpl<B>
320 + ScratchOwnedBorrowImpl<B>
321 + ScratchAvailableImpl<B>
322 + TakeScalarZnxImpl<B>
323 + TakeVecZnxImpl<B>,
324{
325 let n: usize = module.n();
326 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
327 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
328 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
329
330 let mut source_xs: Source = Source::new([0u8; 32]);
331 let mut source_xe: Source = Source::new([0u8; 32]);
332 let mut source_xa: Source = Source::new([0u8; 32]);
333 let mut source_xu: Source = Source::new([0u8; 32]);
334
335 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
336 GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, ct.k())
337 | GLWECiphertext::decrypt_scratch_space(module, n, basek, ct.k())
338 | GLWECiphertext::encrypt_pk_scratch_space(module, n, basek, k_pk),
339 );
340
341 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
342 sk.fill_ternary_prob(0.5, &mut source_xs);
343 let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
344
345 let mut pk: GLWEPublicKey<Vec<u8>> = GLWEPublicKey::alloc(n, basek, k_pk, rank);
346 pk.generate_from_sk(module, &sk_prepared, &mut source_xa, &mut source_xe, sigma);
347
348 module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_ct, &mut source_xa);
349
350 let pk_prepared: GLWEPublicKeyPrepared<Vec<u8>, B> = pk.prepare_alloc(module, scratch.borrow());
351
352 ct.encrypt_pk(
353 module,
354 &pt_want,
355 &pk_prepared,
356 &mut source_xu,
357 &mut source_xe,
358 sigma,
359 scratch.borrow(),
360 );
361
362 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
363
364 pt_want.sub_inplace_ab(module, &pt_have);
365
366 let noise_have: f64 = pt_want.data.std(basek, 0).log2();
367 let noise_want: f64 = ((((rank as f64) + 1.0) * n as f64 * 0.5 * sigma * sigma).sqrt()).log2() - (k_ct as f64);
368
369 assert!(
370 noise_have <= noise_want + 0.2,
371 "{} {}",
372 noise_have,
373 noise_want
374 );
375}