poulpy/core/src/glwe/decryption.rs
core/src/glwe/decryption.rsRaw
1use backend::{FFT64, Module, ScalarZnxDftOps, Scratch, VecZnxBigOps, VecZnxDftOps, ZnxZero};
2
3use crate::{FourierGLWESecret, GLWECiphertext, GLWEPlaintext, Infos};
4
5impl<DataSelf: AsRef<[u8]>> GLWECiphertext<DataSelf> {
6 pub fn clone(&self) -> GLWECiphertext<Vec<u8>> {
7 GLWECiphertext {
8 data: self.data.clone(),
9 basek: self.basek(),
10 k: self.k(),
11 }
12 }
13
14 pub fn decrypt<DataPt: AsMut<[u8]> + AsRef<[u8]>, DataSk: AsRef<[u8]>>(
15 &self,
16 module: &Module<FFT64>,
17 pt: &mut GLWEPlaintext<DataPt>,
18 sk: &FourierGLWESecret<DataSk, FFT64>,
19 scratch: &mut Scratch,
20 ) {
21 #[cfg(debug_assertions)]
22 {
23 assert_eq!(self.rank(), sk.rank());
24 assert_eq!(self.n(), module.n());
25 assert_eq!(pt.n(), module.n());
26 assert_eq!(sk.n(), module.n());
27 }
28
29 let cols: usize = self.rank() + 1;
30
31 let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, self.size()); // TODO optimize size when pt << ct
32 c0_big.zero();
33
34 {
35 (1..cols).for_each(|i| {
36 // ci_dft = DFT(a[i]) * DFT(s[i])
37 let (mut ci_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, self.size()); // TODO optimize size when pt << ct
38 module.vec_znx_dft(1, 0, &mut ci_dft, 0, &self.data, i);
39 module.svp_apply_inplace(&mut ci_dft, 0, &sk.data, i - 1);
40 let ci_big = module.vec_znx_idft_consume(ci_dft);
41
42 // c0_big += a[i] * s[i]
43 module.vec_znx_big_add_inplace(&mut c0_big, 0, &ci_big, 0);
44 });
45 }
46
47 // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e)
48 module.vec_znx_big_add_small_inplace(&mut c0_big, 0, &self.data, 0);
49
50 // pt = norm(BIG(m + e))
51 module.vec_znx_big_normalize(self.basek(), &mut pt.data, 0, &mut c0_big, 0, scratch_1);
52
53 pt.basek = self.basek();
54 pt.k = pt.k().min(self.k());
55 }
56}