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