arnaucube
arnaucube/poulpyPublic Self-hosted repository
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, GLWESecretPreparedFactory, GLWESwitchingKey, GLWESwitchingKeyLayout, GLWESwitchingKeyPreparedFactory,
 12        prepared::{GLWESecretPrepared, GLWESwitchingKeyPrepared},
 13    },
 14    noise::log2_std_noise_gglwe_product,
 15    var_noise_gglwe_product_v2,
 16};
 17
 18pub fn test_gglwe_switching_key_keyswitch<BE: Backend>(module: &Module<BE>)
 19where
 20    Module<BE>: GLWESwitchingKeyEncryptSk<BE>
 21        + GGLWEKeyswitch<BE>
 22        + GLWESwitchingKeyPreparedFactory<BE>
 23        + GLWESecretPreparedFactory<BE>
 24        + GGLWENoise<BE>,
 25    ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
 26    Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
 27{
 28    let base2k_in: usize = 17;
 29    let base2k_key: usize = 13;
 30    let base2k_out: usize = base2k_in; // MUST BE SAME
 31    let k_in: usize = 102;
 32    let max_dsize: usize = k_in.div_ceil(base2k_key);
 33
 34    for rank_in_s0s1 in 1_usize..2 {
 35        for rank_out_s0s1 in 1_usize..3 {
 36            for rank_out_s1s2 in 1_usize..3 {
 37                for dsize in 1_usize..max_dsize + 1 {
 38                    let k_ksk: usize = k_in + base2k_key * dsize;
 39                    let k_out: usize = k_ksk; // Better capture noise.
 40
 41                    let n: usize = module.n();
 42                    let dsize_in: usize = 1;
 43                    let dnum_in: usize = k_in / base2k_in;
 44                    let dnum_ksk: usize = k_in.div_ceil(base2k_key * dsize);
 45
 46                    let gglwe_s0s1_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
 47                        n: n.into(),
 48                        base2k: base2k_in.into(),
 49                        k: k_in.into(),
 50                        dnum: dnum_in.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_key.into(),
 59                        k: k_ksk.into(),
 60                        dnum: dnum_ksk.into(),
 61                        dsize: dsize.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_out.into(),
 69                        k: k_out.into(),
 70                        dnum: dnum_in.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_s0s2_infos,
 92                        &gglwe_s0s1_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 = var_noise_gglwe_product_v2(
142                        module.n() as f64,
143                        k_ksk,
144                        dnum_ksk,
145                        dsize,
146                        base2k_key,
147                        0.5,
148                        0.5,
149                        0f64,
150                        SIGMA * SIGMA,
151                        0f64,
152                        rank_out_s0s1 as f64,
153                    )
154                    .sqrt()
155                    .log2();
156
157                    gglwe_s0s2
158                        .key
159                        .assert_noise(module, &sk2_prepared, &sk0.data, max_noise + 0.5);
160                }
161            }
162        }
163    }
164}
165
166#[allow(clippy::too_many_arguments)]
167pub fn test_gglwe_switching_key_keyswitch_inplace<BE: Backend>(module: &Module<BE>)
168where
169    Module<BE>: GLWESwitchingKeyEncryptSk<BE>
170        + GGLWEKeyswitch<BE>
171        + GLWESecretPreparedFactory<BE>
172        + GGLWENoise<BE>
173        + GLWESwitchingKeyPreparedFactory<BE>,
174    ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
175    Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
176{
177    let base2k_out: usize = 17;
178    let base2k_key: usize = 13;
179    let k_out: usize = 102;
180    let max_dsize: usize = k_out.div_ceil(base2k_key);
181
182    for rank_in in 1_usize..3 {
183        for rank_out in 1_usize..3 {
184            for dsize in 1_usize..max_dsize + 1 {
185                let k_ksk: usize = k_out + base2k_key * dsize;
186
187                let n: usize = module.n();
188                let dsize_in: usize = 1;
189
190                let dnum_in: usize = k_out / base2k_out;
191                let dnum_ksk: usize = k_out.div_ceil(base2k_key * dsize);
192
193                let gglwe_s0s1_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
194                    n: n.into(),
195                    base2k: base2k_out.into(),
196                    k: k_out.into(),
197                    dnum: dnum_in.into(),
198                    dsize: dsize_in.into(),
199                    rank_in: rank_in.into(),
200                    rank_out: rank_out.into(),
201                };
202
203                let gglwe_s1s2_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
204                    n: n.into(),
205                    base2k: base2k_key.into(),
206                    k: k_ksk.into(),
207                    dnum: dnum_ksk.into(),
208                    dsize: dsize.into(),
209                    rank_in: rank_out.into(),
210                    rank_out: rank_out.into(),
211                };
212
213                let mut gglwe_s0s1: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s0s1_infos);
214                let mut gglwe_s1s2: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s1s2_infos);
215
216                let mut source_xs: Source = Source::new([0u8; 32]);
217                let mut source_xe: Source = Source::new([0u8; 32]);
218                let mut source_xa: Source = Source::new([0u8; 32]);
219
220                let mut scratch_enc: ScratchOwned<BE> = ScratchOwned::alloc(
221                    GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s0s1_infos)
222                        | GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s1s2_infos),
223                );
224                let mut scratch_apply: ScratchOwned<BE> = ScratchOwned::alloc(GLWESwitchingKey::keyswitch_tmp_bytes(
225                    module,
226                    &gglwe_s0s1_infos,
227                    &gglwe_s0s1_infos,
228                    &gglwe_s1s2_infos,
229                ));
230
231                let var_xs: f64 = 0.5;
232
233                let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into());
234                sk0.fill_ternary_prob(var_xs, &mut source_xs);
235
236                let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into());
237                sk1.fill_ternary_prob(var_xs, &mut source_xs);
238
239                let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into());
240                sk2.fill_ternary_prob(var_xs, &mut source_xs);
241
242                let mut sk2_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into());
243                sk2_prepared.prepare(module, &sk2);
244
245                // gglwe_{s1}(s0) = s0 -> s1
246                gglwe_s0s1.encrypt_sk(
247                    module,
248                    &sk0,
249                    &sk1,
250                    &mut source_xa,
251                    &mut source_xe,
252                    scratch_enc.borrow(),
253                );
254
255                // gglwe_{s2}(s1) -> s1 -> s2
256                gglwe_s1s2.encrypt_sk(
257                    module,
258                    &sk1,
259                    &sk2,
260                    &mut source_xa,
261                    &mut source_xe,
262                    scratch_enc.borrow(),
263                );
264
265                let mut gglwe_s1s2_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> =
266                    GLWESwitchingKeyPrepared::alloc_from_infos(module, &gglwe_s1s2);
267                gglwe_s1s2_prepared.prepare(module, &gglwe_s1s2, scratch_apply.borrow());
268
269                // gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
270                gglwe_s0s1.keyswitch_inplace(module, &gglwe_s1s2_prepared, scratch_apply.borrow());
271
272                let gglwe_s0s2: GLWESwitchingKey<Vec<u8>> = gglwe_s0s1;
273
274                let max_noise: f64 = log2_std_noise_gglwe_product(
275                    n as f64,
276                    base2k_key * dsize,
277                    var_xs,
278                    var_xs,
279                    0f64,
280                    SIGMA * SIGMA,
281                    0f64,
282                    rank_out as f64,
283                    k_out,
284                    k_ksk,
285                );
286
287                gglwe_s0s2
288                    .key
289                    .assert_noise(module, &sk2_prepared, &sk0.data, max_noise + 0.5);
290            }
291        }
292    }
293}