arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/rlwe.rs
core/src/rlwe.rsRaw
  1use base2k::{
  2    AddNormal, Backend, FFT64, FillUniform, MatZnxDft, MatZnxDftToRef, Module, ScalarZnxAlloc, ScalarZnxDft, ScalarZnxDftAlloc,
  3    ScalarZnxDftOps, ScalarZnxDftToRef, Scratch, VecZnx, VecZnxAlloc, VecZnxBigAlloc, VecZnxBigOps, VecZnxBigScratch, VecZnxDft,
  4    VecZnxDftAlloc, VecZnxDftOps, VecZnxDftToMut, VecZnxDftToRef, VecZnxOps, VecZnxToMut, VecZnxToRef, ZnxInfos,
  5};
  6use sampling::source::Source;
  7
  8use crate::{
  9    elem::{Infos, MatRLWEProduct, MatRLWEProductScratchSpace, ProdInplace, ProdInplaceScratchSpace, ProdScratchSpace, Product},
 10    grlwe::GRLWECt,
 11    keys::{PublicKey, SecretDistribution, SecretKeyDft},
 12    rgsw::RGSWCt,
 13    utils::derive_size,
 14};
 15
 16pub struct RLWECt<C> {
 17    pub data: VecZnx<C>,
 18    pub log_base2k: usize,
 19    pub log_k: usize,
 20}
 21
 22impl RLWECt<Vec<u8>> {
 23    pub fn new<B: Backend>(module: &Module<B>, log_base2k: usize, log_k: usize) -> Self {
 24        Self {
 25            data: module.new_vec_znx(2, derive_size(log_base2k, log_k)),
 26            log_base2k: log_base2k,
 27            log_k: log_k,
 28        }
 29    }
 30}
 31
 32impl<T> Infos for RLWECt<T> {
 33    type Inner = VecZnx<T>;
 34
 35    fn inner(&self) -> &Self::Inner {
 36        &self.data
 37    }
 38
 39    fn log_base2k(&self) -> usize {
 40        self.log_base2k
 41    }
 42
 43    fn log_k(&self) -> usize {
 44        self.log_k
 45    }
 46}
 47
 48impl<C> VecZnxToMut for RLWECt<C>
 49where
 50    VecZnx<C>: VecZnxToMut,
 51{
 52    fn to_mut(&mut self) -> VecZnx<&mut [u8]> {
 53        self.data.to_mut()
 54    }
 55}
 56
 57impl<C> VecZnxToRef for RLWECt<C>
 58where
 59    VecZnx<C>: VecZnxToRef,
 60{
 61    fn to_ref(&self) -> VecZnx<&[u8]> {
 62        self.data.to_ref()
 63    }
 64}
 65
 66impl<C> RLWECt<C>
 67where
 68    VecZnx<C>: VecZnxToRef,
 69{
 70    #[allow(dead_code)]
 71    pub(crate) fn dft<R>(&self, module: &Module<FFT64>, res: &mut RLWECtDft<R, FFT64>)
 72    where
 73        VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64> + ZnxInfos,
 74    {
 75        #[cfg(debug_assertions)]
 76        {
 77            assert_eq!(self.cols(), 2);
 78            assert_eq!(res.cols(), 2);
 79            assert_eq!(self.log_base2k(), res.log_base2k())
 80        }
 81
 82        module.vec_znx_dft(res, 0, self, 0);
 83        module.vec_znx_dft(res, 1, self, 1);
 84    }
 85}
 86
 87impl ProdInplaceScratchSpace for RLWECt<Vec<u8>> {
 88    fn prod_by_grlwe_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize {
 89        <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_inplace_scratch_space(module, lhs, rhs)
 90    }
 91
 92    fn prod_by_rgsw_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize {
 93        <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_inplace_scratch_space(module, lhs, rhs)
 94    }
 95}
 96
 97impl ProdScratchSpace for RLWECt<Vec<u8>> {
 98    fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
 99        <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_scratch_space(module, res_size, lhs, rhs)
100    }
101
102    fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
103        <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_scratch_space(module, res_size, lhs, rhs)
104    }
105}
106
107impl<MUT, REF> ProdInplace<MUT, REF> for RLWECt<MUT>
108where
109    VecZnx<MUT>: VecZnxToMut + VecZnxToRef,
110    MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>,
111{
112    fn prod_by_grlwe_inplace(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) {
113        rhs.prod_with_rlwe_inplace(module, self, scratch);
114    }
115
116    fn prod_by_rgsw_inplace(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) {
117        rhs.prod_with_rlwe_inplace(module, self, scratch);
118    }
119}
120
121impl<MUT, REF> Product<MUT, REF> for RLWECt<MUT>
122where
123    VecZnx<MUT>: VecZnxToMut + VecZnxToRef,
124    VecZnx<REF>: VecZnxToRef,
125    MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>,
126{
127    type Lhs = RLWECt<REF>;
128
129    fn prod_by_grlwe(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) {
130        rhs.prod_with_rlwe(module, self, lhs, scratch);
131    }
132
133    fn prod_by_rgsw(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) {
134        rhs.prod_with_rlwe(module, self, lhs, scratch);
135    }
136}
137
138impl RLWECt<Vec<u8>> {
139    pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, size: usize) -> usize {
140        (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size)
141    }
142
143    pub fn encrypt_pk_scratch_space<B: Backend>(module: &Module<B>, pk_size: usize) -> usize {
144        ((module.bytes_of_vec_znx_dft(1, pk_size) + module.bytes_of_vec_znx_big(1, pk_size)) | module.bytes_of_scalar_znx(1))
145            + module.bytes_of_scalar_znx_dft(1)
146            + module.vec_znx_big_normalize_tmp_bytes()
147    }
148
149    pub fn decrypt_scratch_space<B: Backend>(module: &Module<B>, size: usize) -> usize {
150        (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size)
151    }
152}
153
154pub fn encrypt_rlwe_sk<C, P, S>(
155    module: &Module<FFT64>,
156    ct: &mut RLWECt<C>,
157    pt: Option<(&RLWEPt<P>, usize)>,
158    sk_dft: &SecretKeyDft<S, FFT64>,
159    source_xa: &mut Source,
160    source_xe: &mut Source,
161    sigma: f64,
162    bound: f64,
163    scratch: &mut Scratch,
164) where
165    VecZnx<C>: VecZnxToMut + VecZnxToRef,
166    VecZnx<P>: VecZnxToRef,
167    ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
168{
169    let log_base2k: usize = ct.log_base2k();
170    let log_k: usize = ct.log_k();
171    let size: usize = ct.size();
172
173    // c1 = a
174    ct.data.fill_uniform(log_base2k, 1, size, source_xa);
175
176    let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size);
177
178    {
179        let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size);
180        module.vec_znx_dft(&mut c0_dft, 0, ct, 1);
181
182        // c0_dft = DFT(a) * DFT(s)
183        module.svp_apply_inplace(&mut c0_dft, 0, sk_dft, 0);
184
185        // c0_big = IDFT(c0_dft)
186        module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0);
187    }
188
189    // c0_big = m - c0_big
190    if let Some((pt, col)) = pt {
191        match col {
192            0 => module.vec_znx_big_sub_small_b_inplace(&mut c0_big, 0, pt, 0),
193            1 => {
194                module.vec_znx_big_negate_inplace(&mut c0_big, 0);
195                module.vec_znx_add_inplace(ct, 1, pt, 0);
196                module.vec_znx_normalize_inplace(log_base2k, ct, 1, scratch_1);
197            }
198            _ => panic!("invalid target column: {}", col),
199        }
200    } else {
201        module.vec_znx_big_negate_inplace(&mut c0_big, 0);
202    }
203    // c0_big += e
204    c0_big.add_normal(log_base2k, 0, log_k, source_xe, sigma, bound);
205
206    // c0 = norm(c0_big = -as + m + e)
207    module.vec_znx_big_normalize(log_base2k, ct, 0, &c0_big, 0, scratch_1);
208}
209
210pub fn decrypt_rlwe<P, C, S>(
211    module: &Module<FFT64>,
212    pt: &mut RLWEPt<P>,
213    ct: &RLWECt<C>,
214    sk_dft: &SecretKeyDft<S, FFT64>,
215    scratch: &mut Scratch,
216) where
217    VecZnx<P>: VecZnxToMut + VecZnxToRef,
218    VecZnx<C>: VecZnxToRef,
219    ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
220{
221    let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, ct.size()); // TODO optimize size when pt << ct
222
223    {
224        let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, ct.size()); // TODO optimize size when pt << ct
225        module.vec_znx_dft(&mut c0_dft, 0, ct, 1);
226
227        // c0_dft = DFT(a) * DFT(s)
228        module.svp_apply_inplace(&mut c0_dft, 0, sk_dft, 0);
229
230        // c0_big = IDFT(c0_dft)
231        module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0);
232    }
233
234    // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e)
235    module.vec_znx_big_add_small_inplace(&mut c0_big, 0, ct, 0);
236
237    // pt = norm(BIG(m + e))
238    module.vec_znx_big_normalize(ct.log_base2k(), pt, 0, &mut c0_big, 0, scratch_1);
239
240    pt.log_base2k = ct.log_base2k();
241    pt.log_k = pt.log_k().min(ct.log_k());
242}
243
244impl<C> RLWECt<C> {
245    pub fn encrypt_sk<P, S>(
246        &mut self,
247        module: &Module<FFT64>,
248        pt: Option<&RLWEPt<P>>,
249        sk_dft: &SecretKeyDft<S, FFT64>,
250        source_xa: &mut Source,
251        source_xe: &mut Source,
252        sigma: f64,
253        bound: f64,
254        scratch: &mut Scratch,
255    ) where
256        VecZnx<C>: VecZnxToMut + VecZnxToRef,
257        VecZnx<P>: VecZnxToRef,
258        ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
259    {
260        if let Some(pt) = pt {
261            encrypt_rlwe_sk(
262                module,
263                self,
264                Some((pt, 0)),
265                sk_dft,
266                source_xa,
267                source_xe,
268                sigma,
269                bound,
270                scratch,
271            )
272        } else {
273            encrypt_rlwe_sk::<C, P, S>(
274                module, self, None, sk_dft, source_xa, source_xe, sigma, bound, scratch,
275            )
276        }
277    }
278
279    pub fn decrypt<P, S>(
280        &self,
281        module: &Module<FFT64>,
282        pt: &mut RLWEPt<P>,
283        sk_dft: &SecretKeyDft<S, FFT64>,
284        scratch: &mut Scratch,
285    ) where
286        VecZnx<P>: VecZnxToMut + VecZnxToRef,
287        VecZnx<C>: VecZnxToRef,
288        ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
289    {
290        decrypt_rlwe(module, pt, self, sk_dft, scratch);
291    }
292
293    pub fn encrypt_pk<P, S>(
294        &mut self,
295        module: &Module<FFT64>,
296        pt: Option<&RLWEPt<P>>,
297        pk: &PublicKey<S, FFT64>,
298        source_xu: &mut Source,
299        source_xe: &mut Source,
300        sigma: f64,
301        bound: f64,
302        scratch: &mut Scratch,
303    ) where
304        VecZnx<C>: VecZnxToMut + VecZnxToRef,
305        VecZnx<P>: VecZnxToRef,
306        VecZnxDft<S, FFT64>: VecZnxDftToRef<FFT64>,
307    {
308        encrypt_rlwe_pk(
309            module, self, pt, pk, source_xu, source_xe, sigma, bound, scratch,
310        )
311    }
312}
313
314pub(crate) fn encrypt_rlwe_pk<C, P, S>(
315    module: &Module<FFT64>,
316    ct: &mut RLWECt<C>,
317    pt: Option<&RLWEPt<P>>,
318    pk: &PublicKey<S, FFT64>,
319    source_xu: &mut Source,
320    source_xe: &mut Source,
321    sigma: f64,
322    bound: f64,
323    scratch: &mut Scratch,
324) where
325    VecZnx<C>: VecZnxToMut + VecZnxToRef,
326    VecZnx<P>: VecZnxToRef,
327    VecZnxDft<S, FFT64>: VecZnxDftToRef<FFT64>,
328{
329    #[cfg(debug_assertions)]
330    {
331        assert_eq!(ct.log_base2k(), pk.log_base2k());
332        assert_eq!(ct.n(), module.n());
333        assert_eq!(pk.n(), module.n());
334        if let Some(pt) = pt {
335            assert_eq!(pt.log_base2k(), pk.log_base2k());
336            assert_eq!(pt.n(), module.n());
337        }
338    }
339
340    let log_base2k: usize = pk.log_base2k();
341    let size_pk: usize = pk.size();
342
343    // Generates u according to the underlying secret distribution.
344    let (mut u_dft, scratch_1) = scratch.tmp_scalar_znx_dft(module, 1);
345
346    {
347        let (mut u, _) = scratch_1.tmp_scalar_znx(module, 1);
348        match pk.dist {
349            SecretDistribution::NONE => panic!(
350                "invalid public key: SecretDistribution::NONE, ensure it has been correctly intialized through Self::generate"
351            ),
352            SecretDistribution::TernaryFixed(hw) => u.fill_ternary_hw(0, hw, source_xu),
353            SecretDistribution::TernaryProb(prob) => u.fill_ternary_prob(0, prob, source_xu),
354            SecretDistribution::ZERO => {}
355        }
356
357        module.svp_prepare(&mut u_dft, 0, &u, 0);
358    }
359
360    let (mut tmp_big, scratch_2) = scratch_1.tmp_vec_znx_big(module, 1, size_pk); // TODO optimize size (e.g. when encrypting at low homomorphic capacity)
361    let (mut tmp_dft, scratch_3) = scratch_2.tmp_vec_znx_dft(module, 1, size_pk); // TODO optimize size (e.g. when encrypting at low homomorphic capacity)
362
363    // ct[0] = pk[0] * u + m + e0
364    module.svp_apply(&mut tmp_dft, 0, &u_dft, 0, pk, 0);
365    module.vec_znx_idft_tmp_a(&mut tmp_big, 0, &mut tmp_dft, 0);
366    tmp_big.add_normal(log_base2k, 0, pk.log_k(), source_xe, sigma, bound);
367
368    if let Some(pt) = pt {
369        module.vec_znx_big_add_small_inplace(&mut tmp_big, 0, pt, 0);
370    }
371
372    module.vec_znx_big_normalize(log_base2k, ct, 0, &tmp_big, 0, scratch_3);
373
374    // ct[1] = pk[1] * u + e1
375    module.svp_apply(&mut tmp_dft, 0, &u_dft, 0, pk, 1);
376    module.vec_znx_idft_tmp_a(&mut tmp_big, 0, &mut tmp_dft, 0);
377    tmp_big.add_normal(log_base2k, 0, pk.log_k(), source_xe, sigma, bound);
378    module.vec_znx_big_normalize(log_base2k, ct, 1, &tmp_big, 0, scratch_3);
379}
380
381pub struct RLWEPt<C> {
382    pub data: VecZnx<C>,
383    pub log_base2k: usize,
384    pub log_k: usize,
385}
386
387impl<T> Infos for RLWEPt<T> {
388    type Inner = VecZnx<T>;
389
390    fn inner(&self) -> &Self::Inner {
391        &self.data
392    }
393
394    fn log_base2k(&self) -> usize {
395        self.log_base2k
396    }
397
398    fn log_k(&self) -> usize {
399        self.log_k
400    }
401}
402
403impl<C> VecZnxToMut for RLWEPt<C>
404where
405    VecZnx<C>: VecZnxToMut,
406{
407    fn to_mut(&mut self) -> VecZnx<&mut [u8]> {
408        self.data.to_mut()
409    }
410}
411
412impl<C> VecZnxToRef for RLWEPt<C>
413where
414    VecZnx<C>: VecZnxToRef,
415{
416    fn to_ref(&self) -> VecZnx<&[u8]> {
417        self.data.to_ref()
418    }
419}
420
421impl RLWEPt<Vec<u8>> {
422    pub fn new<B: Backend>(module: &Module<B>, log_base2k: usize, log_k: usize) -> Self {
423        Self {
424            data: module.new_vec_znx(1, derive_size(log_base2k, log_k)),
425            log_base2k: log_base2k,
426            log_k: log_k,
427        }
428    }
429}
430
431pub struct RLWECtDft<C, B: Backend> {
432    pub data: VecZnxDft<C, B>,
433    pub log_base2k: usize,
434    pub log_k: usize,
435}
436
437impl<B: Backend> RLWECtDft<Vec<u8>, B> {
438    pub fn new(module: &Module<B>, log_base2k: usize, log_k: usize) -> Self {
439        Self {
440            data: module.new_vec_znx_dft(2, derive_size(log_base2k, log_k)),
441            log_base2k: log_base2k,
442            log_k: log_k,
443        }
444    }
445}
446
447impl<T, B: Backend> Infos for RLWECtDft<T, B> {
448    type Inner = VecZnxDft<T, B>;
449
450    fn inner(&self) -> &Self::Inner {
451        &self.data
452    }
453
454    fn log_base2k(&self) -> usize {
455        self.log_base2k
456    }
457
458    fn log_k(&self) -> usize {
459        self.log_k
460    }
461}
462
463impl<C, B: Backend> VecZnxDftToMut<B> for RLWECtDft<C, B>
464where
465    VecZnxDft<C, B>: VecZnxDftToMut<B>,
466{
467    fn to_mut(&mut self) -> VecZnxDft<&mut [u8], B> {
468        self.data.to_mut()
469    }
470}
471
472impl<C, B: Backend> VecZnxDftToRef<B> for RLWECtDft<C, B>
473where
474    VecZnxDft<C, B>: VecZnxDftToRef<B>,
475{
476    fn to_ref(&self) -> VecZnxDft<&[u8], B> {
477        self.data.to_ref()
478    }
479}
480
481impl<C> RLWECtDft<C, FFT64>
482where
483    RLWECtDft<C, FFT64>: VecZnxDftToRef<FFT64>,
484{
485    #[allow(dead_code)]
486    pub(crate) fn idft_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
487        module.bytes_of_vec_znx(2, size) + (module.vec_znx_big_normalize_tmp_bytes() | module.vec_znx_idft_tmp_bytes())
488    }
489
490    pub(crate) fn idft<R>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, scratch: &mut Scratch)
491    where
492        RLWECt<R>: VecZnxToMut,
493    {
494        #[cfg(debug_assertions)]
495        {
496            assert_eq!(self.cols(), 2);
497            assert_eq!(res.cols(), 2);
498            assert_eq!(self.log_base2k(), res.log_base2k())
499        }
500
501        let min_size: usize = self.size().min(res.size());
502
503        let (mut res_big, scratch1) = scratch.tmp_vec_znx_big(module, 2, min_size);
504
505        module.vec_znx_idft(&mut res_big, 0, self, 0, scratch1);
506        module.vec_znx_idft(&mut res_big, 1, self, 1, scratch1);
507        module.vec_znx_big_normalize(self.log_base2k(), res, 0, &res_big, 0, scratch1);
508        module.vec_znx_big_normalize(self.log_base2k(), res, 1, &res_big, 1, scratch1);
509    }
510}
511
512pub(crate) fn encrypt_zero_rlwe_dft_sk<C, S>(
513    module: &Module<FFT64>,
514    ct: &mut RLWECtDft<C, FFT64>,
515    sk: &SecretKeyDft<S, FFT64>,
516    source_xa: &mut Source,
517    source_xe: &mut Source,
518    sigma: f64,
519    bound: f64,
520    scratch: &mut Scratch,
521) where
522    VecZnxDft<C, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
523    ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
524{
525    let log_base2k: usize = ct.log_base2k();
526    let log_k: usize = ct.log_k();
527    let size: usize = ct.size();
528
529    #[cfg(debug_assertions)]
530    {
531        match sk.dist {
532            SecretDistribution::NONE => panic!("invalid sk.dist = SecretDistribution::NONE"),
533            _ => {}
534        }
535        assert_eq!(ct.cols(), 2);
536    }
537
538    // ct[1] = DFT(a)
539    {
540        let (mut tmp_znx, _) = scratch.tmp_vec_znx(module, 1, size);
541        tmp_znx.fill_uniform(log_base2k, 0, size, source_xa);
542        module.vec_znx_dft(ct, 1, &tmp_znx, 0);
543    }
544
545    let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size);
546
547    {
548        let (mut tmp_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size);
549        // c0_dft = ct[1] * DFT(s)
550        module.svp_apply(&mut tmp_dft, 0, sk, 0, ct, 1);
551
552        // c0_big = IDFT(c0_dft)
553        module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut tmp_dft, 0);
554    }
555
556    // c0_big += e
557    c0_big.add_normal(log_base2k, 0, log_k, source_xe, sigma, bound);
558
559    // c0 = norm(c0_big = -as - e), NOTE: e is centered at 0.
560    let (mut tmp_znx, scratch_2) = scratch_1.tmp_vec_znx(module, 1, size);
561    module.vec_znx_big_normalize(log_base2k, &mut tmp_znx, 0, &c0_big, 0, scratch_2);
562    module.vec_znx_negate_inplace(&mut tmp_znx, 0);
563    // ct[0] = DFT(-as + e)
564    module.vec_znx_dft(ct, 0, &tmp_znx, 0);
565}
566
567impl RLWECtDft<Vec<u8>, FFT64> {
568    pub fn encrypt_zero_sk_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
569        (module.bytes_of_vec_znx(1, size) | module.bytes_of_vec_znx_dft(1, size))
570            + module.bytes_of_vec_znx_big(1, size)
571            + module.bytes_of_vec_znx(1, size)
572            + module.vec_znx_big_normalize_tmp_bytes()
573    }
574
575    pub fn decrypt_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
576        (module.vec_znx_big_normalize_tmp_bytes()
577            | module.bytes_of_vec_znx_dft(1, size)
578            | (module.bytes_of_vec_znx_big(1, size) + module.vec_znx_idft_tmp_bytes()))
579            + module.bytes_of_vec_znx_big(1, size)
580    }
581}
582
583pub fn decrypt_rlwe_dft<P, C, S>(
584    module: &Module<FFT64>,
585    pt: &mut RLWEPt<P>,
586    ct: &RLWECtDft<C, FFT64>,
587    sk: &SecretKeyDft<S, FFT64>,
588    scratch: &mut Scratch,
589) where
590    VecZnx<P>: VecZnxToMut + VecZnxToRef,
591    VecZnxDft<C, FFT64>: VecZnxDftToRef<FFT64>,
592    ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
593{
594    let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, ct.size()); // TODO optimize size when pt << ct
595
596    {
597        let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, ct.size()); // TODO optimize size when pt << ct
598        // c0_dft = DFT(a) * DFT(s)
599        module.svp_apply(&mut c0_dft, 0, sk, 0, ct, 1);
600        // c0_big = IDFT(c0_dft)
601        module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0);
602    }
603
604    {
605        let (mut c1_big, scratch_2) = scratch_1.tmp_vec_znx_big(module, 1, ct.size());
606        // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e)
607        module.vec_znx_idft(&mut c1_big, 0, ct, 0, scratch_2);
608        module.vec_znx_big_add_inplace(&mut c0_big, 0, &c1_big, 0);
609    }
610
611    // pt = norm(BIG(m + e))
612    module.vec_znx_big_normalize(ct.log_base2k(), pt, 0, &mut c0_big, 0, scratch_1);
613
614    pt.log_base2k = ct.log_base2k();
615    pt.log_k = pt.log_k().min(ct.log_k());
616}
617
618impl<C> RLWECtDft<C, FFT64> {
619    pub(crate) fn encrypt_zero_sk<S>(
620        &mut self,
621        module: &Module<FFT64>,
622        sk_dft: &SecretKeyDft<S, FFT64>,
623        source_xa: &mut Source,
624        source_xe: &mut Source,
625        sigma: f64,
626        bound: f64,
627        scratch: &mut Scratch,
628    ) where
629        VecZnxDft<C, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
630        ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
631    {
632        encrypt_zero_rlwe_dft_sk(
633            module, self, sk_dft, source_xa, source_xe, sigma, bound, scratch,
634        )
635    }
636
637    pub fn decrypt<P, S>(
638        &self,
639        module: &Module<FFT64>,
640        pt: &mut RLWEPt<P>,
641        sk_dft: &SecretKeyDft<S, FFT64>,
642        scratch: &mut Scratch,
643    ) where
644        VecZnx<P>: VecZnxToMut + VecZnxToRef,
645        VecZnxDft<C, FFT64>: VecZnxDftToRef<FFT64>,
646        ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
647    {
648        decrypt_rlwe_dft(module, pt, self, sk_dft, scratch);
649    }
650}
651
652impl ProdInplaceScratchSpace for RLWECtDft<Vec<u8>, FFT64> {
653    fn prod_by_grlwe_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize {
654        <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_inplace_scratch_space(module, lhs, rhs)
655    }
656
657    fn prod_by_rgsw_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize {
658        <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_inplace_scratch_space(module, lhs, rhs)
659    }
660}
661
662impl ProdScratchSpace for RLWECtDft<Vec<u8>, FFT64> {
663    fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
664        <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_scratch_space(module, res_size, lhs, rhs)
665    }
666
667    fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
668        <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_scratch_space(module, res_size, lhs, rhs)
669    }
670}
671
672impl<MUT, REF> ProdInplace<MUT, REF> for RLWECtDft<MUT, FFT64>
673where
674    VecZnxDft<MUT, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
675    MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>,
676{
677    fn prod_by_grlwe_inplace(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) {
678        rhs.prod_with_rlwe_dft_inplace(module, self, scratch);
679    }
680
681    fn prod_by_rgsw_inplace(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) {
682        rhs.prod_with_rlwe_dft_inplace(module, self, scratch);
683    }
684}
685
686impl<MUT, REF> Product<MUT, REF> for RLWECtDft<MUT, FFT64>
687where
688    VecZnxDft<MUT, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
689    VecZnxDft<REF, FFT64>: VecZnxDftToRef<FFT64>,
690    MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>,
691{
692    type Lhs = RLWECtDft<REF, FFT64>;
693
694    fn prod_by_grlwe(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) {
695        rhs.prod_with_rlwe_dft(module, self, lhs, scratch);
696    }
697
698    fn prod_by_rgsw(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) {
699        rhs.prod_with_rlwe_dft(module, self, lhs, scratch);
700    }
701}