poulpy/core/src/tests/generics/automorphism/gglwe_atk.rs
core/src/tests/generics/automorphism/gglwe_atk.rsRaw
1use backend::hal::{
2 api::{
3 ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxCopy,
4 VecZnxStd, VecZnxSubScalarInplace, VecZnxSwithcDegree, VmpPMatAlloc, VmpPMatPrepare,
5 },
6 layouts::{Backend, Module, ScratchOwned},
7 oep::{
8 ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
9 TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
10 },
11};
12use sampling::source::Source;
13
14use crate::{
15 layouts::{
16 GGLWEAutomorphismKey, GLWEPlaintext, GLWESecret, Infos,
17 prepared::{GGLWEAutomorphismKeyExec, GLWESecretExec},
18 },
19 noise::log2_std_noise_gglwe_product,
20 trait_families::{GLWEDecryptFamily, GLWEKeyswitchFamily},
21};
22
23use crate::trait_families::{GGLWEAutomorphismKeyEncryptSkFamily, GLWESecretExecModuleFamily};
24
25pub fn test_gglwe_automorphism_key_automorphism<B: Backend>(
26 module: &Module<B>,
27 p0: i64,
28 p1: i64,
29 basek: usize,
30 digits: usize,
31 k_in: usize,
32 k_out: usize,
33 k_apply: usize,
34 sigma: f64,
35 rank: usize,
36) where
37 Module<B>: GGLWEAutomorphismKeyEncryptSkFamily<B>
38 + GLWESecretExecModuleFamily<B>
39 + GLWEKeyswitchFamily<B>
40 + VecZnxAutomorphism
41 + VecZnxSwithcDegree
42 + VecZnxAddScalarInplace
43 + VecZnxAutomorphism
44 + VecZnxAutomorphismInplace
45 + GLWEDecryptFamily<B>
46 + VecZnxSubScalarInplace
47 + VecZnxStd
48 + VecZnxCopy
49 + VmpPMatAlloc<B>
50 + VmpPMatPrepare<B>,
51 B: ScratchOwnedAllocImpl<B>
52 + ScratchOwnedBorrowImpl<B>
53 + ScratchAvailableImpl<B>
54 + TakeScalarZnxImpl<B>
55 + TakeVecZnxDftImpl<B>
56 + TakeVecZnxImpl<B>
57 + TakeSvpPPolImpl<B>
58 + TakeVecZnxBigImpl<B>,
59{
60 let n: usize = module.n();
61 let digits_in: usize = 1;
62
63 let rows_in: usize = k_in / (basek * digits);
64 let rows_apply: usize = k_in.div_ceil(basek * digits);
65
66 let mut auto_key_in: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_in, rows_in, digits_in, rank);
67 let mut auto_key_out: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_out, rows_in, digits_in, rank);
68 let mut auto_key_apply: GGLWEAutomorphismKey<Vec<u8>> =
69 GGLWEAutomorphismKey::alloc(n, basek, k_apply, rows_apply, digits, rank);
70
71 let mut source_xs: Source = Source::new([0u8; 32]);
72 let mut source_xe: Source = Source::new([0u8; 32]);
73 let mut source_xa: Source = Source::new([0u8; 32]);
74
75 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
76 GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, n, basek, k_apply, rank)
77 | GGLWEAutomorphismKey::automorphism_scratch_space(module, n, basek, k_out, k_in, k_apply, digits, rank),
78 );
79
80 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
81 sk.fill_ternary_prob(0.5, &mut source_xs);
82
83 // gglwe_{s1}(s0) = s0 -> s1
84 auto_key_in.encrypt_sk(
85 module,
86 p0,
87 &sk,
88 &mut source_xa,
89 &mut source_xe,
90 sigma,
91 scratch.borrow(),
92 );
93
94 // gglwe_{s2}(s1) -> s1 -> s2
95 auto_key_apply.encrypt_sk(
96 module,
97 p1,
98 &sk,
99 &mut source_xa,
100 &mut source_xe,
101 sigma,
102 scratch.borrow(),
103 );
104
105 let mut auto_key_apply_exec: GGLWEAutomorphismKeyExec<Vec<u8>, B> =
106 GGLWEAutomorphismKeyExec::alloc(module, n, basek, k_apply, rows_apply, digits, rank);
107
108 auto_key_apply_exec.prepare(module, &auto_key_apply, scratch.borrow());
109
110 // gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
111 auto_key_out.automorphism(module, &auto_key_in, &auto_key_apply_exec, scratch.borrow());
112
113 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_out);
114
115 let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
116 sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
117 (0..rank).for_each(|i| {
118 module.vec_znx_automorphism(
119 module.galois_element_inv(p0 * p1),
120 &mut sk_auto.data.as_vec_znx_mut(),
121 i,
122 &sk.data.as_vec_znx(),
123 i,
124 );
125 });
126
127 let sk_auto_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_auto);
128
129 (0..auto_key_out.rank_in()).for_each(|col_i| {
130 (0..auto_key_out.rows()).for_each(|row_i| {
131 auto_key_out
132 .at(row_i, col_i)
133 .decrypt(module, &mut pt, &sk_auto_dft, scratch.borrow());
134
135 module.vec_znx_sub_scalar_inplace(
136 &mut pt.data,
137 0,
138 (digits_in - 1) + row_i * digits_in,
139 &sk.data,
140 col_i,
141 );
142
143 let noise_have: f64 = module.vec_znx_std(basek, &pt.data, 0).log2();
144 let noise_want: f64 = log2_std_noise_gglwe_product(
145 n as f64,
146 basek * digits,
147 0.5,
148 0.5,
149 0f64,
150 sigma * sigma,
151 0f64,
152 rank as f64,
153 k_out,
154 k_apply,
155 );
156
157 assert!(
158 noise_have < noise_want + 0.5,
159 "{} {}",
160 noise_have,
161 noise_want
162 );
163 });
164 });
165}
166
167pub fn test_gglwe_automorphism_key_automorphism_inplace<B: Backend>(
168 module: &Module<B>,
169 p0: i64,
170 p1: i64,
171 basek: usize,
172 digits: usize,
173 k_in: usize,
174 k_apply: usize,
175 sigma: f64,
176 rank: usize,
177) where
178 Module<B>: GGLWEAutomorphismKeyEncryptSkFamily<B>
179 + GLWESecretExecModuleFamily<B>
180 + GLWEKeyswitchFamily<B>
181 + VecZnxAutomorphism
182 + VecZnxSwithcDegree
183 + VecZnxAddScalarInplace
184 + VecZnxAutomorphism
185 + VecZnxAutomorphismInplace
186 + GLWEDecryptFamily<B>
187 + VecZnxSubScalarInplace
188 + VecZnxStd
189 + VecZnxCopy
190 + VmpPMatAlloc<B>
191 + VmpPMatPrepare<B>,
192 B: ScratchOwnedAllocImpl<B>
193 + ScratchOwnedBorrowImpl<B>
194 + ScratchAvailableImpl<B>
195 + TakeScalarZnxImpl<B>
196 + TakeVecZnxDftImpl<B>
197 + TakeVecZnxImpl<B>
198 + TakeSvpPPolImpl<B>
199 + TakeVecZnxBigImpl<B>,
200{
201 let n: usize = module.n();
202 let digits_in: usize = 1;
203
204 let rows_in: usize = k_in / (basek * digits);
205 let rows_apply: usize = k_in.div_ceil(basek * digits);
206
207 let mut auto_key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_in, rows_in, digits_in, rank);
208 let mut auto_key_apply: GGLWEAutomorphismKey<Vec<u8>> =
209 GGLWEAutomorphismKey::alloc(n, basek, k_apply, rows_apply, digits, rank);
210
211 let mut source_xs: Source = Source::new([0u8; 32]);
212 let mut source_xe: Source = Source::new([0u8; 32]);
213 let mut source_xa: Source = Source::new([0u8; 32]);
214
215 let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
216 GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, n, basek, k_apply, rank)
217 | GGLWEAutomorphismKey::automorphism_inplace_scratch_space(module, n, basek, k_in, k_apply, digits, rank),
218 );
219
220 let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
221 sk.fill_ternary_prob(0.5, &mut source_xs);
222
223 // gglwe_{s1}(s0) = s0 -> s1
224 auto_key.encrypt_sk(
225 module,
226 p0,
227 &sk,
228 &mut source_xa,
229 &mut source_xe,
230 sigma,
231 scratch.borrow(),
232 );
233
234 // gglwe_{s2}(s1) -> s1 -> s2
235 auto_key_apply.encrypt_sk(
236 module,
237 p1,
238 &sk,
239 &mut source_xa,
240 &mut source_xe,
241 sigma,
242 scratch.borrow(),
243 );
244
245 let mut auto_key_apply_exec: GGLWEAutomorphismKeyExec<Vec<u8>, B> =
246 GGLWEAutomorphismKeyExec::alloc(module, n, basek, k_apply, rows_apply, digits, rank);
247
248 auto_key_apply_exec.prepare(module, &auto_key_apply, scratch.borrow());
249
250 // gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
251 auto_key.automorphism_inplace(module, &auto_key_apply_exec, scratch.borrow());
252
253 let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_in);
254
255 let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
256 sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
257
258 (0..rank).for_each(|i| {
259 module.vec_znx_automorphism(
260 module.galois_element_inv(p0 * p1),
261 &mut sk_auto.data.as_vec_znx_mut(),
262 i,
263 &sk.data.as_vec_znx(),
264 i,
265 );
266 });
267
268 let sk_auto_dft: GLWESecretExec<Vec<u8>, B> = GLWESecretExec::from(module, &sk_auto);
269
270 (0..auto_key.rank_in()).for_each(|col_i| {
271 (0..auto_key.rows()).for_each(|row_i| {
272 auto_key
273 .at(row_i, col_i)
274 .decrypt(module, &mut pt, &sk_auto_dft, scratch.borrow());
275 module.vec_znx_sub_scalar_inplace(
276 &mut pt.data,
277 0,
278 (digits_in - 1) + row_i * digits_in,
279 &sk.data,
280 col_i,
281 );
282
283 let noise_have: f64 = module.vec_znx_std(basek, &pt.data, 0).log2();
284 let noise_want: f64 = log2_std_noise_gglwe_product(
285 n as f64,
286 basek * digits,
287 0.5,
288 0.5,
289 0f64,
290 sigma * sigma,
291 0f64,
292 rank as f64,
293 k_in,
294 k_apply,
295 );
296
297 assert!(
298 noise_have < noise_want + 0.5,
299 "{} {}",
300 noise_have,
301 noise_want
302 );
303 });
304 });
305}