use base2k::{ AddNormal, Backend, FFT64, FillUniform, MatZnxDft, MatZnxDftToRef, Module, ScalarZnxAlloc, ScalarZnxDft, ScalarZnxDftAlloc, ScalarZnxDftOps, ScalarZnxDftToRef, Scratch, VecZnx, VecZnxAlloc, VecZnxBigAlloc, VecZnxBigOps, VecZnxBigScratch, VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxDftToMut, VecZnxDftToRef, VecZnxOps, VecZnxToMut, VecZnxToRef, ZnxInfos, }; use sampling::source::Source; use crate::{ elem::Infos, encryption::{EncryptSk, EncryptSkScratchSpace, EncryptZeroSkScratchSpace}, external_product::{ ExternalProduct, ExternalProductInplace, ExternalProductInplaceScratchSpace, ExternalProductScratchSpace, }, ggsw::GGSWCiphertext, keys::{PublicKey, SecretDistribution, SecretKeyFourier}, keyswitch::{KeySwitch, KeySwitchInplace, KeySwitchInplaceScratchSpace, KeySwitchScratchSpace}, keyswitch_key::GLWEKeySwitchKey, utils::derive_size, vec_glwe_product::{VecGLWEProduct, VecGLWEProductScratchSpace}, }; pub struct GLWECiphertext { pub data: VecZnx, pub log_base2k: usize, pub log_k: usize, } impl GLWECiphertext> { pub fn new(module: &Module, log_base2k: usize, log_k: usize) -> Self { Self { data: module.new_vec_znx(2, derive_size(log_base2k, log_k)), log_base2k: log_base2k, log_k: log_k, } } } impl Infos for GLWECiphertext { type Inner = VecZnx; fn inner(&self) -> &Self::Inner { &self.data } fn basek(&self) -> usize { self.log_base2k } fn k(&self) -> usize { self.log_k } } impl VecZnxToMut for GLWECiphertext where VecZnx: VecZnxToMut, { fn to_mut(&mut self) -> VecZnx<&mut [u8]> { self.data.to_mut() } } impl VecZnxToRef for GLWECiphertext where VecZnx: VecZnxToRef, { fn to_ref(&self) -> VecZnx<&[u8]> { self.data.to_ref() } } impl GLWECiphertext where VecZnx: VecZnxToRef, { #[allow(dead_code)] pub(crate) fn dft(&self, module: &Module, res: &mut GLWECiphertextFourier) where VecZnxDft: VecZnxDftToMut + ZnxInfos, { #[cfg(debug_assertions)] { assert_eq!(self.rank(), 2); assert_eq!(res.rank(), 2); assert_eq!(self.basek(), res.basek()) } module.vec_znx_dft(res, 0, self, 0); module.vec_znx_dft(res, 1, self, 1); } } impl KeySwitchScratchSpace for GLWECiphertext> { fn keyswitch_scratch_space(module: &Module, res_size: usize, lhs: usize, rhs: usize) -> usize { , FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_scratch_space(module, res_size, lhs, rhs) } } impl KeySwitch for GLWECiphertext where VecZnx: VecZnxToMut + VecZnxToRef, VecZnx: VecZnxToRef, MatZnxDft: MatZnxDftToRef, { type Lhs = GLWECiphertext; type Rhs = GLWEKeySwitchKey; fn keyswitch(&mut self, module: &Module, lhs: &Self::Lhs, rhs: &Self::Rhs, scratch: &mut Scratch) { rhs.prod_with_glwe(module, self, lhs, scratch); } } impl KeySwitchInplaceScratchSpace for GLWECiphertext> { fn keyswitch_inplace_scratch_space(module: &Module, res_size: usize, rhs: usize) -> usize { , FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_inplace_scratch_space( module, res_size, rhs, ) } } impl KeySwitchInplace for GLWECiphertext where VecZnx: VecZnxToMut + VecZnxToRef, MatZnxDft: MatZnxDftToRef, { type Rhs = GLWEKeySwitchKey; fn keyswitch_inplace(&mut self, module: &Module, rhs: &Self::Rhs, scratch: &mut Scratch) { rhs.prod_with_glwe_inplace(module, self, scratch); } } impl ExternalProductScratchSpace for GLWECiphertext> { fn external_product_scratch_space(module: &Module, res_size: usize, lhs: usize, rhs: usize) -> usize { , FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_scratch_space(module, res_size, lhs, rhs) } } impl ExternalProduct for GLWECiphertext where VecZnx: VecZnxToMut + VecZnxToRef, VecZnx: VecZnxToRef, MatZnxDft: MatZnxDftToRef, { type Lhs = GLWECiphertext; type Rhs = GGSWCiphertext; fn external_product(&mut self, module: &Module, lhs: &Self::Lhs, rhs: &Self::Rhs, scratch: &mut Scratch) { rhs.prod_with_glwe(module, self, lhs, scratch); } } impl ExternalProductInplaceScratchSpace for GLWECiphertext> { fn external_product_inplace_scratch_space(module: &Module, res_size: usize, rhs: usize) -> usize { , FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_inplace_scratch_space( module, res_size, rhs, ) } } impl ExternalProductInplace for GLWECiphertext where VecZnx: VecZnxToMut + VecZnxToRef, MatZnxDft: MatZnxDftToRef + ZnxInfos, { type Rhs = GGSWCiphertext; fn external_product_inplace(&mut self, module: &Module, rhs: &Self::Rhs, scratch: &mut Scratch) { rhs.prod_with_glwe_inplace(module, self, scratch); } } impl GLWECiphertext> { pub fn encrypt_pk_scratch_space(module: &Module, pk_size: usize) -> usize { ((module.bytes_of_vec_znx_dft(1, pk_size) + module.bytes_of_vec_znx_big(1, pk_size)) | module.bytes_of_scalar_znx(1)) + module.bytes_of_scalar_znx_dft(1) + module.vec_znx_big_normalize_tmp_bytes() } pub fn decrypt_scratch_space(module: &Module, size: usize) -> usize { (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size) } } impl EncryptSkScratchSpace for GLWECiphertext> { fn encrypt_sk_scratch_space(module: &Module, size: usize) -> usize { (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size) } } impl EncryptSk for GLWECiphertext where VecZnx: VecZnxToMut + VecZnxToRef, VecZnx: VecZnxToRef, ScalarZnxDft: ScalarZnxDftToRef, { type Ciphertext = GLWECiphertext; type Plaintext = GLWEPlaintext; type SecretKey = SecretKeyFourier; fn encrypt_sk( &self, module: &Module, ct: &mut Self::Ciphertext, pt: &Self::Plaintext, sk: &Self::SecretKey, source_xa: &mut Source, source_xe: &mut Source, sigma: f64, bound: f64, scratch: &mut Scratch, ) { encrypt_glwe_sk( module, ct, Some((pt, 0)), sk, source_xa, source_xe, sigma, bound, scratch, ); } } pub(crate) fn encrypt_glwe_sk( module: &Module, ct: &mut GLWECiphertext, pt: Option<(&GLWEPlaintext, usize)>, sk_dft: &SecretKeyFourier, source_xa: &mut Source, source_xe: &mut Source, sigma: f64, bound: f64, scratch: &mut Scratch, ) where VecZnx: VecZnxToMut + VecZnxToRef, VecZnx: VecZnxToRef, ScalarZnxDft: ScalarZnxDftToRef, { let log_base2k: usize = ct.basek(); let log_k: usize = ct.k(); let size: usize = ct.size(); // c1 = a ct.data.fill_uniform(log_base2k, 1, size, source_xa); let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size); { let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size); module.vec_znx_dft(&mut c0_dft, 0, ct, 1); // c0_dft = DFT(a) * DFT(s) module.svp_apply_inplace(&mut c0_dft, 0, sk_dft, 0); // c0_big = IDFT(c0_dft) module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0); } // c0_big = m - c0_big if let Some((pt, col)) = pt { match col { 0 => module.vec_znx_big_sub_small_b_inplace(&mut c0_big, 0, pt, 0), 1 => { module.vec_znx_big_negate_inplace(&mut c0_big, 0); module.vec_znx_add_inplace(ct, 1, pt, 0); module.vec_znx_normalize_inplace(log_base2k, ct, 1, scratch_1); } _ => panic!("invalid target column: {}", col), } } else { module.vec_znx_big_negate_inplace(&mut c0_big, 0); } // c0_big += e c0_big.add_normal(log_base2k, 0, log_k, source_xe, sigma, bound); // c0 = norm(c0_big = -as + m + e) module.vec_znx_big_normalize(log_base2k, ct, 0, &c0_big, 0, scratch_1); } pub fn decrypt_glwe( module: &Module, pt: &mut GLWEPlaintext

, ct: &GLWECiphertext, sk_dft: &SecretKeyFourier, scratch: &mut Scratch, ) where VecZnx

: VecZnxToMut + VecZnxToRef, VecZnx: VecZnxToRef, ScalarZnxDft: ScalarZnxDftToRef, { let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, ct.size()); // TODO optimize size when pt << ct { let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, ct.size()); // TODO optimize size when pt << ct module.vec_znx_dft(&mut c0_dft, 0, ct, 1); // c0_dft = DFT(a) * DFT(s) module.svp_apply_inplace(&mut c0_dft, 0, sk_dft, 0); // c0_big = IDFT(c0_dft) module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0); } // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e) module.vec_znx_big_add_small_inplace(&mut c0_big, 0, ct, 0); // pt = norm(BIG(m + e)) module.vec_znx_big_normalize(ct.basek(), pt, 0, &mut c0_big, 0, scratch_1); pt.log_base2k = ct.basek(); pt.log_k = pt.k().min(ct.k()); } impl GLWECiphertext where VecZnx: VecZnxToMut + VecZnxToRef, { pub fn encrypt_sk( &mut self, module: &Module, pt: &GLWEPlaintext, sk_dft: &SecretKeyFourier, source_xa: &mut Source, source_xe: &mut Source, sigma: f64, bound: f64, scratch: &mut Scratch, ) where VecZnx: VecZnxToRef, ScalarZnxDft: ScalarZnxDftToRef, { encrypt_glwe_sk( module, self, Some((pt, 0)), sk_dft, source_xa, source_xe, sigma, bound, scratch, ) } pub fn encrypt_zero_sk( &mut self, module: &Module, sk_dft: &SecretKeyFourier, source_xa: &mut Source, source_xe: &mut Source, sigma: f64, bound: f64, scratch: &mut Scratch, ) where ScalarZnxDft: ScalarZnxDftToRef, { encrypt_glwe_sk::( module, self, None, sk_dft, source_xa, source_xe, sigma, bound, scratch, ) } pub fn encrypt_pk( &mut self, module: &Module, pt: &GLWEPlaintext, pk: &PublicKey, source_xu: &mut Source, source_xe: &mut Source, sigma: f64, bound: f64, scratch: &mut Scratch, ) where VecZnx: VecZnxToRef, VecZnxDft: VecZnxDftToRef, { encrypt_glwe_pk( module, self, Some(pt), pk, source_xu, source_xe, sigma, bound, scratch, ) } pub fn encrypt_zero_pk( &mut self, module: &Module, pk: &PublicKey, source_xu: &mut Source, source_xe: &mut Source, sigma: f64, bound: f64, scratch: &mut Scratch, ) where VecZnxDft: VecZnxDftToRef, { encrypt_glwe_pk::( module, self, None, pk, source_xu, source_xe, sigma, bound, scratch, ) } } impl GLWECiphertext where VecZnx: VecZnxToRef, { pub fn decrypt( &self, module: &Module, pt: &mut GLWEPlaintext, sk_dft: &SecretKeyFourier, scratch: &mut Scratch, ) where VecZnx: VecZnxToMut + VecZnxToRef, ScalarZnxDft: ScalarZnxDftToRef, { decrypt_glwe(module, pt, self, sk_dft, scratch); } } pub(crate) fn encrypt_glwe_pk( module: &Module, ct: &mut GLWECiphertext, pt: Option<&GLWEPlaintext

>, pk: &PublicKey, source_xu: &mut Source, source_xe: &mut Source, sigma: f64, bound: f64, scratch: &mut Scratch, ) where VecZnx: VecZnxToMut + VecZnxToRef, VecZnx

: VecZnxToRef, VecZnxDft: VecZnxDftToRef, { #[cfg(debug_assertions)] { assert_eq!(ct.basek(), pk.basek()); assert_eq!(ct.n(), module.n()); assert_eq!(pk.n(), module.n()); if let Some(pt) = pt { assert_eq!(pt.basek(), pk.basek()); assert_eq!(pt.n(), module.n()); } } let log_base2k: usize = pk.basek(); let size_pk: usize = pk.size(); // Generates u according to the underlying secret distribution. let (mut u_dft, scratch_1) = scratch.tmp_scalar_znx_dft(module, 1); { let (mut u, _) = scratch_1.tmp_scalar_znx(module, 1); match pk.dist { SecretDistribution::NONE => panic!( "invalid public key: SecretDistribution::NONE, ensure it has been correctly intialized through Self::generate" ), SecretDistribution::TernaryFixed(hw) => u.fill_ternary_hw(0, hw, source_xu), SecretDistribution::TernaryProb(prob) => u.fill_ternary_prob(0, prob, source_xu), SecretDistribution::ZERO => {} } module.svp_prepare(&mut u_dft, 0, &u, 0); } 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) 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) // ct[0] = pk[0] * u + m + e0 module.svp_apply(&mut tmp_dft, 0, &u_dft, 0, pk, 0); module.vec_znx_idft_tmp_a(&mut tmp_big, 0, &mut tmp_dft, 0); tmp_big.add_normal(log_base2k, 0, pk.k(), source_xe, sigma, bound); if let Some(pt) = pt { module.vec_znx_big_add_small_inplace(&mut tmp_big, 0, pt, 0); } module.vec_znx_big_normalize(log_base2k, ct, 0, &tmp_big, 0, scratch_3); // ct[1] = pk[1] * u + e1 module.svp_apply(&mut tmp_dft, 0, &u_dft, 0, pk, 1); module.vec_znx_idft_tmp_a(&mut tmp_big, 0, &mut tmp_dft, 0); tmp_big.add_normal(log_base2k, 0, pk.k(), source_xe, sigma, bound); module.vec_znx_big_normalize(log_base2k, ct, 1, &tmp_big, 0, scratch_3); } pub struct GLWEPlaintext { pub data: VecZnx, pub log_base2k: usize, pub log_k: usize, } impl Infos for GLWEPlaintext { type Inner = VecZnx; fn inner(&self) -> &Self::Inner { &self.data } fn basek(&self) -> usize { self.log_base2k } fn k(&self) -> usize { self.log_k } } impl VecZnxToMut for GLWEPlaintext where VecZnx: VecZnxToMut, { fn to_mut(&mut self) -> VecZnx<&mut [u8]> { self.data.to_mut() } } impl VecZnxToRef for GLWEPlaintext where VecZnx: VecZnxToRef, { fn to_ref(&self) -> VecZnx<&[u8]> { self.data.to_ref() } } impl GLWEPlaintext> { pub fn new(module: &Module, log_base2k: usize, log_k: usize) -> Self { Self { data: module.new_vec_znx(1, derive_size(log_base2k, log_k)), log_base2k: log_base2k, log_k: log_k, } } } pub struct GLWECiphertextFourier { pub data: VecZnxDft, pub log_base2k: usize, pub log_k: usize, } impl GLWECiphertextFourier, B> { pub fn new(module: &Module, log_base2k: usize, log_k: usize) -> Self { Self { data: module.new_vec_znx_dft(2, derive_size(log_base2k, log_k)), log_base2k: log_base2k, log_k: log_k, } } } impl Infos for GLWECiphertextFourier { type Inner = VecZnxDft; fn inner(&self) -> &Self::Inner { &self.data } fn basek(&self) -> usize { self.log_base2k } fn k(&self) -> usize { self.log_k } } impl VecZnxDftToMut for GLWECiphertextFourier where VecZnxDft: VecZnxDftToMut, { fn to_mut(&mut self) -> VecZnxDft<&mut [u8], B> { self.data.to_mut() } } impl VecZnxDftToRef for GLWECiphertextFourier where VecZnxDft: VecZnxDftToRef, { fn to_ref(&self) -> VecZnxDft<&[u8], B> { self.data.to_ref() } } impl GLWECiphertextFourier where GLWECiphertextFourier: VecZnxDftToRef, { #[allow(dead_code)] pub(crate) fn idft_scratch_space(module: &Module, size: usize) -> usize { module.bytes_of_vec_znx(2, size) + (module.vec_znx_big_normalize_tmp_bytes() | module.vec_znx_idft_tmp_bytes()) } pub(crate) fn idft(&self, module: &Module, res: &mut GLWECiphertext, scratch: &mut Scratch) where GLWECiphertext: VecZnxToMut, { #[cfg(debug_assertions)] { assert_eq!(self.rank(), 2); assert_eq!(res.rank(), 2); assert_eq!(self.basek(), res.basek()) } let min_size: usize = self.size().min(res.size()); let (mut res_big, scratch1) = scratch.tmp_vec_znx_big(module, 2, min_size); module.vec_znx_idft(&mut res_big, 0, self, 0, scratch1); module.vec_znx_idft(&mut res_big, 1, self, 1, scratch1); module.vec_znx_big_normalize(self.basek(), res, 0, &res_big, 0, scratch1); module.vec_znx_big_normalize(self.basek(), res, 1, &res_big, 1, scratch1); } } pub(crate) fn encrypt_zero_glwe_dft_sk( module: &Module, ct: &mut GLWECiphertextFourier, sk: &SecretKeyFourier, source_xa: &mut Source, source_xe: &mut Source, sigma: f64, bound: f64, scratch: &mut Scratch, ) where VecZnxDft: VecZnxDftToMut + VecZnxDftToRef, ScalarZnxDft: ScalarZnxDftToRef, { let log_base2k: usize = ct.basek(); let log_k: usize = ct.k(); let size: usize = ct.size(); #[cfg(debug_assertions)] { match sk.dist { SecretDistribution::NONE => panic!("invalid sk.dist = SecretDistribution::NONE"), _ => {} } assert_eq!(ct.rank(), 2); } // ct[1] = DFT(a) { let (mut tmp_znx, _) = scratch.tmp_vec_znx(module, 1, size); tmp_znx.fill_uniform(log_base2k, 0, size, source_xa); module.vec_znx_dft(ct, 1, &tmp_znx, 0); } let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size); { let (mut tmp_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size); // c0_dft = ct[1] * DFT(s) module.svp_apply(&mut tmp_dft, 0, sk, 0, ct, 1); // c0_big = IDFT(c0_dft) module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut tmp_dft, 0); } // c0_big += e c0_big.add_normal(log_base2k, 0, log_k, source_xe, sigma, bound); // c0 = norm(c0_big = -as - e), NOTE: e is centered at 0. let (mut tmp_znx, scratch_2) = scratch_1.tmp_vec_znx(module, 1, size); module.vec_znx_big_normalize(log_base2k, &mut tmp_znx, 0, &c0_big, 0, scratch_2); module.vec_znx_negate_inplace(&mut tmp_znx, 0); // ct[0] = DFT(-as + e) module.vec_znx_dft(ct, 0, &tmp_znx, 0); } impl GLWECiphertextFourier, FFT64> { pub fn encrypt_zero_sk_scratch_space(module: &Module, size: usize) -> usize { (module.bytes_of_vec_znx(1, size) | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size) + module.bytes_of_vec_znx(1, size) + module.vec_znx_big_normalize_tmp_bytes() } pub fn decrypt_scratch_space(module: &Module, size: usize) -> usize { (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size) | (module.bytes_of_vec_znx_big(1, size) + module.vec_znx_idft_tmp_bytes())) + module.bytes_of_vec_znx_big(1, size) } } pub fn decrypt_rlwe_dft( module: &Module, pt: &mut GLWEPlaintext

, ct: &GLWECiphertextFourier, sk: &SecretKeyFourier, scratch: &mut Scratch, ) where VecZnx

: VecZnxToMut + VecZnxToRef, VecZnxDft: VecZnxDftToRef, ScalarZnxDft: ScalarZnxDftToRef, { let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, ct.size()); // TODO optimize size when pt << ct { let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, ct.size()); // TODO optimize size when pt << ct // c0_dft = DFT(a) * DFT(s) module.svp_apply(&mut c0_dft, 0, sk, 0, ct, 1); // c0_big = IDFT(c0_dft) module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0); } { let (mut c1_big, scratch_2) = scratch_1.tmp_vec_znx_big(module, 1, ct.size()); // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e) module.vec_znx_idft(&mut c1_big, 0, ct, 0, scratch_2); module.vec_znx_big_add_inplace(&mut c0_big, 0, &c1_big, 0); } // pt = norm(BIG(m + e)) module.vec_znx_big_normalize(ct.basek(), pt, 0, &mut c0_big, 0, scratch_1); pt.log_base2k = ct.basek(); pt.log_k = pt.k().min(ct.k()); } impl GLWECiphertextFourier where VecZnxDft: VecZnxDftToMut + VecZnxDftToRef, { pub(crate) fn encrypt_zero_sk( &mut self, module: &Module, sk_dft: &SecretKeyFourier, source_xa: &mut Source, source_xe: &mut Source, sigma: f64, bound: f64, scratch: &mut Scratch, ) where ScalarZnxDft: ScalarZnxDftToRef, { encrypt_zero_glwe_dft_sk( module, self, sk_dft, source_xa, source_xe, sigma, bound, scratch, ) } pub fn decrypt( &self, module: &Module, pt: &mut GLWEPlaintext

, sk_dft: &SecretKeyFourier, scratch: &mut Scratch, ) where VecZnx

: VecZnxToMut + VecZnxToRef, ScalarZnxDft: ScalarZnxDftToRef, { decrypt_rlwe_dft(module, pt, self, sk_dft, scratch); } } impl KeySwitchScratchSpace for GLWECiphertextFourier, FFT64> { fn keyswitch_scratch_space(module: &Module, res_size: usize, lhs: usize, rhs: usize) -> usize { , FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_scratch_space(module, res_size, lhs, rhs) } } impl KeySwitch for GLWECiphertextFourier where VecZnxDft: VecZnxDftToMut + VecZnxDftToRef, VecZnxDft: VecZnxDftToRef, MatZnxDft: MatZnxDftToRef, { type Lhs = GLWECiphertextFourier; type Rhs = GLWEKeySwitchKey; fn keyswitch(&mut self, module: &Module, lhs: &Self::Lhs, rhs: &Self::Rhs, scratch: &mut Scratch) { rhs.prod_with_glwe_fourier(module, self, lhs, scratch); } } impl KeySwitchInplaceScratchSpace for GLWECiphertextFourier, FFT64> { fn keyswitch_inplace_scratch_space(module: &Module, res_size: usize, rhs: usize) -> usize { , FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_inplace_scratch_space( module, res_size, rhs, ) } } impl KeySwitchInplace for GLWECiphertextFourier where VecZnxDft: VecZnxDftToMut + VecZnxDftToRef, MatZnxDft: MatZnxDftToRef, { type Rhs = GLWEKeySwitchKey; fn keyswitch_inplace(&mut self, module: &Module, rhs: &Self::Rhs, scratch: &mut Scratch) { rhs.prod_with_glwe_fourier_inplace(module, self, scratch); } } impl ExternalProductScratchSpace for GLWECiphertextFourier, FFT64> { fn external_product_scratch_space(module: &Module, res_size: usize, lhs: usize, rhs: usize) -> usize { , FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_scratch_space(module, res_size, lhs, rhs) } } impl ExternalProduct for GLWECiphertextFourier where VecZnxDft: VecZnxDftToMut + VecZnxDftToRef, VecZnxDft: VecZnxDftToRef, MatZnxDft: MatZnxDftToRef, { type Lhs = GLWECiphertextFourier; type Rhs = GGSWCiphertext; fn external_product(&mut self, module: &Module, lhs: &Self::Lhs, rhs: &Self::Rhs, scratch: &mut Scratch) { rhs.prod_with_glwe_fourier(module, self, lhs, scratch); } } impl ExternalProductInplaceScratchSpace for GLWECiphertextFourier, FFT64> { fn external_product_inplace_scratch_space(module: &Module, res_size: usize, rhs: usize) -> usize { , FFT64> as VecGLWEProductScratchSpace>::prod_with_glwe_inplace_scratch_space( module, res_size, rhs, ) } } impl ExternalProductInplace for GLWECiphertextFourier where VecZnxDft: VecZnxDftToMut + VecZnxDftToRef, MatZnxDft: MatZnxDftToRef + ZnxInfos, { type Rhs = GGSWCiphertext; fn external_product_inplace(&mut self, module: &Module, rhs: &Self::Rhs, scratch: &mut Scratch) { rhs.prod_with_glwe_fourier_inplace(module, self, scratch); } }