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