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