poulpy/core/src/tests/generics/encryption/glwe_ct.rs
core/src/tests/generics/encryption/glwe_ct.rsRaw
1use backend::hal::{
2 api::{ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxCopy, VecZnxDftAlloc, VecZnxFillUniform, VecZnxSubABInplace},
3 layouts::{Backend, Module, ScratchOwned},
4 oep::{
5 ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
6 TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
7 },
8};
9use sampling::source::Source;
10
11use crate::{
12 layouts::{
13 GLWECiphertext, GLWEPlaintext, GLWEPublicKey, GLWESecret, Infos,
14 compressed::GLWECiphertextCompressed,
15 prepared::{GLWEPublicKeyPrepared, GLWESecretPrepared, PrepareAlloc},
16 },
17 operations::GLWEOperations,
18 trait_families::Decompress,
19};
20
21use crate::trait_families::{GLWEDecryptFamily, GLWEEncryptPkFamily, GLWEEncryptSkFamily, GLWESecretPreparedModuleFamily};
22
23pub trait EncryptionTestModuleFamily<B: Backend> =
24 GLWEDecryptFamily<B> + GLWESecretPreparedModuleFamily<B> + GLWEEncryptPkFamily<B>;
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>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B>,
29 B: TakeVecZnxDftImpl<B>
30 + TakeVecZnxBigImpl<B>
31 + TakeSvpPPolImpl<B>
32 + ScratchOwnedAllocImpl<B>
33 + ScratchOwnedBorrowImpl<B>
34 + ScratchAvailableImpl<B>
35 + TakeScalarZnxImpl<B>
36 + TakeVecZnxImpl<B>,
37{
38 let n = module.n();
39 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
40 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
41 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
42
43 let mut source_xs: Source = Source::new([0u8; 32]);
44 let mut source_xe: Source = Source::new([0u8; 32]);
45 let mut source_xa: Source = Source::new([0u8; 32]);
46
47 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
48 GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, ct.k())
49 | GLWECiphertext::decrypt_scratch_space(module, n, basek, ct.k()),
50 );
51
52 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
53 sk.fill_ternary_prob(0.5, &mut source_xs);
54 let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
55
56 module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_pt, &mut source_xa);
57
58 ct.encrypt_sk(
59 module,
60 &pt_want,
61 &sk_prepared,
62 &mut source_xa,
63 &mut source_xe,
64 sigma,
65 scratch.borrow(),
66 );
67
68 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
69
70 pt_want.sub_inplace_ab(module, &pt_have);
71
72 let noise_have: f64 = pt_want.data.std(basek, 0) * (ct.k() as f64).exp2();
73 let noise_want: f64 = sigma;
74
75 assert!(noise_have <= noise_want + 0.2);
76}
77
78pub fn test_glwe_compressed_encrypt_sk<B: Backend>(
79 module: &Module<B>,
80 basek: usize,
81 k_ct: usize,
82 k_pt: usize,
83 sigma: f64,
84 rank: usize,
85) where
86 Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B> + VecZnxCopy,
87 B: TakeVecZnxDftImpl<B>
88 + TakeVecZnxBigImpl<B>
89 + TakeSvpPPolImpl<B>
90 + ScratchOwnedAllocImpl<B>
91 + ScratchOwnedBorrowImpl<B>
92 + ScratchAvailableImpl<B>
93 + TakeScalarZnxImpl<B>
94 + TakeVecZnxImpl<B>,
95{
96 let n = module.n();
97 let mut ct_compressed: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(n, basek, k_ct, rank);
98
99 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
100 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
101
102 let mut source_xs: Source = Source::new([0u8; 32]);
103 let mut source_xe: Source = Source::new([0u8; 32]);
104 let mut source_xa: Source = Source::new([0u8; 32]);
105
106 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
107 GLWECiphertextCompressed::encrypt_sk_scratch_space(module, n, basek, k_ct)
108 | GLWECiphertext::decrypt_scratch_space(module, n, basek, k_ct),
109 );
110
111 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
112 sk.fill_ternary_prob(0.5, &mut source_xs);
113 let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
114
115 module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_pt, &mut source_xa);
116
117 let seed_xa: [u8; 32] = [1u8; 32];
118
119 ct_compressed.encrypt_sk(
120 module,
121 &pt_want,
122 &sk_prepared,
123 seed_xa,
124 &mut source_xe,
125 sigma,
126 scratch.borrow(),
127 );
128
129 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
130 ct.decompress(module, &ct_compressed);
131
132 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
133
134 pt_want.sub_inplace_ab(module, &pt_have);
135
136 let noise_have: f64 = pt_want.data.std(basek, 0) * (ct.k() as f64).exp2();
137 let noise_want: f64 = sigma;
138
139 assert!(
140 noise_have <= noise_want + 0.2,
141 "{} <= {}",
142 noise_have,
143 noise_want + 0.2
144 );
145}
146
147pub fn test_glwe_encrypt_zero_sk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, sigma: f64, rank: usize)
148where
149 Module<B>: EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B>,
150 B: TakeVecZnxDftImpl<B>
151 + TakeVecZnxBigImpl<B>
152 + TakeSvpPPolImpl<B>
153 + ScratchOwnedAllocImpl<B>
154 + ScratchOwnedBorrowImpl<B>
155 + ScratchAvailableImpl<B>
156 + TakeScalarZnxImpl<B>
157 + TakeVecZnxImpl<B>,
158{
159 let n = module.n();
160 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
161
162 let mut source_xs: Source = Source::new([0u8; 32]);
163 let mut source_xe: Source = Source::new([1u8; 32]);
164 let mut source_xa: Source = Source::new([0u8; 32]);
165
166 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
167 GLWECiphertext::decrypt_scratch_space(module, n, basek, k_ct)
168 | GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, k_ct),
169 );
170
171 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
172 sk.fill_ternary_prob(0.5, &mut source_xs);
173 let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
174
175 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
176
177 ct.encrypt_zero_sk(
178 module,
179 &sk_prepared,
180 &mut source_xa,
181 &mut source_xe,
182 sigma,
183 scratch.borrow(),
184 );
185 ct.decrypt(module, &mut pt, &sk_prepared, scratch.borrow());
186
187 assert!((sigma - pt.data.std(basek, 0) * (k_ct as f64).exp2()) <= 0.2);
188}
189
190pub fn test_glwe_encrypt_pk<B: Backend>(module: &Module<B>, basek: usize, k_ct: usize, k_pk: usize, sigma: f64, rank: usize)
191where
192 Module<B>:
193 EncryptionTestModuleFamily<B> + GLWEEncryptSkFamily<B> + VecZnxDftAlloc<B> + VecZnxFillUniform + VecZnxSubABInplace,
194 B: TakeVecZnxDftImpl<B>
195 + TakeVecZnxBigImpl<B>
196 + TakeSvpPPolImpl<B>
197 + ScratchOwnedAllocImpl<B>
198 + ScratchOwnedBorrowImpl<B>
199 + ScratchAvailableImpl<B>
200 + TakeScalarZnxImpl<B>
201 + TakeVecZnxImpl<B>,
202{
203 let n: usize = module.n();
204 let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
205 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
206 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
207
208 let mut source_xs: Source = Source::new([0u8; 32]);
209 let mut source_xe: Source = Source::new([0u8; 32]);
210 let mut source_xa: Source = Source::new([0u8; 32]);
211 let mut source_xu: Source = Source::new([0u8; 32]);
212
213 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
214 GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, ct.k())
215 | GLWECiphertext::decrypt_scratch_space(module, n, basek, ct.k())
216 | GLWECiphertext::encrypt_pk_scratch_space(module, n, basek, k_pk),
217 );
218
219 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
220 sk.fill_ternary_prob(0.5, &mut source_xs);
221 let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
222
223 let mut pk: GLWEPublicKey<Vec<u8>> = GLWEPublicKey::alloc(n, basek, k_pk, rank);
224 pk.generate_from_sk(module, &sk_prepared, &mut source_xa, &mut source_xe, sigma);
225
226 module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_ct, &mut source_xa);
227
228 let pk_prepared: GLWEPublicKeyPrepared<Vec<u8>, B> = pk.prepare_alloc(module, scratch.borrow());
229
230 ct.encrypt_pk(
231 module,
232 &pt_want,
233 &pk_prepared,
234 &mut source_xu,
235 &mut source_xe,
236 sigma,
237 scratch.borrow(),
238 );
239
240 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
241
242 pt_want.sub_inplace_ab(module, &pt_have);
243
244 let noise_have: f64 = pt_want.data.std(basek, 0).log2();
245 let noise_want: f64 = ((((rank as f64) + 1.0) * n as f64 * 0.5 * sigma * sigma).sqrt()).log2() - (k_ct as f64);
246
247 assert!(
248 noise_have <= noise_want + 0.2,
249 "{} {}",
250 noise_have,
251 noise_want
252 );
253}