arnaucube
arnaucube/poulpyPublic Self-hosted repository
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},
  3    layouts::{Backend, Module, Scratch, ScratchOwned},
  4    source::Source,
  5};
  6
  7use crate::{
  8    ScratchTakeCore,
  9    encryption::SIGMA,
 10    layouts::{
 11        GLWE, GLWELayout, GLWEPlaintext, GLWESecret, GLWESwitchingKey, GLWESwitchingKeyLayout,
 12        prepared::{GLWESecretPrepared, GLWESwitchingKeyPrepared},
 13    },
 14    noise::log2_std_noise_gglwe_product,
 15};
 16
 17#[allow(clippy::too_many_arguments)]
 18pub fn test_glwe_keyswitch<BE: Backend>(module: &Module<BE>)
 19where
 20    Module<BE>:,
 21    ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
 22    Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
 23{
 24    let base2k: usize = 12;
 25    let k_in: usize = 45;
 26    let dsize: usize = k_in.div_ceil(base2k);
 27
 28    for rank_in in 1_usize..3 {
 29        for rank_out in 1_usize..3 {
 30            for di in 1_usize..dsize + 1 {
 31                let k_ksk: usize = k_in + base2k * di;
 32                let k_out: usize = k_ksk; // better capture noise
 33
 34                let n: usize = module.n();
 35                let dnum: usize = k_in.div_ceil(base2k * dsize);
 36
 37                let glwe_in_infos: GLWELayout = GLWELayout {
 38                    n: n.into(),
 39                    base2k: base2k.into(),
 40                    k: k_in.into(),
 41                    rank: rank_in.into(),
 42                };
 43
 44                let glwe_out_infos: GLWELayout = GLWELayout {
 45                    n: n.into(),
 46                    base2k: base2k.into(),
 47                    k: k_out.into(),
 48                    rank: rank_out.into(),
 49                };
 50
 51                let key_apply: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
 52                    n: n.into(),
 53                    base2k: base2k.into(),
 54                    k: k_ksk.into(),
 55                    dnum: dnum.into(),
 56                    dsize: di.into(),
 57                    rank_in: rank_in.into(),
 58                    rank_out: rank_out.into(),
 59                };
 60
 61                let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&key_apply);
 62                let mut glwe_in: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_in_infos);
 63                let mut glwe_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos);
 64                let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_in_infos);
 65
 66                let mut source_xs: Source = Source::new([0u8; 32]);
 67                let mut source_xe: Source = Source::new([0u8; 32]);
 68                let mut source_xa: Source = Source::new([0u8; 32]);
 69
 70                module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
 71
 72                let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
 73                    GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &key_apply)
 74                        | GLWE::encrypt_sk_tmp_bytes(module, &glwe_in_infos)
 75                        | GLWE::keyswitch_tmp_bytes(module, &glwe_out_infos, &glwe_in_infos, &key_apply),
 76                );
 77
 78                let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into());
 79                sk_in.fill_ternary_prob(0.5, &mut source_xs);
 80                let sk_in_prepared: GLWESecretPrepared<Vec<u8>, BE> = sk_in.prepare_alloc(module, scratch.borrow());
 81
 82                let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into());
 83                sk_out.fill_ternary_prob(0.5, &mut source_xs);
 84                let sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = sk_out.prepare_alloc(module, scratch.borrow());
 85
 86                ksk.encrypt_sk(
 87                    module,
 88                    &sk_in,
 89                    &sk_out,
 90                    &mut source_xa,
 91                    &mut source_xe,
 92                    scratch.borrow(),
 93                );
 94
 95                glwe_in.encrypt_sk(
 96                    module,
 97                    &pt_want,
 98                    &sk_in_prepared,
 99                    &mut source_xa,
100                    &mut source_xe,
101                    scratch.borrow(),
102                );
103
104                let ksk_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> = ksk.prepare_alloc(module, scratch.borrow());
105
106                glwe_out.keyswitch(module, &glwe_in, &ksk_prepared, scratch.borrow());
107
108                let max_noise: f64 = log2_std_noise_gglwe_product(
109                    module.n() as f64,
110                    base2k * dsize,
111                    0.5,
112                    0.5,
113                    0f64,
114                    SIGMA * SIGMA,
115                    0f64,
116                    rank_in as f64,
117                    k_in,
118                    k_ksk,
119                );
120
121                glwe_out.assert_noise(module, &sk_out_prepared, &pt_want, max_noise + 0.5);
122            }
123        }
124    }
125}
126
127pub fn test_glwe_keyswitch_inplace<BE: Backend>(module: &Module<BE>)
128where
129    Module<BE>:,
130    ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
131    Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
132{
133    let base2k: usize = 12;
134    let k_out: usize = 45;
135    let dsize: usize = k_out.div_ceil(base2k);
136
137    for rank in 1_usize..3 {
138        for di in 1..dsize + 1 {
139            let k_ksk: usize = k_out + base2k * di;
140
141            let n: usize = module.n();
142            let dnum: usize = k_out.div_ceil(base2k * dsize);
143
144            let glwe_out_infos: GLWELayout = GLWELayout {
145                n: n.into(),
146                base2k: base2k.into(),
147                k: k_out.into(),
148                rank: rank.into(),
149            };
150
151            let key_apply_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
152                n: n.into(),
153                base2k: base2k.into(),
154                k: k_ksk.into(),
155                dnum: dnum.into(),
156                dsize: di.into(),
157                rank_in: rank.into(),
158                rank_out: rank.into(),
159            };
160
161            let mut key_apply: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&key_apply_infos);
162            let mut glwe_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos);
163            let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_infos);
164
165            let mut source_xs: Source = Source::new([0u8; 32]);
166            let mut source_xe: Source = Source::new([0u8; 32]);
167            let mut source_xa: Source = Source::new([0u8; 32]);
168
169            module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
170
171            let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
172                GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &key_apply_infos)
173                    | GLWE::encrypt_sk_tmp_bytes(module, &glwe_out_infos)
174                    | GLWE::keyswitch_inplace_tmp_bytes(module, &glwe_out_infos, &key_apply_infos),
175            );
176
177            let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into());
178            sk_in.fill_ternary_prob(0.5, &mut source_xs);
179            let sk_in_prepared: GLWESecretPrepared<Vec<u8>, BE> = sk_in.prepare_alloc(module, scratch.borrow());
180
181            let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into());
182            sk_out.fill_ternary_prob(0.5, &mut source_xs);
183            let sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = sk_out.prepare_alloc(module, scratch.borrow());
184
185            key_apply.encrypt_sk(
186                module,
187                &sk_in,
188                &sk_out,
189                &mut source_xa,
190                &mut source_xe,
191                scratch.borrow(),
192            );
193
194            glwe_out.encrypt_sk(
195                module,
196                &pt_want,
197                &sk_in_prepared,
198                &mut source_xa,
199                &mut source_xe,
200                scratch.borrow(),
201            );
202
203            let ksk_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> = key_apply.prepare_alloc(module, scratch.borrow());
204
205            glwe_out.keyswitch_inplace(module, &ksk_prepared, scratch.borrow());
206
207            let max_noise: f64 = log2_std_noise_gglwe_product(
208                module.n() as f64,
209                base2k * dsize,
210                0.5,
211                0.5,
212                0f64,
213                SIGMA * SIGMA,
214                0f64,
215                rank as f64,
216                k_out,
217                k_ksk,
218            );
219
220            glwe_out.assert_noise(module, &sk_out_prepared, &pt_want, max_noise + 0.5);
221        }
222    }
223}