poulpy/poulpy-core/src/tests/test_suite/keyswitch/gglwe_ct.rs
poulpy-core/src/tests/test_suite/keyswitch/gglwe_ct.rsRaw
1use poulpy_hal::{
2 api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow},
3 layouts::{Backend, Module, Scratch, ScratchOwned},
4 source::Source,
5};
6
7use crate::{
8 GGLWEKeyswitch, GGLWENoise, GLWESwitchingKeyEncryptSk, ScratchTakeCore,
9 encryption::SIGMA,
10 layouts::{
11 GLWESecret, GLWESecretPrepare, GLWESecretPreparedAlloc, GLWESwitchingKey, GLWESwitchingKeyLayout,
12 GLWESwitchingKeyPrepare, GLWESwitchingKeyPreparedAlloc,
13 prepared::{GLWESecretPrepared, GLWESwitchingKeyPrepared},
14 },
15 noise::log2_std_noise_gglwe_product,
16};
17
18pub fn test_gglwe_switching_key_keyswitch<BE: Backend>(module: &Module<BE>)
19where
20 Module<BE>: GLWESwitchingKeyEncryptSk<BE>
21 + GGLWEKeyswitch<BE>
22 + GLWESecretPrepare<BE>
23 + GLWESwitchingKeyPreparedAlloc<BE>
24 + GLWESecretPreparedAlloc<BE>
25 + GLWESwitchingKeyPrepare<BE>
26 + GGLWENoise<BE>,
27 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
28 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
29{
30 let base2k: usize = 12;
31 let k_in: usize = 60;
32 let dsize: usize = k_in.div_ceil(base2k);
33
34 for rank_in_s0s1 in 1_usize..3 {
35 for rank_out_s0s1 in 1_usize..3 {
36 for rank_out_s1s2 in 1_usize..3 {
37 for di in 1_usize..dsize + 1 {
38 let k_ksk: usize = k_in + base2k * di;
39 let k_out: usize = k_ksk; // Better capture noise.
40
41 let n: usize = module.n();
42 let dnum: usize = k_in / base2k;
43 let dnum_apply: usize = k_in.div_ceil(base2k * di);
44 let dsize_in: usize = 1;
45
46 let gglwe_s0s1_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
47 n: n.into(),
48 base2k: base2k.into(),
49 k: k_in.into(),
50 dnum: dnum.into(),
51 dsize: dsize_in.into(),
52 rank_in: rank_in_s0s1.into(),
53 rank_out: rank_out_s0s1.into(),
54 };
55
56 let gglwe_s1s2_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
57 n: n.into(),
58 base2k: base2k.into(),
59 k: k_ksk.into(),
60 dnum: dnum_apply.into(),
61 dsize: di.into(),
62 rank_in: rank_out_s0s1.into(),
63 rank_out: rank_out_s1s2.into(),
64 };
65
66 let gglwe_s0s2_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
67 n: n.into(),
68 base2k: base2k.into(),
69 k: k_out.into(),
70 dnum: dnum_apply.into(),
71 dsize: dsize_in.into(),
72 rank_in: rank_in_s0s1.into(),
73 rank_out: rank_out_s1s2.into(),
74 };
75
76 let mut gglwe_s0s1: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s0s1_infos);
77 let mut gglwe_s1s2: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s1s2_infos);
78 let mut gglwe_s0s2: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s0s2_infos);
79
80 let mut source_xs: Source = Source::new([0u8; 32]);
81 let mut source_xe: Source = Source::new([0u8; 32]);
82 let mut source_xa: Source = Source::new([0u8; 32]);
83
84 let mut scratch_enc: ScratchOwned<BE> = ScratchOwned::alloc(
85 GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s0s1_infos)
86 | GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s1s2_infos)
87 | GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s0s2_infos),
88 );
89 let mut scratch_apply: ScratchOwned<BE> = ScratchOwned::alloc(GLWESwitchingKey::keyswitch_tmp_bytes(
90 module,
91 &gglwe_s0s1_infos,
92 &gglwe_s0s2_infos,
93 &gglwe_s1s2_infos,
94 ));
95
96 let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in_s0s1.into());
97 sk0.fill_ternary_prob(0.5, &mut source_xs);
98
99 let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out_s0s1.into());
100 sk1.fill_ternary_prob(0.5, &mut source_xs);
101
102 let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out_s1s2.into());
103 sk2.fill_ternary_prob(0.5, &mut source_xs);
104
105 let mut sk2_prepared: GLWESecretPrepared<Vec<u8>, BE> =
106 GLWESecretPrepared::alloc(module, rank_out_s1s2.into());
107 sk2_prepared.prepare(module, &sk2);
108
109 // gglwe_{s1}(s0) = s0 -> s1
110 gglwe_s0s1.encrypt_sk(
111 module,
112 &sk0,
113 &sk1,
114 &mut source_xa,
115 &mut source_xe,
116 scratch_enc.borrow(),
117 );
118
119 // gglwe_{s2}(s1) -> s1 -> s2
120 gglwe_s1s2.encrypt_sk(
121 module,
122 &sk1,
123 &sk2,
124 &mut source_xa,
125 &mut source_xe,
126 scratch_enc.borrow(),
127 );
128
129 let mut gglwe_s1s2_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> =
130 GLWESwitchingKeyPrepared::alloc_from_infos(module, &gglwe_s1s2);
131 gglwe_s1s2_prepared.prepare(module, &gglwe_s1s2, scratch_apply.borrow());
132
133 // gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
134 gglwe_s0s2.keyswitch(
135 module,
136 &gglwe_s0s1,
137 &gglwe_s1s2_prepared,
138 scratch_apply.borrow(),
139 );
140
141 let max_noise: f64 = log2_std_noise_gglwe_product(
142 n as f64,
143 base2k * di,
144 0.5,
145 0.5,
146 0f64,
147 SIGMA * SIGMA,
148 0f64,
149 rank_out_s0s1 as f64,
150 k_in,
151 k_ksk,
152 );
153
154 gglwe_s0s2
155 .key
156 .assert_noise(module, &sk2_prepared, &sk0.data, max_noise + 0.5);
157 }
158 }
159 }
160 }
161}
162
163#[allow(clippy::too_many_arguments)]
164pub fn test_gglwe_switching_key_keyswitch_inplace<BE: Backend>(module: &Module<BE>)
165where
166 Module<BE>: GLWESwitchingKeyEncryptSk<BE>
167 + GGLWEKeyswitch<BE>
168 + GLWESecretPrepare<BE>
169 + GLWESecretPreparedAlloc<BE>
170 + GLWESwitchingKeyPrepare<BE>
171 + GGLWENoise<BE>
172 + GLWESwitchingKeyPreparedAlloc<BE>,
173 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
174 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
175{
176 let base2k: usize = 12;
177 let k_out: usize = 60;
178 let dsize: usize = k_out.div_ceil(base2k);
179 for rank_in in 1_usize..3 {
180 for rank_out in 1_usize..3 {
181 for di in 1_usize..dsize + 1 {
182 let k_ksk: usize = k_out + base2k * di;
183
184 let n: usize = module.n();
185 let dnum: usize = k_out.div_ceil(base2k * di);
186 let dsize_in: usize = 1;
187
188 let gglwe_s0s1_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
189 n: n.into(),
190 base2k: base2k.into(),
191 k: k_out.into(),
192 dnum: dnum.into(),
193 dsize: dsize_in.into(),
194 rank_in: rank_in.into(),
195 rank_out: rank_out.into(),
196 };
197
198 let gglwe_s1s2_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
199 n: n.into(),
200 base2k: base2k.into(),
201 k: k_ksk.into(),
202 dnum: dnum.into(),
203 dsize: di.into(),
204 rank_in: rank_out.into(),
205 rank_out: rank_out.into(),
206 };
207
208 let mut gglwe_s0s1: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s0s1_infos);
209 let mut gglwe_s1s2: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s1s2_infos);
210
211 let mut source_xs: Source = Source::new([0u8; 32]);
212 let mut source_xe: Source = Source::new([0u8; 32]);
213 let mut source_xa: Source = Source::new([0u8; 32]);
214
215 let mut scratch_enc: ScratchOwned<BE> = ScratchOwned::alloc(
216 GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s0s1_infos)
217 | GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s1s2_infos),
218 );
219 let mut scratch_apply: ScratchOwned<BE> = ScratchOwned::alloc(GLWESwitchingKey::keyswitch_tmp_bytes(
220 module,
221 &gglwe_s0s1_infos,
222 &gglwe_s0s1_infos,
223 &gglwe_s1s2_infos,
224 ));
225
226 let var_xs: f64 = 0.5;
227
228 let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into());
229 sk0.fill_ternary_prob(var_xs, &mut source_xs);
230
231 let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into());
232 sk1.fill_ternary_prob(var_xs, &mut source_xs);
233
234 let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into());
235 sk2.fill_ternary_prob(var_xs, &mut source_xs);
236
237 let mut sk2_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into());
238 sk2_prepared.prepare(module, &sk2);
239
240 // gglwe_{s1}(s0) = s0 -> s1
241 gglwe_s0s1.encrypt_sk(
242 module,
243 &sk0,
244 &sk1,
245 &mut source_xa,
246 &mut source_xe,
247 scratch_enc.borrow(),
248 );
249
250 // gglwe_{s2}(s1) -> s1 -> s2
251 gglwe_s1s2.encrypt_sk(
252 module,
253 &sk1,
254 &sk2,
255 &mut source_xa,
256 &mut source_xe,
257 scratch_enc.borrow(),
258 );
259
260 let mut gglwe_s1s2_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> =
261 GLWESwitchingKeyPrepared::alloc_from_infos(module, &gglwe_s1s2);
262 gglwe_s1s2_prepared.prepare(module, &gglwe_s1s2, scratch_apply.borrow());
263
264 // gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
265 gglwe_s0s1.keyswitch_inplace(module, &gglwe_s1s2_prepared, scratch_apply.borrow());
266
267 let gglwe_s0s2: GLWESwitchingKey<Vec<u8>> = gglwe_s0s1;
268
269 let max_noise: f64 = log2_std_noise_gglwe_product(
270 n as f64,
271 base2k * di,
272 var_xs,
273 var_xs,
274 0f64,
275 SIGMA * SIGMA,
276 0f64,
277 rank_out as f64,
278 k_out,
279 k_ksk,
280 );
281
282 gglwe_s0s2
283 .key
284 .assert_noise(module, &sk2_prepared, &sk0.data, max_noise + 0.5);
285 }
286 }
287 }
288}