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