poulpy/poulpy-core/src/tests/test_suite/keyswitch/glwe_ct.rs
poulpy-core/src/tests/test_suite/keyswitch/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 GLWEEncryptSk, GLWEKeyswitch, GLWENoise, GLWENormalize, GLWESwitchingKeyEncryptSk, ScratchTakeCore,
9 encryption::SIGMA,
10 layouts::{
11 GLWE, GLWELayout, GLWEPlaintext, GLWESecret, GLWESecretPreparedFactory, GLWESwitchingKey, GLWESwitchingKeyLayout,
12 GLWESwitchingKeyPreparedFactory, LWEInfos,
13 prepared::{GLWESecretPrepared, GLWESwitchingKeyPrepared},
14 },
15 var_noise_gglwe_product_v2,
16};
17
18#[allow(clippy::too_many_arguments)]
19pub fn test_glwe_keyswitch<BE: Backend>(module: &Module<BE>)
20where
21 Module<BE>: VecZnxFillUniform
22 + GLWESwitchingKeyEncryptSk<BE>
23 + GLWEEncryptSk<BE>
24 + GLWEKeyswitch<BE>
25 + GLWESecretPreparedFactory<BE>
26 + GLWESwitchingKeyPreparedFactory<BE>
27 + GLWENoise<BE>
28 + GLWENormalize<BE>,
29 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
30 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
31{
32 let base2k_in: usize = 17;
33 let base2k_key: usize = 13;
34 let base2k_out: usize = 15;
35 let k_in: usize = 102;
36 let max_dsize: usize = k_in.div_ceil(base2k_key);
37
38 for rank_in in 1_usize..3 {
39 for rank_out in 1_usize..3 {
40 for dsize in 1_usize..max_dsize + 1 {
41 let k_ksk: usize = k_in + base2k_key * dsize;
42 let k_out: usize = k_ksk; // better capture noise
43
44 let n: usize = module.n();
45 let dnum: usize = k_in.div_ceil(base2k_key * dsize);
46
47 let glwe_in_infos: GLWELayout = GLWELayout {
48 n: n.into(),
49 base2k: base2k_in.into(),
50 k: k_in.into(),
51 rank: rank_in.into(),
52 };
53
54 let glwe_out_infos: GLWELayout = GLWELayout {
55 n: n.into(),
56 base2k: base2k_out.into(),
57 k: k_out.into(),
58 rank: rank_out.into(),
59 };
60
61 let ksk: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
62 n: n.into(),
63 base2k: base2k_key.into(),
64 k: k_ksk.into(),
65 dnum: dnum.into(),
66 dsize: dsize.into(),
67 rank_in: rank_in.into(),
68 rank_out: rank_out.into(),
69 };
70
71 let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&ksk);
72 let mut glwe_in: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_in_infos);
73 let mut glwe_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos);
74 let mut pt_in: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_in_infos);
75 let mut pt_out: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_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 module.vec_znx_fill_uniform(pt_in.base2k().into(), &mut pt_in.data, 0, &mut source_xa);
82
83 let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
84 GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &ksk)
85 | GLWE::encrypt_sk_tmp_bytes(module, &glwe_in_infos)
86 | GLWE::keyswitch_tmp_bytes(module, &glwe_out_infos, &glwe_in_infos, &ksk),
87 );
88
89 let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into());
90 sk_in.fill_ternary_prob(0.5, &mut source_xs);
91
92 let mut sk_in_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_in.into());
93 sk_in_prepared.prepare(module, &sk_in);
94
95 let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into());
96 sk_out.fill_ternary_prob(0.5, &mut source_xs);
97
98 let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into());
99 sk_out_prepared.prepare(module, &sk_out);
100
101 ksk.encrypt_sk(
102 module,
103 &sk_in,
104 &sk_out,
105 &mut source_xa,
106 &mut source_xe,
107 scratch.borrow(),
108 );
109
110 glwe_in.encrypt_sk(
111 module,
112 &pt_in,
113 &sk_in_prepared,
114 &mut source_xa,
115 &mut source_xe,
116 scratch.borrow(),
117 );
118
119 let mut ksk_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> =
120 GLWESwitchingKeyPrepared::alloc_from_infos(module, &ksk);
121 ksk_prepared.prepare(module, &ksk, scratch.borrow());
122
123 glwe_out.keyswitch(module, &glwe_in, &ksk_prepared, scratch.borrow());
124
125 let max_noise: f64 = var_noise_gglwe_product_v2(
126 module.n() as f64,
127 k_ksk,
128 dnum,
129 dsize,
130 base2k_key,
131 0.5,
132 0.5,
133 0f64,
134 SIGMA * SIGMA,
135 0f64,
136 rank_in as f64,
137 )
138 .sqrt()
139 .log2();
140
141 module.glwe_normalize(&mut pt_out, &pt_in, scratch.borrow());
142
143 glwe_out.assert_noise(module, &sk_out_prepared, &pt_out, max_noise + 0.5);
144 }
145 }
146 }
147}
148
149pub fn test_glwe_keyswitch_inplace<BE: Backend>(module: &Module<BE>)
150where
151 Module<BE>: VecZnxFillUniform
152 + GLWESwitchingKeyEncryptSk<BE>
153 + GLWEEncryptSk<BE>
154 + GLWEKeyswitch<BE>
155 + GLWESecretPreparedFactory<BE>
156 + GLWESwitchingKeyPreparedFactory<BE>
157 + GLWENoise<BE>,
158 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
159 Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
160{
161 let base2k_out: usize = 17;
162 let base2k_key: usize = 13;
163
164 let k_out: usize = 102;
165 let max_dsize: usize = k_out.div_ceil(base2k_key);
166
167 for rank in 1_usize..3 {
168 for dsize in 1..max_dsize + 1 {
169 let k_ksk: usize = k_out + base2k_key * dsize;
170
171 let n: usize = module.n();
172 let dnum: usize = k_out.div_ceil(base2k_key * dsize);
173 let glwe_out_infos: GLWELayout = GLWELayout {
174 n: n.into(),
175 base2k: base2k_out.into(),
176 k: k_out.into(),
177 rank: rank.into(),
178 };
179
180 let ksk_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
181 n: n.into(),
182 base2k: base2k_key.into(),
183 k: k_ksk.into(),
184 dnum: dnum.into(),
185 dsize: dsize.into(),
186 rank_in: rank.into(),
187 rank_out: rank.into(),
188 };
189
190 let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&ksk_infos);
191 let mut glwe_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos);
192 let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_infos);
193
194 let mut source_xs: Source = Source::new([0u8; 32]);
195 let mut source_xe: Source = Source::new([0u8; 32]);
196 let mut source_xa: Source = Source::new([0u8; 32]);
197
198 module.vec_znx_fill_uniform(
199 pt_want.base2k().into(),
200 &mut pt_want.data,
201 0,
202 &mut source_xa,
203 );
204
205 let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
206 GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &ksk_infos)
207 | GLWE::encrypt_sk_tmp_bytes(module, &glwe_out_infos)
208 | GLWE::keyswitch_tmp_bytes(module, &glwe_out_infos, &glwe_out_infos, &ksk_infos),
209 );
210
211 let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into());
212 sk_in.fill_ternary_prob(0.5, &mut source_xs);
213
214 let mut sk_in_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into());
215 sk_in_prepared.prepare(module, &sk_in);
216
217 let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into());
218 sk_out.fill_ternary_prob(0.5, &mut source_xs);
219
220 let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into());
221 sk_out_prepared.prepare(module, &sk_out);
222
223 ksk.encrypt_sk(
224 module,
225 &sk_in,
226 &sk_out,
227 &mut source_xa,
228 &mut source_xe,
229 scratch.borrow(),
230 );
231
232 glwe_out.encrypt_sk(
233 module,
234 &pt_want,
235 &sk_in_prepared,
236 &mut source_xa,
237 &mut source_xe,
238 scratch.borrow(),
239 );
240
241 let mut ksk_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> =
242 GLWESwitchingKeyPrepared::alloc_from_infos(module, &ksk);
243 ksk_prepared.prepare(module, &ksk, scratch.borrow());
244
245 glwe_out.keyswitch_inplace(module, &ksk_prepared, scratch.borrow());
246
247 let max_noise: f64 = var_noise_gglwe_product_v2(
248 module.n() as f64,
249 k_ksk,
250 dnum,
251 dsize,
252 base2k_key,
253 0.5,
254 0.5,
255 0f64,
256 SIGMA * SIGMA,
257 0f64,
258 rank as f64,
259 )
260 .sqrt()
261 .log2();
262
263 glwe_out.assert_noise(module, &sk_out_prepared, &pt_want, max_noise + 0.5);
264 }
265 }
266}