poulpy/poulpy-core/src/noise/ggsw_ct.rs
poulpy-core/src/noise/ggsw_ct.rsRaw
1use poulpy_hal::{
2 api::{
3 ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, VecZnxAddScalarInplace, VecZnxBigAddInplace,
4 VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigBytesOf, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes,
5 VecZnxDftAlloc, VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalizeTmpBytes,
6 VecZnxSubInplace,
7 ScratchTakeBasic,
8 },
9 layouts::{Backend, DataRef, Module, ScalarZnx, ScalarZnxToRef, Scratch, ScratchOwned, VecZnxBig, VecZnxDft, ZnxZero},
10 oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl},
11};
12
13use crate::layouts::{GGSW, GGSWInfos, GLWEInfos, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared, GGSWToRef};
14use crate::layouts::prepared::GLWESecretPreparedToRef;
15use crate::decryption::GLWEDecryption;
16
17impl<D: DataRef> GGSW<D> {
18 pub fn assert_noise<M, BE, DataSk, DataScalar, F>(
19 &self,
20 module: &M,
21 sk_prepared: &GLWESecretPrepared<DataSk, BE>,
22 pt_want: &ScalarZnx<DataScalar>,
23 max_noise: F
24 ) where
25 DataSk: DataRef,
26 DataScalar: DataRef,
27 M: GGSWNoise<BE>,
28 BE: Backend + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>,
29 F: Fn(usize) -> f64,
30 {
31 module.ggsw_assert_noise(self, sk_prepared, pt_want, max_noise);
32 }
33
34 pub fn print_noise<M, BE, DataSk, DataScalar>(
35 &self,
36 module: &M,
37 sk_prepared: &GLWESecretPrepared<DataSk, BE>,
38 pt_want: &ScalarZnx<DataScalar>,
39 ) where
40 DataSk: DataRef,
41 DataScalar: DataRef,
42 M: GGSWNoise<BE>,
43 BE: Backend + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>,
44 {
45 module.ggsw_print_noise(self, sk_prepared, pt_want);
46 }
47}
48
49pub trait GGSWNoise<BE: Backend> {
50 fn ggsw_assert_noise<R, S, P, F>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: F)
51 where
52 R: GGSWToRef,
53 S: GLWESecretPreparedToRef<BE>,
54 P: ScalarZnxToRef,
55 BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>,
56 F: Fn(usize) -> f64;
57
58 fn ggsw_print_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P)
59 where
60 R: GGSWToRef,
61 S: GLWESecretPreparedToRef<BE>,
62 P: ScalarZnxToRef,
63 BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>;
64}
65
66impl<BE: Backend> GGSWNoise<BE> for Module<BE>
67where
68 Module<BE>: VecZnxDftBytesOf
69 + VecZnxBigBytesOf
70 + VecZnxDftApply<BE>
71 + SvpApplyDftToDftInplace<BE>
72 + VecZnxIdftApplyConsume<BE>
73 + VecZnxBigAddInplace<BE>
74 + VecZnxBigAddSmallInplace<BE>
75 + VecZnxBigNormalize<BE>
76 + VecZnxNormalizeTmpBytes
77 + VecZnxBigAlloc<BE>
78 + VecZnxDftAlloc<BE>
79 + VecZnxBigNormalizeTmpBytes
80 + VecZnxIdftApplyTmpA<BE>
81 + VecZnxAddScalarInplace
82 + VecZnxSubInplace
83 + GLWEDecryption<BE>,
84 Scratch<BE>: ScratchTakeBasic,
85{
86 fn ggsw_assert_noise<R, S, P, F>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: F)
87 where
88 R: GGSWToRef,
89 S: GLWESecretPreparedToRef<BE>,
90 P: ScalarZnxToRef,
91 BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>,
92 F: Fn(usize) -> f64,
93 {
94
95 let res: &GGSW<&[u8]> = &res.to_ref();
96 let sk_prepared: &GLWESecretPrepared<&[u8], BE> = &sk_prepared.to_ref();
97
98 let base2k: usize = res.base2k().into();
99 let dsize: usize = res.dsize().into();
100
101 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res);
102 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res);
103 let mut pt_dft: VecZnxDft<Vec<u8>, BE> = self.vec_znx_dft_alloc(1, res.size());
104 let mut pt_big: VecZnxBig<Vec<u8>, BE> = self.vec_znx_big_alloc(1, res.size());
105
106 let mut scratch: ScratchOwned<BE> =
107 ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res) | self.vec_znx_normalize_tmp_bytes());
108
109 (0..(res.rank() + 1).into()).for_each(|col_j| {
110 (0..res.dnum().into()).for_each(|row_i| {
111 self.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0);
112
113 // mul with sk[col_j-1]
114 if col_j > 0 {
115 self.vec_znx_dft_apply(1, 0, &mut pt_dft, 0, &pt.data, 0);
116 self.svp_apply_dft_to_dft_inplace(&mut pt_dft, 0, &sk_prepared.data, col_j - 1);
117 self.vec_znx_idft_apply_tmpa(&mut pt_big, 0, &mut pt_dft, 0);
118 self.vec_znx_big_normalize(
119 base2k,
120 &mut pt.data,
121 0,
122 base2k,
123 &pt_big,
124 0,
125 scratch.borrow(),
126 );
127 }
128
129 self.glwe_decrypt(&res.at(row_i, col_j), &mut pt_have, sk_prepared, scratch.borrow());
130
131 self.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0);
132
133 let std_pt: f64 = pt_have.data.std(base2k, 0).log2();
134 let noise: f64 = max_noise(col_j);
135 assert!(std_pt <= noise, "{std_pt} > {noise}");
136
137 pt.data.zero();
138 });
139 });
140 }
141
142 fn ggsw_print_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P)
143 where
144 R: GGSWToRef,
145 S: GLWESecretPreparedToRef<BE>,
146 P: ScalarZnxToRef,
147 BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE> + ScratchOwnedBorrow<BE>,
148 {
149 let res: &GGSW<&[u8]> = &res.to_ref();
150 let sk_prepared: &GLWESecretPrepared<&[u8], BE> = &sk_prepared.to_ref();
151
152 let base2k: usize = res.base2k().into();
153 let dsize: usize = res.dsize().into();
154
155 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res);
156 let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(self, res);
157 let mut pt_dft: VecZnxDft<Vec<u8>, BE> = self.vec_znx_dft_alloc(1, res.size());
158 let mut pt_big: VecZnxBig<Vec<u8>, BE> = self.vec_znx_big_alloc(1, res.size());
159
160 let mut scratch: ScratchOwned<BE> =
161 ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res) | self.vec_znx_normalize_tmp_bytes());
162
163 (0..(res.rank() + 1).into()).for_each(|col_j| {
164 (0..res.dnum().into()).for_each(|row_i| {
165 self.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0);
166
167 // mul with sk[col_j-1]
168 if col_j > 0 {
169 self.vec_znx_dft_apply(1, 0, &mut pt_dft, 0, &pt.data, 0);
170 self.svp_apply_dft_to_dft_inplace(&mut pt_dft, 0, &sk_prepared.data, col_j - 1);
171 self.vec_znx_idft_apply_tmpa(&mut pt_big, 0, &mut pt_dft, 0);
172 self.vec_znx_big_normalize(
173 base2k,
174 &mut pt.data,
175 0,
176 base2k,
177 &pt_big,
178 0,
179 scratch.borrow(),
180 );
181 }
182
183 self.glwe_decrypt(&res.at(row_i, col_j), &mut pt_have, sk_prepared, scratch.borrow());
184 self.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0);
185
186 let std_pt: f64 = pt_have.data.std(base2k, 0).log2();
187 println!("col: {col_j} row: {row_i}: {std_pt}");
188 pt.data.zero();
189 });
190 });
191 }
192}