diff --git a/core/src/blind_rotation/key.rs b/core/src/blind_rotation/key.rs index a517d19..7f4aa51 100644 --- a/core/src/blind_rotation/key.rs +++ b/core/src/blind_rotation/key.rs @@ -1,7 +1,7 @@ use backend::hal::{ api::{ - ScratchAvailable, SvpPPolAlloc, SvpPrepare, TakeVecZnx, TakeVecZnxDft, VecZnxAddScalarInplace, ZnxInfos, ZnxView, - ZnxViewMut, + FillUniform, Reset, ScratchAvailable, SvpPPolAlloc, SvpPrepare, TakeVecZnx, TakeVecZnxDft, VecZnxAddScalarInplace, + ZnxInfos, ZnxView, ZnxViewMut, }, layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, ScalarZnx, ScalarZnxToRef, Scratch, SvpPPol, WriterTo}, }; @@ -10,12 +10,20 @@ use sampling::source::Source; use crate::{ Distribution, GGSWCiphertext, GGSWCiphertextExec, GGSWEncryptSkFamily, GGSWLayoutFamily, GLWESecretExec, Infos, LWESecret, }; +use std::fmt; +#[derive(Clone)] pub struct BlindRotationKeyCGGI { pub(crate) keys: Vec>, pub(crate) dist: Distribution, } +impl fmt::Debug for BlindRotationKeyCGGI { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + impl PartialEq for BlindRotationKeyCGGI { fn eq(&self, other: &Self) -> bool { if self.keys.len() != other.keys.len() { @@ -32,6 +40,30 @@ impl PartialEq for BlindRotationKeyCGGI { impl Eq for BlindRotationKeyCGGI {} +impl fmt::Display for BlindRotationKeyCGGI { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for (i, key) in self.keys.iter().enumerate() { + write!(f, "key[{}]: {}", i, key)?; + } + writeln!(f, "{:?}", self.dist) + } +} + +impl Reset for BlindRotationKeyCGGI { + fn reset(&mut self) { + self.keys.iter_mut().for_each(|key| key.reset()); + self.dist = Distribution::NONE; + } +} + +impl FillUniform for BlindRotationKeyCGGI { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.keys + .iter_mut() + .for_each(|key| key.fill_uniform(source)); + } +} + use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; impl ReaderFrom for BlindRotationKeyCGGI { diff --git a/core/src/blind_rotation/key_compressed.rs b/core/src/blind_rotation/key_compressed.rs new file mode 100644 index 0000000..b30c753 --- /dev/null +++ b/core/src/blind_rotation/key_compressed.rs @@ -0,0 +1,212 @@ +use backend::hal::{ + api::{FillUniform, Reset, ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxAddScalarInplace, ZnxView, ZnxViewMut}, + layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, ScalarZnx, ScalarZnxToRef, Scratch, WriterTo}, +}; +use sampling::source::Source; + +use crate::{Distribution, GGSWCiphertextCompressed, GGSWEncryptSkFamily, GLWESecretExec, Infos, LWESecret}; +use std::fmt; + +#[derive(Clone)] +pub struct BlindRotationKeyCGGICompressed { + pub(crate) keys: Vec>, + pub(crate) dist: Distribution, +} + +impl fmt::Debug for BlindRotationKeyCGGICompressed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl PartialEq for BlindRotationKeyCGGICompressed { + fn eq(&self, other: &Self) -> bool { + if self.keys.len() != other.keys.len() { + return false; + } + for (a, b) in self.keys.iter().zip(other.keys.iter()) { + if a != b { + return false; + } + } + self.dist == other.dist + } +} + +impl Eq for BlindRotationKeyCGGICompressed {} + +impl fmt::Display for BlindRotationKeyCGGICompressed { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for (i, key) in self.keys.iter().enumerate() { + write!(f, "key[{}]: {}", i, key)?; + } + writeln!(f, "{:?}", self.dist) + } +} + +impl Reset for BlindRotationKeyCGGICompressed { + fn reset(&mut self) { + self.keys.iter_mut().for_each(|key| key.reset()); + self.dist = Distribution::NONE; + } +} + +impl FillUniform for BlindRotationKeyCGGICompressed { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.keys + .iter_mut() + .for_each(|key| key.fill_uniform(source)); + } +} + +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +impl ReaderFrom for BlindRotationKeyCGGICompressed { + fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { + match Distribution::read_from(reader) { + Ok(dist) => self.dist = dist, + Err(e) => return Err(e), + } + let len: usize = reader.read_u64::()? as usize; + if self.keys.len() != len { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("self.keys.len()={} != read len={}", self.keys.len(), len), + )); + } + for key in &mut self.keys { + key.read_from(reader)?; + } + Ok(()) + } +} + +impl WriterTo for BlindRotationKeyCGGICompressed { + fn write_to(&self, writer: &mut W) -> std::io::Result<()> { + match self.dist.write_to(writer) { + Ok(()) => {} + Err(e) => return Err(e), + } + writer.write_u64::(self.keys.len() as u64)?; + for key in &self.keys { + key.write_to(writer)?; + } + Ok(()) + } +} + +impl BlindRotationKeyCGGICompressed> { + pub fn alloc(n_gglwe: usize, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self { + let mut data: Vec>> = Vec::with_capacity(n_lwe); + (0..n_lwe).for_each(|_| { + data.push(GGSWCiphertextCompressed::alloc( + n_gglwe, basek, k, rows, 1, rank, + )) + }); + Self { + keys: data, + dist: Distribution::NONE, + } + } + + pub fn generate_from_sk_scratch_space(module: &Module, n: usize, basek: usize, k: usize, rank: usize) -> usize + where + Module: GGSWEncryptSkFamily, + { + GGSWCiphertextCompressed::encrypt_sk_scratch_space(module, n, basek, k, rank) + } +} + +impl BlindRotationKeyCGGICompressed { + #[allow(dead_code)] + pub(crate) fn n(&self) -> usize { + self.keys[0].n() + } + + #[allow(dead_code)] + pub(crate) fn rows(&self) -> usize { + self.keys[0].rows() + } + + #[allow(dead_code)] + pub(crate) fn k(&self) -> usize { + self.keys[0].k() + } + + #[allow(dead_code)] + pub(crate) fn size(&self) -> usize { + self.keys[0].size() + } + + #[allow(dead_code)] + pub(crate) fn rank(&self) -> usize { + self.keys[0].rank() + } + + #[allow(dead_code)] + pub(crate) fn basek(&self) -> usize { + self.keys[0].basek() + } + + #[allow(dead_code)] + pub(crate) fn block_size(&self) -> usize { + match self.dist { + Distribution::BinaryBlock(value) => value, + _ => 1, + } + } +} + +impl BlindRotationKeyCGGICompressed { + pub fn generate_from_sk( + &mut self, + module: &Module, + sk_glwe: &GLWESecretExec, + sk_lwe: &LWESecret, + seed_xa: [u8; 32], + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch, + ) where + DataSkGLWE: DataRef, + DataSkLWE: DataRef, + Module: GGSWEncryptSkFamily + VecZnxAddScalarInplace, + Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx, + { + #[cfg(debug_assertions)] + { + assert_eq!(self.keys.len(), sk_lwe.n()); + assert!(sk_glwe.n() <= module.n()); + assert_eq!(sk_glwe.rank(), self.keys[0].rank()); + match sk_lwe.dist { + Distribution::BinaryBlock(_) + | Distribution::BinaryFixed(_) + | Distribution::BinaryProb(_) + | Distribution::ZERO => {} + _ => panic!( + "invalid GLWESecret distribution: must be BinaryBlock, BinaryFixed or BinaryProb (or ZERO for debugging)" + ), + } + } + + self.dist = sk_lwe.dist; + + let mut pt: ScalarZnx> = ScalarZnx::alloc(sk_glwe.n(), 1); + let sk_ref: ScalarZnx<&[u8]> = sk_lwe.data.to_ref(); + + let mut source_xa: Source = Source::new(seed_xa); + + self.keys.iter_mut().enumerate().for_each(|(i, ggsw)| { + pt.at_mut(0, 0)[0] = sk_ref.at(0, 0)[i]; + ggsw.encrypt_sk( + module, + &pt, + sk_glwe, + source_xa.new_seed(), + source_xe, + sigma, + scratch, + ); + }); + } +} diff --git a/core/src/blind_rotation/mod.rs b/core/src/blind_rotation/mod.rs index 9a31472..3ec8f09 100644 --- a/core/src/blind_rotation/mod.rs +++ b/core/src/blind_rotation/mod.rs @@ -1,9 +1,11 @@ mod cggi; mod key; +mod key_compressed; mod lut; pub use cggi::*; pub use key::*; +pub use key_compressed::*; pub use lut::*; #[cfg(test)] diff --git a/core/src/blind_rotation/test_fft64/cggi.rs b/core/src/blind_rotation/test_fft64/cggi.rs deleted file mode 100644 index 446dcd2..0000000 --- a/core/src/blind_rotation/test_fft64/cggi.rs +++ /dev/null @@ -1,130 +0,0 @@ -use backend::{Encoding, FFT64, Module, ScratchOwned, ZnxView}; -use sampling::source::Source; - -use crate::{ - FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos, LWECiphertext, LWESecret, - blind_rotation::{ - cggi::{cggi_blind_rotate, cggi_blind_rotate_scratch_space, mod_switch_2n}, - key::BlindRotationKeyCGGI, - lut::LookUpTable, - }, - lwe::{LWEPlaintext, ciphertext::LWECiphertextToRef}, -}; - -#[test] -fn standard() { - blind_rotatio_test(224, 1, 1); -} - -#[test] -fn block_binary() { - blind_rotatio_test(224, 7, 1); -} - -#[test] -fn block_binary_extended() { - blind_rotatio_test(224, 7, 2); -} - -fn blind_rotatio_test(n_lwe: usize, block_size: usize, extension_factor: usize) { - let module: Module = Module::::new(512); - let basek: usize = 19; - - let k_lwe: usize = 24; - let k_brk: usize = 3 * basek; - let rows_brk: usize = 2; // Ensures first limb is noise-free. - let k_lut: usize = 1 * basek; - let k_res: usize = 2 * basek; - let rank: usize = 1; - - let message_modulus: usize = 1 << 4; - - let mut source_xs: Source = Source::new([2u8; 32]); - let mut source_xe: Source = Source::new([2u8; 32]); - let mut source_xa: Source = Source::new([1u8; 32]); - - let mut sk_glwe: GLWESecret> = GLWESecret::alloc(&module, rank); - sk_glwe.fill_ternary_prob(0.5, &mut source_xs); - let sk_glwe_dft: FourierGLWESecret, FFT64> = FourierGLWESecret::from(&module, &sk_glwe); - - let mut sk_lwe: LWESecret> = LWESecret::alloc(n_lwe); - sk_lwe.fill_binary_block(block_size, &mut source_xs); - - let mut scratch: ScratchOwned = ScratchOwned::new(BlindRotationKeyCGGI::generate_from_sk_scratch_space( - &module, basek, k_brk, rank, - )); - - let mut scratch_br: ScratchOwned = ScratchOwned::new(cggi_blind_rotate_scratch_space( - &module, - block_size, - extension_factor, - basek, - k_res, - k_brk, - rows_brk, - rank, - )); - - let mut brk: BlindRotationKeyCGGI, FFT64> = - BlindRotationKeyCGGI::allocate(&module, n_lwe, basek, k_brk, rows_brk, rank); - - brk.generate_from_sk( - &module, - &sk_glwe_dft, - &sk_lwe, - &mut source_xa, - &mut source_xe, - 3.2, - scratch.borrow(), - ); - - let mut lwe: LWECiphertext> = LWECiphertext::alloc(n_lwe, basek, k_lwe); - - let mut pt_lwe: LWEPlaintext> = LWEPlaintext::alloc(basek, k_lwe); - - let x: i64 = 2; - let bits: usize = 8; - - pt_lwe.data.encode_coeff_i64(0, basek, bits, 0, x, bits); - - lwe.encrypt_sk(&pt_lwe, &sk_lwe, &mut source_xa, &mut source_xe, 3.2); - - let mut f: Vec = vec![0i64; message_modulus]; - f.iter_mut() - .enumerate() - .for_each(|(i, x)| *x = 2 * (i as i64) + 1); - - let mut lut: LookUpTable = LookUpTable::alloc(&module, basek, k_lut, extension_factor); - lut.set(&module, &f, message_modulus); - - let mut res: GLWECiphertext> = GLWECiphertext::alloc(&module, basek, k_res, rank); - - cggi_blind_rotate(&module, &mut res, &lwe, &lut, &brk, scratch_br.borrow()); - - let mut pt_have: GLWEPlaintext> = GLWEPlaintext::alloc(&module, basek, k_res); - - res.decrypt(&module, &mut pt_have, &sk_glwe_dft, scratch.borrow()); - - let mut lwe_2n: Vec = vec![0i64; lwe.n() + 1]; // TODO: from scratch space - - mod_switch_2n( - 2 * lut.domain_size(), - &mut lwe_2n, - &lwe.to_ref(), - lut.rotation_direction(), - ); - - let pt_want: i64 = (lwe_2n[0] - + lwe_2n[1..] - .iter() - .zip(sk_lwe.data.at(0, 0)) - .map(|(x, y)| x * y) - .sum::()) - & (2 * lut.domain_size() - 1) as i64; - - lut.rotate(pt_want); - - // First limb should be exactly equal (test are parameterized such that the noise does not reach - // the first limb) - assert_eq!(pt_have.data.at(0, 0), lut.data[0].at(0, 0)); -} diff --git a/core/src/blind_rotation/tests/generic_serialization.rs b/core/src/blind_rotation/tests/generic_serialization.rs new file mode 100644 index 0000000..69592c9 --- /dev/null +++ b/core/src/blind_rotation/tests/generic_serialization.rs @@ -0,0 +1,15 @@ +use backend::hal::tests::serialization::test_reader_writer_interface; + +use crate::{BlindRotationKeyCGGI, BlindRotationKeyCGGICompressed}; + +#[test] +fn test_cggi_blind_rotation_key_serialization() { + let original: BlindRotationKeyCGGI> = BlindRotationKeyCGGI::alloc(256, 64, 12, 54, 2, 2); + test_reader_writer_interface(original); +} + +#[test] +fn test_cggi_blind_rotation_key_compressed_serialization() { + let original: BlindRotationKeyCGGICompressed> = BlindRotationKeyCGGICompressed::alloc(256, 64, 12, 54, 2, 2); + test_reader_writer_interface(original); +} diff --git a/core/src/blind_rotation/tests/mod.rs b/core/src/blind_rotation/tests/mod.rs index ed5e334..a5e931c 100644 --- a/core/src/blind_rotation/tests/mod.rs +++ b/core/src/blind_rotation/tests/mod.rs @@ -1,3 +1,4 @@ mod cpu_spqlios; mod generic_cggi; mod generic_lut; +mod generic_serialization; diff --git a/core/src/gglwe/layout.rs b/core/src/gglwe/layout.rs index 6659641..99f78ee 100644 --- a/core/src/gglwe/layout.rs +++ b/core/src/gglwe/layout.rs @@ -29,10 +29,7 @@ impl FillUniform for GGLWECiphertext { } } -impl Reset for GGLWECiphertext -where - MatZnx: Reset, -{ +impl Reset for GGLWECiphertext { fn reset(&mut self) { self.data.reset(); self.basek = 0; diff --git a/core/src/gglwe/tests/generic_serialization.rs b/core/src/gglwe/tests/generic_serialization.rs index a89c269..903c396 100644 --- a/core/src/gglwe/tests/generic_serialization.rs +++ b/core/src/gglwe/tests/generic_serialization.rs @@ -12,7 +12,7 @@ fn test_gglwe_serialization() { } #[test] -fn test_gglwe_serialization_compressed() { +fn test_gglwe_compressed_serialization() { let original: GGLWECiphertextCompressed> = GGLWECiphertextCompressed::alloc(1024, 12, 54, 3, 1, 2, 2); test_reader_writer_interface(original); } @@ -24,7 +24,7 @@ fn test_glwe_switching_key_serialization() { } #[test] -fn test_glwe_switching_key_serialization_compressed() { +fn test_glwe_switching_key_compressed_serialization() { let original: GLWESwitchingKeyCompressed> = GLWESwitchingKeyCompressed::alloc(1024, 12, 54, 3, 1, 2, 2); test_reader_writer_interface(original); } @@ -36,7 +36,7 @@ fn test_automorphism_key_serialization() { } #[test] -fn test_automorphism_key_serialization_compressed() { +fn test_automorphism_key_compressed_serialization() { let original: AutomorphismKeyCompressed> = AutomorphismKeyCompressed::alloc(1024, 12, 54, 3, 1, 2); test_reader_writer_interface(original); } @@ -48,7 +48,7 @@ fn test_tensor_key_serialization() { } #[test] -fn test_tensor_key_serialization_compressed() { +fn test_tensor_key_compressed_serialization() { let original: GLWETensorKeyCompressed> = GLWETensorKeyCompressed::alloc(1024, 12, 54, 3, 1, 2); test_reader_writer_interface(original); } diff --git a/core/src/ggsw/layout.rs b/core/src/ggsw/layout.rs index 9d209aa..f4e1458 100644 --- a/core/src/ggsw/layout.rs +++ b/core/src/ggsw/layout.rs @@ -18,6 +18,12 @@ pub struct GGSWCiphertext { impl fmt::Debug for GGSWCiphertext { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.data) + } +} + +impl fmt::Display for GGSWCiphertext { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "(GGSWCiphertext: basek={} k={} digits={}) {}", @@ -26,10 +32,7 @@ impl fmt::Debug for GGSWCiphertext { } } -impl Reset for GGSWCiphertext -where - MatZnx: Reset, -{ +impl Reset for GGSWCiphertext { fn reset(&mut self) { self.data.reset(); self.basek = 0; @@ -38,10 +41,7 @@ where } } -impl FillUniform for GGSWCiphertext -where - MatZnx: FillUniform, -{ +impl FillUniform for GGSWCiphertext { fn fill_uniform(&mut self, source: &mut sampling::source::Source) { self.data.fill_uniform(source); } diff --git a/core/src/ggsw/layout_compressed.rs b/core/src/ggsw/layout_compressed.rs index f2a88b2..6aef85f 100644 --- a/core/src/ggsw/layout_compressed.rs +++ b/core/src/ggsw/layout_compressed.rs @@ -19,6 +19,12 @@ pub struct GGSWCiphertextCompressed { impl fmt::Debug for GGSWCiphertextCompressed { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.data) + } +} + +impl fmt::Display for GGSWCiphertextCompressed { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "(GGSWCiphertextCompressed: basek={} k={} digits={}) {}", @@ -27,10 +33,7 @@ impl fmt::Debug for GGSWCiphertextCompressed { } } -impl Reset for GGSWCiphertextCompressed -where - MatZnx: Reset, -{ +impl Reset for GGSWCiphertextCompressed { fn reset(&mut self) { self.data.reset(); self.basek = 0; @@ -41,10 +44,7 @@ where } } -impl FillUniform for GGSWCiphertextCompressed -where - MatZnx: FillUniform, -{ +impl FillUniform for GGSWCiphertextCompressed { fn fill_uniform(&mut self, source: &mut sampling::source::Source) { self.data.fill_uniform(source); } diff --git a/core/src/ggsw/test/generic_serialization.rs b/core/src/ggsw/test/generic_serialization.rs index ee39727..e12108d 100644 --- a/core/src/ggsw/test/generic_serialization.rs +++ b/core/src/ggsw/test/generic_serialization.rs @@ -9,7 +9,7 @@ fn ggsw_test_serialization() { } #[test] -fn ggsw_test_serialization_compressed() { +fn ggsw_test_compressed_serialization() { let original: GGSWCiphertextCompressed> = GGSWCiphertextCompressed::alloc(1024, 12, 54, 3, 1, 2); test_reader_writer_interface(original); } diff --git a/core/src/glwe/external_product.rs b/core/src/glwe/external_product.rs index eae6dba..91fb70c 100644 --- a/core/src/glwe/external_product.rs +++ b/core/src/glwe/external_product.rs @@ -45,7 +45,7 @@ impl GLWECiphertext> { rank + 1, // cols out ggsw_size, ); - let normalize: usize = module.vec_znx_normalize_tmp_bytes(module.n()); + let normalize: usize = module.vec_znx_normalize_tmp_bytes(n); res_dft + a_dft + (vmp | normalize) } diff --git a/core/src/glwe/tests/generic_serialization.rs b/core/src/glwe/tests/generic_serialization.rs index dd2084f..9ae772b 100644 --- a/core/src/glwe/tests/generic_serialization.rs +++ b/core/src/glwe/tests/generic_serialization.rs @@ -9,7 +9,7 @@ fn test_serialization() { } #[test] -fn test_serialization_compressed() { +fn test_compressed_serialization() { let original: GLWECiphertextCompressed> = GLWECiphertextCompressed::alloc(1024, 12, 54, 3); test_reader_writer_interface(original); } diff --git a/core/src/lwe/conversion.rs b/core/src/lwe/conversion.rs index 7dfb741..1bcdd52 100644 --- a/core/src/lwe/conversion.rs +++ b/core/src/lwe/conversion.rs @@ -8,6 +8,39 @@ use crate::{ LWEToGLWESwitchingKeyExec, TakeGLWECt, }; +impl LWECiphertext> { + pub fn from_glwe_scratch_space( + module: &Module, + n: usize, + basek: usize, + k_lwe: usize, + k_glwe: usize, + k_ksk: usize, + rank: usize, + ) -> usize + where + Module: GLWEKeyswitchFamily, + { + GLWECiphertext::bytes_of(n, basek, k_lwe, 1) + + GLWECiphertext::keyswitch_scratch_space(module, n, basek, k_lwe, k_glwe, k_ksk, 1, rank, 1) + } + + pub fn keyswitch_scratch_space( + module: &Module, + n: usize, + basek: usize, + k_lwe_out: usize, + k_lwe_in: usize, + k_ksk: usize, + ) -> usize + where + Module: GLWEKeyswitchFamily, + { + GLWECiphertext::bytes_of(n, basek, k_lwe_out.max(k_lwe_in), 1) + + GLWECiphertext::keyswitch_inplace_scratch_space(module, n, basek, k_lwe_out, k_ksk, 1, 1) + } +} + impl LWECiphertext { pub fn sample_extract(&mut self, a: &GLWECiphertext) { #[cfg(debug_assertions)] diff --git a/core/src/lwe/encryption.rs b/core/src/lwe/encryption.rs index 21db6d8..845b151 100644 --- a/core/src/lwe/encryption.rs +++ b/core/src/lwe/encryption.rs @@ -1,13 +1,18 @@ use backend::hal::{ api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddNormal, VecZnxFillUniform, VecZnxNormalizeInplace, ZnxView, ZnxViewMut, + ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, VecZnxAddNormal, + VecZnxAddScalarInplace, VecZnxAutomorphismInplace, VecZnxFillUniform, VecZnxNormalizeInplace, VecZnxSwithcDegree, + ZnxView, ZnxViewMut, ZnxZero, }, - layouts::{Backend, DataMut, DataRef, Module, ScratchOwned, VecZnx}, + layouts::{Backend, DataMut, DataRef, Module, Scratch, ScratchOwned, VecZnx}, oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl}, }; use sampling::source::Source; -use crate::{Infos, LWECiphertext, LWESecret, SIX_SIGMA, lwe::LWEPlaintext}; +use crate::{ + GGLWEEncryptSkFamily, GLWESecret, GLWEToLWESwitchingKey, Infos, LWECiphertext, LWESecret, LWESwitchingKey, + LWEToGLWESwitchingKey, SIX_SIGMA, TakeGLWESecret, TakeGLWESecretExec, lwe::LWEPlaintext, +}; impl LWECiphertext { pub fn encrypt_sk( @@ -77,3 +82,125 @@ impl LWECiphertext { }); } } + +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 + VecZnxSwithcDegree + 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(sk_glwe.n(), 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.as_vec_znx_mut(), 0); + + self.0.encrypt_sk( + module, + sk_glwe, + &sk_lwe_as_glwe, + source_xa, + source_xe, + sigma, + scratch1, + ); + } +} + +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 + VecZnxSwithcDegree + 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(sk_glwe.n(), 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.as_vec_znx_mut(), 0); + + self.0.encrypt_sk( + module, + &sk_lwe_as_glwe, + &sk_glwe, + source_xa, + source_xe, + sigma, + scratch1, + ); + } +} + +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 + VecZnxSwithcDegree + VecZnxAddScalarInplace, + Scratch: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft + TakeGLWESecretExec + TakeVecZnx, + { + #[cfg(debug_assertions)] + { + assert!(sk_lwe_in.n() <= self.n()); + assert!(sk_lwe_out.n() <= self.n()); + assert!(self.n() <= module.n()); + } + + let (mut sk_in_glwe, scratch1) = scratch.take_glwe_secret(self.n(), 1); + let (mut sk_out_glwe, scratch2) = scratch1.take_glwe_secret(self.n(), 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.as_vec_znx_mut(), 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.as_vec_znx_mut(), 0); + + self.0.encrypt_sk( + module, + &sk_in_glwe, + &sk_out_glwe, + source_xa, + source_xe, + sigma, + scratch2, + ); + } +} diff --git a/core/src/lwe/keyswtich_layouts.rs b/core/src/lwe/keyswtich_layouts.rs index 1348b87..c602097 100644 --- a/core/src/lwe/keyswtich_layouts.rs +++ b/core/src/lwe/keyswtich_layouts.rs @@ -1,21 +1,40 @@ use backend::hal::{ - api::{ - ScratchAvailable, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, VecZnxAddScalarInplace, VecZnxAutomorphismInplace, - VecZnxSwithcDegree, ZnxView, ZnxViewMut, ZnxZero, - }, - layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, Scratch, WriterTo}, + api::{FillUniform, Reset}, + layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo}, }; -use sampling::source::Source; -use crate::{ - GGLWEEncryptSkFamily, GLWECiphertext, GLWEKeyswitchFamily, GLWESecret, GLWESecretExec, GLWESwitchingKey, Infos, - LWECiphertext, LWESecret, TakeGLWESecret, TakeGLWESecretExec, -}; +use crate::{GGLWEEncryptSkFamily, GLWESecret, GLWESecretExec, GLWESwitchingKey, Infos}; + +use std::fmt; /// A special [GLWESwitchingKey] required to for the conversion from [GLWECiphertext] to [LWECiphertext]. -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Clone)] pub struct GLWEToLWESwitchingKey(pub(crate) GLWESwitchingKey); +impl fmt::Debug for GLWEToLWESwitchingKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl FillUniform for GLWEToLWESwitchingKey { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} + +impl Reset for GLWEToLWESwitchingKey { + fn reset(&mut self) { + self.0.reset(); + } +} + +impl fmt::Display for GLWEToLWESwitchingKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(GLWEToLWESwitchingKey) {}", self.0) + } +} + impl Infos for GLWEToLWESwitchingKey { type Inner = MatZnx; @@ -76,46 +95,32 @@ impl GLWEToLWESwitchingKey> { } } -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 + VecZnxSwithcDegree + VecZnxAddScalarInplace, - Scratch: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft + TakeGLWESecretExec + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - assert!(sk_lwe.n() <= module.n()); - } +#[derive(PartialEq, Eq, Clone)] +pub struct LWEToGLWESwitchingKey(pub(crate) GLWESwitchingKey); - let (mut sk_lwe_as_glwe, scratch1) = scratch.take_glwe_secret(sk_glwe.n(), 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.as_vec_znx_mut(), 0); - - self.0.encrypt_sk( - module, - sk_glwe, - &sk_lwe_as_glwe, - source_xa, - source_xe, - sigma, - scratch1, - ); +impl fmt::Debug for LWEToGLWESwitchingKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) } } -#[derive(PartialEq, Eq)] -pub struct LWEToGLWESwitchingKey(pub(crate) GLWESwitchingKey); +impl FillUniform for LWEToGLWESwitchingKey { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} + +impl Reset for LWEToGLWESwitchingKey { + fn reset(&mut self) { + self.0.reset(); + } +} + +impl fmt::Display for LWEToGLWESwitchingKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(LWEToGLWESwitchingKey) {}", self.0) + } +} impl Infos for LWEToGLWESwitchingKey { type Inner = MatZnx; @@ -176,46 +181,32 @@ impl LWEToGLWESwitchingKey> { } } -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 + VecZnxSwithcDegree + VecZnxAddScalarInplace, - Scratch: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft + TakeGLWESecretExec + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - assert!(sk_lwe.n() <= module.n()); - } +#[derive(PartialEq, Eq, Clone)] +pub struct LWESwitchingKey(pub(crate) GLWESwitchingKey); - let (mut sk_lwe_as_glwe, scratch1) = scratch.take_glwe_secret(sk_glwe.n(), 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.as_vec_znx_mut(), 0); - - self.0.encrypt_sk( - module, - &sk_lwe_as_glwe, - &sk_glwe, - source_xa, - source_xe, - sigma, - scratch1, - ); +impl fmt::Debug for LWESwitchingKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) } } -#[derive(PartialEq, Eq)] -pub struct LWESwitchingKey(pub(crate) GLWESwitchingKey); +impl FillUniform for LWESwitchingKey { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} + +impl Reset for LWESwitchingKey { + fn reset(&mut self) { + self.0.reset(); + } +} + +impl fmt::Display for LWESwitchingKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(LWESwitchingKey) {}", self.0) + } +} impl Infos for LWESwitchingKey { type Inner = MatZnx; @@ -277,82 +268,3 @@ impl LWESwitchingKey> { + GLWESwitchingKey::encrypt_sk_scratch_space(module, n, 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 + VecZnxSwithcDegree + VecZnxAddScalarInplace, - Scratch: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft + TakeGLWESecretExec + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - assert!(sk_lwe_in.n() <= self.n()); - assert!(sk_lwe_out.n() <= self.n()); - assert!(self.n() <= module.n()); - } - - let (mut sk_in_glwe, scratch1) = scratch.take_glwe_secret(self.n(), 1); - let (mut sk_out_glwe, scratch2) = scratch1.take_glwe_secret(self.n(), 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.as_vec_znx_mut(), 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.as_vec_znx_mut(), 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, - n: usize, - basek: usize, - k_lwe: usize, - k_glwe: usize, - k_ksk: usize, - rank: usize, - ) -> usize - where - Module: GLWEKeyswitchFamily, - { - GLWECiphertext::bytes_of(n, basek, k_lwe, 1) - + GLWECiphertext::keyswitch_scratch_space(module, n, basek, k_lwe, k_glwe, k_ksk, 1, rank, 1) - } - - pub fn keyswitch_scratch_space( - module: &Module, - n: usize, - basek: usize, - k_lwe_out: usize, - k_lwe_in: usize, - k_ksk: usize, - ) -> usize - where - Module: GLWEKeyswitchFamily, - { - GLWECiphertext::bytes_of(n, basek, k_lwe_out.max(k_lwe_in), 1) - + GLWECiphertext::keyswitch_inplace_scratch_space(module, n, basek, k_lwe_out, k_ksk, 1, 1) - } -} diff --git a/core/src/lwe/layouts_compressed.rs b/core/src/lwe/layouts_compressed.rs index 28dd8b1..975d621 100644 --- a/core/src/lwe/layouts_compressed.rs +++ b/core/src/lwe/layouts_compressed.rs @@ -2,11 +2,14 @@ use std::fmt; use backend::hal::{ api::{FillUniform, Reset, VecZnxFillUniform, ZnxInfos, ZnxView, ZnxViewMut}, - layouts::{Backend, Data, DataMut, DataRef, Module, ReaderFrom, VecZnx, WriterTo}, + layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, VecZnx, WriterTo}, }; use sampling::source::Source; -use crate::{Decompress, Infos, LWECiphertext, SetMetaData}; +use crate::{ + Decompress, GGLWEEncryptSkFamily, GLWESwitchingKeyCompressed, GLWEToLWESwitchingKey, Infos, LWECiphertext, LWESwitchingKey, + LWEToGLWESwitchingKey, SetMetaData, +}; #[derive(PartialEq, Eq, Clone)] pub struct LWECiphertextCompressed { @@ -47,10 +50,7 @@ where } } -impl FillUniform for LWECiphertextCompressed -where - VecZnx: FillUniform, -{ +impl FillUniform for LWECiphertextCompressed { fn fill_uniform(&mut self, source: &mut Source) { self.data.fill_uniform(source); } @@ -132,3 +132,267 @@ impl Decompress(pub(crate) GLWESwitchingKeyCompressed); + +impl fmt::Debug for GLWEToLWESwitchingKeyCompressed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl FillUniform for GLWEToLWESwitchingKeyCompressed { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} + +impl Reset for GLWEToLWESwitchingKeyCompressed { + fn reset(&mut self) { + self.0.reset(); + } +} + +impl fmt::Display for GLWEToLWESwitchingKeyCompressed { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(GLWEToLWESwitchingKeyCompressed) {}", self.0) + } +} + +impl Infos for GLWEToLWESwitchingKeyCompressed { + type Inner = MatZnx; + + fn inner(&self) -> &Self::Inner { + &self.0.inner() + } + + fn basek(&self) -> usize { + self.0.basek() + } + + fn k(&self) -> usize { + self.0.k() + } +} + +impl GLWEToLWESwitchingKeyCompressed { + pub fn digits(&self) -> usize { + self.0.digits() + } + + pub fn rank(&self) -> usize { + self.0.rank() + } + + pub fn rank_in(&self) -> usize { + self.0.rank_in() + } + + pub fn rank_out(&self) -> usize { + self.0.rank_out() + } +} + +impl ReaderFrom for GLWEToLWESwitchingKeyCompressed { + fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { + self.0.read_from(reader) + } +} + +impl WriterTo for GLWEToLWESwitchingKeyCompressed { + fn write_to(&self, writer: &mut W) -> std::io::Result<()> { + self.0.write_to(writer) + } +} + +impl GLWEToLWESwitchingKeyCompressed> { + pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, rank_in: usize) -> Self { + Self(GLWESwitchingKeyCompressed::alloc( + n, basek, k, rows, 1, rank_in, 1, + )) + } + + pub fn encrypt_sk_scratch_space(module: &Module, n: usize, basek: usize, k: usize, rank_in: usize) -> usize + where + Module: GGLWEEncryptSkFamily, + { + GLWEToLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k, rank_in) + } +} + +#[derive(PartialEq, Eq, Clone)] +pub struct LWEToGLWESwitchingKeyCompressed(pub(crate) GLWESwitchingKeyCompressed); + +impl fmt::Debug for LWEToGLWESwitchingKeyCompressed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl FillUniform for LWEToGLWESwitchingKeyCompressed { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} + +impl Reset for LWEToGLWESwitchingKeyCompressed { + fn reset(&mut self) { + self.0.reset(); + } +} + +impl fmt::Display for LWEToGLWESwitchingKeyCompressed { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(LWEToGLWESwitchingKeyCompressed) {}", self.0) + } +} + +impl Infos for LWEToGLWESwitchingKeyCompressed { + type Inner = MatZnx; + + fn inner(&self) -> &Self::Inner { + &self.0.inner() + } + + fn basek(&self) -> usize { + self.0.basek() + } + + fn k(&self) -> usize { + self.0.k() + } +} + +impl LWEToGLWESwitchingKeyCompressed { + pub fn digits(&self) -> usize { + self.0.digits() + } + + pub fn rank(&self) -> usize { + self.0.rank() + } + + pub fn rank_in(&self) -> usize { + self.0.rank_in() + } + + pub fn rank_out(&self) -> usize { + self.0.rank_out() + } +} + +impl ReaderFrom for LWEToGLWESwitchingKeyCompressed { + fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { + self.0.read_from(reader) + } +} + +impl WriterTo for LWEToGLWESwitchingKeyCompressed { + fn write_to(&self, writer: &mut W) -> std::io::Result<()> { + self.0.write_to(writer) + } +} + +impl LWEToGLWESwitchingKeyCompressed> { + pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, rank_out: usize) -> Self { + Self(GLWESwitchingKeyCompressed::alloc( + n, basek, k, rows, 1, 1, rank_out, + )) + } + + pub fn encrypt_sk_scratch_space(module: &Module, n: usize, basek: usize, k: usize, rank_out: usize) -> usize + where + Module: GGLWEEncryptSkFamily, + { + LWEToGLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k, rank_out) + } +} + +#[derive(PartialEq, Eq, Clone)] +pub struct LWESwitchingKeyCompressed(pub(crate) GLWESwitchingKeyCompressed); + +impl fmt::Debug for LWESwitchingKeyCompressed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl FillUniform for LWESwitchingKeyCompressed { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} + +impl Reset for LWESwitchingKeyCompressed { + fn reset(&mut self) { + self.0.reset(); + } +} + +impl fmt::Display for LWESwitchingKeyCompressed { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(LWESwitchingKeyCompressed) {}", self.0) + } +} + +impl Infos for LWESwitchingKeyCompressed { + type Inner = MatZnx; + + fn inner(&self) -> &Self::Inner { + &self.0.inner() + } + + fn basek(&self) -> usize { + self.0.basek() + } + + fn k(&self) -> usize { + self.0.k() + } +} + +impl LWESwitchingKeyCompressed { + pub fn digits(&self) -> usize { + self.0.digits() + } + + pub fn rank(&self) -> usize { + self.0.rank() + } + + pub fn rank_in(&self) -> usize { + self.0.rank_in() + } + + pub fn rank_out(&self) -> usize { + self.0.rank_out() + } +} + +impl ReaderFrom for LWESwitchingKeyCompressed { + fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { + self.0.read_from(reader) + } +} + +impl WriterTo for LWESwitchingKeyCompressed { + fn write_to(&self, writer: &mut W) -> std::io::Result<()> { + self.0.write_to(writer) + } +} + +impl LWESwitchingKeyCompressed> { + pub fn alloc(n: usize, basek: usize, k: usize, rows: usize) -> Self { + Self(GLWESwitchingKeyCompressed::alloc( + n, basek, k, rows, 1, 1, 1, + )) + } + + pub fn encrypt_sk_scratch_space(module: &Module, n: usize, basek: usize, k: usize) -> usize + where + Module: GGLWEEncryptSkFamily, + { + LWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k) + } +} diff --git a/core/src/lwe/tests/generic_serialization.rs b/core/src/lwe/tests/generic_serialization.rs index 24d2c35..74a7636 100644 --- a/core/src/lwe/tests/generic_serialization.rs +++ b/core/src/lwe/tests/generic_serialization.rs @@ -1,6 +1,9 @@ use backend::hal::tests::serialization::test_reader_writer_interface; -use crate::{LWECiphertext, LWECiphertextCompressed}; +use crate::{ + GLWEToLWESwitchingKey, GLWEToLWESwitchingKeyCompressed, LWECiphertext, LWECiphertextCompressed, LWESwitchingKey, + LWESwitchingKeyCompressed, LWEToGLWESwitchingKey, LWEToGLWESwitchingKeyCompressed, +}; #[test] fn lwe_serialization() { @@ -9,7 +12,43 @@ fn lwe_serialization() { } #[test] -fn lwe_serialization_compressed() { +fn lwe_compressed_serialization() { let original: LWECiphertextCompressed> = LWECiphertextCompressed::alloc(12, 54); test_reader_writer_interface(original); } + +#[test] +fn glwe_to_lwe_switching_key_serialization() { + let original: GLWEToLWESwitchingKey> = GLWEToLWESwitchingKey::alloc(1024, 12, 54, 2, 2); + test_reader_writer_interface(original); +} + +#[test] +fn glwe_to_lwe_switching_key_compressed_serialization() { + let original: GLWEToLWESwitchingKeyCompressed> = GLWEToLWESwitchingKeyCompressed::alloc(1024, 12, 54, 2, 2); + test_reader_writer_interface(original); +} + +#[test] +fn lwe_to_glwe_switching_key_serialization() { + let original: LWEToGLWESwitchingKey> = LWEToGLWESwitchingKey::alloc(1024, 12, 54, 2, 2); + test_reader_writer_interface(original); +} + +#[test] +fn lwe_to_glwe_switching_key_compressed_serialization() { + let original: LWEToGLWESwitchingKeyCompressed> = LWEToGLWESwitchingKeyCompressed::alloc(1024, 12, 54, 2, 2); + test_reader_writer_interface(original); +} + +#[test] +fn lwe_switching_key_serialization() { + let original: LWESwitchingKey> = LWESwitchingKey::alloc(1024, 12, 54, 2); + test_reader_writer_interface(original); +} + +#[test] +fn lwe_switching_key_compressed_serialization() { + let original: LWESwitchingKeyCompressed> = LWESwitchingKeyCompressed::alloc(1024, 12, 54, 2); + test_reader_writer_interface(original); +} diff --git a/sampling/src/source.rs b/sampling/src/source.rs index 77c786c..5107525 100644 --- a/sampling/src/source.rs +++ b/sampling/src/source.rs @@ -15,11 +15,16 @@ impl Source { } pub fn branch(&mut self) -> ([u8; 32], Self) { - let mut seed = [0; 32]; - self.source.fill_bytes(&mut seed); + let seed: [u8; 32] = self.new_seed(); (seed, Source::new(seed)) } + pub fn new_seed(&mut self) -> [u8; 32] { + let mut seed: [u8; 32] = [0u8; 32]; + self.fill_bytes(&mut seed); + seed + } + #[inline(always)] pub fn next_u64n(&mut self, max: u64, mask: u64) -> u64 { let mut x: u64 = self.next_u64() & mask;