arnaucube
arnaucube/poulpyPublic Self-hosted repository
More serialization tests & compressed structs
Pro7ech jeanphilippe.bossuat@gmail.com
Wed, 13 Aug 2025 20:01:44 +0200
commit

6303346eef440469839f7369280b5906ffb5a569

parent

504cb72f82bac2f381513f89f3174383eb99441f

M core/src/blind_rotation/key.rs → 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 crate::{ Distribution, GGSWCiphertext, GGSWCiphertextExec, GGSWEncryptSkFamily, GGSWLayoutFamily, GLWESecretExec, Infos, LWESecret, }; +use std::fmt; +#[derive(Clone)] pub struct BlindRotationKeyCGGI<D: Data> { pub(crate) keys: Vec<GGSWCiphertext<D>>, pub(crate) dist: Distribution, } +impl<D: DataRef> fmt::Debug for BlindRotationKeyCGGI<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + impl<D: Data> PartialEq for BlindRotationKeyCGGI<D> { fn eq(&self, other: &Self) -> bool { if self.keys.len() != other.keys.len() {

@@ -31,6 +39,30 @@ }

} impl<D: Data> Eq for BlindRotationKeyCGGI<D> {} + +impl<D: DataRef> fmt::Display for BlindRotationKeyCGGI<D> { + 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<D: DataMut> Reset for BlindRotationKeyCGGI<D> { + fn reset(&mut self) { + self.keys.iter_mut().for_each(|key| key.reset()); + self.dist = Distribution::NONE; + } +} + +impl<D: DataMut> FillUniform for BlindRotationKeyCGGI<D> { + 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};
A 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<D: Data> { + pub(crate) keys: Vec<GGSWCiphertextCompressed<D>>, + pub(crate) dist: Distribution, +} + +impl<D: DataRef> fmt::Debug for BlindRotationKeyCGGICompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl<D: Data> PartialEq for BlindRotationKeyCGGICompressed<D> { + 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<D: Data> Eq for BlindRotationKeyCGGICompressed<D> {} + +impl<D: DataRef> fmt::Display for BlindRotationKeyCGGICompressed<D> { + 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<D: DataMut> Reset for BlindRotationKeyCGGICompressed<D> { + fn reset(&mut self) { + self.keys.iter_mut().for_each(|key| key.reset()); + self.dist = Distribution::NONE; + } +} + +impl<D: DataMut> FillUniform for BlindRotationKeyCGGICompressed<D> { + 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<D: DataMut> ReaderFrom for BlindRotationKeyCGGICompressed<D> { + fn read_from<R: std::io::Read>(&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::<LittleEndian>()? 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<D: DataRef> WriterTo for BlindRotationKeyCGGICompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + match self.dist.write_to(writer) { + Ok(()) => {} + Err(e) => return Err(e), + } + writer.write_u64::<LittleEndian>(self.keys.len() as u64)?; + for key in &self.keys { + key.write_to(writer)?; + } + Ok(()) + } +} + +impl BlindRotationKeyCGGICompressed<Vec<u8>> { + pub fn alloc(n_gglwe: usize, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self { + let mut data: Vec<GGSWCiphertextCompressed<Vec<u8>>> = 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<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize, rank: usize) -> usize + where + Module<B>: GGSWEncryptSkFamily<B>, + { + GGSWCiphertextCompressed::encrypt_sk_scratch_space(module, n, basek, k, rank) + } +} + +impl<D: DataRef> BlindRotationKeyCGGICompressed<D> { + #[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<D: DataMut> BlindRotationKeyCGGICompressed<D> { + pub fn generate_from_sk<DataSkGLWE, DataSkLWE, B: Backend>( + &mut self, + module: &Module<B>, + sk_glwe: &GLWESecretExec<DataSkGLWE, B>, + sk_lwe: &LWESecret<DataSkLWE>, + seed_xa: [u8; 32], + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch<B>, + ) where + DataSkGLWE: DataRef, + DataSkLWE: DataRef, + Module<B>: GGSWEncryptSkFamily<B> + VecZnxAddScalarInplace, + Scratch<B>: TakeVecZnxDft<B> + 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<Vec<u8>> = 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, + ); + }); + } +}
M core/src/blind_rotation/mod.rs → 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)]
D core/src/blind_rotation/test_fft64/cggi.rs

@@ -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<FFT64> = Module::<FFT64>::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<Vec<u8>> = GLWESecret::alloc(&module, rank); - sk_glwe.fill_ternary_prob(0.5, &mut source_xs); - let sk_glwe_dft: FourierGLWESecret<Vec<u8>, FFT64> = FourierGLWESecret::from(&module, &sk_glwe); - - let mut sk_lwe: LWESecret<Vec<u8>> = 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<Vec<u8>, 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<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe); - - let mut pt_lwe: LWEPlaintext<Vec<u8>> = 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<i64> = 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<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_res, rank); - - cggi_blind_rotate(&module, &mut res, &lwe, &lut, &brk, scratch_br.borrow()); - - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_res); - - res.decrypt(&module, &mut pt_have, &sk_glwe_dft, scratch.borrow()); - - let mut lwe_2n: Vec<i64> = 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::<i64>()) - & (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)); -}
A 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<Vec<u8>> = 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<Vec<u8>> = BlindRotationKeyCGGICompressed::alloc(256, 64, 12, 54, 2, 2); + test_reader_writer_interface(original); +}
M core/src/blind_rotation/tests/mod.rs → core/src/blind_rotation/tests/mod.rs

@@ -1,3 +1,4 @@

mod cpu_spqlios; mod generic_cggi; mod generic_lut; +mod generic_serialization;
M core/src/gglwe/layout.rs → core/src/gglwe/layout.rs

@@ -29,10 +29,7 @@ self.data.fill_uniform(source);

} } -impl<D: DataMut> Reset for GGLWECiphertext<D> -where - MatZnx<D>: Reset, -{ +impl<D: DataMut> Reset for GGLWECiphertext<D> { fn reset(&mut self) { self.data.reset(); self.basek = 0;
M core/src/gglwe/tests/generic_serialization.rs → core/src/gglwe/tests/generic_serialization.rs

@@ -12,7 +12,7 @@ test_reader_writer_interface(original);

} #[test] -fn test_gglwe_serialization_compressed() { +fn test_gglwe_compressed_serialization() { let original: GGLWECiphertextCompressed<Vec<u8>> = GGLWECiphertextCompressed::alloc(1024, 12, 54, 3, 1, 2, 2); test_reader_writer_interface(original); }

@@ -24,7 +24,7 @@ test_reader_writer_interface(original);

} #[test] -fn test_glwe_switching_key_serialization_compressed() { +fn test_glwe_switching_key_compressed_serialization() { let original: GLWESwitchingKeyCompressed<Vec<u8>> = GLWESwitchingKeyCompressed::alloc(1024, 12, 54, 3, 1, 2, 2); test_reader_writer_interface(original); }

@@ -36,7 +36,7 @@ test_reader_writer_interface(original);

} #[test] -fn test_automorphism_key_serialization_compressed() { +fn test_automorphism_key_compressed_serialization() { let original: AutomorphismKeyCompressed<Vec<u8>> = AutomorphismKeyCompressed::alloc(1024, 12, 54, 3, 1, 2); test_reader_writer_interface(original); }

@@ -48,7 +48,7 @@ test_reader_writer_interface(original);

} #[test] -fn test_tensor_key_serialization_compressed() { +fn test_tensor_key_compressed_serialization() { let original: GLWETensorKeyCompressed<Vec<u8>> = GLWETensorKeyCompressed::alloc(1024, 12, 54, 3, 1, 2); test_reader_writer_interface(original); }
M core/src/ggsw/layout.rs → core/src/ggsw/layout.rs

@@ -18,6 +18,12 @@ }

impl<D: DataRef> fmt::Debug for GGSWCiphertext<D> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.data) + } +} + +impl<D: DataRef> fmt::Display for GGSWCiphertext<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "(GGSWCiphertext: basek={} k={} digits={}) {}",

@@ -26,10 +32,7 @@ )

} } -impl<D: DataMut> Reset for GGSWCiphertext<D> -where - MatZnx<D>: Reset, -{ +impl<D: DataMut> Reset for GGSWCiphertext<D> { fn reset(&mut self) { self.data.reset(); self.basek = 0;

@@ -38,10 +41,7 @@ self.digits = 0;

} } -impl<D: DataMut> FillUniform for GGSWCiphertext<D> -where - MatZnx<D>: FillUniform, -{ +impl<D: DataMut> FillUniform for GGSWCiphertext<D> { fn fill_uniform(&mut self, source: &mut sampling::source::Source) { self.data.fill_uniform(source); }
M core/src/ggsw/layout_compressed.rs → core/src/ggsw/layout_compressed.rs

@@ -19,6 +19,12 @@ }

impl<D: DataRef> fmt::Debug for GGSWCiphertextCompressed<D> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.data) + } +} + +impl<D: DataRef> fmt::Display for GGSWCiphertextCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "(GGSWCiphertextCompressed: basek={} k={} digits={}) {}",

@@ -27,10 +33,7 @@ )

} } -impl<D: DataMut> Reset for GGSWCiphertextCompressed<D> -where - MatZnx<D>: Reset, -{ +impl<D: DataMut> Reset for GGSWCiphertextCompressed<D> { fn reset(&mut self) { self.data.reset(); self.basek = 0;

@@ -41,10 +44,7 @@ self.seed = Vec::new();

} } -impl<D: DataMut> FillUniform for GGSWCiphertextCompressed<D> -where - MatZnx<D>: FillUniform, -{ +impl<D: DataMut> FillUniform for GGSWCiphertextCompressed<D> { fn fill_uniform(&mut self, source: &mut sampling::source::Source) { self.data.fill_uniform(source); }
M core/src/ggsw/test/generic_serialization.rs → core/src/ggsw/test/generic_serialization.rs

@@ -9,7 +9,7 @@ test_reader_writer_interface(original);

} #[test] -fn ggsw_test_serialization_compressed() { +fn ggsw_test_compressed_serialization() { let original: GGSWCiphertextCompressed<Vec<u8>> = GGSWCiphertextCompressed::alloc(1024, 12, 54, 3, 1, 2); test_reader_writer_interface(original); }
M core/src/glwe/external_product.rs → core/src/glwe/external_product.rs

@@ -45,7 +45,7 @@ rank + 1, // cols in

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) }
M core/src/glwe/tests/generic_serialization.rs → core/src/glwe/tests/generic_serialization.rs

@@ -9,7 +9,7 @@ test_reader_writer_interface(original);

} #[test] -fn test_serialization_compressed() { +fn test_compressed_serialization() { let original: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(1024, 12, 54, 3); test_reader_writer_interface(original); }
M core/src/lwe/conversion.rs → core/src/lwe/conversion.rs

@@ -8,6 +8,39 @@ GLWECiphertext, GLWEKeyswitchFamily, GLWEToLWESwitchingKeyExec, Infos, LWECiphertext, LWESwitchingKeyExec,

LWEToGLWESwitchingKeyExec, TakeGLWECt, }; +impl LWECiphertext<Vec<u8>> { + pub fn from_glwe_scratch_space<B: Backend>( + module: &Module<B>, + n: usize, + basek: usize, + k_lwe: usize, + k_glwe: usize, + k_ksk: usize, + rank: usize, + ) -> usize + where + Module<B>: GLWEKeyswitchFamily<B>, + { + 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<B: Backend>( + module: &Module<B>, + n: usize, + basek: usize, + k_lwe_out: usize, + k_lwe_in: usize, + k_ksk: usize, + ) -> usize + where + Module<B>: GLWEKeyswitchFamily<B>, + { + 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<DLwe: DataMut> LWECiphertext<DLwe> { pub fn sample_extract<DGlwe: DataRef>(&mut self, a: &GLWECiphertext<DGlwe>) { #[cfg(debug_assertions)]
M core/src/lwe/encryption.rs → 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<DataSelf: DataMut> LWECiphertext<DataSelf> { pub fn encrypt_sk<DataPt, DataSk, B: Backend>(

@@ -77,3 +82,125 @@ self.data.at_mut(0, i)[0] = tmp_znx.at(0, i)[0];

}); } } + +impl<D: DataMut> GLWEToLWESwitchingKey<D> { + pub fn encrypt_sk<DLwe, DGlwe, B: Backend>( + &mut self, + module: &Module<B>, + sk_lwe: &LWESecret<DLwe>, + sk_glwe: &GLWESecret<DGlwe>, + source_xa: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch<B>, + ) where + DLwe: DataRef, + DGlwe: DataRef, + Module<B>: GGLWEEncryptSkFamily<B> + VecZnxAutomorphismInplace + VecZnxSwithcDegree + VecZnxAddScalarInplace, + Scratch<B>: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft<B> + TakeGLWESecretExec<B> + 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<D: DataMut> LWEToGLWESwitchingKey<D> { + pub fn encrypt_sk<DLwe, DGlwe, B: Backend>( + &mut self, + module: &Module<B>, + sk_lwe: &LWESecret<DLwe>, + sk_glwe: &GLWESecret<DGlwe>, + source_xa: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch<B>, + ) where + DLwe: DataRef, + DGlwe: DataRef, + Module<B>: GGLWEEncryptSkFamily<B> + VecZnxAutomorphismInplace + VecZnxSwithcDegree + VecZnxAddScalarInplace, + Scratch<B>: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft<B> + TakeGLWESecretExec<B> + 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<D: DataMut> LWESwitchingKey<D> { + pub fn encrypt_sk<DIn, DOut, B: Backend>( + &mut self, + module: &Module<B>, + sk_lwe_in: &LWESecret<DIn>, + sk_lwe_out: &LWESecret<DOut>, + source_xa: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch<B>, + ) where + DIn: DataRef, + DOut: DataRef, + Module<B>: GGLWEEncryptSkFamily<B> + VecZnxAutomorphismInplace + VecZnxSwithcDegree + VecZnxAddScalarInplace, + Scratch<B>: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft<B> + TakeGLWESecretExec<B> + 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, + ); + } +}
M core/src/lwe/keyswtich_layouts.rs → core/src/lwe/keyswtich_layouts.rs

@@ -1,20 +1,39 @@

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, GLWESecret, GLWESecretExec, GLWESwitchingKey, Infos}; -use crate::{ - GGLWEEncryptSkFamily, GLWECiphertext, GLWEKeyswitchFamily, GLWESecret, GLWESecretExec, GLWESwitchingKey, Infos, - LWECiphertext, LWESecret, TakeGLWESecret, TakeGLWESecretExec, -}; +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<D: Data>(pub(crate) GLWESwitchingKey<D>); + +impl<D: DataRef> fmt::Debug for GLWEToLWESwitchingKey<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl<D: DataMut> FillUniform for GLWEToLWESwitchingKey<D> { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} + +impl<D: DataMut> Reset for GLWEToLWESwitchingKey<D> { + fn reset(&mut self) { + self.0.reset(); + } +} + +impl<D: DataRef> fmt::Display for GLWEToLWESwitchingKey<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(GLWEToLWESwitchingKey) {}", self.0) + } +} impl<D: Data> Infos for GLWEToLWESwitchingKey<D> { type Inner = MatZnx<D>;

@@ -76,46 +95,32 @@ + (GLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k, rank_in, 1) | GLWESecret::bytes_of(n, rank_in))

} } -impl<D: DataMut> GLWEToLWESwitchingKey<D> { - pub fn encrypt_sk<DLwe, DGlwe, B: Backend>( - &mut self, - module: &Module<B>, - sk_lwe: &LWESecret<DLwe>, - sk_glwe: &GLWESecret<DGlwe>, - source_xa: &mut Source, - source_xe: &mut Source, - sigma: f64, - scratch: &mut Scratch<B>, - ) where - DLwe: DataRef, - DGlwe: DataRef, - Module<B>: GGLWEEncryptSkFamily<B> + VecZnxAutomorphismInplace + VecZnxSwithcDegree + VecZnxAddScalarInplace, - Scratch<B>: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft<B> + TakeGLWESecretExec<B> + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - assert!(sk_lwe.n() <= module.n()); - } +#[derive(PartialEq, Eq, Clone)] +pub struct LWEToGLWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>); - 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); +impl<D: DataRef> fmt::Debug for LWEToGLWESwitchingKey<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl<D: DataMut> FillUniform for LWEToGLWESwitchingKey<D> { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} - self.0.encrypt_sk( - module, - sk_glwe, - &sk_lwe_as_glwe, - source_xa, - source_xe, - sigma, - scratch1, - ); +impl<D: DataMut> Reset for LWEToGLWESwitchingKey<D> { + fn reset(&mut self) { + self.0.reset(); } } -#[derive(PartialEq, Eq)] -pub struct LWEToGLWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>); +impl<D: DataRef> fmt::Display for LWEToGLWESwitchingKey<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(LWEToGLWESwitchingKey) {}", self.0) + } +} impl<D: Data> Infos for LWEToGLWESwitchingKey<D> { type Inner = MatZnx<D>;

@@ -176,46 +181,32 @@ GLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k, 1, rank_out) + GLWESecret::bytes_of(n, 1)

} } -impl<D: DataMut> LWEToGLWESwitchingKey<D> { - pub fn encrypt_sk<DLwe, DGlwe, B: Backend>( - &mut self, - module: &Module<B>, - sk_lwe: &LWESecret<DLwe>, - sk_glwe: &GLWESecret<DGlwe>, - source_xa: &mut Source, - source_xe: &mut Source, - sigma: f64, - scratch: &mut Scratch<B>, - ) where - DLwe: DataRef, - DGlwe: DataRef, - Module<B>: GGLWEEncryptSkFamily<B> + VecZnxAutomorphismInplace + VecZnxSwithcDegree + VecZnxAddScalarInplace, - Scratch<B>: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft<B> + TakeGLWESecretExec<B> + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - assert!(sk_lwe.n() <= module.n()); - } +#[derive(PartialEq, Eq, Clone)] +pub struct LWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>); - 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); +impl<D: DataRef> fmt::Debug for LWESwitchingKey<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl<D: DataMut> FillUniform for LWESwitchingKey<D> { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} - self.0.encrypt_sk( - module, - &sk_lwe_as_glwe, - &sk_glwe, - source_xa, - source_xe, - sigma, - scratch1, - ); +impl<D: DataMut> Reset for LWESwitchingKey<D> { + fn reset(&mut self) { + self.0.reset(); } } -#[derive(PartialEq, Eq)] -pub struct LWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>); +impl<D: DataRef> fmt::Display for LWESwitchingKey<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(LWESwitchingKey) {}", self.0) + } +} impl<D: Data> Infos for LWESwitchingKey<D> { type Inner = MatZnx<D>;

@@ -277,82 +268,3 @@ + GLWESecretExec::bytes_of(module, n, 1)

+ GLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k, 1, 1) } } - -impl<D: DataMut> LWESwitchingKey<D> { - pub fn encrypt_sk<DIn, DOut, B: Backend>( - &mut self, - module: &Module<B>, - sk_lwe_in: &LWESecret<DIn>, - sk_lwe_out: &LWESecret<DOut>, - source_xa: &mut Source, - source_xe: &mut Source, - sigma: f64, - scratch: &mut Scratch<B>, - ) where - DIn: DataRef, - DOut: DataRef, - Module<B>: GGLWEEncryptSkFamily<B> + VecZnxAutomorphismInplace + VecZnxSwithcDegree + VecZnxAddScalarInplace, - Scratch<B>: ScratchAvailable + TakeScalarZnx + TakeVecZnxDft<B> + TakeGLWESecretExec<B> + 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<Vec<u8>> { - pub fn from_glwe_scratch_space<B: Backend>( - module: &Module<B>, - n: usize, - basek: usize, - k_lwe: usize, - k_glwe: usize, - k_ksk: usize, - rank: usize, - ) -> usize - where - Module<B>: GLWEKeyswitchFamily<B>, - { - 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<B: Backend>( - module: &Module<B>, - n: usize, - basek: usize, - k_lwe_out: usize, - k_lwe_in: usize, - k_ksk: usize, - ) -> usize - where - Module<B>: GLWEKeyswitchFamily<B>, - { - 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) - } -}
M core/src/lwe/layouts_compressed.rs → 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<D: Data> {

@@ -47,10 +50,7 @@ self.seed = [0u8; 32];

} } -impl<D: DataMut> FillUniform for LWECiphertextCompressed<D> -where - VecZnx<D>: FillUniform, -{ +impl<D: DataMut> FillUniform for LWECiphertextCompressed<D> { fn fill_uniform(&mut self, source: &mut Source) { self.data.fill_uniform(source); }

@@ -132,3 +132,267 @@ self.data.at_mut(0, i)[0] = other.data.at(0, i)[0];

}); } } + +#[derive(PartialEq, Eq, Clone)] +pub struct GLWEToLWESwitchingKeyCompressed<D: Data>(pub(crate) GLWESwitchingKeyCompressed<D>); + +impl<D: DataRef> fmt::Debug for GLWEToLWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl<D: DataMut> FillUniform for GLWEToLWESwitchingKeyCompressed<D> { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} + +impl<D: DataMut> Reset for GLWEToLWESwitchingKeyCompressed<D> { + fn reset(&mut self) { + self.0.reset(); + } +} + +impl<D: DataRef> fmt::Display for GLWEToLWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(GLWEToLWESwitchingKeyCompressed) {}", self.0) + } +} + +impl<D: Data> Infos for GLWEToLWESwitchingKeyCompressed<D> { + type Inner = MatZnx<D>; + + fn inner(&self) -> &Self::Inner { + &self.0.inner() + } + + fn basek(&self) -> usize { + self.0.basek() + } + + fn k(&self) -> usize { + self.0.k() + } +} + +impl<D: Data> GLWEToLWESwitchingKeyCompressed<D> { + 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<D: DataMut> ReaderFrom for GLWEToLWESwitchingKeyCompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.0.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GLWEToLWESwitchingKeyCompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + self.0.write_to(writer) + } +} + +impl GLWEToLWESwitchingKeyCompressed<Vec<u8>> { + 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<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize, rank_in: usize) -> usize + where + Module<B>: GGLWEEncryptSkFamily<B>, + { + GLWEToLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k, rank_in) + } +} + +#[derive(PartialEq, Eq, Clone)] +pub struct LWEToGLWESwitchingKeyCompressed<D: Data>(pub(crate) GLWESwitchingKeyCompressed<D>); + +impl<D: DataRef> fmt::Debug for LWEToGLWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl<D: DataMut> FillUniform for LWEToGLWESwitchingKeyCompressed<D> { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} + +impl<D: DataMut> Reset for LWEToGLWESwitchingKeyCompressed<D> { + fn reset(&mut self) { + self.0.reset(); + } +} + +impl<D: DataRef> fmt::Display for LWEToGLWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(LWEToGLWESwitchingKeyCompressed) {}", self.0) + } +} + +impl<D: Data> Infos for LWEToGLWESwitchingKeyCompressed<D> { + type Inner = MatZnx<D>; + + fn inner(&self) -> &Self::Inner { + &self.0.inner() + } + + fn basek(&self) -> usize { + self.0.basek() + } + + fn k(&self) -> usize { + self.0.k() + } +} + +impl<D: Data> LWEToGLWESwitchingKeyCompressed<D> { + 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<D: DataMut> ReaderFrom for LWEToGLWESwitchingKeyCompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.0.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for LWEToGLWESwitchingKeyCompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + self.0.write_to(writer) + } +} + +impl LWEToGLWESwitchingKeyCompressed<Vec<u8>> { + 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<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize, rank_out: usize) -> usize + where + Module<B>: GGLWEEncryptSkFamily<B>, + { + LWEToGLWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k, rank_out) + } +} + +#[derive(PartialEq, Eq, Clone)] +pub struct LWESwitchingKeyCompressed<D: Data>(pub(crate) GLWESwitchingKeyCompressed<D>); + +impl<D: DataRef> fmt::Debug for LWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + +impl<D: DataMut> FillUniform for LWESwitchingKeyCompressed<D> { + fn fill_uniform(&mut self, source: &mut sampling::source::Source) { + self.0.fill_uniform(source); + } +} + +impl<D: DataMut> Reset for LWESwitchingKeyCompressed<D> { + fn reset(&mut self) { + self.0.reset(); + } +} + +impl<D: DataRef> fmt::Display for LWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(LWESwitchingKeyCompressed) {}", self.0) + } +} + +impl<D: Data> Infos for LWESwitchingKeyCompressed<D> { + type Inner = MatZnx<D>; + + fn inner(&self) -> &Self::Inner { + &self.0.inner() + } + + fn basek(&self) -> usize { + self.0.basek() + } + + fn k(&self) -> usize { + self.0.k() + } +} + +impl<D: Data> LWESwitchingKeyCompressed<D> { + 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<D: DataMut> ReaderFrom for LWESwitchingKeyCompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.0.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for LWESwitchingKeyCompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + self.0.write_to(writer) + } +} + +impl LWESwitchingKeyCompressed<Vec<u8>> { + 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<B: Backend>(module: &Module<B>, n: usize, basek: usize, k: usize) -> usize + where + Module<B>: GGLWEEncryptSkFamily<B>, + { + LWESwitchingKey::encrypt_sk_scratch_space(module, n, basek, k) + } +}
M core/src/lwe/tests/generic_serialization.rs → 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 @@ test_reader_writer_interface(original);

} #[test] -fn lwe_serialization_compressed() { +fn lwe_compressed_serialization() { let original: LWECiphertextCompressed<Vec<u8>> = LWECiphertextCompressed::alloc(12, 54); test_reader_writer_interface(original); } + +#[test] +fn glwe_to_lwe_switching_key_serialization() { + let original: GLWEToLWESwitchingKey<Vec<u8>> = GLWEToLWESwitchingKey::alloc(1024, 12, 54, 2, 2); + test_reader_writer_interface(original); +} + +#[test] +fn glwe_to_lwe_switching_key_compressed_serialization() { + let original: GLWEToLWESwitchingKeyCompressed<Vec<u8>> = GLWEToLWESwitchingKeyCompressed::alloc(1024, 12, 54, 2, 2); + test_reader_writer_interface(original); +} + +#[test] +fn lwe_to_glwe_switching_key_serialization() { + let original: LWEToGLWESwitchingKey<Vec<u8>> = LWEToGLWESwitchingKey::alloc(1024, 12, 54, 2, 2); + test_reader_writer_interface(original); +} + +#[test] +fn lwe_to_glwe_switching_key_compressed_serialization() { + let original: LWEToGLWESwitchingKeyCompressed<Vec<u8>> = LWEToGLWESwitchingKeyCompressed::alloc(1024, 12, 54, 2, 2); + test_reader_writer_interface(original); +} + +#[test] +fn lwe_switching_key_serialization() { + let original: LWESwitchingKey<Vec<u8>> = LWESwitchingKey::alloc(1024, 12, 54, 2); + test_reader_writer_interface(original); +} + +#[test] +fn lwe_switching_key_compressed_serialization() { + let original: LWESwitchingKeyCompressed<Vec<u8>> = LWESwitchingKeyCompressed::alloc(1024, 12, 54, 2); + test_reader_writer_interface(original); +}
M sampling/src/source.rs → sampling/src/source.rs

@@ -15,9 +15,14 @@ }

} 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)]