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