arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/tests/generics/keyswitch/glwe_ct.rs
core/src/tests/generics/keyswitch/glwe_ct.rsRaw
  1use backend::hal::{
  2    api::{
  3        ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxFillUniform, VecZnxStd, VecZnxSwithcDegree,
  4        VmpPMatAlloc, VmpPMatPrepare,
  5    },
  6    layouts::{Backend, Module, ScratchOwned},
  7    oep::{
  8        ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
  9        TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
 10    },
 11};
 12use sampling::source::Source;
 13
 14use crate::{
 15    layouts::{
 16        GLWECiphertext, GLWEPlaintext, GLWESecret, GGLWESwitchingKey, Infos,
 17        prepared::{GLWESecretExec, GGLWESwitchingKeyExec},
 18    },
 19    noise::log2_std_noise_gglwe_product,
 20    trait_families::{GLWEDecryptFamily, GLWEKeyswitchFamily},
 21};
 22
 23use crate::trait_families::{GGLWESwitchingKeyEncryptSkFamily, GLWESecretExecModuleFamily};
 24
 25pub fn test_glwe_keyswitch<B: Backend>(
 26    module: &Module<B>,
 27    basek: usize,
 28    k_out: usize,
 29    k_in: usize,
 30    k_ksk: usize,
 31    digits: usize,
 32    rank_in: usize,
 33    rank_out: usize,
 34    sigma: f64,
 35) where
 36    Module<B>: GGLWESwitchingKeyEncryptSkFamily<B>
 37        + GLWESecretExecModuleFamily<B>
 38        + GLWEKeyswitchFamily<B>
 39        + GLWEDecryptFamily<B>
 40        + VecZnxStd
 41        + VecZnxSwithcDegree
 42        + VecZnxAddScalarInplace
 43        + VmpPMatAlloc<B>
 44        + VmpPMatPrepare<B>,
 45    B: TakeVecZnxDftImpl<B>
 46        + TakeVecZnxBigImpl<B>
 47        + TakeSvpPPolImpl<B>
 48        + ScratchOwnedAllocImpl<B>
 49        + ScratchOwnedBorrowImpl<B>
 50        + ScratchAvailableImpl<B>
 51        + TakeScalarZnxImpl<B>
 52        + TakeVecZnxImpl<B>,
 53{
 54    let n = module.n();
 55    let rows: usize = k_in.div_ceil(basek * digits);
 56
 57    let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(n, basek, k_ksk, rows, digits, rank_in, rank_out);
 58    let mut ct_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_in, rank_in);
 59    let mut ct_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_out, rank_out);
 60    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_in);
 61
 62    let mut source_xs: Source = Source::new([0u8; 32]);
 63    let mut source_xe: Source = Source::new([0u8; 32]);
 64    let mut source_xa: Source = Source::new([0u8; 32]);
 65
 66    module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_in, &mut source_xa);
 67
 68    let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
 69        GGLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, ksk.k(), rank_in, rank_out)
 70            | GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, ct_in.k())
 71            | GLWECiphertext::keyswitch_scratch_space(
 72                module,
 73                n,
 74                basek,
 75                ct_out.k(),
 76                ct_in.k(),
 77                ksk.k(),
 78                digits,
 79                rank_in,
 80                rank_out,
 81            ),
 82    );
 83
 84    let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_in);
 85    sk_in.fill_ternary_prob(0.5, &mut source_xs);
 86    let sk_in_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_in);
 87
 88    let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_out);
 89    sk_out.fill_ternary_prob(0.5, &mut source_xs);
 90    let sk_out_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_out);
 91
 92    ksk.encrypt_sk(
 93        module,
 94        &sk_in,
 95        &sk_out,
 96        &mut source_xa,
 97        &mut source_xe,
 98        sigma,
 99        scratch.borrow(),
100    );
101
102    ct_in.encrypt_sk(
103        module,
104        &pt_want,
105        &sk_in_exec,
106        &mut source_xa,
107        &mut source_xe,
108        sigma,
109        scratch.borrow(),
110    );
111
112    let ksk_exec: GGLWESwitchingKeyExec<Vec<u8>, B> = GGLWESwitchingKeyExec::from(module, &ksk, scratch.borrow());
113
114    ct_out.keyswitch(module, &ct_in, &ksk_exec, scratch.borrow());
115
116    let max_noise: f64 = log2_std_noise_gglwe_product(
117        module.n() as f64,
118        basek * digits,
119        0.5,
120        0.5,
121        0f64,
122        sigma * sigma,
123        0f64,
124        rank_in as f64,
125        k_in,
126        k_ksk,
127    );
128
129    ct_out.assert_noise(module, &sk_out_exec, &pt_want, max_noise + 0.5);
130}
131
132pub fn test_glwe_keyswitch_inplace<B: Backend>(
133    module: &Module<B>,
134    basek: usize,
135    k_ct: usize,
136    k_ksk: usize,
137    digits: usize,
138    rank: usize,
139    sigma: f64,
140) where
141    Module<B>: GGLWESwitchingKeyEncryptSkFamily<B>
142        + GLWESecretExecModuleFamily<B>
143        + GLWEKeyswitchFamily<B>
144        + GLWEDecryptFamily<B>
145        + VecZnxStd
146        + VecZnxSwithcDegree
147        + VecZnxAddScalarInplace
148        + VmpPMatAlloc<B>
149        + VmpPMatPrepare<B>,
150    B: TakeVecZnxDftImpl<B>
151        + TakeVecZnxBigImpl<B>
152        + TakeSvpPPolImpl<B>
153        + ScratchOwnedAllocImpl<B>
154        + ScratchOwnedBorrowImpl<B>
155        + ScratchAvailableImpl<B>
156        + TakeScalarZnxImpl<B>
157        + TakeVecZnxImpl<B>,
158{
159    let n: usize = module.n();
160    let rows: usize = k_ct.div_ceil(basek * digits);
161
162    let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(n, basek, k_ksk, rows, digits, rank, rank);
163    let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
164    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
165
166    let mut source_xs: Source = Source::new([0u8; 32]);
167    let mut source_xe: Source = Source::new([0u8; 32]);
168    let mut source_xa: Source = Source::new([0u8; 32]);
169
170    module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, k_ct, &mut source_xa);
171
172    let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
173        GGLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, ksk.k(), rank, rank)
174            | GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, ct_glwe.k())
175            | GLWECiphertext::keyswitch_inplace_scratch_space(module, n, basek, ct_glwe.k(), ksk.k(), digits, rank),
176    );
177
178    let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
179    sk_in.fill_ternary_prob(0.5, &mut source_xs);
180    let sk_in_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_in);
181
182    let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
183    sk_out.fill_ternary_prob(0.5, &mut source_xs);
184    let sk_out_exec: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_out);
185
186    ksk.encrypt_sk(
187        module,
188        &sk_in,
189        &sk_out,
190        &mut source_xa,
191        &mut source_xe,
192        sigma,
193        scratch.borrow(),
194    );
195
196    ct_glwe.encrypt_sk(
197        module,
198        &pt_want,
199        &sk_in_exec,
200        &mut source_xa,
201        &mut source_xe,
202        sigma,
203        scratch.borrow(),
204    );
205
206    let ksk_exec: GGLWESwitchingKeyExec<Vec<u8>, B> = GGLWESwitchingKeyExec::from(module, &ksk, scratch.borrow());
207
208    ct_glwe.keyswitch_inplace(module, &ksk_exec, scratch.borrow());
209
210    let max_noise: f64 = log2_std_noise_gglwe_product(
211        module.n() as f64,
212        basek * digits,
213        0.5,
214        0.5,
215        0f64,
216        sigma * sigma,
217        0f64,
218        rank as f64,
219        k_ct,
220        k_ksk,
221    );
222
223    ct_glwe.assert_noise(module, &sk_out_exec, &pt_want, max_noise + 0.5);
224}