arnaucube
arnaucube/poulpyPublic Self-hosted repository
remaining in encryption + noise
Rasoul Akhavan Mahdavi rasoul.akhavan.mahdavi@uwaterloo.ca
Fri, 17 Oct 2025 19:56:10 -0400
commit

a282e88126eeb53c01159197a742930c73254a13

parent

957345f9eabb28d2fef4cb6361c749d9fabd8aca

M poulpy-core/src/decryption/glwe_ct.rs → poulpy-core/src/decryption/glwe_ct.rs

@@ -7,7 +7,7 @@ layouts::{Backend, DataMut, DataViewMut, Module, Scratch},

}; use crate::layouts::{ - GLWE, GLWEInfos, GLWEPlaintext, GLWEPlaintextToMut, GLWEToMut, LWEInfos, + GLWE, GLWEInfos, GLWEPlaintext, GLWEPlaintextToMut, GLWEToRef, LWEInfos, prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, };

@@ -55,14 +55,14 @@ let size: usize = infos.size();

(self.vec_znx_normalize_tmp_bytes() | self.bytes_of_vec_znx_dft(1, size)) + self.bytes_of_vec_znx_dft(1, size) } - fn glwe_decrypt<R, P, S>(&self, res: &mut R, pt: &mut P, sk: &S, scratch: &mut Scratch<BE>) + fn glwe_decrypt<R, P, S>(&self, res: &R, pt: &mut P, sk: &S, scratch: &mut Scratch<BE>) where - R: GLWEToMut, + R: GLWEToRef, P: GLWEPlaintextToMut, S: GLWESecretPreparedToRef<BE>, Scratch<BE>: ScratchTakeBasic, { - let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let res: &GLWE<&[u8]> = &res.to_ref(); let pt: &mut GLWEPlaintext<&mut [u8]> = &mut pt.to_ref(); let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref();
M poulpy-core/src/decryption/mod.rs → poulpy-core/src/decryption/mod.rs

@@ -1,2 +1,5 @@

mod glwe_ct; mod lwe_ct; + +pub use glwe_ct::*; +pub use lwe_ct::*;
M poulpy-core/src/encryption/compressed/gglwe_tsk.rs → poulpy-core/src/encryption/compressed/gglwe_tsk.rs

@@ -11,6 +11,7 @@

use crate::{ ScratchTakeCore, encryption::compressed::gglwe_ksk::GLWESwitchingKeyCompressedEncryptSk, + encryption::gglwe_tsk::TensorKeyEncryptSk, layouts::{ GGLWEInfos, GLWEInfos, GLWESecret, GLWESecretToRef, GetDist, LWEInfos, Rank, TensorKey, compressed::{TensorKeyCompressed, TensorKeyCompressedToMut},

@@ -18,58 +19,81 @@ },

}; impl TensorKeyCompressed<Vec<u8>> { - pub fn encrypt_sk_tmp_bytes<B: Backend, A>(module: &Module<B>, infos: &A) -> usize + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize where A: GGLWEInfos, - Module<B>: ModuleN - + SvpPPolBytesOf - + SvpPPolAlloc<B> - + VecZnxNormalizeTmpBytes - + VecZnxDftBytesOf - + VecZnxNormalizeTmpBytes - + VecZnxBigBytesOf, + M: GGLWETensorKeyCompressedEncryptSk<BE>, + { + module.gglwe_tensor_key_compressed_encrypt_sk_tmp_bytes(infos) + } +} + +impl<DataSelf: DataMut> TensorKeyCompressed<DataSelf> { + pub fn encrypt_sk<DataSk: DataRef, BE: Backend>( + &mut self, + module: &Module<BE>, + sk: &GLWESecret<DataSk>, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + GLWESecret<DataSk>: GetDist, + Module<BE>: GGLWETensorKeyCompressedEncryptSk<BE>, { - TensorKey::encrypt_sk_tmp_bytes(module, infos) + module.gglwe_tensor_key_encrypt_sk(self, sk, seed_xa, source_xe, scratch); } } -pub trait GGLWETensorKeyCompressedEncryptSk<B: Backend> { +pub trait GGLWETensorKeyCompressedEncryptSk<BE: Backend> { + + fn gglwe_tensor_key_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + fn gglwe_tensor_key_encrypt_sk<R, S>( &self, res: &mut R, sk: &S, seed_xa: [u8; 32], source_xe: &mut Source, - scratch: &mut Scratch<B>, + scratch: &mut Scratch<BE>, ) where R: TensorKeyCompressedToMut, S: GLWESecretToRef + GetDist; } -impl<B: Backend> GGLWETensorKeyCompressedEncryptSk<B> for Module<B> +impl<BE: Backend> GGLWETensorKeyCompressedEncryptSk<BE> for Module<BE> where - Module<B>: ModuleN - + GLWESwitchingKeyCompressedEncryptSk<B> - + VecZnxDftApply<B> - + SvpApplyDftToDft<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxBigNormalize<B> - + SvpPrepare<B> - + SvpPPolAllocBytesImpl<B> + Module<BE>: ModuleN + + GLWESwitchingKeyCompressedEncryptSk<BE> + + TensorKeyEncryptSk<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDft<BE> + + VecZnxIdftApplyTmpA<BE> + + VecZnxBigNormalize<BE> + + SvpPrepare<BE> + + SvpPPolAllocBytesImpl<BE> + SvpPPolBytesOf - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> + + VecZnxDftAllocBytesImpl<BE> + + VecZnxBigAllocBytesImpl<BE> + VecZnxDftBytesOf + VecZnxBigBytesOf, - Scratch<B>: ScratchTakeBasic + ScratchTakeCore<B>, + Scratch<BE>: ScratchTakeBasic + ScratchTakeCore<BE>, { + fn gglwe_tensor_key_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos + { + self.tensor_key_encrypt_sk_tmp_bytes(infos) + } + fn gglwe_tensor_key_encrypt_sk<R, S>( &self, res: &mut R, sk: &S, seed_xa: [u8; 32], source_xe: &mut Source, - scratch: &mut Scratch<B>, + scratch: &mut Scratch<BE>, ) where R: TensorKeyCompressedToMut, S: GLWESecretToRef + GetDist,

@@ -130,35 +154,4 @@ );

} } } -} - -impl<DataSelf: DataMut> TensorKeyCompressed<DataSelf> { - pub fn encrypt_sk<DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - sk: &GLWESecret<DataSk>, - seed_xa: [u8; 32], - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - GLWESecret<DataSk>: GetDist, - Module<B>: GGLWETensorKeyCompressedEncryptSk<B>, - { - module.gglwe_tensor_key_encrypt_sk(self, sk, seed_xa, source_xe, scratch); - } -} - -impl<DataSelf: DataMut> TensorKeyCompressed<DataSelf> { - pub fn encrypt_sk<DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - sk: &GLWESecret<DataSk>, - seed_xa: [u8; 32], - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: GGLWETensorKeyCompressedEncryptSk<B>, - { - module.gglwe_tensor_key_encrypt_sk(self, sk, seed_xa, source_xe, scratch); - } -} +}
M poulpy-core/src/encryption/compressed/ggsw_ct.rs → poulpy-core/src/encryption/compressed/ggsw_ct.rs

@@ -1,30 +1,52 @@

use poulpy_hal::{ - api::{ModuleN, VecZnxAddScalarInplace, VecZnxDftBytesOf, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes}, + api::{ModuleN, VecZnxAddScalarInplace, VecZnxNormalizeInplace}, layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxZero}, source::Source, }; use crate::{ ScratchTakeCore, - encryption::{SIGMA, glwe_ct::GLWEEncryptSkInternal}, + encryption::{SIGMA, ggsw_ct::GGSWEncryptSk, glwe_ct::GLWEEncryptSkInternal}, layouts::{ - GGSW, GGSWInfos, GLWEInfos, LWEInfos, + GGSWInfos, GLWEInfos, LWEInfos, compressed::{GGSWCompressed, GGSWCompressedToMut}, prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, }, }; impl GGSWCompressed<Vec<u8>> { - pub fn encrypt_sk_tmp_bytes<B: Backend, A>(module: &Module<B>, infos: &A) -> usize + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize where A: GGSWInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftBytesOf, + M: GGSWCompressedEncryptSk<BE>, + { + module.ggsw_compressed_encrypt_sk_tmp_bytes(infos) + } +} + +impl<DataSelf: DataMut> GGSWCompressed<DataSelf> { + #[allow(clippy::too_many_arguments)] + pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, BE: Backend>( + &mut self, + module: &Module<BE>, + pt: &ScalarZnx<DataPt>, + sk: &GLWESecretPrepared<DataSk, BE>, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + Module<BE>: GGSWCompressedEncryptSk<BE>, { - GGSW::encrypt_sk_tmp_bytes(module, infos) + module.ggsw_compressed_encrypt_sk(self, pt, sk, seed_xa, source_xe, scratch); } } -pub trait GGSWCompressedEncryptSk<B: Backend> { + +pub trait GGSWCompressedEncryptSk<BE: Backend> { + fn ggsw_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGSWInfos; + fn ggsw_compressed_encrypt_sk<R, P, S>( &self, res: &mut R,

@@ -32,18 +54,24 @@ pt: &P,

sk: &S, seed_xa: [u8; 32], source_xe: &mut Source, - scratch: &mut Scratch<B>, + scratch: &mut Scratch<BE>, ) where R: GGSWCompressedToMut, P: ScalarZnxToRef, - S: GLWESecretPreparedToRef<B>; + S: GLWESecretPreparedToRef<BE>; } -impl<B: Backend> GGSWCompressedEncryptSk<B> for Module<B> +impl<BE: Backend> GGSWCompressedEncryptSk<BE> for Module<BE> where - Module<B>: ModuleN + GLWEEncryptSkInternal<B> + VecZnxAddScalarInplace + VecZnxNormalizeInplace<B>, - Scratch<B>: ScratchTakeCore<B>, + Module<BE>: ModuleN + GLWEEncryptSkInternal<BE> + GGSWEncryptSk<BE> + VecZnxAddScalarInplace + VecZnxNormalizeInplace<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { + fn ggsw_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where A: GGSWInfos, + { + self.ggsw_encrypt_sk_tmp_bytes(infos) + } + fn ggsw_compressed_encrypt_sk<R, P, S>( &self, res: &mut R,

@@ -51,14 +79,14 @@ pt: &P,

sk: &S, seed_xa: [u8; 32], source_xe: &mut Source, - scratch: &mut Scratch<B>, + scratch: &mut Scratch<BE>, ) where R: GGSWCompressedToMut, P: ScalarZnxToRef, - S: GLWESecretPreparedToRef<B>, + S: GLWESecretPreparedToRef<BE>, { let res: &mut GGSWCompressed<&mut [u8]> = &mut res.to_mut(); - let sk: &GLWESecretPrepared<&[u8], B> = &sk.to_ref(); + let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref(); let pt: &ScalarZnx<&[u8]> = &pt.to_ref(); #[cfg(debug_assertions)]

@@ -111,21 +139,4 @@ );

} } } -} - -impl<DataSelf: DataMut> GGSWCompressed<DataSelf> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: &ScalarZnx<DataPt>, - sk: &GLWESecretPrepared<DataSk, B>, - seed_xa: [u8; 32], - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: GGSWCompressedEncryptSk<B>, - { - module.ggsw_compressed_encrypt_sk(self, pt, sk, seed_xa, source_xe, scratch); - } -} +}
M poulpy-core/src/encryption/compressed/glwe_ct.rs → poulpy-core/src/encryption/compressed/glwe_ct.rs

@@ -5,7 +5,7 @@ source::Source,

}; use crate::{ - encryption::{SIGMA, glwe_ct::GLWEEncryptSkInternal}, + encryption::{SIGMA, glwe_ct::{GLWEEncryptSk, GLWEEncryptSkInternal}}, layouts::{ GLWE, GLWEInfos, GLWEPlaintext, GLWEPlaintextToRef, LWEInfos, compressed::{GLWECompressed, GLWECompressedToMut},

@@ -14,16 +14,38 @@ },

}; impl GLWECompressed<Vec<u8>> { - pub fn encrypt_sk_tmp_bytes<B: Backend, A>(module: &Module<B>, infos: &A) -> usize + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize where A: GLWEInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftBytesOf, + M: GLWECompressedEncryptSk<BE>, { - GLWE::encrypt_sk_tmp_bytes(module, infos) + module.glwe_compressed_encrypt_sk_tmp_bytes(infos) } } -pub trait GLWECompressedEncryptSk<B: Backend> { +impl<D: DataMut> GLWECompressed<D> { + #[allow(clippy::too_many_arguments)] + pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, BE: Backend>( + &mut self, + module: &Module<BE>, + pt: &GLWEPlaintext<DataPt>, + sk: &GLWESecretPrepared<DataSk, BE>, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + Module<BE>: GLWECompressedEncryptSk<BE>, + { + module.glwe_compressed_encrypt_sk(self, pt, sk, seed_xa, source_xe, scratch); + } +} + + +pub trait GLWECompressedEncryptSk<BE: Backend> { + fn glwe_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GLWEInfos; + fn glwe_compressed_encrypt_sk<R, P, S>( &self, res: &mut R,

@@ -31,17 +53,25 @@ pt: &P,

sk: &S, seed_xa: [u8; 32], source_xe: &mut Source, - scratch: &mut Scratch<B>, + scratch: &mut Scratch<BE>, ) where R: GLWECompressedToMut, P: GLWEPlaintextToRef, - S: GLWESecretPreparedToRef<B>; + S: GLWESecretPreparedToRef<BE>; } -impl<B: Backend> GLWECompressedEncryptSk<B> for Module<B> +impl<BE: Backend> GLWECompressedEncryptSk<BE> for Module<BE> where - Module<B>: GLWEEncryptSkInternal<B>, + Module<BE>: GLWEEncryptSkInternal<BE> + GLWEEncryptSk<BE>, { + + fn glwe_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GLWEInfos, + { + self.glwe_encrypt_sk_tmp_bytes(infos) + } + fn glwe_compressed_encrypt_sk<R, P, S>( &self, res: &mut R,

@@ -49,11 +79,11 @@ pt: &P,

sk: &S, seed_xa: [u8; 32], source_xe: &mut Source, - scratch: &mut Scratch<B>, + scratch: &mut Scratch<BE>, ) where R: GLWECompressedToMut, P: GLWEPlaintextToRef, - S: GLWESecretPreparedToRef<B>, + S: GLWESecretPreparedToRef<BE>, { let res: &mut GLWECompressed<&mut [u8]> = &mut res.to_mut(); let mut source_xa: Source = Source::new(seed_xa);

@@ -75,21 +105,4 @@ );

res.seed = seed_xa; } -} - -impl<D: DataMut> GLWECompressed<D> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: &GLWEPlaintext<DataPt>, - sk: &GLWESecretPrepared<DataSk, B>, - seed_xa: [u8; 32], - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: GLWECompressedEncryptSk<B>, - { - module.glwe_compressed_encrypt_sk(self, pt, sk, seed_xa, source_xe, scratch); - } -} +}
M poulpy-core/src/encryption/glwe_pk.rs → poulpy-core/src/encryption/glwe_pk.rs

@@ -14,24 +14,24 @@ },

}; impl<D: DataMut> GLWEPublicKey<D> { - pub fn generate<S: DataRef, B: Backend>( + pub fn generate<S: DataRef, BE: Backend>( &mut self, - module: &Module<B>, - sk: &GLWESecretPrepared<S, B>, + module: &Module<BE>, + sk: &GLWESecretPrepared<S, BE>, source_xa: &mut Source, source_xe: &mut Source, ) where - Module<B>: GLWEPublicKeyGenerate<B>, + Module<BE>: GLWEPublicKeyGenerate<BE>, { module.glwe_public_key_generate(self, sk, source_xa, source_xe); } } -pub trait GLWEPublicKeyGenerate<B: Backend> { +pub trait GLWEPublicKeyGenerate<BE: Backend> { fn glwe_public_key_generate<R, S>(&self, res: &mut R, sk: &S, source_xa: &mut Source, source_xe: &mut Source) where R: GLWEPublicKeyToMut, - S: GLWESecretPreparedToRef<B>; + S: GLWESecretPreparedToRef<BE>; } impl<BE: Backend> GLWEPublicKeyGenerate<BE> for Module<BE>
M poulpy-core/src/noise/gglwe_ct.rs → poulpy-core/src/noise/gglwe_ct.rs

@@ -1,49 +1,120 @@

use poulpy_hal::{ api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigBytesOf, VecZnxBigNormalize, VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalizeTmpBytes, - VecZnxSubScalarInplace, + ScratchOwnedAlloc, ScratchOwnedBorrow, ScratchTakeBasic, VecZnxSubScalarInplace, }, - layouts::{Backend, DataRef, Module, ScalarZnx, ScratchOwned, ZnxZero}, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl}, + layouts::{Backend, DataRef, Module, Scratch, ScratchOwned, ScalarZnx, ScalarZnxToRef, ZnxZero}, + oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, VecZnxSubScalarInplaceImpl}, }; -use crate::layouts::{GGLWE, GGLWEInfos, GLWE, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}; +use crate::layouts::{ + GGLWE, GGLWEToRef, GGLWEInfos, GLWEPlaintext, LWEInfos, + prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, +}; +use crate::decryption::GLWEDecryption; impl<D: DataRef> GGLWE<D> { - pub fn assert_noise<B, DataSk, DataWant>( + + pub fn assert_noise<M, BE, DataSk, DataWant>( &self, - module: &Module<B>, - sk: &GLWESecretPrepared<DataSk, B>, + module: &M, + sk_prepared: &GLWESecretPrepared<DataSk, BE>, pt_want: &ScalarZnx<DataWant>, max_noise: f64, ) where DataSk: DataRef, DataWant: DataRef, - Module<B>: VecZnxDftBytesOf - + VecZnxBigBytesOf - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxSubScalarInplace, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, + M: GGLWENoise<BE>, + BE: Backend + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE> + VecZnxSubScalarInplaceImpl<BE>, + { + module.gglwe_assert_noise(self, sk_prepared, pt_want, max_noise); + } + + + // pub fn assert_noise<B, DataSk, DataWant>( + // &self, + // module: &Module<B>, + // sk: &GLWESecretPrepared<DataSk, B>, + // pt_want: &ScalarZnx<DataWant>, + // max_noise: f64, + // ) where + // DataSk: DataRef, + // DataWant: DataRef, + // Module<B>: VecZnxDftBytesOf + // + VecZnxBigBytesOf + // + VecZnxDftApply<B> + // + SvpApplyDftToDftInplace<B> + // + VecZnxIdftApplyConsume<B> + // + VecZnxBigAddInplace<B> + // + VecZnxBigAddSmallInplace<B> + // + VecZnxBigNormalize<B> + // + VecZnxNormalizeTmpBytes + // + VecZnxSubScalarInplace, + // B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, + // { + // let dsize: usize = self.dsize().into(); + // let base2k: usize = self.base2k().into(); + + // let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, self)); + // let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(module, self); + + // (0..self.rank_in().into()).for_each(|col_i| { + // (0..self.dnum().into()).for_each(|row_i| { + // self.at(row_i, col_i) + // .decrypt(module, &mut pt, sk, scratch.borrow()); + + // module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, col_i); + + // let noise_have: f64 = pt.data.std(base2k, 0).log2(); + + // println!("noise_have: {noise_have}"); + + // assert!( + // noise_have <= max_noise, + // "noise_have: {noise_have} > max_noise: {max_noise}" + // ); + + // pt.data.zero(); + // }); + // }); + // } +} + + +pub trait GGLWENoise<BE: Backend> { + fn gglwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64) + where + R: GGLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE> + VecZnxSubScalarInplaceImpl<BE>; +} + +impl<BE: Backend> GGLWENoise<BE> for Module<BE> +where + Module<BE>: GLWEDecryption<BE>, + Scratch<BE>: ScratchTakeBasic + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>, +{ + fn gglwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64) + where + R: GGLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE> + VecZnxSubScalarInplaceImpl<BE>, { - let dsize: usize = self.dsize().into(); - let base2k: usize = self.base2k().into(); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, self)); - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(module, self); + let res: &GGLWE<&[u8]> = &res.to_ref(); + + let dsize: usize = res.dsize().into(); + let base2k: usize = res.base2k().into(); - (0..self.rank_in().into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_i| { - self.at(row_i, col_i) - .decrypt(module, &mut pt, sk, scratch.borrow()); + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res)); + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res); - module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, col_i); + (0..res.rank_in().into()).for_each(|col_i| { + (0..res.dnum().into()).for_each(|row_i| { + self.glwe_decrypt(&res.at(row_i, col_i), &mut pt, sk_prepared, scratch.borrow()); + + self.vec_znx_sub_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, col_i); let noise_have: f64 = pt.data.std(base2k, 0).log2();

@@ -58,4 +129,4 @@ pt.data.zero();

}); }); } -} +}
M poulpy-core/src/noise/ggsw_ct.rs → poulpy-core/src/noise/ggsw_ct.rs

@@ -4,62 +4,118 @@ ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, VecZnxAddScalarInplace, VecZnxBigAddInplace,

VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigBytesOf, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAlloc, VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalizeTmpBytes, VecZnxSubInplace, + ScratchTakeBasic, }, - layouts::{Backend, DataRef, Module, ScalarZnx, ScratchOwned, VecZnxBig, VecZnxDft, ZnxZero}, + layouts::{Backend, DataRef, Module, ScalarZnx, ScalarZnxToRef, Scratch, ScratchOwned, VecZnxBig, VecZnxDft, ZnxZero}, oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl}, }; -use crate::layouts::{GGSW, GGSWInfos, GLWE, GLWEInfos, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}; +use crate::layouts::{GGSW, GGSWInfos, GLWEInfos, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared, GGSWToRef}; +use crate::layouts::prepared::GLWESecretPreparedToRef; +use crate::decryption::GLWEDecryption; impl<D: DataRef> GGSW<D> { - pub fn assert_noise<B, DataSk, DataScalar, F>( + pub fn assert_noise<M, BE, DataSk, DataScalar, F>( &self, - module: &Module<B>, - sk_prepared: &GLWESecretPrepared<DataSk, B>, + module: &M, + sk_prepared: &GLWESecretPrepared<DataSk, BE>, pt_want: &ScalarZnx<DataScalar>, - max_noise: F, + max_noise: F ) where DataSk: DataRef, DataScalar: DataRef, - Module<B>: VecZnxDftBytesOf - + VecZnxBigBytesOf - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<B> - + VecZnxAddScalarInplace - + VecZnxSubInplace, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, + M: GGSWNoise<BE>, + BE: Backend + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>, F: Fn(usize) -> f64, { - let base2k: usize = self.base2k().into(); - let dsize: usize = self.dsize().into(); + module.ggsw_assert_noise(self, sk_prepared, pt_want, max_noise); + } - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(module, self); - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(module, self); - let mut pt_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(1, self.size()); - let mut pt_big: VecZnxBig<Vec<u8>, B> = module.vec_znx_big_alloc(1, self.size()); + pub fn print_noise<M, BE, DataSk, DataScalar>( + &self, + module: &M, + sk_prepared: &GLWESecretPrepared<DataSk, BE>, + pt_want: &ScalarZnx<DataScalar>, + ) where + DataSk: DataRef, + DataScalar: DataRef, + M: GGSWNoise<BE>, + BE: Backend + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>, + { + module.ggsw_print_noise(self, sk_prepared, pt_want); + } +} - let mut scratch: ScratchOwned<B> = - ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, self) | module.vec_znx_normalize_tmp_bytes()); +pub trait GGSWNoise<BE: Backend> { + fn ggsw_assert_noise<R, S, P, F>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: F) + where + R: GGSWToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>, + F: Fn(usize) -> f64; + + fn ggsw_print_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P) + where + R: GGSWToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>; +} - (0..(self.rank() + 1).into()).for_each(|col_j| { - (0..self.dnum().into()).for_each(|row_i| { - module.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0); +impl<BE: Backend> GGSWNoise<BE> for Module<BE> +where + Module<BE>: VecZnxDftBytesOf + + VecZnxBigBytesOf + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddInplace<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalizeTmpBytes + + VecZnxBigAlloc<BE> + + VecZnxDftAlloc<BE> + + VecZnxBigNormalizeTmpBytes + + VecZnxIdftApplyTmpA<BE> + + VecZnxAddScalarInplace + + VecZnxSubInplace + + GLWEDecryption<BE>, + Scratch<BE>: ScratchTakeBasic, +{ + fn ggsw_assert_noise<R, S, P, F>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: F) + where + R: GGSWToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>, + F: Fn(usize) -> f64, + { + + let res: &GGSW<&[u8]> = &res.to_ref(); + let sk_prepared: &GLWESecretPrepared<&[u8], BE> = &sk_prepared.to_ref(); + + let base2k: usize = res.base2k().into(); + let dsize: usize = res.dsize().into(); + + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res); + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res); + let mut pt_dft: VecZnxDft<Vec<u8>, BE> = self.vec_znx_dft_alloc(1, res.size()); + let mut pt_big: VecZnxBig<Vec<u8>, BE> = self.vec_znx_big_alloc(1, res.size()); + + let mut scratch: ScratchOwned<BE> = + ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res) | self.vec_znx_normalize_tmp_bytes()); + + (0..(res.rank() + 1).into()).for_each(|col_j| { + (0..res.dnum().into()).for_each(|row_i| { + self.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0); // mul with sk[col_j-1] if col_j > 0 { - module.vec_znx_dft_apply(1, 0, &mut pt_dft, 0, &pt.data, 0); - module.svp_apply_dft_to_dft_inplace(&mut pt_dft, 0, &sk_prepared.data, col_j - 1); - module.vec_znx_idft_apply_tmpa(&mut pt_big, 0, &mut pt_dft, 0); - module.vec_znx_big_normalize( + self.vec_znx_dft_apply(1, 0, &mut pt_dft, 0, &pt.data, 0); + self.svp_apply_dft_to_dft_inplace(&mut pt_dft, 0, &sk_prepared.data, col_j - 1); + self.vec_znx_idft_apply_tmpa(&mut pt_big, 0, &mut pt_dft, 0); + self.vec_znx_big_normalize( base2k, &mut pt.data, 0,

@@ -70,10 +126,9 @@ scratch.borrow(),

); } - self.at(row_i, col_j) - .decrypt(module, &mut pt_have, sk_prepared, scratch.borrow()); + self.glwe_decrypt(&res.at(row_i, col_j), &mut pt_have, sk_prepared, scratch.borrow()); - module.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0); + self.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0); let std_pt: f64 = pt_have.data.std(base2k, 0).log2(); let noise: f64 = max_noise(col_j);

@@ -81,57 +136,40 @@ assert!(std_pt <= noise, "{std_pt} > {noise}");

pt.data.zero(); }); - }); + }); } -} -impl<D: DataRef> GGSW<D> { - pub fn print_noise<B, DataSk, DataScalar>( - &self, - module: &Module<B>, - sk_prepared: &GLWESecretPrepared<DataSk, B>, - pt_want: &ScalarZnx<DataScalar>, - ) where - DataSk: DataRef, - DataScalar: DataRef, - Module<B>: VecZnxDftBytesOf - + VecZnxBigBytesOf - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<B> - + VecZnxAddScalarInplace - + VecZnxSubInplace, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, + fn ggsw_print_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P) + where + R: GGSWToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>, { - let base2k: usize = self.base2k().into(); - let dsize: usize = self.dsize().into(); + let res: &GGSW<&[u8]> = &res.to_ref(); + let sk_prepared: &GLWESecretPrepared<&[u8], BE> = &sk_prepared.to_ref(); + + let base2k: usize = res.base2k().into(); + let dsize: usize = res.dsize().into(); - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(module, self); - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(module, self); - let mut pt_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(1, self.size()); - let mut pt_big: VecZnxBig<Vec<u8>, B> = module.vec_znx_big_alloc(1, self.size()); + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res); + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res); + let mut pt_dft: VecZnxDft<Vec<u8>, BE> = self.vec_znx_dft_alloc(1, res.size()); + let mut pt_big: VecZnxBig<Vec<u8>, BE> = self.vec_znx_big_alloc(1, res.size()); - let mut scratch: ScratchOwned<B> = - ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, self) | module.vec_znx_normalize_tmp_bytes()); + let mut scratch: ScratchOwned<BE> = + ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res) | self.vec_znx_normalize_tmp_bytes()); - (0..(self.rank() + 1).into()).for_each(|col_j| { - (0..self.dnum().into()).for_each(|row_i| { - module.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0); + (0..(res.rank() + 1).into()).for_each(|col_j| { + (0..res.dnum().into()).for_each(|row_i| { + self.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0); // mul with sk[col_j-1] if col_j > 0 { - module.vec_znx_dft_apply(1, 0, &mut pt_dft, 0, &pt.data, 0); - module.svp_apply_dft_to_dft_inplace(&mut pt_dft, 0, &sk_prepared.data, col_j - 1); - module.vec_znx_idft_apply_tmpa(&mut pt_big, 0, &mut pt_dft, 0); - module.vec_znx_big_normalize( + self.vec_znx_dft_apply(1, 0, &mut pt_dft, 0, &pt.data, 0); + self.svp_apply_dft_to_dft_inplace(&mut pt_dft, 0, &sk_prepared.data, col_j - 1); + self.vec_znx_idft_apply_tmpa(&mut pt_big, 0, &mut pt_dft, 0); + self.vec_znx_big_normalize( base2k, &mut pt.data, 0,

@@ -142,15 +180,13 @@ scratch.borrow(),

); } - self.at(row_i, col_j) - .decrypt(module, &mut pt_have, sk_prepared, scratch.borrow()); - module.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0); + self.glwe_decrypt(&res.at(row_i, col_j), &mut pt_have, sk_prepared, scratch.borrow()); + self.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0); let std_pt: f64 = pt_have.data.std(base2k, 0).log2(); println!("col: {col_j} row: {row_i}: {std_pt}"); pt.data.zero(); - // println!(">>>>>>>>>>>>>>>>"); }); }); - } -} + } +}
M poulpy-core/src/noise/glwe_ct.rs → poulpy-core/src/noise/glwe_ct.rs

@@ -2,67 +2,159 @@ use poulpy_hal::{

api::{ ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigBytesOf, VecZnxBigNormalize, VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSubInplace, + VecZnxNormalizeTmpBytes, VecZnxSubInplace, ScratchTakeBasic, }, layouts::{Backend, DataRef, Module, Scratch, ScratchOwned}, oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl}, }; -use crate::layouts::{GLWE, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}; +use crate::{ + decryption::GLWEDecryption, + layouts::{ + GLWE, GLWEPlaintext, GLWEPlaintextToRef, GLWEToRef, LWEInfos, + prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, + }, +}; impl<D: DataRef> GLWE<D> { - pub fn noise<B, DataSk, DataPt>( - &self, - module: &Module<B>, - sk_prepared: &GLWESecretPrepared<DataSk, B>, - pt_want: &GLWEPlaintext<DataPt>, - scratch: &mut Scratch<B>, - ) -> f64 + pub fn noise<M, S, P, BE: Backend>(&self, module: &M, sk_prepared: &S, pt_want: &P, scratch: &mut Scratch<BE>) -> f64 where - DataSk: DataRef, - DataPt: DataRef, - B: Backend, - Module<B>: VecZnxDftApply<B> - + VecZnxSubInplace - + VecZnxNormalizeInplace<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B>, - Scratch<B>:, + M: GLWENoise<BE>, + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef, { - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(module, self); - self.decrypt(module, &mut pt_have, sk_prepared, scratch); - module.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt_want.data, 0); - module.vec_znx_normalize_inplace(self.base2k().into(), &mut pt_have.data, 0, scratch); - pt_have.data.std(self.base2k().into(), 0).log2() + module.glwe_noise(self, sk_prepared, pt_want, scratch) } + // pub fn noise<B, DataSk, DataPt>( + // &self, + // module: &Module<B>, + // sk_prepared: &GLWESecretPrepared<DataSk, B>, + // pt_want: &GLWEPlaintext<DataPt>, + // scratch: &mut Scratch<B>, + // ) -> f64 + // where + // DataSk: DataRef, + // DataPt: DataRef, + // B: Backend, + // Module<B>: VecZnxDftApply<B> + // + VecZnxSubInplace + // + VecZnxNormalizeInplace<B> + // + SvpApplyDftToDftInplace<B> + // + VecZnxIdftApplyConsume<B> + // + VecZnxBigAddInplace<B> + // + VecZnxBigAddSmallInplace<B> + // + VecZnxBigNormalize<B>, + // Scratch<B>:, + // { + // let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(module, self); + // self.decrypt(module, &mut pt_have, sk_prepared, scratch); + // module.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt_want.data, 0); + // module.vec_znx_normalize_inplace(self.base2k().into(), &mut pt_have.data, 0, scratch); + // pt_have.data.std(self.base2k().into(), 0).log2() + // } - pub fn assert_noise<B, DataSk, DataPt>( + pub fn assert_noise<M, BE, DataSk, DataPt>( &self, - module: &Module<B>, - sk_prepared: &GLWESecretPrepared<DataSk, B>, + module: &M, + sk_prepared: &GLWESecretPrepared<DataSk, BE>, pt_want: &GLWEPlaintext<DataPt>, max_noise: f64, ) where DataSk: DataRef, DataPt: DataRef, - Module<B>: VecZnxDftBytesOf - + VecZnxBigBytesOf - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxSubInplace - + VecZnxNormalizeInplace<B>, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, + M: GLWENoise<BE>, + BE: Backend + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>, { - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, self)); - let noise_have: f64 = self.noise(module, sk_prepared, pt_want, scratch.borrow()); - assert!(noise_have <= max_noise, "{noise_have} {max_noise}"); + module.glwe_assert_noise(self, sk_prepared, pt_want, max_noise); } + + // pub fn assert_noise<B, DataSk, DataPt>( + // &self, + // module: &Module<B>, + // sk_prepared: &GLWESecretPrepared<DataSk, B>, + // pt_want: &GLWEPlaintext<DataPt>, + // max_noise: f64, + // ) where + // DataSk: DataRef, + // DataPt: DataRef, + // Module<B>: VecZnxDftBytesOf + // + VecZnxBigBytesOf + // + VecZnxDftApply<B> + // + SvpApplyDftToDftInplace<B> + // + VecZnxIdftApplyConsume<B> + // + VecZnxBigAddInplace<B> + // + VecZnxBigAddSmallInplace<B> + // + VecZnxBigNormalize<B> + // + VecZnxNormalizeTmpBytes + // + VecZnxSubInplace + // + VecZnxNormalizeInplace<B>, + // B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, + // { + // let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, self)); + // let noise_have: f64 = self.noise(module, sk_prepared, pt_want, scratch.borrow()); + // assert!(noise_have <= max_noise, "{noise_have} {max_noise}"); + // } } + + +pub trait GLWENoise<BE: Backend> { + fn glwe_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, scratch: &mut Scratch<BE>) -> f64 + where + R: GLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef; + + fn glwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64) + where + R: GLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef, + BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>; +} + +impl<BE: Backend> GLWENoise<BE> for Module<BE> +where + Module<BE>: VecZnxDftBytesOf + + VecZnxBigBytesOf + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddInplace<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalizeTmpBytes + + VecZnxSubInplace + + VecZnxNormalizeInplace<BE> + + GLWEDecryption<BE>, + Scratch<BE>: ScratchTakeBasic + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>, +{ + fn glwe_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, scratch: &mut Scratch<BE>) -> f64 + where + R: GLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef, + { + let res_ref: &GLWE<&[u8]> = &res.to_ref(); + + let pt_want: &GLWEPlaintext<&[u8]> = &pt_want.to_ref(); + + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res_ref); + self.glwe_decrypt(res, &mut pt_have, sk_prepared, scratch); + self.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt_want.data, 0); + self.vec_znx_normalize_inplace(res_ref.base2k().into(), &mut pt_have.data, 0, scratch); + pt_have.data.std(res_ref.base2k().into(), 0).log2() + } + + fn glwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64) + where + R: GLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef, + BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>, + { + let res: &GLWE<&[u8]> = &res.to_ref(); + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res)); + let noise_have: f64 = self.glwe_noise(res, sk_prepared, pt_want, scratch.borrow()); + assert!(noise_have <= max_noise, "{noise_have} {max_noise}"); + } +}