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