arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/fourier_glwe/decryption.rs
core/src/fourier_glwe/decryption.rsRaw
 1use backend::{
 2    FFT64, Module, ScalarZnxDftOps, Scratch, VecZnxBig, VecZnxBigAlloc, VecZnxBigOps, VecZnxBigScratch, VecZnxDftAlloc,
 3    VecZnxDftOps, ZnxZero,
 4};
 5
 6use crate::{FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, GLWEPlaintext, Infos, div_ceil};
 7
 8impl FourierGLWECiphertext<Vec<u8>, FFT64> {
 9    pub fn decrypt_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize {
10        let size: usize = div_ceil(k, basek);
11        (module.vec_znx_big_normalize_tmp_bytes()
12            | module.bytes_of_vec_znx_dft(1, size)
13            | (module.bytes_of_vec_znx_big(1, size) + module.vec_znx_idft_tmp_bytes()))
14            + module.bytes_of_vec_znx_big(1, size)
15    }
16}
17
18impl<DataSelf: AsRef<[u8]>> FourierGLWECiphertext<DataSelf, FFT64> {
19    pub fn decrypt<DataPt: AsRef<[u8]> + AsMut<[u8]>, DataSk: AsRef<[u8]>>(
20        &self,
21        module: &Module<FFT64>,
22        pt: &mut GLWEPlaintext<DataPt>,
23        sk: &FourierGLWESecret<DataSk, FFT64>,
24        scratch: &mut Scratch,
25    ) {
26        #[cfg(debug_assertions)]
27        {
28            assert_eq!(self.rank(), sk.rank());
29            assert_eq!(self.n(), module.n());
30            assert_eq!(pt.n(), module.n());
31            assert_eq!(sk.n(), module.n());
32        }
33
34        let cols = self.rank() + 1;
35
36        let (mut pt_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, self.size()); // TODO optimize size when pt << ct
37        pt_big.zero();
38
39        {
40            (1..cols).for_each(|i| {
41                let (mut ci_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, self.size()); // TODO optimize size when pt << ct
42                module.svp_apply(&mut ci_dft, 0, &sk.data, i - 1, &self.data, i);
43                let ci_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(ci_dft);
44                module.vec_znx_big_add_inplace(&mut pt_big, 0, &ci_big, 0);
45            });
46        }
47
48        {
49            let (mut c0_big, scratch_2) = scratch_1.tmp_vec_znx_big(module, 1, self.size());
50            // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e)
51            module.vec_znx_idft(&mut c0_big, 0, &self.data, 0, scratch_2);
52            module.vec_znx_big_add_inplace(&mut pt_big, 0, &c0_big, 0);
53        }
54
55        // pt = norm(BIG(m + e))
56        module.vec_znx_big_normalize(self.basek(), &mut pt.data, 0, &mut pt_big, 0, scratch_1);
57
58        pt.basek = self.basek();
59        pt.k = pt.k().min(self.k());
60    }
61
62    #[allow(dead_code)]
63    pub(crate) fn idft<DataRes: AsRef<[u8]> + AsMut<[u8]>>(
64        &self,
65        module: &Module<FFT64>,
66        res: &mut GLWECiphertext<DataRes>,
67        scratch: &mut Scratch,
68    ) {
69        #[cfg(debug_assertions)]
70        {
71            assert_eq!(self.rank(), res.rank());
72            assert_eq!(self.basek(), res.basek())
73        }
74
75        let min_size: usize = self.size().min(res.size());
76
77        let (mut res_big, scratch1) = scratch.tmp_vec_znx_big(module, 1, min_size);
78
79        (0..self.rank() + 1).for_each(|i| {
80            module.vec_znx_idft(&mut res_big, 0, &self.data, i, scratch1);
81            module.vec_znx_big_normalize(self.basek(), &mut res.data, i, &res_big, 0, scratch1);
82        });
83    }
84}