arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/lwe/conversion.rs
core/src/lwe/conversion.rsRaw
  1use backend::hal::{
  2    api::{ScratchAvailable, TakeVecZnx, TakeVecZnxDft, ZnxView, ZnxViewMut, ZnxZero},
  3    layouts::{Backend, DataMut, DataRef, Module, Scratch},
  4};
  5
  6use crate::{
  7    GLWECiphertext, GLWEKeyswitchFamily, GLWEToLWESwitchingKeyExec, Infos, LWECiphertext, LWESwitchingKeyExec,
  8    LWEToGLWESwitchingKeyExec, TakeGLWECt,
  9};
 10
 11impl LWECiphertext<Vec<u8>> {
 12    pub fn from_glwe_scratch_space<B: Backend>(
 13        module: &Module<B>,
 14        n: usize,
 15        basek: usize,
 16        k_lwe: usize,
 17        k_glwe: usize,
 18        k_ksk: usize,
 19        rank: usize,
 20    ) -> usize
 21    where
 22        Module<B>: GLWEKeyswitchFamily<B>,
 23    {
 24        GLWECiphertext::bytes_of(n, basek, k_lwe, 1)
 25            + GLWECiphertext::keyswitch_scratch_space(module, n, basek, k_lwe, k_glwe, k_ksk, 1, rank, 1)
 26    }
 27
 28    pub fn keyswitch_scratch_space<B: Backend>(
 29        module: &Module<B>,
 30        n: usize,
 31        basek: usize,
 32        k_lwe_out: usize,
 33        k_lwe_in: usize,
 34        k_ksk: usize,
 35    ) -> usize
 36    where
 37        Module<B>: GLWEKeyswitchFamily<B>,
 38    {
 39        GLWECiphertext::bytes_of(n, basek, k_lwe_out.max(k_lwe_in), 1)
 40            + GLWECiphertext::keyswitch_inplace_scratch_space(module, n, basek, k_lwe_out, k_ksk, 1, 1)
 41    }
 42}
 43
 44impl<DLwe: DataMut> LWECiphertext<DLwe> {
 45    pub fn sample_extract<DGlwe: DataRef>(&mut self, a: &GLWECiphertext<DGlwe>) {
 46        #[cfg(debug_assertions)]
 47        {
 48            assert!(self.n() <= a.n());
 49        }
 50
 51        let min_size: usize = self.size().min(a.size());
 52        let n: usize = self.n();
 53
 54        self.data.zero();
 55        (0..min_size).for_each(|i| {
 56            let data_lwe: &mut [i64] = self.data.at_mut(0, i);
 57            data_lwe[0] = a.data.at(0, i)[0];
 58            data_lwe[1..].copy_from_slice(&a.data.at(1, i)[..n]);
 59        });
 60    }
 61
 62    pub fn from_glwe<DGlwe, DKs, B: Backend>(
 63        &mut self,
 64        module: &Module<B>,
 65        a: &GLWECiphertext<DGlwe>,
 66        ks: &GLWEToLWESwitchingKeyExec<DKs, B>,
 67        scratch: &mut Scratch<B>,
 68    ) where
 69        DGlwe: DataRef,
 70        DKs: DataRef,
 71        Module<B>: GLWEKeyswitchFamily<B>,
 72        Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx,
 73    {
 74        #[cfg(debug_assertions)]
 75        {
 76            assert_eq!(self.basek(), a.basek());
 77            assert_eq!(a.n(), ks.n());
 78        }
 79        let (mut tmp_glwe, scratch1) = scratch.take_glwe_ct(a.n(), a.basek(), self.k(), 1);
 80        tmp_glwe.keyswitch(module, a, &ks.0, scratch1);
 81        self.sample_extract(&tmp_glwe);
 82    }
 83
 84    pub fn keyswitch<A, DKs, B: Backend>(
 85        &mut self,
 86        module: &Module<B>,
 87        a: &LWECiphertext<A>,
 88        ksk: &LWESwitchingKeyExec<DKs, B>,
 89        scratch: &mut Scratch<B>,
 90    ) where
 91        A: DataRef,
 92        DKs: DataRef,
 93        Module<B>: GLWEKeyswitchFamily<B>,
 94        Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx,
 95    {
 96        #[cfg(debug_assertions)]
 97        {
 98            assert!(self.n() <= module.n());
 99            assert!(a.n() <= module.n());
100            assert_eq!(self.basek(), a.basek());
101        }
102
103        let max_k: usize = self.k().max(a.k());
104        let basek: usize = self.basek();
105
106        let (mut glwe, scratch1) = scratch.take_glwe_ct(ksk.n(), basek, max_k, 1);
107        glwe.data.zero();
108
109        let n_lwe: usize = a.n();
110
111        (0..a.size()).for_each(|i| {
112            let data_lwe: &[i64] = a.data.at(0, i);
113            glwe.data.at_mut(0, i)[0] = data_lwe[0];
114            glwe.data.at_mut(1, i)[..n_lwe].copy_from_slice(&data_lwe[1..]);
115        });
116
117        glwe.keyswitch_inplace(module, &ksk.0, scratch1);
118
119        self.sample_extract(&glwe);
120    }
121}
122
123impl GLWECiphertext<Vec<u8>> {
124    pub fn from_lwe_scratch_space<B: Backend>(
125        module: &Module<B>,
126        n: usize,
127        basek: usize,
128        k_lwe: usize,
129        k_glwe: usize,
130        k_ksk: usize,
131        rank: usize,
132    ) -> usize
133    where
134        Module<B>: GLWEKeyswitchFamily<B>,
135    {
136        GLWECiphertext::keyswitch_scratch_space(module, n, basek, k_glwe, k_lwe, k_ksk, 1, 1, rank)
137            + GLWECiphertext::bytes_of(n, basek, k_lwe, 1)
138    }
139}
140
141impl<D: DataMut> GLWECiphertext<D> {
142    pub fn from_lwe<DLwe, DKsk, B: Backend>(
143        &mut self,
144        module: &Module<B>,
145        lwe: &LWECiphertext<DLwe>,
146        ksk: &LWEToGLWESwitchingKeyExec<DKsk, B>,
147        scratch: &mut Scratch<B>,
148    ) where
149        DLwe: DataRef,
150        DKsk: DataRef,
151        Module<B>: GLWEKeyswitchFamily<B>,
152        Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx,
153    {
154        #[cfg(debug_assertions)]
155        {
156            assert!(lwe.n() <= self.n());
157            assert_eq!(self.basek(), self.basek());
158        }
159
160        let (mut glwe, scratch1) = scratch.take_glwe_ct(ksk.n(), lwe.basek(), lwe.k(), 1);
161        glwe.data.zero();
162
163        let n_lwe: usize = lwe.n();
164
165        (0..lwe.size()).for_each(|i| {
166            let data_lwe: &[i64] = lwe.data.at(0, i);
167            glwe.data.at_mut(0, i)[0] = data_lwe[0];
168            glwe.data.at_mut(1, i)[..n_lwe].copy_from_slice(&data_lwe[1..]);
169        });
170
171        self.keyswitch(module, &glwe, &ksk.0, scratch1);
172    }
173}