arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/vec_glwe_product.rs
core/src/vec_glwe_product.rsRaw
  1use base2k::{
  2    FFT64, Module, Scratch, VecZnx, VecZnxAlloc, VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxDftToMut, VecZnxDftToRef,
  3    VecZnxToMut, VecZnxToRef, ZnxInfos, ZnxZero,
  4};
  5
  6use crate::{
  7    elem::{GetRow, Infos, SetRow},
  8    glwe_ciphertext::GLWECiphertext,
  9    glwe_ciphertext_fourier::GLWECiphertextFourier,
 10};
 11
 12pub(crate) trait VecGLWEProductScratchSpace {
 13    fn prod_with_glwe_scratch_space(
 14        module: &Module<FFT64>,
 15        res_size: usize,
 16        lhs: usize,
 17        rhs: usize,
 18        rank_in: usize,
 19        rank_out: usize,
 20    ) -> usize;
 21
 22    fn prod_with_glwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, rhs: usize, rank: usize) -> usize {
 23        Self::prod_with_glwe_scratch_space(module, res_size, res_size, rhs, rank, rank)
 24    }
 25
 26    fn prod_with_glwe_dft_scratch_space(
 27        module: &Module<FFT64>,
 28        res_size: usize,
 29        lhs: usize,
 30        rhs: usize,
 31        rank_in: usize,
 32        rank_out: usize,
 33    ) -> usize {
 34        (Self::prod_with_glwe_scratch_space(module, res_size, lhs, rhs, rank_in, rank_out) | module.vec_znx_idft_tmp_bytes())
 35            + module.bytes_of_vec_znx(rank_in, lhs)
 36            + module.bytes_of_vec_znx(rank_out, res_size)
 37    }
 38
 39    fn prod_with_glwe_dft_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, rhs: usize, rank: usize) -> usize {
 40        (Self::prod_with_glwe_inplace_scratch_space(module, res_size, rhs, rank) | module.vec_znx_idft_tmp_bytes())
 41            + module.bytes_of_vec_znx(rank + 1, res_size)
 42    }
 43
 44    fn prod_with_vec_glwe_scratch_space(
 45        module: &Module<FFT64>,
 46        res_size: usize,
 47        lhs: usize,
 48        rhs: usize,
 49        rank_in: usize,
 50        rank_out: usize,
 51    ) -> usize {
 52        Self::prod_with_glwe_dft_scratch_space(module, res_size, lhs, rhs, rank_in, rank_out)
 53            + module.bytes_of_vec_znx_dft(rank_in + 1, lhs)
 54            + module.bytes_of_vec_znx_dft(rank_out + 1, res_size)
 55    }
 56
 57    fn prod_with_vec_glwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, rhs: usize, rank: usize) -> usize {
 58        Self::prod_with_glwe_dft_inplace_scratch_space(module, res_size, rhs, rank)
 59            + module.bytes_of_vec_znx_dft(rank + 1, res_size)
 60    }
 61}
 62
 63pub(crate) trait VecGLWEProduct: Infos {
 64    fn prod_with_glwe<MUT, REF>(
 65        &self,
 66        module: &Module<FFT64>,
 67        res: &mut GLWECiphertext<MUT>,
 68        a: &GLWECiphertext<REF>,
 69        scratch: &mut Scratch,
 70    ) where
 71        VecZnx<MUT>: VecZnxToMut,
 72        VecZnx<REF>: VecZnxToRef;
 73
 74    fn prod_with_glwe_inplace<MUT>(&self, module: &Module<FFT64>, res: &mut GLWECiphertext<MUT>, scratch: &mut Scratch)
 75    where
 76        VecZnx<MUT>: VecZnxToMut + VecZnxToRef,
 77    {
 78        unsafe {
 79            let res_ptr: *mut GLWECiphertext<MUT> = res as *mut GLWECiphertext<MUT>; // This is ok because [Self::mul_rlwe] only updates res at the end.
 80            self.prod_with_glwe(&module, &mut *res_ptr, &*res_ptr, scratch);
 81        }
 82    }
 83
 84    fn prod_with_glwe_fourier<MUT, REF>(
 85        &self,
 86        module: &Module<FFT64>,
 87        res: &mut GLWECiphertextFourier<MUT, FFT64>,
 88        a: &GLWECiphertextFourier<REF, FFT64>,
 89        scratch: &mut Scratch,
 90    ) where
 91        VecZnxDft<MUT, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64> + ZnxInfos,
 92        VecZnxDft<REF, FFT64>: VecZnxDftToRef<FFT64> + ZnxInfos,
 93    {
 94        let log_base2k: usize = self.basek();
 95
 96        #[cfg(debug_assertions)]
 97        {
 98            assert_eq!(res.basek(), log_base2k);
 99            assert_eq!(self.n(), module.n());
100            assert_eq!(res.n(), module.n());
101        }
102
103        let (a_data, scratch_1) = scratch.tmp_vec_znx(module, a.rank() + 1, a.size());
104
105        let mut a_idft: GLWECiphertext<&mut [u8]> = GLWECiphertext::<&mut [u8]> {
106            data: a_data,
107            basek: a.basek(),
108            k: a.k(),
109        };
110
111        a.idft(module, &mut a_idft, scratch_1);
112
113        let (res_data, scratch_2) = scratch_1.tmp_vec_znx(module, res.rank() + 1, res.size());
114
115        let mut res_idft: GLWECiphertext<&mut [u8]> = GLWECiphertext::<&mut [u8]> {
116            data: res_data,
117            basek: res.basek(),
118            k: res.k(),
119        };
120
121        self.prod_with_glwe(module, &mut res_idft, &a_idft, scratch_2);
122
123        res_idft.dft(module, res);
124    }
125
126    fn prod_with_glwe_fourier_inplace<MUT>(
127        &self,
128        module: &Module<FFT64>,
129        res: &mut GLWECiphertextFourier<MUT, FFT64>,
130        scratch: &mut Scratch,
131    ) where
132        VecZnxDft<MUT, FFT64>: VecZnxDftToRef<FFT64> + VecZnxDftToMut<FFT64>,
133    {
134        let log_base2k: usize = self.basek();
135
136        #[cfg(debug_assertions)]
137        {
138            assert_eq!(res.basek(), log_base2k);
139            assert_eq!(self.n(), module.n());
140            assert_eq!(res.n(), module.n());
141        }
142
143        let (res_data, scratch_1) = scratch.tmp_vec_znx(module, res.rank() + 1, res.size());
144
145        let mut res_idft: GLWECiphertext<&mut [u8]> = GLWECiphertext::<&mut [u8]> {
146            data: res_data,
147            basek: res.basek(),
148            k: res.k(),
149        };
150
151        res.idft(module, &mut res_idft, scratch_1);
152
153        self.prod_with_glwe_inplace(module, &mut res_idft, scratch_1);
154
155        res_idft.dft(module, res);
156    }
157
158    fn prod_with_vec_glwe<RES, LHS>(&self, module: &Module<FFT64>, res: &mut RES, a: &LHS, scratch: &mut Scratch)
159    where
160        LHS: GetRow<FFT64> + Infos,
161        RES: SetRow<FFT64> + Infos,
162    {
163        let (tmp_row_data, scratch1) = scratch.tmp_vec_znx_dft(module, a.cols(), a.size());
164
165        let mut tmp_a_row: GLWECiphertextFourier<&mut [u8], FFT64> = GLWECiphertextFourier::<&mut [u8], FFT64> {
166            data: tmp_row_data,
167            basek: a.basek(),
168            k: a.k(),
169        };
170
171        let (tmp_res_data, scratch2) = scratch1.tmp_vec_znx_dft(module, res.cols(), res.size());
172
173        let mut tmp_res_row: GLWECiphertextFourier<&mut [u8], FFT64> = GLWECiphertextFourier::<&mut [u8], FFT64> {
174            data: tmp_res_data,
175            basek: res.basek(),
176            k: res.k(),
177        };
178
179        let min_rows: usize = res.rows().min(a.rows());
180
181        (0..res.rows()).for_each(|row_i| {
182            (0..res.cols()).for_each(|col_j| {
183                a.get_row(module, row_i, col_j, &mut tmp_a_row);
184                self.prod_with_glwe_fourier(module, &mut tmp_res_row, &tmp_a_row, scratch2);
185                res.set_row(module, row_i, col_j, &tmp_res_row);
186            });
187        });
188
189        tmp_res_row.data.zero();
190
191        (min_rows..res.rows()).for_each(|row_i| {
192            (0..self.cols()).for_each(|col_j| {
193                res.set_row(module, row_i, col_j, &tmp_res_row);
194            });
195        });
196    }
197
198    fn prod_with_vec_glwe_inplace<RES>(&self, module: &Module<FFT64>, res: &mut RES, scratch: &mut Scratch)
199    where
200        RES: GetRow<FFT64> + SetRow<FFT64> + Infos,
201    {
202        let (tmp_row_data, scratch1) = scratch.tmp_vec_znx_dft(module, res.cols(), res.size());
203
204        let mut tmp_row: GLWECiphertextFourier<&mut [u8], FFT64> = GLWECiphertextFourier::<&mut [u8], FFT64> {
205            data: tmp_row_data,
206            basek: res.basek(),
207            k: res.k(),
208        };
209
210        (0..res.rows()).for_each(|row_i| {
211            (0..res.cols()).for_each(|col_j| {
212                res.get_row(module, row_i, col_j, &mut tmp_row);
213                self.prod_with_glwe_fourier_inplace(module, &mut tmp_row, scratch1);
214                res.set_row(module, row_i, col_j, &tmp_row);
215            });
216        });
217    }
218}