use backend::{FFT64, Module, ScalarZnxDftOps, Scratch, VecZnxBigOps, VecZnxDftOps, ZnxZero}; use crate::{FourierGLWESecret, GLWECiphertext, GLWEPlaintext, Infos}; impl> GLWECiphertext { pub fn clone(&self) -> GLWECiphertext> { GLWECiphertext { data: self.data.clone(), basek: self.basek(), k: self.k(), } } pub fn decrypt + AsRef<[u8]>, DataSk: AsRef<[u8]>>( &self, module: &Module, pt: &mut GLWEPlaintext, sk: &FourierGLWESecret, scratch: &mut Scratch, ) { #[cfg(debug_assertions)] { assert_eq!(self.rank(), sk.rank()); assert_eq!(self.n(), module.n()); assert_eq!(pt.n(), module.n()); assert_eq!(sk.n(), module.n()); } let cols: usize = self.rank() + 1; let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, self.size()); // TODO optimize size when pt << ct c0_big.zero(); { (1..cols).for_each(|i| { // ci_dft = DFT(a[i]) * DFT(s[i]) let (mut ci_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, self.size()); // TODO optimize size when pt << ct module.vec_znx_dft(1, 0, &mut ci_dft, 0, &self.data, i); module.svp_apply_inplace(&mut ci_dft, 0, &sk.data, i - 1); let ci_big = module.vec_znx_idft_consume(ci_dft); // c0_big += a[i] * s[i] module.vec_znx_big_add_inplace(&mut c0_big, 0, &ci_big, 0); }); } // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e) module.vec_znx_big_add_small_inplace(&mut c0_big, 0, &self.data, 0); // pt = norm(BIG(m + e)) module.vec_znx_big_normalize(self.basek(), &mut pt.data, 0, &mut c0_big, 0, scratch_1); pt.basek = self.basek(); pt.k = pt.k().min(self.k()); } }