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