arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/rlwe/src/elem_grlwe.rs
rlwe/src/elem_grlwe.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::Infos,
 11    elem_rlwe::{RLWECt, RLWECtDft, RLWEPt},
 12    keys::SecretKeyDft,
 13    utils::derive_size,
 14};
 15
 16pub struct GRLWECt<C, B: Backend> {
 17    pub data: MatZnxDft<C, B>,
 18    pub log_base2k: usize,
 19    pub log_k: usize,
 20}
 21
 22impl<B: Backend> GRLWECt<Vec<u8>, B> {
 23    pub fn new(module: &Module<B>, log_base2k: usize, log_k: usize, rows: usize) -> Self {
 24        Self {
 25            data: module.new_mat_znx_dft(rows, 1, 2, derive_size(log_base2k, log_k)),
 26            log_base2k: log_base2k,
 27            log_k: log_k,
 28        }
 29    }
 30}
 31
 32impl<C> GRLWECt<C, FFT64>
 33where
 34    MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>,
 35{
 36    pub fn get_row<R>(&self, module: &Module<FFT64>, row_i: usize, res: &mut RLWECtDft<R, FFT64>)
 37    where
 38        VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64>,
 39    {
 40        module.vmp_extract_row(res, self, row_i, 0);
 41    }
 42}
 43
 44impl<C> GRLWECt<C, FFT64>
 45where
 46    MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
 47{
 48    pub fn set_row<R>(&mut self, module: &Module<FFT64>, row_i: usize, a: &RLWECtDft<R, FFT64>)
 49    where
 50        VecZnxDft<R, FFT64>: VecZnxDftToRef<FFT64>,
 51    {
 52        module.vmp_prepare_row(self, row_i, 0, a);
 53    }
 54}
 55
 56impl<T, B: Backend> Infos for GRLWECt<T, B> {
 57    type Inner = MatZnxDft<T, B>;
 58
 59    fn inner(&self) -> &Self::Inner {
 60        &self.data
 61    }
 62
 63    fn log_base2k(&self) -> usize {
 64        self.log_base2k
 65    }
 66
 67    fn log_k(&self) -> usize {
 68        self.log_k
 69    }
 70}
 71
 72impl<C, B: Backend> MatZnxDftToMut<B> for GRLWECt<C, B>
 73where
 74    MatZnxDft<C, B>: MatZnxDftToMut<B>,
 75{
 76    fn to_mut(&mut self) -> MatZnxDft<&mut [u8], B> {
 77        self.data.to_mut()
 78    }
 79}
 80
 81impl<C, B: Backend> MatZnxDftToRef<B> for GRLWECt<C, B>
 82where
 83    MatZnxDft<C, B>: MatZnxDftToRef<B>,
 84{
 85    fn to_ref(&self) -> MatZnxDft<&[u8], B> {
 86        self.data.to_ref()
 87    }
 88}
 89
 90impl GRLWECt<Vec<u8>, FFT64> {
 91    pub fn encrypt_sk_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
 92        RLWECt::encrypt_sk_scratch_space(module, size)
 93            + module.bytes_of_vec_znx(2, size)
 94            + module.bytes_of_vec_znx(1, size)
 95            + module.bytes_of_vec_znx_dft(2, size)
 96    }
 97
 98    pub fn mul_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
 99        module.bytes_of_vec_znx_dft(2, grlwe_size)
100            + (module.vec_znx_big_normalize_tmp_bytes()
101                | (module.vmp_apply_tmp_bytes(res_size, a_size, a_size, 1, 2, grlwe_size)
102                    + module.bytes_of_vec_znx_dft(1, a_size)))
103    }
104
105    pub fn mul_rlwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, grlwe_size: usize) -> usize {
106        Self::mul_rlwe_scratch_space(module, res_size, res_size, grlwe_size)
107    }
108
109    pub fn mul_rlwe_dft_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
110        (Self::mul_rlwe_scratch_space(module, res_size, a_size, grlwe_size) | module.vec_znx_idft_tmp_bytes())
111            + module.bytes_of_vec_znx(2, a_size)
112            + module.bytes_of_vec_znx(2, res_size)
113    }
114
115    pub fn mul_rlwe_dft_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, grlwe_size: usize) -> usize {
116        (Self::mul_rlwe_inplace_scratch_space(module, res_size, grlwe_size) | module.vec_znx_idft_tmp_bytes())
117            + module.bytes_of_vec_znx(2, res_size)
118    }
119
120    pub fn mul_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
121        Self::mul_rlwe_dft_inplace_scratch_space(module, res_size, grlwe_size) + module.bytes_of_vec_znx_dft(2, a_size)
122    }
123
124    pub fn mul_grlwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
125        Self::mul_rlwe_dft_inplace_scratch_space(module, res_size, grlwe_size) + module.bytes_of_vec_znx_dft(2, a_size)
126    }
127}
128
129pub fn encrypt_grlwe_sk<C, P, S>(
130    module: &Module<FFT64>,
131    ct: &mut GRLWECt<C, FFT64>,
132    pt: &ScalarZnx<P>,
133    sk_dft: &SecretKeyDft<S, FFT64>,
134    source_xa: &mut Source,
135    source_xe: &mut Source,
136    sigma: f64,
137    bound: f64,
138    scratch: &mut Scratch,
139) where
140    MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
141    ScalarZnx<P>: ScalarZnxToRef,
142    ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
143{
144    let rows: usize = ct.rows();
145    let size: usize = ct.size();
146    let log_base2k: usize = ct.log_base2k();
147
148    let (tmp_znx_pt, scrach_1) = scratch.tmp_vec_znx(module, 1, size);
149    let (tmp_znx_ct, scrach_2) = scrach_1.tmp_vec_znx(module, 2, size);
150    let (mut vec_znx_dft_ct, scratch_3) = scrach_2.tmp_vec_znx_dft(module, 2, size);
151
152    let mut vec_znx_pt: RLWEPt<&mut [u8]> = RLWEPt {
153        data: tmp_znx_pt,
154        log_base2k: log_base2k,
155        log_k: ct.log_k(),
156    };
157
158    let mut vec_znx_ct: RLWECt<&mut [u8]> = RLWECt {
159        data: tmp_znx_ct,
160        log_base2k: log_base2k,
161        log_k: ct.log_k(),
162    };
163
164    (0..rows).for_each(|row_i| {
165        // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
166        module.vec_znx_add_scalar_inplace(&mut vec_znx_pt, 0, row_i, pt, 0);
167        module.vec_znx_normalize_inplace(log_base2k, &mut vec_znx_pt, 0, scratch_3);
168
169        // rlwe encrypt of vec_znx_pt into vec_znx_ct
170        vec_znx_ct.encrypt_sk(
171            module,
172            Some(&vec_znx_pt),
173            sk_dft,
174            source_xa,
175            source_xe,
176            sigma,
177            bound,
178            scratch_3,
179        );
180
181        vec_znx_pt.data.zero(); // zeroes for next iteration
182
183        // Switch vec_znx_ct into DFT domain
184        module.vec_znx_dft(&mut vec_znx_dft_ct, 0, &vec_znx_ct, 0);
185        module.vec_znx_dft(&mut vec_znx_dft_ct, 1, &vec_znx_ct, 1);
186
187        // Stores vec_znx_dft_ct into thw i-th row of the MatZnxDft
188        module.vmp_prepare_row(ct, row_i, 0, &vec_znx_dft_ct);
189    });
190}
191
192impl<C> GRLWECt<C, FFT64> {
193    pub fn encrypt_sk<P, S>(
194        &mut self,
195        module: &Module<FFT64>,
196        pt: &ScalarZnx<P>,
197        sk_dft: &SecretKeyDft<S, FFT64>,
198        source_xa: &mut Source,
199        source_xe: &mut Source,
200        sigma: f64,
201        bound: f64,
202        scratch: &mut Scratch,
203    ) where
204        MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
205        ScalarZnx<P>: ScalarZnxToRef,
206        ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
207    {
208        encrypt_grlwe_sk(
209            module, self, pt, sk_dft, source_xa, source_xe, sigma, bound, scratch,
210        )
211    }
212
213    pub fn mul_rlwe<R, A>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, a: &RLWECt<A>, scratch: &mut Scratch)
214    where
215        MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
216        VecZnx<R>: VecZnxToMut,
217        VecZnx<A>: VecZnxToRef,
218    {
219        let log_base2k: usize = self.log_base2k();
220
221        #[cfg(debug_assertions)]
222        {
223            assert_eq!(res.log_base2k(), log_base2k);
224            assert_eq!(a.log_base2k(), log_base2k);
225            assert_eq!(self.n(), module.n());
226            assert_eq!(res.n(), module.n());
227            assert_eq!(a.n(), module.n());
228        }
229
230        let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, 2, self.size()); // Todo optimise
231
232        {
233            let (mut a1_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, 1, a.size());
234            module.vec_znx_dft(&mut a1_dft, 0, a, 1);
235            module.vmp_apply(&mut res_dft, &a1_dft, self, scratch2);
236        }
237
238        let mut res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(res_dft);
239
240        module.vec_znx_big_add_small_inplace(&mut res_big, 0, a, 0);
241
242        module.vec_znx_big_normalize(log_base2k, res, 0, &res_big, 0, scratch1);
243        module.vec_znx_big_normalize(log_base2k, res, 1, &res_big, 1, scratch1);
244    }
245
246    pub fn mul_rlwe_inplace<R>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, scratch: &mut Scratch)
247    where
248        MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
249        VecZnx<R>: VecZnxToMut + VecZnxToRef,
250    {
251        unsafe {
252            let res_ptr: *mut RLWECt<R> = res as *mut RLWECt<R>; // This is ok because [Self::mul_rlwe] only updates res at the end.
253            self.mul_rlwe(&module, &mut *res_ptr, &*res_ptr, scratch);
254        }
255    }
256
257    pub fn mul_rlwe_dft<R, A>(
258        &self,
259        module: &Module<FFT64>,
260        res: &mut RLWECtDft<R, FFT64>,
261        a: &RLWECtDft<A, FFT64>,
262        scratch: &mut Scratch,
263    ) where
264        MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
265        VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64> + ZnxInfos,
266        VecZnxDft<A, FFT64>: VecZnxDftToRef<FFT64> + ZnxInfos,
267    {
268        let log_base2k: usize = self.log_base2k();
269
270        #[cfg(debug_assertions)]
271        {
272            assert_eq!(res.log_base2k(), log_base2k);
273            assert_eq!(self.n(), module.n());
274            assert_eq!(res.n(), module.n());
275        }
276
277        let (a_data, scratch_1) = scratch.tmp_vec_znx(module, 2, a.size());
278
279        let mut a_idft: RLWECt<&mut [u8]> = RLWECt::<&mut [u8]> {
280            data: a_data,
281            log_base2k: a.log_base2k(),
282            log_k: a.log_k(),
283        };
284
285        a.idft(module, &mut a_idft, scratch_1);
286
287        let (res_data, scratch_2) = scratch_1.tmp_vec_znx(module, 2, res.size());
288
289        let mut res_idft: RLWECt<&mut [u8]> = RLWECt::<&mut [u8]> {
290            data: res_data,
291            log_base2k: res.log_base2k(),
292            log_k: res.log_k(),
293        };
294
295        self.mul_rlwe(module, &mut res_idft, &a_idft, scratch_2);
296
297        module.vec_znx_dft(res, 0, &res_idft, 0);
298        module.vec_znx_dft(res, 1, &res_idft, 1);
299    }
300
301    pub fn mul_rlwe_dft_inplace<R>(&self, module: &Module<FFT64>, res: &mut RLWECtDft<R, FFT64>, scratch: &mut Scratch)
302    where
303        MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
304        VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64> + ZnxInfos,
305    {
306        let log_base2k: usize = self.log_base2k();
307
308        #[cfg(debug_assertions)]
309        {
310            assert_eq!(res.log_base2k(), log_base2k);
311            assert_eq!(self.n(), module.n());
312            assert_eq!(res.n(), module.n());
313        }
314
315        let (res_data, scratch_1) = scratch.tmp_vec_znx(module, 2, res.size());
316
317        let mut res_idft: RLWECt<&mut [u8]> = RLWECt::<&mut [u8]> {
318            data: res_data,
319            log_base2k: res.log_base2k(),
320            log_k: res.log_k(),
321        };
322
323        res.idft(module, &mut res_idft, scratch_1);
324
325        self.mul_rlwe_inplace(module, &mut res_idft, scratch_1);
326
327        module.vec_znx_dft(res, 0, &res_idft, 0);
328        module.vec_znx_dft(res, 1, &res_idft, 1);
329    }
330
331    pub fn mul_grlwe<R, A>(
332        &self,
333        module: &Module<FFT64>,
334        res: &mut GRLWECt<R, FFT64>,
335        a: &GRLWECt<A, FFT64>,
336        scratch: &mut Scratch,
337    ) where
338        MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
339        MatZnxDft<R, FFT64>: MatZnxDftToMut<FFT64> + MatZnxDftToRef<FFT64> + ZnxInfos,
340        MatZnxDft<A, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
341    {
342        let (tmp_row_data, scratch1) = scratch.tmp_vec_znx_dft(module, 2, a.size());
343
344        let mut tmp_row: RLWECtDft<&mut [u8], FFT64> = RLWECtDft::<&mut [u8], FFT64> {
345            data: tmp_row_data,
346            log_base2k: a.log_base2k(),
347            log_k: a.log_k(),
348        };
349
350        let min_rows: usize = res.rows().min(a.rows());
351
352        (0..min_rows).for_each(|row_i| {
353            a.get_row(module, row_i, &mut tmp_row);
354            self.mul_rlwe_dft_inplace(module, &mut tmp_row, scratch1);
355            res.set_row(module, row_i, &tmp_row);
356        });
357
358        tmp_row.data.zero();
359
360        (min_rows..res.rows()).for_each(|row_i| {
361            res.set_row(module, row_i, &tmp_row);
362        })
363    }
364
365    pub fn mul_grlwe_inplace<R>(&self, module: &Module<FFT64>, res: &mut GRLWECt<R, FFT64>, scratch: &mut Scratch)
366    where
367        MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
368        MatZnxDft<R, FFT64>: MatZnxDftToMut<FFT64> + MatZnxDftToRef<FFT64> + ZnxInfos,
369    {
370        let (tmp_row_data, scratch1) = scratch.tmp_vec_znx_dft(module, 2, res.size());
371
372        let mut tmp_row: RLWECtDft<&mut [u8], FFT64> = RLWECtDft::<&mut [u8], FFT64> {
373            data: tmp_row_data,
374            log_base2k: res.log_base2k(),
375            log_k: res.log_k(),
376        };
377
378        (0..res.rows()).for_each(|row_i| {
379            res.get_row(module, row_i, &mut tmp_row);
380            self.mul_rlwe_dft_inplace(module, &mut tmp_row, scratch1);
381            res.set_row(module, row_i, &tmp_row);
382        });
383    }
384}