arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/keyswitch_key.rs
core/src/keyswitch_key.rsRaw
  1use base2k::{
  2    Backend, FFT64, MatZnxDft, MatZnxDftAlloc, MatZnxDftOps, MatZnxDftScratch, MatZnxDftToMut, MatZnxDftToRef, Module, ScalarZnx,
  3    ScalarZnxDft, ScalarZnxDftToRef, ScalarZnxToRef, Scratch, VecZnx, VecZnxAlloc, VecZnxBig, VecZnxBigOps, VecZnxBigScratch,
  4    VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxDftToMut, VecZnxDftToRef, VecZnxOps, VecZnxToMut, VecZnxToRef, ZnxInfos,
  5    ZnxZero,
  6};
  7use sampling::source::Source;
  8
  9use crate::{
 10    elem::{GetRow, Infos, SetRow},
 11    encryption::EncryptSkScratchSpace,
 12    external_product::{
 13        ExternalProduct, ExternalProductInplace, ExternalProductInplaceScratchSpace, ExternalProductScratchSpace,
 14    },
 15    ggsw::GGSWCiphertext,
 16    glwe::{GLWECiphertext, GLWECiphertextFourier, GLWEPlaintext},
 17    keys::SecretKeyFourier,
 18    keyswitch::{KeySwitch, KeySwitchInplace, KeySwitchInplaceScratchSpace, KeySwitchScratchSpace},
 19    utils::derive_size,
 20    vec_glwe_product::{VecGLWEProduct, VecGLWEProductScratchSpace},
 21};
 22
 23pub struct GLWEKeySwitchKey<C, B: Backend> {
 24    pub data: MatZnxDft<C, B>,
 25    pub log_base2k: usize,
 26    pub log_k: usize,
 27}
 28
 29impl<B: Backend> GLWEKeySwitchKey<Vec<u8>, B> {
 30    pub fn new(module: &Module<B>, log_base2k: usize, log_k: usize, rows: usize) -> Self {
 31        Self {
 32            data: module.new_mat_znx_dft(rows, 1, 2, derive_size(log_base2k, log_k)),
 33            log_base2k: log_base2k,
 34            log_k: log_k,
 35        }
 36    }
 37}
 38
 39impl<T, B: Backend> Infos for GLWEKeySwitchKey<T, B> {
 40    type Inner = MatZnxDft<T, B>;
 41
 42    fn inner(&self) -> &Self::Inner {
 43        &self.data
 44    }
 45
 46    fn basek(&self) -> usize {
 47        self.log_base2k
 48    }
 49
 50    fn k(&self) -> usize {
 51        self.log_k
 52    }
 53}
 54
 55impl<C, B: Backend> MatZnxDftToMut<B> for GLWEKeySwitchKey<C, B>
 56where
 57    MatZnxDft<C, B>: MatZnxDftToMut<B>,
 58{
 59    fn to_mut(&mut self) -> MatZnxDft<&mut [u8], B> {
 60        self.data.to_mut()
 61    }
 62}
 63
 64impl<C, B: Backend> MatZnxDftToRef<B> for GLWEKeySwitchKey<C, B>
 65where
 66    MatZnxDft<C, B>: MatZnxDftToRef<B>,
 67{
 68    fn to_ref(&self) -> MatZnxDft<&[u8], B> {
 69        self.data.to_ref()
 70    }
 71}
 72
 73impl GLWEKeySwitchKey<Vec<u8>, FFT64> {
 74    pub fn encrypt_sk_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
 75        GLWECiphertext::encrypt_sk_scratch_space(module, size)
 76            + module.bytes_of_vec_znx(2, size)
 77            + module.bytes_of_vec_znx(1, size)
 78            + module.bytes_of_vec_znx_dft(2, size)
 79    }
 80}
 81
 82pub fn encrypt_glwe_key_switch_key_sk<C, P, S>(
 83    module: &Module<FFT64>,
 84    ct: &mut GLWEKeySwitchKey<C, FFT64>,
 85    pt: &ScalarZnx<P>,
 86    sk_dft: &SecretKeyFourier<S, FFT64>,
 87    source_xa: &mut Source,
 88    source_xe: &mut Source,
 89    sigma: f64,
 90    bound: f64,
 91    scratch: &mut Scratch,
 92) where
 93    MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
 94    ScalarZnx<P>: ScalarZnxToRef,
 95    ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
 96{
 97    let rows: usize = ct.rows();
 98    let size: usize = ct.size();
 99    let log_base2k: usize = ct.basek();
100
101    let (tmp_znx_pt, scrach_1) = scratch.tmp_vec_znx(module, 1, size);
102    let (tmp_znx_ct, scrach_2) = scrach_1.tmp_vec_znx(module, 2, size);
103    let (mut vec_znx_dft_ct, scratch_3) = scrach_2.tmp_vec_znx_dft(module, 2, size);
104
105    let mut vec_znx_pt: GLWEPlaintext<&mut [u8]> = GLWEPlaintext {
106        data: tmp_znx_pt,
107        log_base2k: log_base2k,
108        log_k: ct.k(),
109    };
110
111    let mut vec_znx_ct: GLWECiphertext<&mut [u8]> = GLWECiphertext {
112        data: tmp_znx_ct,
113        log_base2k: log_base2k,
114        log_k: ct.k(),
115    };
116
117    (0..rows).for_each(|row_i| {
118        // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
119        module.vec_znx_add_scalar_inplace(&mut vec_znx_pt, 0, row_i, pt, 0);
120        module.vec_znx_normalize_inplace(log_base2k, &mut vec_znx_pt, 0, scratch_3);
121
122        // rlwe encrypt of vec_znx_pt into vec_znx_ct
123        vec_znx_ct.encrypt_sk(
124            module,
125            &vec_znx_pt,
126            sk_dft,
127            source_xa,
128            source_xe,
129            sigma,
130            bound,
131            scratch_3,
132        );
133
134        vec_znx_pt.data.zero(); // zeroes for next iteration
135
136        // Switch vec_znx_ct into DFT domain
137        module.vec_znx_dft(&mut vec_znx_dft_ct, 0, &vec_znx_ct, 0);
138        module.vec_znx_dft(&mut vec_znx_dft_ct, 1, &vec_znx_ct, 1);
139
140        // Stores vec_znx_dft_ct into thw i-th row of the MatZnxDft
141        module.vmp_prepare_row(ct, row_i, 0, &vec_znx_dft_ct);
142    });
143}
144
145impl<C> GLWEKeySwitchKey<C, FFT64> {
146    pub fn encrypt_sk<P, S>(
147        &mut self,
148        module: &Module<FFT64>,
149        pt: &ScalarZnx<P>,
150        sk_dft: &SecretKeyFourier<S, FFT64>,
151        source_xa: &mut Source,
152        source_xe: &mut Source,
153        sigma: f64,
154        bound: f64,
155        scratch: &mut Scratch,
156    ) where
157        MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
158        ScalarZnx<P>: ScalarZnxToRef,
159        ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
160    {
161        encrypt_glwe_key_switch_key_sk(
162            module, self, pt, sk_dft, source_xa, source_xe, sigma, bound, scratch,
163        )
164    }
165}
166
167impl<C> GetRow<FFT64> for GLWEKeySwitchKey<C, FFT64>
168where
169    MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>,
170{
171    fn get_row<R>(&self, module: &Module<FFT64>, row_i: usize, col_j: usize, res: &mut GLWECiphertextFourier<R, FFT64>)
172    where
173        VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64>,
174    {
175        #[cfg(debug_assertions)]
176        {
177            assert_eq!(col_j, 0);
178        }
179        module.vmp_extract_row(res, self, row_i, col_j);
180    }
181}
182
183impl<C> SetRow<FFT64> for GLWEKeySwitchKey<C, FFT64>
184where
185    MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
186{
187    fn set_row<R>(&mut self, module: &Module<FFT64>, row_i: usize, col_j: usize, a: &GLWECiphertextFourier<R, FFT64>)
188    where
189        VecZnxDft<R, FFT64>: VecZnxDftToRef<FFT64>,
190    {
191        #[cfg(debug_assertions)]
192        {
193            assert_eq!(col_j, 0);
194        }
195        module.vmp_prepare_row(self, row_i, col_j, a);
196    }
197}
198
199impl KeySwitchScratchSpace for GLWEKeySwitchKey<Vec<u8>, FFT64> {
200    fn keyswitch_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
201        <GLWEKeySwitchKey<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_vec_glwe_scratch_space(
202            module, res_size, lhs, rhs,
203        )
204    }
205}
206
207impl<DataSelf, DataLhs, DataRhs> KeySwitch<DataLhs, DataRhs> for GLWEKeySwitchKey<DataSelf, FFT64>
208where
209    MatZnxDft<DataSelf, FFT64>: MatZnxDftToMut<FFT64> + MatZnxDftToRef<FFT64>,
210    MatZnxDft<DataLhs, FFT64>: MatZnxDftToRef<FFT64>,
211    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64>,
212{
213    type Lhs = GLWEKeySwitchKey<DataLhs, FFT64>;
214    type Rhs = GLWEKeySwitchKey<DataRhs, FFT64>;
215
216    fn keyswitch(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &Self::Rhs, scratch: &mut Scratch) {
217        rhs.prod_with_vec_glwe(module, self, lhs, scratch);
218    }
219}
220
221impl KeySwitchInplaceScratchSpace for GLWEKeySwitchKey<Vec<u8>, FFT64> {
222    fn keyswitch_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, rhs: usize) -> usize {
223        <GLWEKeySwitchKey<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_vec_glwe_inplace_scratch_space(
224            module, res_size, rhs,
225        )
226    }
227}
228
229impl<DataSelf, DataRhs> KeySwitchInplace<DataRhs> for GLWEKeySwitchKey<DataSelf, FFT64>
230where
231    MatZnxDft<DataSelf, FFT64>: MatZnxDftToMut<FFT64> + MatZnxDftToRef<FFT64>,
232    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64>,
233{
234    type Rhs = GLWEKeySwitchKey<DataRhs, FFT64>;
235
236    fn keyswitch_inplace(&mut self, module: &Module<FFT64>, rhs: &Self::Rhs, scratch: &mut Scratch) {
237        rhs.prod_with_vec_glwe(module, self, rhs, scratch);
238    }
239}
240
241impl ExternalProductScratchSpace for GLWEKeySwitchKey<Vec<u8>, FFT64> {
242    fn external_product_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
243        <GGSWCiphertext<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_vec_glwe_scratch_space(
244            module, res_size, lhs, rhs,
245        )
246    }
247}
248
249impl<DataSelf, DataLhs, DataRhs> ExternalProduct<DataLhs, DataRhs> for GLWEKeySwitchKey<DataSelf, FFT64>
250where
251    MatZnxDft<DataSelf, FFT64>: MatZnxDftToMut<FFT64> + MatZnxDftToRef<FFT64>,
252    MatZnxDft<DataLhs, FFT64>: MatZnxDftToRef<FFT64>,
253    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64>,
254{
255    type Lhs = GLWEKeySwitchKey<DataLhs, FFT64>;
256    type Rhs = GGSWCiphertext<DataRhs, FFT64>;
257
258    fn external_product(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &Self::Rhs, scratch: &mut Scratch) {
259        rhs.prod_with_vec_glwe(module, self, lhs, scratch);
260    }
261}
262
263impl ExternalProductInplaceScratchSpace for GLWEKeySwitchKey<Vec<u8>, FFT64> {
264    fn external_product_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, rhs: usize) -> usize {
265        <GGSWCiphertext<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_inplace_scratch_space(
266            module, res_size, rhs,
267        )
268    }
269}
270
271impl<DataSelf, DataRhs> ExternalProductInplace<DataRhs> for GLWEKeySwitchKey<DataSelf, FFT64>
272where
273    MatZnxDft<DataSelf, FFT64>: MatZnxDftToMut<FFT64> + MatZnxDftToRef<FFT64>,
274    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64>,
275{
276    type Rhs = GGSWCiphertext<DataRhs, FFT64>;
277
278    fn external_product_inplace(&mut self, module: &Module<FFT64>, rhs: &Self::Rhs, scratch: &mut Scratch) {
279        rhs.prod_with_vec_glwe_inplace(module, self, scratch);
280    }
281}
282
283impl VecGLWEProductScratchSpace for GLWEKeySwitchKey<Vec<u8>, FFT64> {
284    fn prod_with_glwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
285        module.bytes_of_vec_znx_dft(2, grlwe_size)
286            + (module.vec_znx_big_normalize_tmp_bytes()
287                | (module.vmp_apply_tmp_bytes(res_size, a_size, a_size, 1, 2, grlwe_size)
288                    + module.bytes_of_vec_znx_dft(1, a_size)))
289    }
290}
291
292impl<C> VecGLWEProduct for GLWEKeySwitchKey<C, FFT64>
293where
294    MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
295{
296    fn prod_with_glwe<R, A>(
297        &self,
298        module: &Module<FFT64>,
299        res: &mut GLWECiphertext<R>,
300        a: &GLWECiphertext<A>,
301        scratch: &mut Scratch,
302    ) where
303        MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>,
304        VecZnx<R>: VecZnxToMut,
305        VecZnx<A>: VecZnxToRef,
306    {
307        let log_base2k: usize = self.basek();
308
309        #[cfg(debug_assertions)]
310        {
311            assert_eq!(res.basek(), log_base2k);
312            assert_eq!(a.basek(), log_base2k);
313            assert_eq!(self.n(), module.n());
314            assert_eq!(res.n(), module.n());
315            assert_eq!(a.n(), module.n());
316        }
317
318        let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, 2, self.size()); // Todo optimise
319
320        {
321            let (mut a1_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, 1, a.size());
322            module.vec_znx_dft(&mut a1_dft, 0, a, 1);
323            module.vmp_apply(&mut res_dft, &a1_dft, self, scratch2);
324        }
325
326        let mut res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(res_dft);
327
328        module.vec_znx_big_add_small_inplace(&mut res_big, 0, a, 0);
329
330        module.vec_znx_big_normalize(log_base2k, res, 0, &res_big, 0, scratch1);
331        module.vec_znx_big_normalize(log_base2k, res, 1, &res_big, 1, scratch1);
332    }
333}