use backend::hal::{ api::{ MatZnxAlloc, ScalarZnxAllocBytes, ScratchAvailable, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, VecZnxAddScalarInplace, VecZnxAllocBytes, VecZnxAutomorphismInplace, VecZnxSwithcDegree, ZnxView, ZnxViewMut, ZnxZero, }, layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, Scratch, WriterTo}, }; use sampling::source::Source; use crate::{ GGLWEEncryptSkFamily, GGLWEExecLayoutFamily, GLWECiphertext, GLWEKeyswitchFamily, GLWESecret, GLWESecretExec, GLWESwitchingKey, GLWESwitchingKeyExec, Infos, LWECiphertext, LWESecret, TakeGLWECt, TakeGLWESecret, TakeGLWESecretExec, }; /// A special [GLWESwitchingKey] required to for the conversion from [GLWECiphertext] to [LWECiphertext]. #[derive(PartialEq, Eq)] pub struct GLWEToLWESwitchingKey(GLWESwitchingKey); impl ReaderFrom for GLWEToLWESwitchingKey { fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { self.0.read_from(reader) } } impl WriterTo for GLWEToLWESwitchingKey { fn write_to(&self, writer: &mut W) -> std::io::Result<()> { self.0.write_to(writer) } } #[derive(PartialEq, Eq)] pub struct GLWEToLWESwitchingKeyExec(GLWESwitchingKeyExec); impl GLWEToLWESwitchingKeyExec, B> { pub fn alloc(module: &Module, basek: usize, k: usize, rows: usize, rank_in: usize) -> Self where Module: GGLWEExecLayoutFamily, { Self(GLWESwitchingKeyExec::alloc( module, basek, k, rows, 1, rank_in, 1, )) } pub fn bytes_of(module: &Module, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize) -> usize where Module: GGLWEExecLayoutFamily, { GLWESwitchingKeyExec::, B>::bytes_of(module, basek, k, rows, digits, rank_in, 1) } pub fn from( module: &Module, other: &GLWEToLWESwitchingKey, scratch: &mut Scratch, ) -> Self where Module: GGLWEExecLayoutFamily, { let mut ksk_exec: GLWEToLWESwitchingKeyExec, B> = Self::alloc( module, other.0.basek(), other.0.k(), other.0.rows(), other.0.rank_in(), ); ksk_exec.prepare(module, other, scratch); ksk_exec } } impl GLWEToLWESwitchingKeyExec { pub fn prepare(&mut self, module: &Module, other: &GLWEToLWESwitchingKey, scratch: &mut Scratch) where DataOther: DataRef, Module: GGLWEExecLayoutFamily, { self.0.prepare(module, &other.0, scratch); } } impl GLWEToLWESwitchingKey> { pub fn alloc(module: &Module, basek: usize, k: usize, rows: usize, rank_in: usize) -> Self where Module: MatZnxAlloc, { Self(GLWESwitchingKey::alloc( module, basek, k, rows, 1, rank_in, 1, )) } pub fn encrypt_sk_scratch_space(module: &Module, basek: usize, k: usize, rank_in: usize) -> usize where Module: GGLWEEncryptSkFamily + ScalarZnxAllocBytes + VecZnxAllocBytes, { GLWESecretExec::bytes_of(module, rank_in) + (GLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k, rank_in, 1) | GLWESecret::bytes_of(module, rank_in)) } } impl GLWEToLWESwitchingKey { pub fn encrypt_sk( &mut self, module: &Module, sk_lwe: &LWESecret, sk_glwe: &GLWESecret, source_xa: &mut Source, source_xe: &mut Source, sigma: f64, scratch: &mut Scratch, ) where DLwe: DataRef, DGlwe: DataRef, Module: GGLWEEncryptSkFamily + VecZnxAutomorphismInplace + ScalarZnxAllocBytes + VecZnxSwithcDegree + VecZnxAllocBytes + VecZnxAddScalarInplace, Scratch: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft + TakeGLWESecretExec + TakeVecZnx, { #[cfg(debug_assertions)] { assert!(sk_lwe.n() <= module.n()); } let (mut sk_lwe_as_glwe, scratch1) = scratch.take_glwe_secret(module, 1); sk_lwe_as_glwe.data.zero(); sk_lwe_as_glwe.data.at_mut(0, 0)[..sk_lwe.n()].copy_from_slice(sk_lwe.data.at(0, 0)); module.vec_znx_automorphism_inplace(-1, &mut sk_lwe_as_glwe.data, 0); self.0.encrypt_sk( module, sk_glwe, &sk_lwe_as_glwe, source_xa, source_xe, sigma, scratch1, ); } } /// A special [GLWESwitchingKey] required to for the conversion from [LWECiphertext] to [GLWECiphertext]. #[derive(PartialEq, Eq)] pub struct LWEToGLWESwitchingKeyExec(GLWESwitchingKeyExec); impl LWEToGLWESwitchingKeyExec, B> { pub fn alloc(module: &Module, basek: usize, k: usize, rows: usize, rank_out: usize) -> Self where Module: GGLWEExecLayoutFamily, { Self(GLWESwitchingKeyExec::alloc( module, basek, k, rows, 1, 1, rank_out, )) } pub fn bytes_of(module: &Module, basek: usize, k: usize, rows: usize, digits: usize, rank_out: usize) -> usize where Module: GGLWEExecLayoutFamily, { GLWESwitchingKeyExec::, B>::bytes_of(module, basek, k, rows, digits, 1, rank_out) } pub fn from( module: &Module, other: &LWEToGLWESwitchingKey, scratch: &mut Scratch, ) -> Self where Module: GGLWEExecLayoutFamily, { let mut ksk_exec: LWEToGLWESwitchingKeyExec, B> = Self::alloc( module, other.0.basek(), other.0.k(), other.0.rows(), other.0.rank(), ); ksk_exec.prepare(module, other, scratch); ksk_exec } } impl LWEToGLWESwitchingKeyExec { pub fn prepare(&mut self, module: &Module, other: &LWEToGLWESwitchingKey, scratch: &mut Scratch) where DataOther: DataRef, Module: GGLWEExecLayoutFamily, { self.0.prepare(module, &other.0, scratch); } } #[derive(PartialEq, Eq)] pub struct LWEToGLWESwitchingKey(GLWESwitchingKey); impl ReaderFrom for LWEToGLWESwitchingKey { fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { self.0.read_from(reader) } } impl WriterTo for LWEToGLWESwitchingKey { fn write_to(&self, writer: &mut W) -> std::io::Result<()> { self.0.write_to(writer) } } impl LWEToGLWESwitchingKey> { pub fn alloc(module: &Module, basek: usize, k: usize, rows: usize, rank_out: usize) -> Self where Module: MatZnxAlloc, { Self(GLWESwitchingKey::alloc( module, basek, k, rows, 1, 1, rank_out, )) } pub fn encrypt_sk_scratch_space(module: &Module, basek: usize, k: usize, rank_out: usize) -> usize where Module: GGLWEEncryptSkFamily + ScalarZnxAllocBytes + VecZnxAllocBytes, { GLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k, 1, rank_out) + GLWESecret::bytes_of(module, 1) } } impl LWEToGLWESwitchingKey { pub fn encrypt_sk( &mut self, module: &Module, sk_lwe: &LWESecret, sk_glwe: &GLWESecret, source_xa: &mut Source, source_xe: &mut Source, sigma: f64, scratch: &mut Scratch, ) where DLwe: DataRef, DGlwe: DataRef, Module: GGLWEEncryptSkFamily + VecZnxAutomorphismInplace + ScalarZnxAllocBytes + VecZnxSwithcDegree + VecZnxAllocBytes + VecZnxAddScalarInplace, Scratch: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft + TakeGLWESecretExec + TakeVecZnx, { #[cfg(debug_assertions)] { assert!(sk_lwe.n() <= module.n()); } let (mut sk_lwe_as_glwe, scratch1) = scratch.take_glwe_secret(module, 1); sk_lwe_as_glwe.data.at_mut(0, 0)[..sk_lwe.n()].copy_from_slice(sk_lwe.data.at(0, 0)); sk_lwe_as_glwe.data.at_mut(0, 0)[sk_lwe.n()..].fill(0); module.vec_znx_automorphism_inplace(-1, &mut sk_lwe_as_glwe.data, 0); self.0.encrypt_sk( module, &sk_lwe_as_glwe, &sk_glwe, source_xa, source_xe, sigma, scratch1, ); } } #[derive(PartialEq, Eq)] pub struct LWESwitchingKeyExec(GLWESwitchingKeyExec); impl LWESwitchingKeyExec, B> { pub fn alloc(module: &Module, basek: usize, k: usize, rows: usize) -> Self where Module: GGLWEExecLayoutFamily, { Self(GLWESwitchingKeyExec::alloc(module, basek, k, rows, 1, 1, 1)) } pub fn bytes_of(module: &Module, basek: usize, k: usize, rows: usize, digits: usize) -> usize where Module: GGLWEExecLayoutFamily, { GLWESwitchingKeyExec::, B>::bytes_of(module, basek, k, rows, digits, 1, 1) } pub fn from(module: &Module, other: &LWESwitchingKey, scratch: &mut Scratch) -> Self where Module: GGLWEExecLayoutFamily, { let mut ksk_exec: LWESwitchingKeyExec, B> = Self::alloc(module, other.0.basek(), other.0.k(), other.0.rows()); ksk_exec.prepare(module, other, scratch); ksk_exec } } impl LWESwitchingKeyExec { pub fn prepare(&mut self, module: &Module, other: &LWESwitchingKey, scratch: &mut Scratch) where DataOther: DataRef, Module: GGLWEExecLayoutFamily, { self.0.prepare(module, &other.0, scratch); } } #[derive(PartialEq, Eq)] pub struct LWESwitchingKey(GLWESwitchingKey); impl ReaderFrom for LWESwitchingKey { fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { self.0.read_from(reader) } } impl WriterTo for LWESwitchingKey { fn write_to(&self, writer: &mut W) -> std::io::Result<()> { self.0.write_to(writer) } } impl LWESwitchingKey> { pub fn alloc(module: &Module, basek: usize, k: usize, rows: usize) -> Self where Module: MatZnxAlloc, { Self(GLWESwitchingKey::alloc(module, basek, k, rows, 1, 1, 1)) } pub fn encrypt_sk_scratch_space(module: &Module, basek: usize, k: usize) -> usize where Module: GGLWEEncryptSkFamily + ScalarZnxAllocBytes + VecZnxAllocBytes, { GLWESecret::bytes_of(module, 1) + GLWESecretExec::bytes_of(module, 1) + GLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k, 1, 1) } } impl LWESwitchingKey { pub fn encrypt_sk( &mut self, module: &Module, sk_lwe_in: &LWESecret, sk_lwe_out: &LWESecret, source_xa: &mut Source, source_xe: &mut Source, sigma: f64, scratch: &mut Scratch, ) where DIn: DataRef, DOut: DataRef, Module: GGLWEEncryptSkFamily + VecZnxAutomorphismInplace + ScalarZnxAllocBytes + VecZnxSwithcDegree + VecZnxAllocBytes + VecZnxAddScalarInplace, Scratch: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft + TakeGLWESecretExec + TakeVecZnx, { #[cfg(debug_assertions)] { assert!(sk_lwe_in.n() <= module.n()); assert!(sk_lwe_out.n() <= module.n()); } let (mut sk_in_glwe, scratch1) = scratch.take_glwe_secret(module, 1); let (mut sk_out_glwe, scratch2) = scratch1.take_glwe_secret(module, 1); sk_out_glwe.data.at_mut(0, 0)[..sk_lwe_out.n()].copy_from_slice(sk_lwe_out.data.at(0, 0)); sk_out_glwe.data.at_mut(0, 0)[sk_lwe_out.n()..].fill(0); module.vec_znx_automorphism_inplace(-1, &mut sk_out_glwe.data, 0); sk_in_glwe.data.at_mut(0, 0)[..sk_lwe_in.n()].copy_from_slice(sk_lwe_in.data.at(0, 0)); sk_in_glwe.data.at_mut(0, 0)[sk_lwe_in.n()..].fill(0); module.vec_znx_automorphism_inplace(-1, &mut sk_in_glwe.data, 0); self.0.encrypt_sk( module, &sk_in_glwe, &sk_out_glwe, source_xa, source_xe, sigma, scratch2, ); } } impl LWECiphertext> { pub fn from_glwe_scratch_space( module: &Module, basek: usize, k_lwe: usize, k_glwe: usize, k_ksk: usize, rank: usize, ) -> usize where Module: GLWEKeyswitchFamily + VecZnxAllocBytes, { GLWECiphertext::bytes_of(module, basek, k_lwe, 1) + GLWECiphertext::keyswitch_scratch_space(module, basek, k_lwe, k_glwe, k_ksk, 1, rank, 1) } pub fn keyswitch_scratch_space( module: &Module, basek: usize, k_lwe_out: usize, k_lwe_in: usize, k_ksk: usize, ) -> usize where Module: GLWEKeyswitchFamily + ScalarZnxAllocBytes + VecZnxAllocBytes, { GLWECiphertext::bytes_of(module, basek, k_lwe_out.max(k_lwe_in), 1) + GLWECiphertext::keyswitch_inplace_scratch_space(module, basek, k_lwe_out, k_ksk, 1, 1) } } impl LWECiphertext { pub fn sample_extract(&mut self, a: &GLWECiphertext) { #[cfg(debug_assertions)] { assert!(self.n() <= a.n()); } let min_size: usize = self.size().min(a.size()); let n: usize = self.n(); self.data.zero(); (0..min_size).for_each(|i| { let data_lwe: &mut [i64] = self.data.at_mut(0, i); data_lwe[0] = a.data.at(0, i)[0]; data_lwe[1..].copy_from_slice(&a.data.at(1, i)[..n]); }); } pub fn from_glwe( &mut self, module: &Module, a: &GLWECiphertext, ks: &GLWEToLWESwitchingKeyExec, scratch: &mut Scratch, ) where DGlwe: DataRef, DKs: DataRef, Module: GLWEKeyswitchFamily, Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx, { #[cfg(debug_assertions)] { assert_eq!(self.basek(), a.basek()); } let (mut tmp_glwe, scratch1) = scratch.take_glwe_ct(module, a.basek(), self.k(), 1); tmp_glwe.keyswitch(module, a, &ks.0, scratch1); self.sample_extract(&tmp_glwe); } pub fn keyswitch( &mut self, module: &Module, a: &LWECiphertext, ksk: &LWESwitchingKeyExec, scratch: &mut Scratch, ) where A: DataRef, DKs: DataRef, Module: GLWEKeyswitchFamily, Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx, { #[cfg(debug_assertions)] { assert!(self.n() <= module.n()); assert!(a.n() <= module.n()); assert_eq!(self.basek(), a.basek()); } let max_k: usize = self.k().max(a.k()); let basek: usize = self.basek(); let (mut glwe, scratch1) = scratch.take_glwe_ct(&module, basek, max_k, 1); glwe.data.zero(); let n_lwe: usize = a.n(); (0..a.size()).for_each(|i| { let data_lwe: &[i64] = a.data.at(0, i); glwe.data.at_mut(0, i)[0] = data_lwe[0]; glwe.data.at_mut(1, i)[..n_lwe].copy_from_slice(&data_lwe[1..]); }); glwe.keyswitch_inplace(module, &ksk.0, scratch1); self.sample_extract(&glwe); } } impl GLWECiphertext> { pub fn from_lwe_scratch_space( module: &Module, basek: usize, k_lwe: usize, k_glwe: usize, k_ksk: usize, rank: usize, ) -> usize where Module: GLWEKeyswitchFamily + VecZnxAllocBytes, { GLWECiphertext::keyswitch_scratch_space(module, basek, k_glwe, k_lwe, k_ksk, 1, 1, rank) + GLWECiphertext::bytes_of(module, basek, k_lwe, 1) } } impl GLWECiphertext { pub fn from_lwe( &mut self, module: &Module, lwe: &LWECiphertext, ksk: &LWEToGLWESwitchingKeyExec, scratch: &mut Scratch, ) where DLwe: DataRef, DKsk: DataRef, Module: GLWEKeyswitchFamily, Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx, { #[cfg(debug_assertions)] { assert!(lwe.n() <= self.n()); assert_eq!(self.basek(), self.basek()); } let (mut glwe, scratch1) = scratch.take_glwe_ct(module, lwe.basek(), lwe.k(), 1); glwe.data.zero(); let n_lwe: usize = lwe.n(); (0..lwe.size()).for_each(|i| { let data_lwe: &[i64] = lwe.data.at(0, i); glwe.data.at_mut(0, i)[0] = data_lwe[0]; glwe.data.at_mut(1, i)[..n_lwe].copy_from_slice(&data_lwe[1..]); }); self.keyswitch(module, &glwe, &ksk.0, scratch1); } }