arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/glwe.rs
core/src/glwe.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,
 10    encryption::{EncryptSk, EncryptSkScratchSpace, EncryptZeroSkScratchSpace},
 11    external_product::{
 12        ExternalProduct, ExternalProductInplace, ExternalProductInplaceScratchSpace, ExternalProductScratchSpace,
 13    },
 14    ggsw::GGSWCiphertext,
 15    keys::{PublicKey, SecretDistribution, SecretKeyFourier},
 16    keyswitch::{KeySwitch, KeySwitchInplace, KeySwitchInplaceScratchSpace, KeySwitchScratchSpace},
 17    keyswitch_key::GLWEKeySwitchKey,
 18    utils::derive_size,
 19    vec_glwe_product::{VecGLWEProduct, VecGLWEProductScratchSpace},
 20};
 21
 22pub struct GLWECiphertext<C> {
 23    pub data: VecZnx<C>,
 24    pub log_base2k: usize,
 25    pub log_k: usize,
 26}
 27
 28impl GLWECiphertext<Vec<u8>> {
 29    pub fn new<B: Backend>(module: &Module<B>, log_base2k: usize, log_k: usize) -> Self {
 30        Self {
 31            data: module.new_vec_znx(2, derive_size(log_base2k, log_k)),
 32            log_base2k: log_base2k,
 33            log_k: log_k,
 34        }
 35    }
 36}
 37
 38impl<T> Infos for GLWECiphertext<T> {
 39    type Inner = VecZnx<T>;
 40
 41    fn inner(&self) -> &Self::Inner {
 42        &self.data
 43    }
 44
 45    fn basek(&self) -> usize {
 46        self.log_base2k
 47    }
 48
 49    fn k(&self) -> usize {
 50        self.log_k
 51    }
 52}
 53
 54impl<C> VecZnxToMut for GLWECiphertext<C>
 55where
 56    VecZnx<C>: VecZnxToMut,
 57{
 58    fn to_mut(&mut self) -> VecZnx<&mut [u8]> {
 59        self.data.to_mut()
 60    }
 61}
 62
 63impl<C> VecZnxToRef for GLWECiphertext<C>
 64where
 65    VecZnx<C>: VecZnxToRef,
 66{
 67    fn to_ref(&self) -> VecZnx<&[u8]> {
 68        self.data.to_ref()
 69    }
 70}
 71
 72impl<C> GLWECiphertext<C>
 73where
 74    VecZnx<C>: VecZnxToRef,
 75{
 76    #[allow(dead_code)]
 77    pub(crate) fn dft<R>(&self, module: &Module<FFT64>, res: &mut GLWECiphertextFourier<R, FFT64>)
 78    where
 79        VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64> + ZnxInfos,
 80    {
 81        #[cfg(debug_assertions)]
 82        {
 83            assert_eq!(self.rank(), 2);
 84            assert_eq!(res.rank(), 2);
 85            assert_eq!(self.basek(), res.basek())
 86        }
 87
 88        module.vec_znx_dft(res, 0, self, 0);
 89        module.vec_znx_dft(res, 1, self, 1);
 90    }
 91}
 92
 93impl KeySwitchScratchSpace for GLWECiphertext<Vec<u8>> {
 94    fn keyswitch_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
 95        <GLWEKeySwitchKey<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_scratch_space(module, res_size, lhs, rhs)
 96    }
 97}
 98
 99impl<DataSelf, DataLhs, DataRhs> KeySwitch<DataLhs, DataRhs> for GLWECiphertext<DataSelf>
100where
101    VecZnx<DataSelf>: VecZnxToMut + VecZnxToRef,
102    VecZnx<DataLhs>: VecZnxToRef,
103    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64>,
104{
105    type Lhs = GLWECiphertext<DataLhs>;
106    type Rhs = GLWEKeySwitchKey<DataRhs, FFT64>;
107
108    fn keyswitch(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &Self::Rhs, scratch: &mut Scratch) {
109        rhs.prod_with_glwe(module, self, lhs, scratch);
110    }
111}
112
113impl KeySwitchInplaceScratchSpace for GLWECiphertext<Vec<u8>> {
114    fn keyswitch_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, rhs: usize) -> usize {
115        <GLWEKeySwitchKey<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_inplace_scratch_space(
116            module, res_size, rhs,
117        )
118    }
119}
120
121impl<DataSelf, DataRhs> KeySwitchInplace<DataRhs> for GLWECiphertext<DataSelf>
122where
123    VecZnx<DataSelf>: VecZnxToMut + VecZnxToRef,
124    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64>,
125{
126    type Rhs = GLWEKeySwitchKey<DataRhs, FFT64>;
127
128    fn keyswitch_inplace(&mut self, module: &Module<FFT64>, rhs: &Self::Rhs, scratch: &mut Scratch) {
129        rhs.prod_with_glwe_inplace(module, self, scratch);
130    }
131}
132
133impl ExternalProductScratchSpace for GLWECiphertext<Vec<u8>> {
134    fn external_product_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
135        <GGSWCiphertext<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_scratch_space(module, res_size, lhs, rhs)
136    }
137}
138
139impl<DataSelf, DataLhs, DataRhs> ExternalProduct<DataLhs, DataRhs> for GLWECiphertext<DataSelf>
140where
141    VecZnx<DataSelf>: VecZnxToMut + VecZnxToRef,
142    VecZnx<DataLhs>: VecZnxToRef,
143    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64>,
144{
145    type Lhs = GLWECiphertext<DataLhs>;
146    type Rhs = GGSWCiphertext<DataRhs, FFT64>;
147
148    fn external_product(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &Self::Rhs, scratch: &mut Scratch) {
149        rhs.prod_with_glwe(module, self, lhs, scratch);
150    }
151}
152
153impl ExternalProductInplaceScratchSpace for GLWECiphertext<Vec<u8>> {
154    fn external_product_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, rhs: usize) -> usize {
155        <GGSWCiphertext<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_inplace_scratch_space(
156            module, res_size, rhs,
157        )
158    }
159}
160
161impl<DataSelf, DataRhs> ExternalProductInplace<DataRhs> for GLWECiphertext<DataSelf>
162where
163    VecZnx<DataSelf>: VecZnxToMut + VecZnxToRef,
164    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
165{
166    type Rhs = GGSWCiphertext<DataRhs, FFT64>;
167
168    fn external_product_inplace(&mut self, module: &Module<FFT64>, rhs: &Self::Rhs, scratch: &mut Scratch) {
169        rhs.prod_with_glwe_inplace(module, self, scratch);
170    }
171}
172
173impl GLWECiphertext<Vec<u8>> {
174    pub fn encrypt_pk_scratch_space<B: Backend>(module: &Module<B>, pk_size: usize) -> usize {
175        ((module.bytes_of_vec_znx_dft(1, pk_size) + module.bytes_of_vec_znx_big(1, pk_size)) | module.bytes_of_scalar_znx(1))
176            + module.bytes_of_scalar_znx_dft(1)
177            + module.vec_znx_big_normalize_tmp_bytes()
178    }
179
180    pub fn decrypt_scratch_space<B: Backend>(module: &Module<B>, size: usize) -> usize {
181        (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size)
182    }
183}
184
185impl EncryptSkScratchSpace for GLWECiphertext<Vec<u8>> {
186    fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, size: usize) -> usize {
187        (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size)
188    }
189}
190
191impl<DataCt, DataPt, DataSk> EncryptSk<DataCt, DataPt, DataSk, FFT64> for GLWECiphertext<DataCt>
192where
193    VecZnx<DataCt>: VecZnxToMut + VecZnxToRef,
194    VecZnx<DataPt>: VecZnxToRef,
195    ScalarZnxDft<DataSk, FFT64>: ScalarZnxDftToRef<FFT64>,
196{
197    type Ciphertext = GLWECiphertext<DataCt>;
198    type Plaintext = GLWEPlaintext<DataPt>;
199    type SecretKey = SecretKeyFourier<DataSk, FFT64>;
200
201    fn encrypt_sk(
202        &self,
203        module: &Module<FFT64>,
204        ct: &mut Self::Ciphertext,
205        pt: &Self::Plaintext,
206        sk: &Self::SecretKey,
207        source_xa: &mut Source,
208        source_xe: &mut Source,
209        sigma: f64,
210        bound: f64,
211        scratch: &mut Scratch,
212    ) {
213        encrypt_glwe_sk(
214            module,
215            ct,
216            Some((pt, 0)),
217            sk,
218            source_xa,
219            source_xe,
220            sigma,
221            bound,
222            scratch,
223        );
224    }
225}
226
227pub(crate) fn encrypt_glwe_sk<DataCt, DataPt, DataSk>(
228    module: &Module<FFT64>,
229    ct: &mut GLWECiphertext<DataCt>,
230    pt: Option<(&GLWEPlaintext<DataPt>, usize)>,
231    sk_dft: &SecretKeyFourier<DataSk, FFT64>,
232    source_xa: &mut Source,
233    source_xe: &mut Source,
234    sigma: f64,
235    bound: f64,
236    scratch: &mut Scratch,
237) where
238    VecZnx<DataCt>: VecZnxToMut + VecZnxToRef,
239    VecZnx<DataPt>: VecZnxToRef,
240    ScalarZnxDft<DataSk, FFT64>: ScalarZnxDftToRef<FFT64>,
241{
242    let log_base2k: usize = ct.basek();
243    let log_k: usize = ct.k();
244    let size: usize = ct.size();
245
246    // c1 = a
247    ct.data.fill_uniform(log_base2k, 1, size, source_xa);
248
249    let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size);
250
251    {
252        let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size);
253        module.vec_znx_dft(&mut c0_dft, 0, ct, 1);
254
255        // c0_dft = DFT(a) * DFT(s)
256        module.svp_apply_inplace(&mut c0_dft, 0, sk_dft, 0);
257
258        // c0_big = IDFT(c0_dft)
259        module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0);
260    }
261
262    // c0_big = m - c0_big
263    if let Some((pt, col)) = pt {
264        match col {
265            0 => module.vec_znx_big_sub_small_b_inplace(&mut c0_big, 0, pt, 0),
266            1 => {
267                module.vec_znx_big_negate_inplace(&mut c0_big, 0);
268                module.vec_znx_add_inplace(ct, 1, pt, 0);
269                module.vec_znx_normalize_inplace(log_base2k, ct, 1, scratch_1);
270            }
271            _ => panic!("invalid target column: {}", col),
272        }
273    } else {
274        module.vec_znx_big_negate_inplace(&mut c0_big, 0);
275    }
276    // c0_big += e
277    c0_big.add_normal(log_base2k, 0, log_k, source_xe, sigma, bound);
278
279    // c0 = norm(c0_big = -as + m + e)
280    module.vec_znx_big_normalize(log_base2k, ct, 0, &c0_big, 0, scratch_1);
281}
282
283pub fn decrypt_glwe<P, C, S>(
284    module: &Module<FFT64>,
285    pt: &mut GLWEPlaintext<P>,
286    ct: &GLWECiphertext<C>,
287    sk_dft: &SecretKeyFourier<S, FFT64>,
288    scratch: &mut Scratch,
289) where
290    VecZnx<P>: VecZnxToMut + VecZnxToRef,
291    VecZnx<C>: VecZnxToRef,
292    ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
293{
294    let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, ct.size()); // TODO optimize size when pt << ct
295
296    {
297        let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, ct.size()); // TODO optimize size when pt << ct
298        module.vec_znx_dft(&mut c0_dft, 0, ct, 1);
299
300        // c0_dft = DFT(a) * DFT(s)
301        module.svp_apply_inplace(&mut c0_dft, 0, sk_dft, 0);
302
303        // c0_big = IDFT(c0_dft)
304        module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0);
305    }
306
307    // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e)
308    module.vec_znx_big_add_small_inplace(&mut c0_big, 0, ct, 0);
309
310    // pt = norm(BIG(m + e))
311    module.vec_znx_big_normalize(ct.basek(), pt, 0, &mut c0_big, 0, scratch_1);
312
313    pt.log_base2k = ct.basek();
314    pt.log_k = pt.k().min(ct.k());
315}
316
317impl<MUT> GLWECiphertext<MUT>
318where
319    VecZnx<MUT>: VecZnxToMut + VecZnxToRef,
320{
321    pub fn encrypt_sk<R0, R1>(
322        &mut self,
323        module: &Module<FFT64>,
324        pt: &GLWEPlaintext<R0>,
325        sk_dft: &SecretKeyFourier<R1, FFT64>,
326        source_xa: &mut Source,
327        source_xe: &mut Source,
328        sigma: f64,
329        bound: f64,
330        scratch: &mut Scratch,
331    ) where
332        VecZnx<R0>: VecZnxToRef,
333        ScalarZnxDft<R1, FFT64>: ScalarZnxDftToRef<FFT64>,
334    {
335        encrypt_glwe_sk(
336            module,
337            self,
338            Some((pt, 0)),
339            sk_dft,
340            source_xa,
341            source_xe,
342            sigma,
343            bound,
344            scratch,
345        )
346    }
347
348    pub fn encrypt_zero_sk<R>(
349        &mut self,
350        module: &Module<FFT64>,
351        sk_dft: &SecretKeyFourier<R, FFT64>,
352        source_xa: &mut Source,
353        source_xe: &mut Source,
354        sigma: f64,
355        bound: f64,
356        scratch: &mut Scratch,
357    ) where
358        ScalarZnxDft<R, FFT64>: ScalarZnxDftToRef<FFT64>,
359    {
360        encrypt_glwe_sk::<MUT, _, R>(
361            module, self, None, sk_dft, source_xa, source_xe, sigma, bound, scratch,
362        )
363    }
364
365    pub fn encrypt_pk<R0, R1>(
366        &mut self,
367        module: &Module<FFT64>,
368        pt: &GLWEPlaintext<R0>,
369        pk: &PublicKey<R1, FFT64>,
370        source_xu: &mut Source,
371        source_xe: &mut Source,
372        sigma: f64,
373        bound: f64,
374        scratch: &mut Scratch,
375    ) where
376        VecZnx<R0>: VecZnxToRef,
377        VecZnxDft<R1, FFT64>: VecZnxDftToRef<FFT64>,
378    {
379        encrypt_glwe_pk(
380            module,
381            self,
382            Some(pt),
383            pk,
384            source_xu,
385            source_xe,
386            sigma,
387            bound,
388            scratch,
389        )
390    }
391
392    pub fn encrypt_zero_pk<R>(
393        &mut self,
394        module: &Module<FFT64>,
395        pk: &PublicKey<R, FFT64>,
396        source_xu: &mut Source,
397        source_xe: &mut Source,
398        sigma: f64,
399        bound: f64,
400        scratch: &mut Scratch,
401    ) where
402        VecZnxDft<R, FFT64>: VecZnxDftToRef<FFT64>,
403    {
404        encrypt_glwe_pk::<MUT, _, R>(
405            module, self, None, pk, source_xu, source_xe, sigma, bound, scratch,
406        )
407    }
408}
409
410impl<REF> GLWECiphertext<REF>
411where
412    VecZnx<REF>: VecZnxToRef,
413{
414    pub fn decrypt<MUT, REF1>(
415        &self,
416        module: &Module<FFT64>,
417        pt: &mut GLWEPlaintext<MUT>,
418        sk_dft: &SecretKeyFourier<REF1, FFT64>,
419        scratch: &mut Scratch,
420    ) where
421        VecZnx<MUT>: VecZnxToMut + VecZnxToRef,
422        ScalarZnxDft<REF1, FFT64>: ScalarZnxDftToRef<FFT64>,
423    {
424        decrypt_glwe(module, pt, self, sk_dft, scratch);
425    }
426}
427
428pub(crate) fn encrypt_glwe_pk<C, P, S>(
429    module: &Module<FFT64>,
430    ct: &mut GLWECiphertext<C>,
431    pt: Option<&GLWEPlaintext<P>>,
432    pk: &PublicKey<S, FFT64>,
433    source_xu: &mut Source,
434    source_xe: &mut Source,
435    sigma: f64,
436    bound: f64,
437    scratch: &mut Scratch,
438) where
439    VecZnx<C>: VecZnxToMut + VecZnxToRef,
440    VecZnx<P>: VecZnxToRef,
441    VecZnxDft<S, FFT64>: VecZnxDftToRef<FFT64>,
442{
443    #[cfg(debug_assertions)]
444    {
445        assert_eq!(ct.basek(), pk.basek());
446        assert_eq!(ct.n(), module.n());
447        assert_eq!(pk.n(), module.n());
448        if let Some(pt) = pt {
449            assert_eq!(pt.basek(), pk.basek());
450            assert_eq!(pt.n(), module.n());
451        }
452    }
453
454    let log_base2k: usize = pk.basek();
455    let size_pk: usize = pk.size();
456
457    // Generates u according to the underlying secret distribution.
458    let (mut u_dft, scratch_1) = scratch.tmp_scalar_znx_dft(module, 1);
459
460    {
461        let (mut u, _) = scratch_1.tmp_scalar_znx(module, 1);
462        match pk.dist {
463            SecretDistribution::NONE => panic!(
464                "invalid public key: SecretDistribution::NONE, ensure it has been correctly intialized through Self::generate"
465            ),
466            SecretDistribution::TernaryFixed(hw) => u.fill_ternary_hw(0, hw, source_xu),
467            SecretDistribution::TernaryProb(prob) => u.fill_ternary_prob(0, prob, source_xu),
468            SecretDistribution::ZERO => {}
469        }
470
471        module.svp_prepare(&mut u_dft, 0, &u, 0);
472    }
473
474    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)
475    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)
476
477    // ct[0] = pk[0] * u + m + e0
478    module.svp_apply(&mut tmp_dft, 0, &u_dft, 0, pk, 0);
479    module.vec_znx_idft_tmp_a(&mut tmp_big, 0, &mut tmp_dft, 0);
480    tmp_big.add_normal(log_base2k, 0, pk.k(), source_xe, sigma, bound);
481
482    if let Some(pt) = pt {
483        module.vec_znx_big_add_small_inplace(&mut tmp_big, 0, pt, 0);
484    }
485
486    module.vec_znx_big_normalize(log_base2k, ct, 0, &tmp_big, 0, scratch_3);
487
488    // ct[1] = pk[1] * u + e1
489    module.svp_apply(&mut tmp_dft, 0, &u_dft, 0, pk, 1);
490    module.vec_znx_idft_tmp_a(&mut tmp_big, 0, &mut tmp_dft, 0);
491    tmp_big.add_normal(log_base2k, 0, pk.k(), source_xe, sigma, bound);
492    module.vec_znx_big_normalize(log_base2k, ct, 1, &tmp_big, 0, scratch_3);
493}
494
495pub struct GLWEPlaintext<C> {
496    pub data: VecZnx<C>,
497    pub log_base2k: usize,
498    pub log_k: usize,
499}
500
501impl<T> Infos for GLWEPlaintext<T> {
502    type Inner = VecZnx<T>;
503
504    fn inner(&self) -> &Self::Inner {
505        &self.data
506    }
507
508    fn basek(&self) -> usize {
509        self.log_base2k
510    }
511
512    fn k(&self) -> usize {
513        self.log_k
514    }
515}
516
517impl<C> VecZnxToMut for GLWEPlaintext<C>
518where
519    VecZnx<C>: VecZnxToMut,
520{
521    fn to_mut(&mut self) -> VecZnx<&mut [u8]> {
522        self.data.to_mut()
523    }
524}
525
526impl<C> VecZnxToRef for GLWEPlaintext<C>
527where
528    VecZnx<C>: VecZnxToRef,
529{
530    fn to_ref(&self) -> VecZnx<&[u8]> {
531        self.data.to_ref()
532    }
533}
534
535impl GLWEPlaintext<Vec<u8>> {
536    pub fn new<B: Backend>(module: &Module<B>, log_base2k: usize, log_k: usize) -> Self {
537        Self {
538            data: module.new_vec_znx(1, derive_size(log_base2k, log_k)),
539            log_base2k: log_base2k,
540            log_k: log_k,
541        }
542    }
543}
544
545pub struct GLWECiphertextFourier<C, B: Backend> {
546    pub data: VecZnxDft<C, B>,
547    pub log_base2k: usize,
548    pub log_k: usize,
549}
550
551impl<B: Backend> GLWECiphertextFourier<Vec<u8>, B> {
552    pub fn new(module: &Module<B>, log_base2k: usize, log_k: usize) -> Self {
553        Self {
554            data: module.new_vec_znx_dft(2, derive_size(log_base2k, log_k)),
555            log_base2k: log_base2k,
556            log_k: log_k,
557        }
558    }
559}
560
561impl<T, B: Backend> Infos for GLWECiphertextFourier<T, B> {
562    type Inner = VecZnxDft<T, B>;
563
564    fn inner(&self) -> &Self::Inner {
565        &self.data
566    }
567
568    fn basek(&self) -> usize {
569        self.log_base2k
570    }
571
572    fn k(&self) -> usize {
573        self.log_k
574    }
575}
576
577impl<C, B: Backend> VecZnxDftToMut<B> for GLWECiphertextFourier<C, B>
578where
579    VecZnxDft<C, B>: VecZnxDftToMut<B>,
580{
581    fn to_mut(&mut self) -> VecZnxDft<&mut [u8], B> {
582        self.data.to_mut()
583    }
584}
585
586impl<C, B: Backend> VecZnxDftToRef<B> for GLWECiphertextFourier<C, B>
587where
588    VecZnxDft<C, B>: VecZnxDftToRef<B>,
589{
590    fn to_ref(&self) -> VecZnxDft<&[u8], B> {
591        self.data.to_ref()
592    }
593}
594
595impl<C> GLWECiphertextFourier<C, FFT64>
596where
597    GLWECiphertextFourier<C, FFT64>: VecZnxDftToRef<FFT64>,
598{
599    #[allow(dead_code)]
600    pub(crate) fn idft_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
601        module.bytes_of_vec_znx(2, size) + (module.vec_znx_big_normalize_tmp_bytes() | module.vec_znx_idft_tmp_bytes())
602    }
603
604    pub(crate) fn idft<R>(&self, module: &Module<FFT64>, res: &mut GLWECiphertext<R>, scratch: &mut Scratch)
605    where
606        GLWECiphertext<R>: VecZnxToMut,
607    {
608        #[cfg(debug_assertions)]
609        {
610            assert_eq!(self.rank(), 2);
611            assert_eq!(res.rank(), 2);
612            assert_eq!(self.basek(), res.basek())
613        }
614
615        let min_size: usize = self.size().min(res.size());
616
617        let (mut res_big, scratch1) = scratch.tmp_vec_znx_big(module, 2, min_size);
618
619        module.vec_znx_idft(&mut res_big, 0, self, 0, scratch1);
620        module.vec_znx_idft(&mut res_big, 1, self, 1, scratch1);
621        module.vec_znx_big_normalize(self.basek(), res, 0, &res_big, 0, scratch1);
622        module.vec_znx_big_normalize(self.basek(), res, 1, &res_big, 1, scratch1);
623    }
624}
625
626pub(crate) fn encrypt_zero_glwe_dft_sk<C, S>(
627    module: &Module<FFT64>,
628    ct: &mut GLWECiphertextFourier<C, FFT64>,
629    sk: &SecretKeyFourier<S, FFT64>,
630    source_xa: &mut Source,
631    source_xe: &mut Source,
632    sigma: f64,
633    bound: f64,
634    scratch: &mut Scratch,
635) where
636    VecZnxDft<C, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
637    ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
638{
639    let log_base2k: usize = ct.basek();
640    let log_k: usize = ct.k();
641    let size: usize = ct.size();
642
643    #[cfg(debug_assertions)]
644    {
645        match sk.dist {
646            SecretDistribution::NONE => panic!("invalid sk.dist = SecretDistribution::NONE"),
647            _ => {}
648        }
649        assert_eq!(ct.rank(), 2);
650    }
651
652    // ct[1] = DFT(a)
653    {
654        let (mut tmp_znx, _) = scratch.tmp_vec_znx(module, 1, size);
655        tmp_znx.fill_uniform(log_base2k, 0, size, source_xa);
656        module.vec_znx_dft(ct, 1, &tmp_znx, 0);
657    }
658
659    let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size);
660
661    {
662        let (mut tmp_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size);
663        // c0_dft = ct[1] * DFT(s)
664        module.svp_apply(&mut tmp_dft, 0, sk, 0, ct, 1);
665
666        // c0_big = IDFT(c0_dft)
667        module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut tmp_dft, 0);
668    }
669
670    // c0_big += e
671    c0_big.add_normal(log_base2k, 0, log_k, source_xe, sigma, bound);
672
673    // c0 = norm(c0_big = -as - e), NOTE: e is centered at 0.
674    let (mut tmp_znx, scratch_2) = scratch_1.tmp_vec_znx(module, 1, size);
675    module.vec_znx_big_normalize(log_base2k, &mut tmp_znx, 0, &c0_big, 0, scratch_2);
676    module.vec_znx_negate_inplace(&mut tmp_znx, 0);
677    // ct[0] = DFT(-as + e)
678    module.vec_znx_dft(ct, 0, &tmp_znx, 0);
679}
680
681impl GLWECiphertextFourier<Vec<u8>, FFT64> {
682    pub fn encrypt_zero_sk_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
683        (module.bytes_of_vec_znx(1, size) | module.bytes_of_vec_znx_dft(1, size))
684            + module.bytes_of_vec_znx_big(1, size)
685            + module.bytes_of_vec_znx(1, size)
686            + module.vec_znx_big_normalize_tmp_bytes()
687    }
688
689    pub fn decrypt_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
690        (module.vec_znx_big_normalize_tmp_bytes()
691            | module.bytes_of_vec_znx_dft(1, size)
692            | (module.bytes_of_vec_znx_big(1, size) + module.vec_znx_idft_tmp_bytes()))
693            + module.bytes_of_vec_znx_big(1, size)
694    }
695}
696
697pub fn decrypt_rlwe_dft<P, C, S>(
698    module: &Module<FFT64>,
699    pt: &mut GLWEPlaintext<P>,
700    ct: &GLWECiphertextFourier<C, FFT64>,
701    sk: &SecretKeyFourier<S, FFT64>,
702    scratch: &mut Scratch,
703) where
704    VecZnx<P>: VecZnxToMut + VecZnxToRef,
705    VecZnxDft<C, FFT64>: VecZnxDftToRef<FFT64>,
706    ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
707{
708    let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, ct.size()); // TODO optimize size when pt << ct
709
710    {
711        let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, ct.size()); // TODO optimize size when pt << ct
712        // c0_dft = DFT(a) * DFT(s)
713        module.svp_apply(&mut c0_dft, 0, sk, 0, ct, 1);
714        // c0_big = IDFT(c0_dft)
715        module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0);
716    }
717
718    {
719        let (mut c1_big, scratch_2) = scratch_1.tmp_vec_znx_big(module, 1, ct.size());
720        // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e)
721        module.vec_znx_idft(&mut c1_big, 0, ct, 0, scratch_2);
722        module.vec_znx_big_add_inplace(&mut c0_big, 0, &c1_big, 0);
723    }
724
725    // pt = norm(BIG(m + e))
726    module.vec_znx_big_normalize(ct.basek(), pt, 0, &mut c0_big, 0, scratch_1);
727
728    pt.log_base2k = ct.basek();
729    pt.log_k = pt.k().min(ct.k());
730}
731
732impl<C> GLWECiphertextFourier<C, FFT64>
733where
734    VecZnxDft<C, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
735{
736    pub(crate) fn encrypt_zero_sk<S>(
737        &mut self,
738        module: &Module<FFT64>,
739        sk_dft: &SecretKeyFourier<S, FFT64>,
740        source_xa: &mut Source,
741        source_xe: &mut Source,
742        sigma: f64,
743        bound: f64,
744        scratch: &mut Scratch,
745    ) where
746        ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
747    {
748        encrypt_zero_glwe_dft_sk(
749            module, self, sk_dft, source_xa, source_xe, sigma, bound, scratch,
750        )
751    }
752
753    pub fn decrypt<P, S>(
754        &self,
755        module: &Module<FFT64>,
756        pt: &mut GLWEPlaintext<P>,
757        sk_dft: &SecretKeyFourier<S, FFT64>,
758        scratch: &mut Scratch,
759    ) where
760        VecZnx<P>: VecZnxToMut + VecZnxToRef,
761        ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
762    {
763        decrypt_rlwe_dft(module, pt, self, sk_dft, scratch);
764    }
765}
766
767impl KeySwitchScratchSpace for GLWECiphertextFourier<Vec<u8>, FFT64> {
768    fn keyswitch_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
769        <GLWEKeySwitchKey<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_scratch_space(module, res_size, lhs, rhs)
770    }
771}
772
773impl<DataSelf, DataLhs, DataRhs> KeySwitch<DataLhs, DataRhs> for GLWECiphertextFourier<DataSelf, FFT64>
774where
775    VecZnxDft<DataSelf, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
776    VecZnxDft<DataLhs, FFT64>: VecZnxDftToRef<FFT64>,
777    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64>,
778{
779    type Lhs = GLWECiphertextFourier<DataLhs, FFT64>;
780    type Rhs = GLWEKeySwitchKey<DataRhs, FFT64>;
781
782    fn keyswitch(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &Self::Rhs, scratch: &mut Scratch) {
783        rhs.prod_with_glwe_fourier(module, self, lhs, scratch);
784    }
785}
786
787impl KeySwitchInplaceScratchSpace for GLWECiphertextFourier<Vec<u8>, FFT64> {
788    fn keyswitch_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, rhs: usize) -> usize {
789        <GLWEKeySwitchKey<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_inplace_scratch_space(
790            module, res_size, rhs,
791        )
792    }
793}
794
795impl<DataSelf, DataRhs> KeySwitchInplace<DataRhs> for GLWECiphertextFourier<DataSelf, FFT64>
796where
797    VecZnxDft<DataSelf, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
798    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64>,
799{
800    type Rhs = GLWEKeySwitchKey<DataRhs, FFT64>;
801
802    fn keyswitch_inplace(&mut self, module: &Module<FFT64>, rhs: &Self::Rhs, scratch: &mut Scratch) {
803        rhs.prod_with_glwe_fourier_inplace(module, self, scratch);
804    }
805}
806
807impl ExternalProductScratchSpace for GLWECiphertextFourier<Vec<u8>, FFT64> {
808    fn external_product_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
809        <GGSWCiphertext<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_scratch_space(module, res_size, lhs, rhs)
810    }
811}
812
813impl<DataSelf, DataLhs, DataRhs> ExternalProduct<DataLhs, DataRhs> for GLWECiphertextFourier<DataSelf, FFT64>
814where
815    VecZnxDft<DataSelf, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
816    VecZnxDft<DataLhs, FFT64>: VecZnxDftToRef<FFT64>,
817    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64>,
818{
819    type Lhs = GLWECiphertextFourier<DataLhs, FFT64>;
820    type Rhs = GGSWCiphertext<DataRhs, FFT64>;
821
822    fn external_product(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &Self::Rhs, scratch: &mut Scratch) {
823        rhs.prod_with_glwe_fourier(module, self, lhs, scratch);
824    }
825}
826
827impl ExternalProductInplaceScratchSpace for GLWECiphertextFourier<Vec<u8>, FFT64> {
828    fn external_product_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, rhs: usize) -> usize {
829        <GGSWCiphertext<Vec<u8>, FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_inplace_scratch_space(
830            module, res_size, rhs,
831        )
832    }
833}
834
835impl<DataSelf, DataRhs> ExternalProductInplace<DataRhs> for GLWECiphertextFourier<DataSelf, FFT64>
836where
837    VecZnxDft<DataSelf, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
838    MatZnxDft<DataRhs, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
839{
840    type Rhs = GGSWCiphertext<DataRhs, FFT64>;
841
842    fn external_product_inplace(&mut self, module: &Module<FFT64>, rhs: &Self::Rhs, scratch: &mut Scratch) {
843        rhs.prod_with_glwe_fourier_inplace(module, self, scratch);
844    }
845}