poulpy/poulpy-core/src/tests/test_suite/encryption/glwe_ct.rs
poulpy-core/src/tests/test_suite/encryption/glwe_ct.rsRaw
1use poulpy_hal::{
2 api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform},
3 layouts::{Backend, Module, Scratch, ScratchOwned},
4 source::Source,
5};
6
7use crate::{
8 GLWECompressedEncryptSk, GLWEEncryptPk, GLWEEncryptSk, GLWEPublicKeyGenerate, GLWESub, ScratchTakeCore,
9 decryption::GLWEDecrypt,
10 encryption::SIGMA,
11 layouts::{
12 GLWE, GLWELayout, GLWEPlaintext, GLWEPlaintextLayout, GLWEPublicKey, GLWEPublicKeyPrepare, GLWEPublicKeyPreparedAlloc,
13 GLWESecret, GLWESecretPrepare, GLWESecretPreparedAlloc, LWEInfos,
14 compressed::GLWECompressed,
15 prepared::{GLWEPublicKeyPrepared, GLWESecretPrepared},
16 },
17};
18
19pub fn test_glwe_encrypt_sk<BE: Backend>(module: &Module<BE>)
20where
21 Module<BE>:
22 GLWEEncryptSk<BE> + GLWEDecrypt<BE> + GLWESecretPreparedAlloc<BE> + GLWESecretPrepare<BE> + VecZnxFillUniform + GLWESub,
23 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
24 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
25{
26 let base2k: usize = 8;
27 let k_ct: usize = 54;
28 let k_pt: usize = 30;
29
30 for rank in 1_usize..3 {
31 let n: usize = module.n();
32
33 let glwe_infos: GLWELayout = GLWELayout {
34 n: n.into(),
35 base2k: base2k.into(),
36 k: k_ct.into(),
37 rank: rank.into(),
38 };
39
40 let pt_infos: GLWEPlaintextLayout = GLWEPlaintextLayout {
41 n: n.into(),
42 base2k: base2k.into(),
43 k: k_pt.into(),
44 };
45
46 let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos);
47 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&pt_infos);
48 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&pt_infos);
49
50 let mut source_xs: Source = Source::new([0u8; 32]);
51 let mut source_xe: Source = Source::new([0u8; 32]);
52 let mut source_xa: Source = Source::new([0u8; 32]);
53
54 let mut scratch: ScratchOwned<BE> =
55 ScratchOwned::alloc(GLWE::encrypt_sk_tmp_bytes(module, &glwe_infos) | GLWE::decrypt_tmp_bytes(module, &glwe_infos));
56
57 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos);
58 sk.fill_ternary_prob(0.5, &mut source_xs);
59
60 let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into());
61 sk_prepared.prepare(module, &sk);
62
63 module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
64
65 ct.encrypt_sk(
66 module,
67 &pt_want,
68 &sk_prepared,
69 &mut source_xa,
70 &mut source_xe,
71 scratch.borrow(),
72 );
73
74 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
75
76 module.glwe_sub_inplace(&mut pt_want, &pt_have);
77
78 let noise_have: f64 = pt_want.data.std(base2k, 0) * (ct.k().as_u32() as f64).exp2();
79 let noise_want: f64 = SIGMA;
80
81 assert!(noise_have <= noise_want + 0.2);
82 }
83}
84
85pub fn test_glwe_compressed_encrypt_sk<BE: Backend>(module: &Module<BE>)
86where
87 Module<BE>: GLWECompressedEncryptSk<BE>
88 + GLWEDecrypt<BE>
89 + GLWESecretPreparedAlloc<BE>
90 + GLWESecretPrepare<BE>
91 + VecZnxFillUniform
92 + GLWESub,
93 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
94 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
95{
96 let base2k: usize = 8;
97 let k_ct: usize = 54;
98 let k_pt: usize = 30;
99
100 for rank in 1_usize..3 {
101 // println!("rank: {}", rank);
102 let n: usize = module.n();
103
104 let glwe_infos: GLWELayout = GLWELayout {
105 n: n.into(),
106 base2k: base2k.into(),
107 k: k_ct.into(),
108 rank: rank.into(),
109 };
110
111 let pt_infos: GLWEPlaintextLayout = GLWEPlaintextLayout {
112 n: n.into(),
113 base2k: base2k.into(),
114 k: k_pt.into(),
115 };
116
117 let mut ct_compressed: GLWECompressed<Vec<u8>> = GLWECompressed::alloc_from_infos(&glwe_infos);
118
119 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&pt_infos);
120 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&pt_infos);
121
122 let mut source_xs: Source = Source::new([0u8; 32]);
123 let mut source_xe: Source = Source::new([0u8; 32]);
124 let mut source_xa: Source = Source::new([0u8; 32]);
125
126 let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
127 GLWECompressed::encrypt_sk_tmp_bytes(module, &glwe_infos) | GLWE::decrypt_tmp_bytes(module, &glwe_infos),
128 );
129
130 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos);
131 sk.fill_ternary_prob(0.5, &mut source_xs);
132
133 let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into());
134 sk_prepared.prepare(module, &sk);
135
136 module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
137
138 let seed_xa: [u8; 32] = [1u8; 32];
139
140 ct_compressed.encrypt_sk(
141 module,
142 &pt_want,
143 &sk_prepared,
144 seed_xa,
145 &mut source_xe,
146 scratch.borrow(),
147 );
148
149 let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos);
150 ct.decompress(module, &ct_compressed);
151
152 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
153
154 module.glwe_sub_inplace(&mut pt_want, &pt_have);
155
156 let noise_have: f64 = pt_want.data.std(base2k, 0) * (ct.k().as_u32() as f64).exp2();
157 let noise_want: f64 = SIGMA;
158
159 assert!(
160 noise_have <= noise_want + 0.2,
161 "{noise_have} <= {}",
162 noise_want + 0.2
163 );
164 }
165}
166
167pub fn test_glwe_encrypt_zero_sk<BE: Backend>(module: &Module<BE>)
168where
169 Module<BE>:
170 GLWEEncryptSk<BE> + GLWEDecrypt<BE> + GLWESecretPreparedAlloc<BE> + GLWESecretPrepare<BE> + VecZnxFillUniform + GLWESub,
171 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
172 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
173{
174 let base2k: usize = 8;
175 let k_ct: usize = 54;
176
177 for rank in 1_usize..3 {
178 let n: usize = module.n();
179
180 let glwe_infos: GLWELayout = GLWELayout {
181 n: n.into(),
182 base2k: base2k.into(),
183 k: k_ct.into(),
184 rank: rank.into(),
185 };
186
187 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos);
188
189 let mut source_xs: Source = Source::new([0u8; 32]);
190 let mut source_xe: Source = Source::new([1u8; 32]);
191 let mut source_xa: Source = Source::new([0u8; 32]);
192
193 let mut scratch: ScratchOwned<BE> =
194 ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, &glwe_infos) | GLWE::encrypt_sk_tmp_bytes(module, &glwe_infos));
195
196 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos);
197 sk.fill_ternary_prob(0.5, &mut source_xs);
198
199 let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into());
200 sk_prepared.prepare(module, &sk);
201
202 let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos);
203
204 ct.encrypt_zero_sk(
205 module,
206 &sk_prepared,
207 &mut source_xa,
208 &mut source_xe,
209 scratch.borrow(),
210 );
211 ct.decrypt(module, &mut pt, &sk_prepared, scratch.borrow());
212
213 assert!((SIGMA - pt.data.std(base2k, 0) * (k_ct as f64).exp2()) <= 0.2);
214 }
215}
216
217pub fn test_glwe_encrypt_pk<BE: Backend>(module: &Module<BE>)
218where
219 Module<BE>: GLWEEncryptPk<BE>
220 + GLWEPublicKeyPrepare<BE>
221 + GLWEPublicKeyPreparedAlloc<BE>
222 + GLWEPublicKeyGenerate<BE>
223 + GLWEDecrypt<BE>
224 + GLWESecretPreparedAlloc<BE>
225 + GLWESecretPrepare<BE>
226 + VecZnxFillUniform
227 + GLWESub,
228 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
229 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
230{
231 let base2k: usize = 8;
232 let k_ct: usize = 54;
233
234 for rank in 1_usize..3 {
235 let n: usize = module.n();
236
237 let glwe_infos: GLWELayout = GLWELayout {
238 n: n.into(),
239 base2k: base2k.into(),
240 k: k_ct.into(),
241 rank: rank.into(),
242 };
243
244 let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos);
245 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos);
246 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos);
247
248 let mut source_xs: Source = Source::new([0u8; 32]);
249 let mut source_xe: Source = Source::new([0u8; 32]);
250 let mut source_xa: Source = Source::new([0u8; 32]);
251 let mut source_xu: Source = Source::new([0u8; 32]);
252
253 let mut scratch: ScratchOwned<BE> =
254 ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, &glwe_infos) | GLWE::encrypt_pk_tmp_bytes(module, &glwe_infos));
255
256 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos);
257 sk.fill_ternary_prob(0.5, &mut source_xs);
258
259 let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into());
260 sk_prepared.prepare(module, &sk);
261
262 let mut pk: GLWEPublicKey<Vec<u8>> = GLWEPublicKey::alloc_from_infos(&glwe_infos);
263 pk.generate(module, &sk_prepared, &mut source_xa, &mut source_xe);
264
265 module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
266
267 let mut pk_prepared: GLWEPublicKeyPrepared<Vec<u8>, BE> = GLWEPublicKeyPrepared::alloc_from_infos(module, &glwe_infos);
268 pk_prepared.prepare(module, &pk);
269
270 ct.encrypt_pk(
271 module,
272 &pt_want,
273 &pk_prepared,
274 &mut source_xu,
275 &mut source_xe,
276 scratch.borrow(),
277 );
278
279 ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
280
281 module.glwe_sub_inplace(&mut pt_want, &pt_have);
282
283 let noise_have: f64 = pt_want.data.std(base2k, 0).log2();
284 let noise_want: f64 = ((((rank as f64) + 1.0) * n as f64 * 0.5 * SIGMA * SIGMA).sqrt()).log2() - (k_ct as f64);
285
286 assert!(
287 noise_have <= noise_want + 0.2,
288 "{noise_have} <= {}",
289 noise_want + 0.2
290 );
291 }
292}