poulpy/poulpy-core/src/noise/gglwe_ct.rs
poulpy-core/src/noise/gglwe_ct.rsRaw
1use poulpy_hal::{
2 api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, ScratchTakeBasic, VecZnxFillUniform, VecZnxSubScalarInplace},
3 layouts::{Backend, DataRef, Module, ScalarZnx, ScalarZnxToRef, Scratch, ScratchOwned, ZnxZero},
4};
5
6use crate::decryption::GLWEDecrypt;
7use crate::layouts::{
8 GGLWE, GGLWEInfos, GGLWEToRef, GLWEPlaintext, LWEInfos,
9 prepared::{GLWESecretPrepared, GLWESecretPreparedToRef},
10};
11
12impl<D: DataRef> GGLWE<D> {
13 pub fn assert_noise<M, DataSk, DataWant, BE: Backend>(
14 &self,
15 module: &M,
16 sk_prepared: &GLWESecretPrepared<DataSk, BE>,
17 pt_want: &ScalarZnx<DataWant>,
18 max_noise: f64,
19 ) where
20 DataSk: DataRef,
21 DataWant: DataRef,
22 M: GGLWENoise<BE>,
23 Scratch<BE>: ScratchTakeBasic,
24 {
25 module.gglwe_assert_noise(self, sk_prepared, pt_want, max_noise);
26 }
27
28
29}
30
31pub trait GGLWENoise<BE: Backend> {
32 fn gglwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64)
33 where
34 R: GGLWEToRef,
35 S: GLWESecretPreparedToRef<BE>,
36 P: ScalarZnxToRef,
37 Scratch<BE>: ScratchTakeBasic;
38}
39
40impl<BE: Backend> GGLWENoise<BE> for Module<BE>
41where
42 Module<BE>: GLWEDecrypt<BE> + VecZnxFillUniform + VecZnxSubScalarInplace,
43 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
44 Scratch<BE>: ScratchAvailable + ScratchTakeBasic,
45{
46 fn gglwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64)
47 where
48 R: GGLWEToRef,
49 S: GLWESecretPreparedToRef<BE>,
50 P: ScalarZnxToRef,
51 ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
52 Scratch<BE>: ScratchAvailable + ScratchTakeBasic,
53 {
54 let res: &GGLWE<&[u8]> = &res.to_ref();
55
56 let dsize: usize = res.dsize().into();
57 let base2k: usize = res.base2k().into();
58
59 let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res));
60 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res);
61
62 (0..res.rank_in().into()).for_each(|col_i| {
63 (0..res.dnum().into()).for_each(|row_i| {
64 self.glwe_decrypt(
65 &res.at(row_i, col_i),
66 &mut pt,
67 sk_prepared,
68 scratch.borrow(),
69 );
70
71 self.vec_znx_sub_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, col_i);
72
73 let noise_have: f64 = pt.data.std(base2k, 0).log2();
74
75 // println!("noise_have: {noise_have}");
76
77 assert!(
78 noise_have <= max_noise,
79 "noise_have: {noise_have} > max_noise: {max_noise}"
80 );
81
82 pt.data.zero();
83 });
84 });
85 }
86}