poulpy/poulpy-core/src/tests/test_suite/encryption/gglwe_ct.rs
poulpy-core/src/tests/test_suite/encryption/gglwe_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 GGLWECompressedEncryptSk, GGLWEEncryptSk, GGLWEKeyswitch, GLWESwitchingKeyCompressedEncryptSk, GLWESwitchingKeyEncryptSk,
9 ScratchTakeCore,
10 decryption::GLWEDecrypt,
11 encryption::SIGMA,
12 layouts::{
13 GGLWE, GGLWECompressed, GGLWEInfos, GGLWELayout, GLWESecret, GLWESecretPreparedFactory, GLWESwitchingKey,
14 GLWESwitchingKeyCompressed, GLWESwitchingKeyDecompress, LWEInfos,
15 prepared::{GGLWEPreparedFactory, GLWESecretPrepared},
16 },
17 noise::GGLWENoise,
18};
19
20pub fn test_gglwe_switching_key_encrypt_sk<BE: Backend>(module: &Module<BE>)
21where
22 Module<BE>: GGLWEEncryptSk<BE>
23 + GGLWEPreparedFactory<BE>
24 + GGLWEKeyswitch<BE>
25 + GLWEDecrypt<BE>
26 + GLWESecretPreparedFactory<BE>
27 + GLWESwitchingKeyEncryptSk<BE>
28 + VecZnxFillUniform
29 + GGLWENoise<BE>,
30 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
31 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
32{
33 let n: usize = module.n();
34 let base2k: usize = 12;
35 let k_ksk: usize = 54;
36 let dsize: usize = k_ksk / base2k;
37 for rank_in in 1_usize..3 {
38 for rank_out in 1_usize..3 {
39 for di in 1_usize..dsize + 1 {
40 let dnum: usize = (k_ksk - di * base2k) / (di * base2k);
41
42 let gglwe_infos: GGLWELayout = GGLWELayout {
43 n: n.into(),
44 base2k: base2k.into(),
45 k: k_ksk.into(),
46 dnum: dnum.into(),
47 dsize: di.into(),
48 rank_in: rank_in.into(),
49 rank_out: rank_out.into(),
50 };
51
52 let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_infos);
53
54 let mut source_xs: Source = Source::new([0u8; 32]);
55 let mut source_xe: Source = Source::new([0u8; 32]);
56 let mut source_xa: Source = Source::new([0u8; 32]);
57
58 let mut scratch: ScratchOwned<BE> =
59 ScratchOwned::alloc(GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_infos));
60
61 let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into());
62 sk_in.fill_ternary_prob(0.5, &mut source_xs);
63
64 let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into());
65 sk_out.fill_ternary_prob(0.5, &mut source_xs);
66 let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into());
67 sk_out_prepared.prepare(module, &sk_out);
68
69 ksk.encrypt_sk(
70 module,
71 &sk_in,
72 &sk_out,
73 &mut source_xa,
74 &mut source_xe,
75 scratch.borrow(),
76 );
77
78 let max_noise: f64 = SIGMA.log2() - (ksk.k().as_usize() as f64) + 0.5;
79
80 for row in 0..ksk.dnum().as_usize() {
81 for col in 0..ksk.rank_in().as_usize() {
82 let noise_have = ksk
83 .key
84 .noise(
85 module,
86 row,
87 col,
88 &sk_in.data,
89 &sk_out_prepared,
90 scratch.borrow(),
91 )
92 .std()
93 .log2();
94
95 assert!(
96 noise_have < max_noise + 0.5,
97 "row:{row} col:{col} noise_have:{noise_have} > max_noise:{}",
98 max_noise + 0.5
99 );
100 }
101 }
102 }
103 }
104 }
105}
106
107pub fn test_gglwe_switching_key_compressed_encrypt_sk<BE: Backend>(module: &Module<BE>)
108where
109 Module<BE>: GGLWEEncryptSk<BE>
110 + GGLWEPreparedFactory<BE>
111 + GGLWEKeyswitch<BE>
112 + GLWEDecrypt<BE>
113 + GLWESecretPreparedFactory<BE>
114 + GLWESwitchingKeyEncryptSk<BE>
115 + GLWESwitchingKeyCompressedEncryptSk<BE>
116 + GLWESwitchingKeyDecompress
117 + GGLWENoise<BE>
118 + VecZnxFillUniform,
119 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
120 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
121{
122 let n: usize = module.n();
123 let base2k: usize = 12;
124 let k_ksk: usize = 54;
125 let max_dsize: usize = k_ksk / base2k;
126 for rank_in in 1_usize..3 {
127 for rank_out in 1_usize..3 {
128 for dsize in 1_usize..max_dsize {
129 let dnum: usize = (k_ksk - dsize * base2k) / (dsize * base2k);
130
131 let gglwe_infos: GGLWELayout = GGLWELayout {
132 n: n.into(),
133 base2k: base2k.into(),
134 k: k_ksk.into(),
135 dnum: dnum.into(),
136 dsize: dsize.into(),
137 rank_in: rank_in.into(),
138 rank_out: rank_out.into(),
139 };
140
141 let mut ksk_compressed: GLWESwitchingKeyCompressed<Vec<u8>> =
142 GLWESwitchingKeyCompressed::alloc_from_infos(&gglwe_infos);
143
144 let mut source_xs: Source = Source::new([0u8; 32]);
145 let mut source_xe: Source = Source::new([0u8; 32]);
146
147 let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(GLWESwitchingKeyCompressed::encrypt_sk_tmp_bytes(
148 module,
149 &gglwe_infos,
150 ));
151
152 let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into());
153 sk_in.fill_ternary_prob(0.5, &mut source_xs);
154
155 let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into());
156 sk_out.fill_ternary_prob(0.5, &mut source_xs);
157 let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into());
158 sk_out_prepared.prepare(module, &sk_out);
159
160 let seed_xa = [1u8; 32];
161
162 ksk_compressed.encrypt_sk(
163 module,
164 &sk_in,
165 &sk_out,
166 seed_xa,
167 &mut source_xe,
168 scratch.borrow(),
169 );
170
171 let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_infos);
172 ksk.decompress(module, &ksk_compressed);
173
174 let max_noise: f64 = SIGMA.log2() - (ksk.k().as_usize() as f64) + 0.5;
175
176 for row in 0..ksk.dnum().as_usize() {
177 for col in 0..ksk.rank_in().as_usize() {
178 let noise_have = ksk
179 .key
180 .noise(
181 module,
182 row,
183 col,
184 &sk_in.data,
185 &sk_out_prepared,
186 scratch.borrow(),
187 )
188 .std()
189 .log2();
190
191 assert!(
192 noise_have < max_noise + 0.5,
193 "row:{row} col:{col} noise_have:{noise_have} > max_noise:{}",
194 max_noise + 0.5
195 );
196 }
197 }
198 }
199 }
200 }
201}
202
203pub fn test_gglwe_compressed_encrypt_sk<BE: Backend>(module: &Module<BE>)
204where
205 Module<BE>: GGLWEEncryptSk<BE>
206 + GGLWEPreparedFactory<BE>
207 + GGLWEKeyswitch<BE>
208 + GLWEDecrypt<BE>
209 + GLWESecretPreparedFactory<BE>
210 + GLWESwitchingKeyEncryptSk<BE>
211 + GGLWECompressedEncryptSk<BE>
212 + GLWESwitchingKeyDecompress
213 + GGLWENoise<BE>
214 + VecZnxFillUniform,
215 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
216 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
217{
218 let n: usize = module.n();
219 let base2k: usize = 12;
220 let k_ksk: usize = 54;
221 let max_dsize: usize = k_ksk / base2k;
222 for rank_in in 1_usize..3 {
223 for rank_out in 1_usize..3 {
224 for dsize in 1_usize..max_dsize + 1 {
225 let dnum: usize = (k_ksk - dsize * base2k) / (dsize * base2k);
226
227 let gglwe_infos: GGLWELayout = GGLWELayout {
228 n: n.into(),
229 base2k: base2k.into(),
230 k: k_ksk.into(),
231 dnum: dnum.into(),
232 dsize: dsize.into(),
233 rank_in: rank_in.into(),
234 rank_out: rank_out.into(),
235 };
236
237 let mut ksk_compressed: GGLWECompressed<Vec<u8>> = GGLWECompressed::alloc_from_infos(&gglwe_infos);
238
239 let mut source_xs: Source = Source::new([0u8; 32]);
240 let mut source_xe: Source = Source::new([0u8; 32]);
241
242 let mut scratch: ScratchOwned<BE> =
243 ScratchOwned::alloc(GGLWECompressed::encrypt_sk_tmp_bytes(module, &gglwe_infos));
244
245 let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into());
246 sk_in.fill_ternary_prob(0.5, &mut source_xs);
247
248 let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into());
249 sk_out.fill_ternary_prob(0.5, &mut source_xs);
250 let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into());
251 sk_out_prepared.prepare(module, &sk_out);
252
253 let seed_xa = [1u8; 32];
254
255 ksk_compressed.encrypt_sk(
256 module,
257 &sk_in.data,
258 &sk_out_prepared,
259 seed_xa,
260 &mut source_xe,
261 scratch.borrow(),
262 );
263
264 let mut ksk: GGLWE<Vec<u8>> = GGLWE::alloc_from_infos(&gglwe_infos);
265 ksk.decompress(module, &ksk_compressed);
266
267 let max_noise: f64 = SIGMA.log2() - (ksk.k().as_usize() as f64) + 0.5;
268
269 for row in 0..ksk.dnum().as_usize() {
270 for col in 0..ksk.rank_in().as_usize() {
271 let noise_have = ksk
272 .noise(
273 module,
274 row,
275 col,
276 &sk_in.data,
277 &sk_out_prepared,
278 scratch.borrow(),
279 )
280 .std()
281 .log2();
282
283 assert!(
284 noise_have < max_noise + 0.5,
285 "row:{row} col:{col} noise_have:{noise_have} > max_noise:{}",
286 max_noise + 0.5
287 );
288 }
289 }
290 }
291 }
292 }
293}