1#[macro_use]
31mod macros;
32
33mod diagonals;
34mod gglwe;
35mod gglwe_to_ggsw_key;
36mod ggsw;
37mod glwe;
38mod glwe_automorphism_key;
39mod glwe_plaintext;
40mod glwe_public_key;
41mod glwe_secret;
42mod glwe_secret_tensor;
43mod glwe_switching_key;
44mod glwe_tensor;
45mod glwe_tensor_key;
46mod glwe_to_lwe_key;
47mod key_helpers;
48mod linear_transformation;
49mod lwe;
50mod lwe_matrix;
51mod lwe_plaintext;
52mod lwe_secret;
53mod lwe_switching_key;
54mod lwe_to_glwe_key;
55mod polynomial_evaluation;
56mod scratch_views;
57
58pub mod compressed;
59pub mod prepared;
60
61pub use self::compressed::{
62 GGLWECompressed, GGLWECompressedSeed, GGLWECompressedSeedMut, GGLWECompressedToBackendMut, GGLWECompressedToBackendRef,
63 GGLWEDecompress, GGLWEToGGSWKeyCompressed, GGLWEToGGSWKeyCompressedToBackendMut, GGLWEToGGSWKeyCompressedToBackendRef,
64 GGLWEToGGSWKeyDecompress, GGSWCompressed, GGSWCompressedSeed, GGSWCompressedSeedMut, GGSWCompressedToBackendMut,
65 GGSWCompressedToBackendRef, GGSWDecompress, GLWEAutomorphismKeyCompressed, GLWEAutomorphismKeyDecompress, GLWECompressed,
66 GLWECompressedSeed, GLWECompressedSeedMut, GLWECompressedToBackendMut, GLWECompressedToBackendRef, GLWEDecompress,
67 GLWESwitchingKeyCompressed, GLWESwitchingKeyDecompress, GLWETensorKeyCompressed, GLWETensorKeyDecompress,
68 GLWEToLWESwitchingKeyCompressed, GLWEToLWESwitchingKeyDecompress, LWECompressed, LWECompressedToBackendMut,
69 LWECompressedToBackendRef, LWEDecompress, LWESwitchingKeyCompressed, LWESwitchingKeyDecompress, LWEToGLWEKeyCompressed,
70 LWEToGLWEKeyDecompress,
71};
72pub use diagonals::*;
73pub use gglwe::*;
74pub use gglwe_to_ggsw_key::*;
75pub use ggsw::*;
76pub use glwe::*;
77pub use glwe_automorphism_key::*;
78pub use glwe_plaintext::*;
79pub use glwe_public_key::*;
80pub use glwe_secret::*;
81pub use glwe_secret_tensor::*;
82pub use glwe_switching_key::*;
83pub use glwe_tensor::*;
84pub use glwe_tensor_key::*;
85pub use glwe_to_lwe_key::*;
86pub use key_helpers::*;
87pub use linear_transformation::*;
88#[cfg(test)]
89pub(crate) use linear_transformation::{linear_transformation_plan, normalize_linear_transform_diagonal};
90pub use lwe::*;
91pub use lwe_matrix::*;
92pub use lwe_plaintext::*;
93pub use lwe_secret::*;
94pub use lwe_switching_key::*;
95pub use lwe_to_glwe_key::*;
96pub use polynomial_evaluation::*;
97pub use prepared::*;
98pub use scratch_views::*;
99
100use crate::dist::Distribution;
101use poulpy_hal::layouts::{Backend, Data, MatZnx, Module, ScalarZnx, ZnxWord, vec_znx_alloc_zeroed};
102
103pub type BackendGLWE<BE> = GLWE<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
110pub type BackendGGLWE<BE> = GGLWE<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
111pub type BackendGGSW<BE> = GGSW<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
112pub type BackendLWE<BE> = LWE<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
113pub type BackendLWEMatrix<BE> = LWEMatrix<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
114pub type BackendGLWESecret<BE> = GLWESecret<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
115pub type BackendLWESecret<BE> = LWESecret<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
116pub type BackendGLWEAutomorphismKey<BE> = GLWEAutomorphismKey<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
117pub type BackendGLWESwitchingKey<BE> = GLWESwitchingKey<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
118pub type BackendGLWEPlaintext<BE> = GLWEPlaintext<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
119pub type BackendLWEPlaintext<BE> = LWEPlaintext<<BE as Backend>::OwnedBuf, <BE as Backend>::ZnxWord>;
120pub type BackendGLWEPrepared<BE> = GLWEPrepared<<BE as Backend>::OwnedBuf, BE>;
121pub type BackendGGLWEPrepared<BE> = GGLWEPrepared<<BE as Backend>::OwnedBuf, BE>;
122pub type BackendGGSWPrepared<BE> = GGSWPrepared<<BE as Backend>::OwnedBuf, BE>;
123pub type BackendGLWESecretPrepared<BE> = GLWESecretPrepared<<BE as Backend>::OwnedBuf, BE>;
124pub type BackendGLWEPublicKeyPrepared<BE> = GLWEPublicKeyPrepared<<BE as Backend>::OwnedBuf, BE>;
125pub type BackendGLWESecretTensorPrepared<BE> = GLWESecretTensorPrepared<<BE as Backend>::OwnedBuf, BE>;
126pub type BackendGLWESwitchingKeyPrepared<BE> = GLWESwitchingKeyPrepared<<BE as Backend>::OwnedBuf, BE>;
127pub type BackendGLWEAutomorphismKeyPrepared<BE> = GLWEAutomorphismKeyPrepared<<BE as Backend>::OwnedBuf, BE>;
128pub type BackendGLWETensorKeyPrepared<BE> = GLWETensorKeyPrepared<<BE as Backend>::OwnedBuf, BE>;
129pub type BackendGLWEToLWEKeyPrepared<BE> = GLWEToLWEKeyPrepared<<BE as Backend>::OwnedBuf, BE>;
130pub type BackendLWESwitchingKeyPrepared<BE> = LWESwitchingKeyPrepared<<BE as Backend>::OwnedBuf, BE>;
131pub type BackendLWEToGLWEKeyPrepared<BE> = LWEToGLWEKeyPrepared<<BE as Backend>::OwnedBuf, BE>;
132pub type BackendGGLWEToGGSWKeyPrepared<BE> = GGLWEToGGSWKeyPrepared<<BE as Backend>::OwnedBuf, BE>;
133
134pub trait GetDegree {
136 fn ring_degree(&self) -> Degree;
138}
139
140impl<B: Backend> GetDegree for Module<B> {
141 fn ring_degree(&self) -> Degree {
142 Self::n(self).into()
143 }
144}
145
146pub trait ModuleCoreAlloc {
151 type OwnedBuf: Data;
152 type ZnxWord: ZnxWord;
153
154 fn glwe_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWE<Self::OwnedBuf, Self::ZnxWord>;
155 fn glwe_alloc(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWE<Self::OwnedBuf, Self::ZnxWord>;
156
157 fn glwe_alloc_with_size(&self, base2k: Base2K, size: usize, rank: Rank) -> GLWE<Self::OwnedBuf, Self::ZnxWord>;
163
164 fn gglwe_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GGLWE<Self::OwnedBuf, Self::ZnxWord>;
165 fn gglwe_alloc(
166 &self,
167 base2k: Base2K,
168 dnum: Dnum,
169 dsize: Dsize,
170 k_aux: TorusPrecision,
171 rank_in: Rank,
172 rank_out: Rank,
173 ) -> GGLWE<Self::OwnedBuf, Self::ZnxWord>;
174
175 fn ggsw_alloc_from_infos<A: GGSWInfos>(&self, infos: &A) -> GGSW<Self::OwnedBuf, Self::ZnxWord>;
176 fn ggsw_alloc(
177 &self,
178 base2k: Base2K,
179 dnum: Dnum,
180 dsize: Dsize,
181 k_aux: TorusPrecision,
182 rank: Rank,
183 ) -> GGSW<Self::OwnedBuf, Self::ZnxWord>;
184
185 fn glwe_plaintext_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWEPlaintext<Self::OwnedBuf, Self::ZnxWord>;
186 fn glwe_plaintext_alloc(&self, base2k: Base2K, k: TorusPrecision) -> GLWEPlaintext<Self::OwnedBuf, Self::ZnxWord>;
187
188 fn glwe_secret_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWESecret<Self::OwnedBuf, Self::ZnxWord>;
189 fn glwe_secret_alloc(&self, rank: Rank) -> GLWESecret<Self::OwnedBuf, Self::ZnxWord>;
190
191 fn glwe_secret_tensor_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWESecretTensor<Self::OwnedBuf, Self::ZnxWord>;
192 fn glwe_secret_tensor_alloc(&self, rank: Rank) -> GLWESecretTensor<Self::OwnedBuf, Self::ZnxWord>;
193
194 fn glwe_tensor_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWETensor<Self::OwnedBuf, Self::ZnxWord>;
195 fn glwe_tensor_alloc(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWETensor<Self::OwnedBuf, Self::ZnxWord>;
196
197 fn glwe_public_key_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWEPublicKey<Self::OwnedBuf, Self::ZnxWord>;
198 fn glwe_public_key_alloc(
199 &self,
200 base2k: Base2K,
201 k: TorusPrecision,
202 rank: Rank,
203 ) -> GLWEPublicKey<Self::OwnedBuf, Self::ZnxWord>;
204
205 fn glwe_switching_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GLWESwitchingKey<Self::OwnedBuf, Self::ZnxWord>;
206 fn glwe_switching_key_alloc(
207 &self,
208 base2k: Base2K,
209 dnum: Dnum,
210 dsize: Dsize,
211 k_aux: TorusPrecision,
212 rank_in: Rank,
213 rank_out: Rank,
214 ) -> GLWESwitchingKey<Self::OwnedBuf, Self::ZnxWord>;
215
216 fn glwe_automorphism_key_alloc_from_infos<A: GGLWEInfos>(
217 &self,
218 infos: &A,
219 ) -> GLWEAutomorphismKey<Self::OwnedBuf, Self::ZnxWord>;
220 fn glwe_automorphism_key_alloc(
221 &self,
222 base2k: Base2K,
223 dnum: Dnum,
224 dsize: Dsize,
225 k_aux: TorusPrecision,
226 rank: Rank,
227 ) -> GLWEAutomorphismKey<Self::OwnedBuf, Self::ZnxWord>;
228
229 fn glwe_tensor_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GLWETensorKey<Self::OwnedBuf, Self::ZnxWord>;
230 fn glwe_tensor_key_alloc(
231 &self,
232 base2k: Base2K,
233 dnum: Dnum,
234 dsize: Dsize,
235 k_aux: TorusPrecision,
236 rank: Rank,
237 ) -> GLWETensorKey<Self::OwnedBuf, Self::ZnxWord>;
238
239 fn glwe_to_lwe_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GLWEToLWEKey<Self::OwnedBuf, Self::ZnxWord>;
240 fn glwe_to_lwe_key_alloc(
241 &self,
242 base2k: Base2K,
243 dnum: Dnum,
244 k_aux: TorusPrecision,
245 rank_in: Rank,
246 ) -> GLWEToLWEKey<Self::OwnedBuf, Self::ZnxWord>;
247
248 fn gglwe_to_ggsw_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GGLWEToGGSWKey<Self::OwnedBuf, Self::ZnxWord>;
249 fn gglwe_to_ggsw_key_alloc(
250 &self,
251 base2k: Base2K,
252 dnum: Dnum,
253 dsize: Dsize,
254 k_aux: TorusPrecision,
255 rank: Rank,
256 ) -> GGLWEToGGSWKey<Self::OwnedBuf, Self::ZnxWord>;
257
258 fn lwe_alloc_from_infos<A: LWEInfos>(&self, infos: &A) -> LWE<Self::OwnedBuf, Self::ZnxWord>;
259 fn lwe_alloc(&self, n: Degree, base2k: Base2K, k: TorusPrecision) -> LWE<Self::OwnedBuf, Self::ZnxWord>;
260
261 fn lwe_matrix_alloc_from_infos<A: LWEMatrixInfos>(&self, infos: &A) -> LWEMatrix<Self::OwnedBuf, Self::ZnxWord>;
262 fn lwe_matrix_alloc(
263 &self,
264 rows: usize,
265 lwe_n: Degree,
266 base2k: Base2K,
267 k: TorusPrecision,
268 ) -> LWEMatrix<Self::OwnedBuf, Self::ZnxWord>;
269
270 fn lwe_plaintext_alloc_from_infos<A: LWEInfos>(&self, infos: &A) -> LWEPlaintext<Self::OwnedBuf, Self::ZnxWord>;
271 fn lwe_plaintext_alloc(&self, base2k: Base2K, k: TorusPrecision) -> LWEPlaintext<Self::OwnedBuf, Self::ZnxWord>;
272
273 fn lwe_secret_alloc(&self, n: Degree) -> LWESecret<Self::OwnedBuf, Self::ZnxWord>;
274
275 fn lwe_switching_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> LWESwitchingKey<Self::OwnedBuf, Self::ZnxWord>;
276 fn lwe_switching_key_alloc(
277 &self,
278 n: Degree,
279 base2k: Base2K,
280 dnum: Dnum,
281 k_aux: TorusPrecision,
282 ) -> LWESwitchingKey<Self::OwnedBuf, Self::ZnxWord>;
283
284 fn lwe_to_glwe_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> LWEToGLWEKey<Self::OwnedBuf, Self::ZnxWord>;
285 fn lwe_to_glwe_key_alloc(
286 &self,
287 n: Degree,
288 base2k: Base2K,
289 dnum: Dnum,
290 k_aux: TorusPrecision,
291 rank_out: Rank,
292 ) -> LWEToGLWEKey<Self::OwnedBuf, Self::ZnxWord>;
293}
294
295impl<B: Backend> ModuleCoreAlloc for Module<B> {
296 type OwnedBuf = B::OwnedBuf;
297 type ZnxWord = B::ZnxWord;
298
299 fn glwe_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWE<B::OwnedBuf, B::ZnxWord> {
300 let size = infos.k().as_usize().div_ceil(infos.base2k().as_usize());
301 GLWE {
302 data: vec_znx_alloc_zeroed::<B>(infos.n().as_usize(), (infos.rank() + 1).as_usize(), size),
303 k: infos.k(),
304 base2k: infos.base2k(),
305 }
306 }
307 fn glwe_alloc(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWE<B::OwnedBuf, B::ZnxWord> {
308 self.glwe_alloc_from_infos(&GLWELayout {
309 n: self.ring_degree(),
310 base2k,
311 k,
312 rank,
313 })
314 }
315
316 fn glwe_alloc_with_size(&self, base2k: Base2K, size: usize, rank: Rank) -> GLWE<B::OwnedBuf, B::ZnxWord> {
317 let n = self.ring_degree().as_usize();
318 let cols = (rank + 1).as_usize();
319 GLWE {
320 data: vec_znx_alloc_zeroed::<B>(n, cols, size),
321 k: TorusPrecision((size * base2k.as_usize()) as u32),
322 base2k,
323 }
324 }
325
326 fn gglwe_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GGLWE<B::OwnedBuf, B::ZnxWord> {
327 let dnum = infos.dnum();
328 let size = crate::layouts::key_size(infos.base2k(), dnum, infos.dsize(), infos.k_aux());
329
330 GGLWE {
331 data: MatZnx::from_data(
332 B::alloc_zeroed_bytes(B::bytes_of_mat_znx(
333 infos.n().as_usize(),
334 dnum.as_usize(),
335 infos.rank_in().as_usize(),
336 (infos.rank_out() + 1).as_usize(),
337 size,
338 )),
339 infos.n().as_usize(),
340 dnum.as_usize(),
341 infos.rank_in().as_usize(),
342 (infos.rank_out() + 1).as_usize(),
343 size,
344 ),
345 k_aux: infos.k_aux(),
346 base2k: infos.base2k(),
347 dsize: infos.dsize(),
348 }
349 }
350 fn gglwe_alloc(
351 &self,
352 base2k: Base2K,
353 dnum: Dnum,
354 dsize: Dsize,
355 k_aux: TorusPrecision,
356 rank_in: Rank,
357 rank_out: Rank,
358 ) -> GGLWE<B::OwnedBuf, B::ZnxWord> {
359 self.gglwe_alloc_from_infos(&GGLWELayout {
360 n: self.ring_degree(),
361 base2k,
362 dnum,
363 dsize,
364 k_aux,
365 rank_in,
366 rank_out,
367 stride: 1,
368 })
369 }
370
371 fn ggsw_alloc_from_infos<A: GGSWInfos>(&self, infos: &A) -> GGSW<B::OwnedBuf, B::ZnxWord> {
372 let dnum = infos.dnum();
373 let size = crate::layouts::key_size(infos.base2k(), dnum, infos.dsize(), infos.k_aux());
374
375 GGSW {
376 data: MatZnx::from_data(
377 B::alloc_zeroed_bytes(B::bytes_of_mat_znx(
378 infos.n().as_usize(),
379 dnum.as_usize(),
380 (infos.rank() + 1).as_usize(),
381 (infos.rank() + 1).as_usize(),
382 size,
383 )),
384 infos.n().as_usize(),
385 dnum.as_usize(),
386 (infos.rank() + 1).as_usize(),
387 (infos.rank() + 1).as_usize(),
388 size,
389 ),
390 k_aux: infos.k_aux(),
391 base2k: infos.base2k(),
392 dsize: infos.dsize(),
393 }
394 }
395 fn ggsw_alloc(
396 &self,
397 base2k: Base2K,
398 dnum: Dnum,
399 dsize: Dsize,
400 k_aux: TorusPrecision,
401 rank: Rank,
402 ) -> GGSW<B::OwnedBuf, B::ZnxWord> {
403 self.ggsw_alloc_from_infos(&GGSWLayout {
404 n: self.ring_degree(),
405 base2k,
406 dnum,
407 dsize,
408 k_aux,
409 rank,
410 })
411 }
412
413 fn glwe_plaintext_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWEPlaintext<B::OwnedBuf, B::ZnxWord> {
414 let size = infos.k().as_usize().div_ceil(infos.base2k().as_usize());
415 GLWEPlaintext {
416 data: vec_znx_alloc_zeroed::<B>(infos.n().as_usize(), 1, size),
417 k: infos.k(),
418 base2k: infos.base2k(),
419 }
420 }
421 fn glwe_plaintext_alloc(&self, base2k: Base2K, k: TorusPrecision) -> GLWEPlaintext<B::OwnedBuf, B::ZnxWord> {
422 self.glwe_plaintext_alloc_from_infos(&GLWEPlaintextLayout {
423 n: self.ring_degree(),
424 base2k,
425 k,
426 })
427 }
428
429 fn glwe_secret_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWESecret<B::OwnedBuf, B::ZnxWord> {
430 GLWESecret {
431 data: ScalarZnx::from_data(
432 B::alloc_zeroed_bytes(B::bytes_of_scalar_znx(infos.n().as_usize(), infos.rank().as_usize())),
433 infos.n().as_usize(),
434 infos.rank().as_usize(),
435 ),
436 dist: Distribution::NONE,
437 }
438 }
439 fn glwe_secret_alloc(&self, rank: Rank) -> GLWESecret<B::OwnedBuf, B::ZnxWord> {
440 self.glwe_secret_alloc_from_infos(&GLWESecretLayout {
441 n: self.ring_degree(),
442 rank,
443 })
444 }
445
446 fn glwe_secret_tensor_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWESecretTensor<B::OwnedBuf, B::ZnxWord> {
447 let pairs = crate::layouts::pairs(infos.rank().as_usize());
448 GLWESecretTensor {
449 data: ScalarZnx::from_data(
450 B::alloc_zeroed_bytes(B::bytes_of_scalar_znx(infos.n().as_usize(), pairs)),
451 infos.n().as_usize(),
452 pairs,
453 ),
454 rank: infos.rank(),
455 dist: Distribution::NONE,
456 }
457 }
458 fn glwe_secret_tensor_alloc(&self, rank: Rank) -> GLWESecretTensor<B::OwnedBuf, B::ZnxWord> {
459 self.glwe_secret_tensor_alloc_from_infos(&GLWESecretLayout {
460 n: self.ring_degree(),
461 rank,
462 })
463 }
464
465 fn glwe_tensor_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWETensor<B::OwnedBuf, B::ZnxWord> {
466 let cols = infos.rank().as_usize() + 1;
467 let pairs = (((cols + 1) * cols) >> 1).max(1);
468 let size = infos.k().as_usize().div_ceil(infos.base2k().as_usize());
469 GLWETensor {
470 data: vec_znx_alloc_zeroed::<B>(infos.n().as_usize(), pairs, size),
471 k: infos.k(),
472 base2k: infos.base2k(),
473 rank: infos.rank(),
474 }
475 }
476 fn glwe_tensor_alloc(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWETensor<B::OwnedBuf, B::ZnxWord> {
477 self.glwe_tensor_alloc_from_infos(&GLWELayout {
478 n: self.ring_degree(),
479 base2k,
480 k,
481 rank,
482 })
483 }
484
485 fn glwe_public_key_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWEPublicKey<B::OwnedBuf, B::ZnxWord> {
486 GLWEPublicKey {
487 key: self.glwe_alloc_from_infos(infos),
488 dist: Distribution::NONE,
489 }
490 }
491 fn glwe_public_key_alloc(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWEPublicKey<B::OwnedBuf, B::ZnxWord> {
492 self.glwe_public_key_alloc_from_infos(&GLWELayout {
493 n: self.ring_degree(),
494 base2k,
495 k,
496 rank,
497 })
498 }
499
500 fn glwe_switching_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GLWESwitchingKey<B::OwnedBuf, B::ZnxWord> {
501 GLWESwitchingKey {
502 key: self.gglwe_alloc_from_infos(infos),
503 input_degree: Degree(0),
504 output_degree: Degree(0),
505 }
506 }
507 fn glwe_switching_key_alloc(
508 &self,
509 base2k: Base2K,
510 dnum: Dnum,
511 dsize: Dsize,
512 k_aux: TorusPrecision,
513 rank_in: Rank,
514 rank_out: Rank,
515 ) -> GLWESwitchingKey<B::OwnedBuf, B::ZnxWord> {
516 self.glwe_switching_key_alloc_from_infos(&GGLWELayout {
517 n: self.ring_degree(),
518 base2k,
519 dnum,
520 dsize,
521 k_aux,
522 rank_in,
523 rank_out,
524 stride: 1,
525 })
526 }
527
528 fn glwe_automorphism_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GLWEAutomorphismKey<B::OwnedBuf, B::ZnxWord> {
529 GLWEAutomorphismKey {
530 key: self.gglwe_alloc_from_infos(infos),
531 p: 0,
532 }
533 }
534 fn glwe_automorphism_key_alloc(
535 &self,
536 base2k: Base2K,
537 dnum: Dnum,
538 dsize: Dsize,
539 k_aux: TorusPrecision,
540 rank: Rank,
541 ) -> GLWEAutomorphismKey<B::OwnedBuf, B::ZnxWord> {
542 self.glwe_automorphism_key_alloc_from_infos(&GGLWELayout {
543 n: self.ring_degree(),
544 base2k,
545 dnum,
546 k_aux,
547 rank_in: rank,
548 rank_out: rank,
549 dsize,
550 stride: 1,
551 })
552 }
553
554 fn glwe_tensor_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GLWETensorKey<B::OwnedBuf, B::ZnxWord> {
555 GLWETensorKey(self.gglwe_alloc_from_infos(infos))
556 }
557 fn glwe_tensor_key_alloc(
558 &self,
559 base2k: Base2K,
560 dnum: Dnum,
561 dsize: Dsize,
562 k_aux: TorusPrecision,
563 rank: Rank,
564 ) -> GLWETensorKey<B::OwnedBuf, B::ZnxWord> {
565 let pairs = (((rank.0 + 1) * rank.0) >> 1).max(1);
566 self.glwe_tensor_key_alloc_from_infos(&GGLWELayout {
567 n: self.ring_degree(),
568 base2k,
569 dnum,
570 k_aux,
571 rank_in: Rank(pairs),
572 rank_out: rank,
573 dsize,
574 stride: 1,
575 })
576 }
577
578 fn glwe_to_lwe_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GLWEToLWEKey<B::OwnedBuf, B::ZnxWord> {
579 assert_eq!(infos.rank_out().0, 1, "rank_out > 1 is not supported for GLWEToLWEKey");
580 assert_eq!(infos.dsize().0, 1, "dsize > 1 is not supported for GLWEToLWEKey");
581 GLWEToLWEKey(self.glwe_switching_key_alloc_from_infos(infos))
582 }
583 fn glwe_to_lwe_key_alloc(
584 &self,
585 base2k: Base2K,
586 dnum: Dnum,
587 k_aux: TorusPrecision,
588 rank_in: Rank,
589 ) -> GLWEToLWEKey<B::OwnedBuf, B::ZnxWord> {
590 self.glwe_to_lwe_key_alloc_from_infos(&GGLWELayout {
591 n: self.ring_degree(),
592 base2k,
593 dnum,
594 k_aux,
595 rank_in,
596 rank_out: Rank(1),
597 dsize: Dsize(1),
598 stride: 1,
599 })
600 }
601
602 fn gglwe_to_ggsw_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GGLWEToGGSWKey<B::OwnedBuf, B::ZnxWord> {
603 assert_eq!(
604 infos.rank_in(),
605 infos.rank_out(),
606 "rank_in != rank_out is not supported for GGLWEToGGSWKey"
607 );
608 GGLWEToGGSWKey {
609 keys: (0..infos.rank().as_usize())
610 .map(|_| self.gglwe_alloc_from_infos(infos))
611 .collect(),
612 }
613 }
614 fn gglwe_to_ggsw_key_alloc(
615 &self,
616 base2k: Base2K,
617 dnum: Dnum,
618 dsize: Dsize,
619 k_aux: TorusPrecision,
620 rank: Rank,
621 ) -> GGLWEToGGSWKey<B::OwnedBuf, B::ZnxWord> {
622 self.gglwe_to_ggsw_key_alloc_from_infos(&GGLWELayout {
623 n: self.ring_degree(),
624 base2k,
625 dnum,
626 k_aux,
627 rank_in: rank,
628 rank_out: rank,
629 dsize,
630 stride: 1,
631 })
632 }
633
634 fn lwe_alloc_from_infos<A: LWEInfos>(&self, infos: &A) -> LWE<B::OwnedBuf, B::ZnxWord> {
635 let size = infos.k().as_usize().div_ceil(infos.base2k().as_usize());
636 let n = infos.n().as_usize();
637 LWE {
638 body: vec_znx_alloc_zeroed::<B>(1, 1, size),
639 mask: vec_znx_alloc_zeroed::<B>(n, 1, size),
640 base2k: infos.base2k(),
641 k: infos.k(),
642 }
643 }
644 fn lwe_alloc(&self, n: Degree, base2k: Base2K, k: TorusPrecision) -> LWE<B::OwnedBuf, B::ZnxWord> {
645 self.lwe_alloc_from_infos(&LWELayout { n, base2k, k })
646 }
647
648 fn lwe_matrix_alloc_from_infos<A: LWEMatrixInfos>(&self, infos: &A) -> LWEMatrix<B::OwnedBuf, B::ZnxWord> {
649 let size = infos.k().as_usize().div_ceil(infos.base2k().as_usize());
650 let rows = infos.rows();
651 LWEMatrix {
652 body: vec_znx_alloc_zeroed::<B>(rows, 1, size),
653 mask: vec_znx_alloc_zeroed::<B>(rows, infos.n().as_usize(), size),
654 k: infos.k(),
655 base2k: infos.base2k(),
656 }
657 }
658 fn lwe_matrix_alloc(
659 &self,
660 rows: usize,
661 lwe_n: Degree,
662 base2k: Base2K,
663 k: TorusPrecision,
664 ) -> LWEMatrix<B::OwnedBuf, B::ZnxWord> {
665 self.lwe_matrix_alloc_from_infos(&LWEMatrixLayout {
666 rows,
667 n: lwe_n,
668 base2k,
669 k,
670 })
671 }
672
673 fn lwe_plaintext_alloc_from_infos<A: LWEInfos>(&self, infos: &A) -> LWEPlaintext<B::OwnedBuf, B::ZnxWord> {
674 let size = infos.k().as_usize().div_ceil(infos.base2k().as_usize());
675 LWEPlaintext {
676 data: vec_znx_alloc_zeroed::<B>(1, 1, size),
677 k: infos.k(),
678 base2k: infos.base2k(),
679 }
680 }
681 fn lwe_plaintext_alloc(&self, base2k: Base2K, k: TorusPrecision) -> LWEPlaintext<B::OwnedBuf, B::ZnxWord> {
682 let size = k.as_usize().div_ceil(base2k.as_usize());
683 LWEPlaintext {
684 data: vec_znx_alloc_zeroed::<B>(1, 1, size),
685 k,
686 base2k,
687 }
688 }
689
690 fn lwe_secret_alloc(&self, n: Degree) -> LWESecret<B::OwnedBuf, B::ZnxWord> {
691 LWESecret {
692 data: ScalarZnx::from_data(
693 B::alloc_zeroed_bytes(B::bytes_of_scalar_znx(n.as_usize(), 1)),
694 n.as_usize(),
695 1,
696 ),
697 dist: Distribution::NONE,
698 }
699 }
700
701 fn lwe_switching_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> LWESwitchingKey<B::OwnedBuf, B::ZnxWord> {
702 assert_eq!(infos.dsize().0, 1, "dsize > 1 is not supported for LWESwitchingKey");
703 assert_eq!(infos.rank_in().0, 1, "rank_in > 1 is not supported for LWESwitchingKey");
704 assert_eq!(infos.rank_out().0, 1, "rank_out > 1 is not supported for LWESwitchingKey");
705 LWESwitchingKey(self.glwe_switching_key_alloc_from_infos(infos))
706 }
707 fn lwe_switching_key_alloc(
708 &self,
709 n: Degree,
710 base2k: Base2K,
711 dnum: Dnum,
712 k_aux: TorusPrecision,
713 ) -> LWESwitchingKey<B::OwnedBuf, B::ZnxWord> {
714 self.lwe_switching_key_alloc_from_infos(&LWESwitchingKeyLayout { n, base2k, dnum, k_aux })
715 }
716
717 fn lwe_to_glwe_key_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> LWEToGLWEKey<B::OwnedBuf, B::ZnxWord> {
718 assert_eq!(infos.rank_in().0, 1, "rank_in > 1 is not supported for LWEToGLWEKey");
719 assert_eq!(infos.dsize().0, 1, "dsize > 1 is not supported for LWEToGLWEKey");
720 LWEToGLWEKey(self.glwe_switching_key_alloc_from_infos(infos))
721 }
722 fn lwe_to_glwe_key_alloc(
723 &self,
724 n: Degree,
725 base2k: Base2K,
726 dnum: Dnum,
727 k_aux: TorusPrecision,
728 rank_out: Rank,
729 ) -> LWEToGLWEKey<B::OwnedBuf, B::ZnxWord> {
730 self.lwe_to_glwe_key_alloc_from_infos(&GGLWELayout {
731 n,
732 base2k,
733 dnum,
734 k_aux,
735 rank_in: Rank(1),
736 rank_out,
737 dsize: Dsize(1),
738 stride: 1,
739 })
740 }
741}
742
743pub trait ModuleCoreCompressedAlloc {
748 type OwnedBuf: Data;
749 type ZnxWord: ZnxWord;
750
751 fn glwe_compressed_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWECompressed<Self::OwnedBuf, Self::ZnxWord>;
752 fn glwe_compressed_alloc(
753 &self,
754 base2k: Base2K,
755 k: TorusPrecision,
756 rank: Rank,
757 ) -> GLWECompressed<Self::OwnedBuf, Self::ZnxWord>;
758
759 fn lwe_compressed_alloc_from_infos<A: LWEInfos>(&self, infos: &A) -> LWECompressed<Self::OwnedBuf, Self::ZnxWord>;
760 fn lwe_compressed_alloc(&self, base2k: Base2K, k: TorusPrecision) -> LWECompressed<Self::OwnedBuf, Self::ZnxWord>;
761
762 fn gglwe_compressed_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GGLWECompressed<Self::OwnedBuf, Self::ZnxWord>;
763 fn gglwe_compressed_alloc(
764 &self,
765 base2k: Base2K,
766 dnum: Dnum,
767 dsize: Dsize,
768 k_aux: TorusPrecision,
769 rank_in: Rank,
770 rank_out: Rank,
771 ) -> GGLWECompressed<Self::OwnedBuf, Self::ZnxWord>;
772
773 fn ggsw_compressed_alloc_from_infos<A: GGSWInfos>(&self, infos: &A) -> GGSWCompressed<Self::OwnedBuf, Self::ZnxWord>;
774 fn ggsw_compressed_alloc(
775 &self,
776 base2k: Base2K,
777 dnum: Dnum,
778 dsize: Dsize,
779 k_aux: TorusPrecision,
780 rank: Rank,
781 ) -> GGSWCompressed<Self::OwnedBuf, Self::ZnxWord>;
782
783 fn glwe_switching_key_compressed_alloc_from_infos<A: GGLWEInfos>(
784 &self,
785 infos: &A,
786 ) -> GLWESwitchingKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
787 fn glwe_switching_key_compressed_alloc(
788 &self,
789 base2k: Base2K,
790 dnum: Dnum,
791 dsize: Dsize,
792 k_aux: TorusPrecision,
793 rank_in: Rank,
794 rank_out: Rank,
795 ) -> GLWESwitchingKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
796
797 fn glwe_automorphism_key_compressed_alloc_from_infos<A: GGLWEInfos>(
798 &self,
799 infos: &A,
800 ) -> GLWEAutomorphismKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
801 fn glwe_automorphism_key_compressed_alloc(
802 &self,
803 base2k: Base2K,
804 dnum: Dnum,
805 dsize: Dsize,
806 k_aux: TorusPrecision,
807 rank: Rank,
808 ) -> GLWEAutomorphismKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
809
810 fn glwe_tensor_key_compressed_alloc_from_infos<A: GGLWEInfos>(
811 &self,
812 infos: &A,
813 ) -> GLWETensorKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
814 fn glwe_tensor_key_compressed_alloc(
815 &self,
816 base2k: Base2K,
817 dnum: Dnum,
818 dsize: Dsize,
819 k_aux: TorusPrecision,
820 rank: Rank,
821 ) -> GLWETensorKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
822
823 fn glwe_to_lwe_key_compressed_alloc_from_infos<A: GGLWEInfos>(
824 &self,
825 infos: &A,
826 ) -> GLWEToLWESwitchingKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
827 fn glwe_to_lwe_key_compressed_alloc(
828 &self,
829 base2k: Base2K,
830 dnum: Dnum,
831 k_aux: TorusPrecision,
832 rank_in: Rank,
833 ) -> GLWEToLWESwitchingKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
834
835 fn lwe_to_glwe_key_compressed_alloc_from_infos<A: GGLWEInfos>(
836 &self,
837 infos: &A,
838 ) -> LWEToGLWEKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
839 fn lwe_to_glwe_key_compressed_alloc(
840 &self,
841 n: Degree,
842 base2k: Base2K,
843 dnum: Dnum,
844 k_aux: TorusPrecision,
845 rank_out: Rank,
846 ) -> LWEToGLWEKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
847
848 fn lwe_switching_key_compressed_alloc_from_infos<A: GGLWEInfos>(
849 &self,
850 infos: &A,
851 ) -> LWESwitchingKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
852 fn lwe_switching_key_compressed_alloc(
853 &self,
854 n: Degree,
855 base2k: Base2K,
856 dnum: Dnum,
857 k_aux: TorusPrecision,
858 ) -> LWESwitchingKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
859
860 fn gglwe_to_ggsw_key_compressed_alloc_from_infos<A: GGLWEInfos>(
861 &self,
862 infos: &A,
863 ) -> GGLWEToGGSWKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
864 fn gglwe_to_ggsw_key_compressed_alloc(
865 &self,
866 base2k: Base2K,
867 dnum: Dnum,
868 dsize: Dsize,
869 k_aux: TorusPrecision,
870 rank: Rank,
871 ) -> GGLWEToGGSWKeyCompressed<Self::OwnedBuf, Self::ZnxWord>;
872}
873
874impl<B: Backend> ModuleCoreCompressedAlloc for Module<B> {
875 type OwnedBuf = B::OwnedBuf;
876 type ZnxWord = B::ZnxWord;
877 fn glwe_compressed_alloc_from_infos<A: GLWEInfos>(&self, infos: &A) -> GLWECompressed<B::OwnedBuf, B::ZnxWord> {
878 GLWECompressed::alloc_from_infos::<B, _>(infos)
879 }
880 fn glwe_compressed_alloc(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWECompressed<B::OwnedBuf, B::ZnxWord> {
881 GLWECompressed::alloc::<B>(self.ring_degree(), base2k, k, rank)
882 }
883
884 fn lwe_compressed_alloc_from_infos<A: LWEInfos>(&self, infos: &A) -> LWECompressed<B::OwnedBuf, B::ZnxWord> {
885 LWECompressed::alloc_from_infos::<B, _>(infos)
886 }
887 fn lwe_compressed_alloc(&self, base2k: Base2K, k: TorusPrecision) -> LWECompressed<B::OwnedBuf, B::ZnxWord> {
888 LWECompressed::alloc::<B>(base2k, k)
889 }
890
891 fn gglwe_compressed_alloc_from_infos<A: GGLWEInfos>(&self, infos: &A) -> GGLWECompressed<B::OwnedBuf, B::ZnxWord> {
892 GGLWECompressed::alloc_from_infos::<B, _>(infos)
893 }
894 fn gglwe_compressed_alloc(
895 &self,
896 base2k: Base2K,
897 dnum: Dnum,
898 dsize: Dsize,
899 k_aux: TorusPrecision,
900 rank_in: Rank,
901 rank_out: Rank,
902 ) -> GGLWECompressed<B::OwnedBuf, B::ZnxWord> {
903 GGLWECompressed::alloc::<B>(self.ring_degree(), base2k, dnum, dsize, k_aux, rank_in, rank_out)
904 }
905
906 fn ggsw_compressed_alloc_from_infos<A: GGSWInfos>(&self, infos: &A) -> GGSWCompressed<B::OwnedBuf, B::ZnxWord> {
907 GGSWCompressed::alloc_from_infos::<B, _>(infos)
908 }
909 fn ggsw_compressed_alloc(
910 &self,
911 base2k: Base2K,
912 dnum: Dnum,
913 dsize: Dsize,
914 k_aux: TorusPrecision,
915 rank: Rank,
916 ) -> GGSWCompressed<B::OwnedBuf, B::ZnxWord> {
917 GGSWCompressed::alloc::<B>(self.ring_degree(), base2k, dnum, dsize, k_aux, rank)
918 }
919
920 fn glwe_switching_key_compressed_alloc_from_infos<A: GGLWEInfos>(
921 &self,
922 infos: &A,
923 ) -> GLWESwitchingKeyCompressed<B::OwnedBuf, B::ZnxWord> {
924 GLWESwitchingKeyCompressed::alloc_from_infos::<B, _>(infos)
925 }
926 fn glwe_switching_key_compressed_alloc(
927 &self,
928 base2k: Base2K,
929 dnum: Dnum,
930 dsize: Dsize,
931 k_aux: TorusPrecision,
932 rank_in: Rank,
933 rank_out: Rank,
934 ) -> GLWESwitchingKeyCompressed<B::OwnedBuf, B::ZnxWord> {
935 GLWESwitchingKeyCompressed::alloc::<B>(self.ring_degree(), base2k, dnum, dsize, k_aux, rank_in, rank_out)
936 }
937
938 fn glwe_automorphism_key_compressed_alloc_from_infos<A: GGLWEInfos>(
939 &self,
940 infos: &A,
941 ) -> GLWEAutomorphismKeyCompressed<B::OwnedBuf, B::ZnxWord> {
942 GLWEAutomorphismKeyCompressed::alloc_from_infos::<B, _>(infos)
943 }
944 fn glwe_automorphism_key_compressed_alloc(
945 &self,
946 base2k: Base2K,
947 dnum: Dnum,
948 dsize: Dsize,
949 k_aux: TorusPrecision,
950 rank: Rank,
951 ) -> GLWEAutomorphismKeyCompressed<B::OwnedBuf, B::ZnxWord> {
952 GLWEAutomorphismKeyCompressed::alloc::<B>(self.ring_degree(), base2k, dnum, dsize, k_aux, rank)
953 }
954
955 fn glwe_tensor_key_compressed_alloc_from_infos<A: GGLWEInfos>(
956 &self,
957 infos: &A,
958 ) -> GLWETensorKeyCompressed<B::OwnedBuf, B::ZnxWord> {
959 GLWETensorKeyCompressed::alloc_from_infos::<B, _>(infos)
960 }
961 fn glwe_tensor_key_compressed_alloc(
962 &self,
963 base2k: Base2K,
964 dnum: Dnum,
965 dsize: Dsize,
966 k_aux: TorusPrecision,
967 rank: Rank,
968 ) -> GLWETensorKeyCompressed<B::OwnedBuf, B::ZnxWord> {
969 GLWETensorKeyCompressed::alloc::<B>(self.ring_degree(), base2k, dnum, dsize, k_aux, rank)
970 }
971
972 fn glwe_to_lwe_key_compressed_alloc_from_infos<A: GGLWEInfos>(
973 &self,
974 infos: &A,
975 ) -> GLWEToLWESwitchingKeyCompressed<B::OwnedBuf, B::ZnxWord> {
976 GLWEToLWESwitchingKeyCompressed::alloc_from_infos::<B, _>(infos)
977 }
978 fn glwe_to_lwe_key_compressed_alloc(
979 &self,
980 base2k: Base2K,
981 dnum: Dnum,
982 k_aux: TorusPrecision,
983 rank_in: Rank,
984 ) -> GLWEToLWESwitchingKeyCompressed<B::OwnedBuf, B::ZnxWord> {
985 GLWEToLWESwitchingKeyCompressed::alloc::<B>(self.ring_degree(), base2k, dnum, k_aux, rank_in)
986 }
987
988 fn lwe_to_glwe_key_compressed_alloc_from_infos<A: GGLWEInfos>(
989 &self,
990 infos: &A,
991 ) -> LWEToGLWEKeyCompressed<B::OwnedBuf, B::ZnxWord> {
992 LWEToGLWEKeyCompressed::alloc_from_infos::<B, _>(infos)
993 }
994 fn lwe_to_glwe_key_compressed_alloc(
995 &self,
996 n: Degree,
997 base2k: Base2K,
998 dnum: Dnum,
999 k_aux: TorusPrecision,
1000 rank_out: Rank,
1001 ) -> LWEToGLWEKeyCompressed<B::OwnedBuf, B::ZnxWord> {
1002 LWEToGLWEKeyCompressed::alloc::<B>(n, base2k, dnum, k_aux, rank_out)
1003 }
1004
1005 fn lwe_switching_key_compressed_alloc_from_infos<A: GGLWEInfos>(
1006 &self,
1007 infos: &A,
1008 ) -> LWESwitchingKeyCompressed<B::OwnedBuf, B::ZnxWord> {
1009 LWESwitchingKeyCompressed::alloc_from_infos::<B, _>(infos)
1010 }
1011 fn lwe_switching_key_compressed_alloc(
1012 &self,
1013 n: Degree,
1014 base2k: Base2K,
1015 dnum: Dnum,
1016 k_aux: TorusPrecision,
1017 ) -> LWESwitchingKeyCompressed<B::OwnedBuf, B::ZnxWord> {
1018 LWESwitchingKeyCompressed::alloc::<B>(n, base2k, dnum, k_aux)
1019 }
1020
1021 fn gglwe_to_ggsw_key_compressed_alloc_from_infos<A: GGLWEInfos>(
1022 &self,
1023 infos: &A,
1024 ) -> GGLWEToGGSWKeyCompressed<B::OwnedBuf, B::ZnxWord> {
1025 GGLWEToGGSWKeyCompressed::alloc_from_infos::<B, _>(infos)
1026 }
1027 fn gglwe_to_ggsw_key_compressed_alloc(
1028 &self,
1029 base2k: Base2K,
1030 dnum: Dnum,
1031 dsize: Dsize,
1032 k_aux: TorusPrecision,
1033 rank: Rank,
1034 ) -> GGLWEToGGSWKeyCompressed<B::OwnedBuf, B::ZnxWord> {
1035 GGLWEToGGSWKeyCompressed::alloc::<B>(self.ring_degree(), base2k, dnum, dsize, k_aux, rank)
1036 }
1037}
1038
1039macro_rules! newtype_u32 {
1042 ($(#[$meta:meta])* $name:ident) => {
1043 $(#[$meta])*
1044 #[repr(transparent)]
1045 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1046 pub struct $name(pub u32);
1047
1048 impl From<$name> for u32 {
1050 #[inline]
1051 fn from(v: $name) -> u32 {
1052 v.0
1053 }
1054 }
1055 impl From<$name> for usize {
1056 #[inline]
1057 fn from(v: $name) -> usize {
1058 v.0 as usize
1059 }
1060 }
1061
1062 impl From<u32> for $name {
1063 #[inline]
1064 fn from(v: u32) -> $name {
1065 $name(v)
1066 }
1067 }
1068 impl From<usize> for $name {
1069 #[inline]
1070 fn from(v: usize) -> $name {
1071 debug_assert!(v <= u32::MAX as usize, "{} overflow: {v} > u32::MAX", stringify!($name));
1072 $name(v as u32)
1073 }
1074 }
1075
1076 impl ::core::fmt::Display for $name {
1078 #[inline]
1079 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
1080 write!(f, "{}", self.0)
1081 }
1082 }
1083
1084 impl ::core::ops::Add for $name {
1086 type Output = $name;
1087 #[inline]
1088 fn add(self, rhs: $name) -> $name {
1089 $name(self.0.saturating_add(rhs.0))
1090 }
1091 }
1092 impl ::core::ops::Sub for $name {
1093 type Output = $name;
1094 #[inline]
1095 fn sub(self, rhs: $name) -> $name {
1096 $name(self.0.saturating_sub(rhs.0))
1097 }
1098 }
1099 impl ::core::ops::Mul for $name {
1100 type Output = $name;
1101 #[inline]
1102 fn mul(self, rhs: $name) -> $name {
1103 $name(self.0.saturating_mul(rhs.0))
1104 }
1105 }
1106
1107 impl ::core::ops::Add<u32> for $name {
1109 type Output = $name;
1110 #[inline]
1111 fn add(self, rhs: u32) -> $name {
1112 $name(self.0.saturating_add(rhs))
1113 }
1114 }
1115 impl ::core::ops::Sub<u32> for $name {
1116 type Output = $name;
1117 #[inline]
1118 fn sub(self, rhs: u32) -> $name {
1119 $name(self.0.saturating_sub(rhs))
1120 }
1121 }
1122 impl ::core::ops::Mul<u32> for $name {
1123 type Output = $name;
1124 #[inline]
1125 fn mul(self, rhs: u32) -> $name {
1126 $name(self.0.saturating_mul(rhs))
1127 }
1128 }
1129
1130 impl $name {
1131 #[inline]
1132 pub const fn as_u32(self) -> u32 {
1133 self.0
1134 }
1135 #[inline]
1136 pub const fn as_usize(self) -> usize {
1137 self.0 as usize
1138 }
1139
1140 #[inline]
1141 pub fn div_ceil<T: Into<u32>>(self, rhs: T) -> u32 {
1142 self.0.div_ceil(rhs.into())
1143 }
1144 }
1145
1146 impl ::core::ops::Add<$name> for u32 {
1148 type Output = $name;
1149 #[inline]
1150 fn add(self, rhs: $name) -> $name {
1151 $name(self.saturating_add(rhs.0))
1152 }
1153 }
1154 impl ::core::ops::Sub<$name> for u32 {
1155 type Output = $name;
1156 #[inline]
1157 fn sub(self, rhs: $name) -> $name {
1158 $name(self.saturating_sub(rhs.0))
1159 }
1160 }
1161 impl ::core::ops::Mul<$name> for u32 {
1162 type Output = $name;
1163 #[inline]
1164 fn mul(self, rhs: $name) -> $name {
1165 $name(self.saturating_mul(rhs.0))
1166 }
1167 }
1168
1169 impl ::core::cmp::PartialEq<u32> for $name {
1171 #[inline]
1172 fn eq(&self, other: &u32) -> bool {
1173 self.0 == *other
1174 }
1175 }
1176 impl ::core::cmp::PartialEq<$name> for u32 {
1177 #[inline]
1178 fn eq(&self, other: &$name) -> bool {
1179 *self == other.0
1180 }
1181 }
1182
1183 impl ::core::cmp::PartialOrd<u32> for $name {
1184 #[inline]
1185 fn partial_cmp(&self, other: &u32) -> Option<::core::cmp::Ordering> {
1186 self.0.partial_cmp(other)
1187 }
1188 }
1189 impl ::core::cmp::PartialOrd<$name> for u32 {
1190 #[inline]
1191 fn partial_cmp(&self, other: &$name) -> Option<::core::cmp::Ordering> {
1192 self.partial_cmp(&other.0)
1193 }
1194 }
1195 };
1196}
1197
1198newtype_u32!(
1199 Degree
1203);
1204
1205newtype_u32!(
1206 TorusPrecision
1211);
1212
1213newtype_u32!(
1214 Base2K
1222);
1223
1224newtype_u32!(
1225 Dnum
1230);
1231
1232newtype_u32!(
1233 Rank
1239);
1240
1241newtype_u32!(
1242 Dsize
1246);
1247
1248impl Degree {
1249 pub fn log2(&self) -> usize {
1251 debug_assert!(
1252 self.0 > 0 && self.0.is_power_of_two(),
1253 "Degree::log2 requires a positive power of two, got {}",
1254 self.0
1255 );
1256 self.0.trailing_zeros() as usize
1257 }
1258}
1259
1260pub fn key_k(base2k: Base2K, dnum: Dnum, dsize: Dsize, k_aux: TorusPrecision) -> TorusPrecision {
1266 debug_assert!(
1267 k_aux.0 >= dsize.0 * base2k.0,
1268 "k_aux ({}) must be at least dsize * base2k ({} * {} = {}): the auxiliary guard must \
1269 cover at least one full gadget digit, otherwise operations truncate mid-digit",
1270 k_aux.0,
1271 dsize.0,
1272 base2k.0,
1273 dsize.0 * base2k.0
1274 );
1275 TorusPrecision(dnum.0 * dsize.0 * base2k.0 + k_aux.0)
1276}
1277
1278pub fn key_size(base2k: Base2K, dnum: Dnum, dsize: Dsize, k_aux: TorusPrecision) -> usize {
1282 key_k(base2k, dnum, dsize, k_aux).0.div_ceil(base2k.0) as usize
1283}
1284
1285pub fn key_work_size(base2k: Base2K, input_k: TorusPrecision, dsize: Dsize, k_aux: TorusPrecision) -> usize {
1299 let digits: u32 = GGLWELayout::dnum_for_input(base2k, input_k, dsize).0;
1300 (digits * dsize.0 + k_aux.0.div_ceil(base2k.0)) as usize
1301}
1302
1303pub(crate) struct GadgetProductOutputSizeParams {
1305 pub(crate) key_size: usize,
1306 pub(crate) key_base2k: Base2K,
1307 pub(crate) input_k: TorusPrecision,
1308 pub(crate) output_k: TorusPrecision,
1309 pub(crate) dsize: Dsize,
1310 pub(crate) k_aux: TorusPrecision,
1311 pub(crate) product_terms: usize,
1312 pub(crate) extra_live_limbs: usize,
1313}
1314
1315pub(crate) fn gadget_product_limbs(key_base2k: Base2K, product_terms: usize) -> usize {
1320 let base2k = key_base2k.as_usize();
1321 let accumulation_bits = if product_terms <= 1 {
1322 0
1323 } else {
1324 usize::BITS as usize - (product_terms - 1).leading_zeros() as usize
1325 };
1326 base2k.saturating_mul(2).saturating_add(accumulation_bits).div_ceil(base2k)
1327}
1328
1329pub(crate) fn gadget_product_output_size(params: GadgetProductOutputSizeParams) -> usize {
1341 let GadgetProductOutputSizeParams {
1342 key_size,
1343 key_base2k,
1344 input_k,
1345 output_k,
1346 dsize,
1347 k_aux,
1348 product_terms,
1349 extra_live_limbs,
1350 } = params;
1351 let work_size = key_size.min(key_work_size(key_base2k, input_k, dsize, k_aux));
1352
1353 let base2k = key_base2k.as_usize();
1354 let live_limbs = input_k
1355 .as_usize()
1356 .max(output_k.as_usize())
1357 .div_ceil(base2k)
1358 .saturating_add(extra_live_limbs);
1359 let product_limbs = gadget_product_limbs(key_base2k, product_terms);
1360 work_size.min(live_limbs.saturating_add(product_limbs))
1361}
1362
1363#[cfg(test)]
1364mod gadget_sizing_tests {
1365 use super::*;
1366
1367 #[test]
1368 fn dnum_for_input_is_the_inverse_of_gadget_k() {
1369 let (base2k, dsize) = (Base2K(52), Dsize(4));
1370 let digit = dsize.0 * base2k.0;
1371 let dnum_for = |input_k: u32| GGLWELayout::dnum_for_input(base2k, TorusPrecision(input_k), dsize);
1372 assert_eq!(dnum_for(1404), Dnum(7));
1374 assert_eq!(dnum_for(7 * digit), Dnum(7));
1375 assert_eq!(dnum_for(7 * digit + 1), Dnum(8));
1376 assert_eq!(dnum_for(1), Dnum(1));
1377 for dnum in 1..10 {
1378 let k_aux = TorusPrecision(digit + 16);
1379 let layout = GGLWELayout {
1380 n: Degree(16),
1381 base2k,
1382 dnum: Dnum(dnum),
1383 k_aux,
1384 rank_in: Rank(1),
1385 rank_out: Rank(1),
1386 dsize,
1387 stride: 1,
1388 };
1389 let gadget = layout.gadget_k();
1390 assert_eq!(gadget.0, dnum * digit);
1391 assert_eq!(dnum_for(gadget.0), Dnum(dnum));
1392 assert_eq!(key_k(base2k, Dnum(dnum), dsize, k_aux).0, gadget.0 + k_aux.0);
1393 assert_eq!(
1394 key_work_size(base2k, gadget, dsize, k_aux),
1395 (dnum * dsize.0 + k_aux.0.div_ceil(base2k.0)) as usize
1396 );
1397 }
1398 }
1399
1400 #[test]
1401 fn work_size_rounds_input_to_a_whole_digit_before_aux_limbs() {
1402 assert_eq!(key_work_size(Base2K(30), TorusPrecision(61), Dsize(2), TorusPrecision(31)), 6);
1404 }
1405
1406 #[test]
1407 fn output_size_converts_precision_to_the_key_radix_and_caps_at_work_size() {
1408 assert_eq!(
1409 gadget_product_output_size(GadgetProductOutputSizeParams {
1410 key_size: 12,
1411 key_base2k: Base2K(30),
1412 input_k: TorusPrecision(61),
1413 output_k: TorusPrecision(91),
1414 dsize: Dsize(2),
1415 k_aux: TorusPrecision(31),
1416 product_terms: 1,
1417 extra_live_limbs: 0,
1418 }),
1419 6
1420 );
1421 }
1422
1423 #[test]
1424 fn output_size_accounts_for_polynomial_accumulation_growth() {
1425 assert_eq!(
1426 gadget_product_output_size(GadgetProductOutputSizeParams {
1427 key_size: 12,
1428 key_base2k: Base2K(30),
1429 input_k: TorusPrecision(60),
1430 output_k: TorusPrecision(90),
1431 dsize: Dsize(1),
1432 k_aux: TorusPrecision(180),
1433 product_terms: 1,
1434 extra_live_limbs: 0,
1435 }),
1436 5
1437 );
1438 assert_eq!(
1439 gadget_product_output_size(GadgetProductOutputSizeParams {
1440 key_size: 12,
1441 key_base2k: Base2K(30),
1442 input_k: TorusPrecision(60),
1443 output_k: TorusPrecision(90),
1444 dsize: Dsize(1),
1445 k_aux: TorusPrecision(180),
1446 product_terms: 1 << 16,
1447 extra_live_limbs: 0,
1448 }),
1449 6
1450 );
1451 }
1452
1453 #[test]
1454 fn product_limbs_include_coefficient_accumulation_growth() {
1455 assert_eq!(gadget_product_limbs(Base2K(30), 1), 2);
1456 assert_eq!(gadget_product_limbs(Base2K(30), 1 << 16), 3);
1457 assert_eq!(gadget_product_limbs(Base2K(19), 1 << 20), 4);
1458 }
1459}