concrete_core/commons/crypto/bootstrap/standard/mod.rs
1use crate::commons::crypto::encoding::Plaintext;
2use crate::commons::crypto::ggsw::StandardGgswCiphertext;
3use crate::commons::crypto::secret::generators::EncryptionRandomGenerator;
4use crate::commons::crypto::secret::{GlweSecretKey, LweSecretKey};
5use crate::commons::math::polynomial::Polynomial;
6use crate::commons::math::random::ByteRandomGenerator;
7#[cfg(feature = "__commons_parallel")]
8use crate::commons::math::random::ParallelByteRandomGenerator;
9use crate::commons::math::tensor::{
10 ck_dim_div, ck_dim_eq, tensor_traits, AsMutTensor, AsRefSlice, AsRefTensor, Container, Tensor,
11};
12use crate::commons::math::torus::UnsignedTorus;
13use crate::commons::numeric::Numeric;
14use crate::commons::utils::{zip, zip_args};
15use crate::prelude::{
16 BinaryKeyKind, DecompositionBaseLog, DecompositionLevelCount, DispersionParameter, GlweSize,
17 LweDimension, PolynomialSize,
18};
19#[cfg(feature = "__commons_parallel")]
20use rayon::{iter::IndexedParallelIterator, prelude::*};
21#[cfg(feature = "__commons_serialization")]
22use serde::{Deserialize, Serialize};
23
24/// A bootstrapping key represented in the standard domain.
25#[cfg_attr(feature = "__commons_serialization", derive(Serialize, Deserialize))]
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct StandardBootstrapKey<Cont> {
28 pub(crate) tensor: Tensor<Cont>,
29 poly_size: PolynomialSize,
30 rlwe_size: GlweSize,
31 decomp_level: DecompositionLevelCount,
32 decomp_base_log: DecompositionBaseLog,
33}
34
35tensor_traits!(StandardBootstrapKey);
36
37impl<Scalar> StandardBootstrapKey<Vec<Scalar>> {
38 /// Allocates a new bootstrapping key in the standard domain whose polynomials coefficients are
39 /// all `value`.
40 ///
41 /// # Example
42 ///
43 /// ```
44 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
45 /// use concrete_core::prelude::{
46 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
47 /// };
48 /// let bsk = StandardBootstrapKey::allocate(
49 /// 9u32,
50 /// GlweSize(7),
51 /// PolynomialSize(9),
52 /// DecompositionLevelCount(3),
53 /// DecompositionBaseLog(5),
54 /// LweDimension(4),
55 /// );
56 /// assert_eq!(bsk.polynomial_size(), PolynomialSize(9));
57 /// assert_eq!(bsk.glwe_size(), GlweSize(7));
58 /// assert_eq!(bsk.level_count(), DecompositionLevelCount(3));
59 /// assert_eq!(bsk.base_log(), DecompositionBaseLog(5));
60 /// assert_eq!(bsk.key_size(), LweDimension(4));
61 /// ```
62 pub fn allocate(
63 value: Scalar,
64 rlwe_size: GlweSize,
65 poly_size: PolynomialSize,
66 decomp_level: DecompositionLevelCount,
67 decomp_base_log: DecompositionBaseLog,
68 key_size: LweDimension,
69 ) -> StandardBootstrapKey<Vec<Scalar>>
70 where
71 Scalar: UnsignedTorus,
72 {
73 StandardBootstrapKey {
74 tensor: Tensor::from_container(vec![
75 value;
76 key_size.0
77 * decomp_level.0
78 * rlwe_size.0
79 * rlwe_size.0
80 * poly_size.0
81 ]),
82 decomp_level,
83 decomp_base_log,
84 rlwe_size,
85 poly_size,
86 }
87 }
88}
89
90impl<Cont> StandardBootstrapKey<Cont> {
91 /// Creates a bootstrapping key from an existing container of values.
92 ///
93 /// # Example
94 ///
95 /// ```
96 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
97 /// use concrete_core::prelude::{
98 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
99 /// };
100 /// let vector = vec![0u32; 10 * 5 * 4 * 4 * 15];
101 /// let bsk = StandardBootstrapKey::from_container(
102 /// vector.as_slice(),
103 /// GlweSize(4),
104 /// PolynomialSize(10),
105 /// DecompositionLevelCount(5),
106 /// DecompositionBaseLog(4),
107 /// );
108 /// assert_eq!(bsk.polynomial_size(), PolynomialSize(10));
109 /// assert_eq!(bsk.glwe_size(), GlweSize(4));
110 /// assert_eq!(bsk.level_count(), DecompositionLevelCount(5));
111 /// assert_eq!(bsk.base_log(), DecompositionBaseLog(4));
112 /// assert_eq!(bsk.key_size(), LweDimension(15));
113 /// ```
114 pub fn from_container<Coef>(
115 cont: Cont,
116 glwe_size: GlweSize,
117 poly_size: PolynomialSize,
118 decomp_level: DecompositionLevelCount,
119 decomp_base_log: DecompositionBaseLog,
120 ) -> StandardBootstrapKey<Cont>
121 where
122 Cont: AsRefSlice<Element = Coef>,
123 {
124 let tensor = Tensor::from_container(cont);
125 ck_dim_div!(tensor.len() =>
126 decomp_level.0,
127 glwe_size.0 * glwe_size.0,
128 poly_size.0
129 );
130 StandardBootstrapKey {
131 tensor,
132 rlwe_size: glwe_size,
133 poly_size,
134 decomp_level,
135 decomp_base_log,
136 }
137 }
138
139 pub fn into_container(self) -> Cont {
140 self.tensor.into_container()
141 }
142
143 pub fn as_view(&self) -> StandardBootstrapKey<&'_ [Cont::Element]>
144 where
145 Cont: Container,
146 {
147 StandardBootstrapKey {
148 tensor: Tensor::from_container(self.tensor.as_container().as_ref()),
149 rlwe_size: self.rlwe_size,
150 poly_size: self.poly_size,
151 decomp_level: self.decomp_level,
152 decomp_base_log: self.decomp_base_log,
153 }
154 }
155
156 pub fn as_mut_view(&mut self) -> StandardBootstrapKey<&'_ mut [Cont::Element]>
157 where
158 Cont: Container,
159 Cont: AsMut<[Cont::Element]>,
160 {
161 StandardBootstrapKey {
162 tensor: Tensor::from_container(self.tensor.as_mut_container().as_mut()),
163 rlwe_size: self.rlwe_size,
164 poly_size: self.poly_size,
165 decomp_level: self.decomp_level,
166 decomp_base_log: self.decomp_base_log,
167 }
168 }
169
170 /// Generate a new bootstrap key from the input parameters, and fills the current container
171 /// with it.
172 ///
173 /// # Example
174 ///
175 /// ```
176 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
177 /// use concrete_core::commons::crypto::secret::generators::{
178 /// EncryptionRandomGenerator, SecretRandomGenerator,
179 /// };
180 /// use concrete_core::commons::crypto::secret::{GlweSecretKey, LweSecretKey};
181 /// use concrete_core::prelude::{
182 /// DecompositionBaseLog, DecompositionLevelCount, GlweDimension, LogStandardDev, LweDimension,
183 /// PolynomialSize,
184 /// };
185 /// use concrete_csprng::generators::SoftwareRandomGenerator;
186 /// use concrete_csprng::seeders::{Seed, UnixSeeder};
187 /// let mut secret_generator = SecretRandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
188 /// let mut encryption_generator =
189 /// EncryptionRandomGenerator::<SoftwareRandomGenerator>::new(Seed(0), &mut UnixSeeder::new(0));
190 ///
191 /// let (lwe_dim, glwe_dim, poly_size) = (LweDimension(4), GlweDimension(6), PolynomialSize(9));
192 /// let (dec_lc, dec_bl) = (DecompositionLevelCount(3), DecompositionBaseLog(5));
193 /// let mut bsk = StandardBootstrapKey::allocate(
194 /// 9u32,
195 /// glwe_dim.to_glwe_size(),
196 /// poly_size,
197 /// dec_lc,
198 /// dec_bl,
199 /// lwe_dim,
200 /// );
201 /// let lwe_sk = LweSecretKey::generate_binary(lwe_dim, &mut secret_generator);
202 /// let glwe_sk = GlweSecretKey::generate_binary(glwe_dim, poly_size, &mut secret_generator);
203 /// bsk.fill_with_new_key(
204 /// &lwe_sk,
205 /// &glwe_sk,
206 /// LogStandardDev::from_log_standard_dev(-15.),
207 /// &mut encryption_generator,
208 /// );
209 /// ```
210 pub fn fill_with_new_key<LweCont, RlweCont, Scalar, Gen>(
211 &mut self,
212 lwe_secret_key: &LweSecretKey<BinaryKeyKind, LweCont>,
213 glwe_secret_key: &GlweSecretKey<BinaryKeyKind, RlweCont>,
214 noise_parameters: impl DispersionParameter,
215 generator: &mut EncryptionRandomGenerator<Gen>,
216 ) where
217 Self: AsMutTensor<Element = Scalar>,
218 LweSecretKey<BinaryKeyKind, LweCont>: AsRefTensor<Element = Scalar>,
219 GlweSecretKey<BinaryKeyKind, RlweCont>: AsRefTensor<Element = Scalar>,
220 Scalar: UnsignedTorus,
221 Gen: ByteRandomGenerator,
222 {
223 ck_dim_eq!(self.key_size().0 => lwe_secret_key.key_size().0);
224 self.as_mut_tensor()
225 .fill_with_element(<Scalar as Numeric>::ZERO);
226
227 let gen_iter = generator
228 .fork_bsk_to_ggsw::<Scalar>(
229 lwe_secret_key.key_size(),
230 self.decomp_level,
231 glwe_secret_key.key_size().to_glwe_size(),
232 self.poly_size,
233 )
234 .unwrap();
235
236 for zip_args!(mut rgsw, sk_scalar, mut generator) in zip!(
237 self.ggsw_iter_mut(),
238 lwe_secret_key.as_tensor().iter(),
239 gen_iter
240 ) {
241 let encoded = Plaintext(*sk_scalar);
242 glwe_secret_key.encrypt_constant_ggsw(
243 &mut rgsw,
244 &encoded,
245 noise_parameters,
246 &mut generator,
247 );
248 }
249 }
250
251 /// Generate a new bootstrap key from the input parameters, and fills the current container
252 /// with it, using all the available threads.
253 ///
254 /// # Note
255 ///
256 /// This method uses _rayon_ internally, and is hidden behind the "__commons_parallel" feature
257 /// gate.
258 ///
259 /// # Example
260 ///
261 /// ```
262 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
263 /// use concrete_core::commons::crypto::secret::generators::{
264 /// EncryptionRandomGenerator, SecretRandomGenerator,
265 /// };
266 /// use concrete_core::commons::crypto::secret::{GlweSecretKey, LweSecretKey};
267 /// use concrete_core::prelude::{
268 /// DecompositionBaseLog, DecompositionLevelCount, GlweDimension, LogStandardDev, LweDimension,
269 /// PolynomialSize,
270 /// };
271 /// use concrete_csprng::generators::SoftwareRandomGenerator;
272 /// use concrete_csprng::seeders::{Seed, UnixSeeder};
273 ///
274 /// let mut secret_generator = SecretRandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
275 /// let mut encryption_generator =
276 /// EncryptionRandomGenerator::<SoftwareRandomGenerator>::new(Seed(0), &mut UnixSeeder::new(0));
277 /// let (lwe_dim, glwe_dim, poly_size) = (LweDimension(4), GlweDimension(6), PolynomialSize(9));
278 /// let (dec_lc, dec_bl) = (DecompositionLevelCount(3), DecompositionBaseLog(5));
279 /// let mut bsk = StandardBootstrapKey::allocate(
280 /// 9u32,
281 /// glwe_dim.to_glwe_size(),
282 /// poly_size,
283 /// dec_lc,
284 /// dec_bl,
285 /// lwe_dim,
286 /// );
287 /// let lwe_sk = LweSecretKey::generate_binary(lwe_dim, &mut secret_generator);
288 /// let glwe_sk = GlweSecretKey::generate_binary(glwe_dim, poly_size, &mut secret_generator);
289 /// let mut secret_generator =
290 /// EncryptionRandomGenerator::<SoftwareRandomGenerator>::new(Seed(0), &mut UnixSeeder::new(0));
291 /// bsk.par_fill_with_new_key(
292 /// &lwe_sk,
293 /// &glwe_sk,
294 /// LogStandardDev::from_log_standard_dev(-15.),
295 /// &mut secret_generator,
296 /// );
297 /// ```
298 #[cfg(feature = "__commons_parallel")]
299 pub fn par_fill_with_new_key<LweCont, RlweCont, Scalar, Gen>(
300 &mut self,
301 lwe_secret_key: &LweSecretKey<BinaryKeyKind, LweCont>,
302 glwe_secret_key: &GlweSecretKey<BinaryKeyKind, RlweCont>,
303 noise_parameters: impl DispersionParameter + Sync + Send,
304 generator: &mut EncryptionRandomGenerator<Gen>,
305 ) where
306 Self: AsMutTensor<Element = Scalar>,
307 LweSecretKey<BinaryKeyKind, LweCont>: AsRefTensor<Element = Scalar>,
308 GlweSecretKey<BinaryKeyKind, RlweCont>: AsRefTensor<Element = Scalar>,
309 Scalar: UnsignedTorus + Sync + Send,
310 RlweCont: Sync,
311 Gen: ParallelByteRandomGenerator,
312 {
313 ck_dim_eq!(self.key_size().0 => lwe_secret_key.key_size().0);
314 self.as_mut_tensor()
315 .fill_with_element(<Scalar as Numeric>::ZERO);
316 let gen_iter = generator
317 .par_fork_bsk_to_ggsw::<Scalar>(
318 lwe_secret_key.key_size(),
319 self.decomp_level,
320 glwe_secret_key.key_size().to_glwe_size(),
321 self.poly_size,
322 )
323 .unwrap();
324 self.par_ggsw_iter_mut()
325 .zip(lwe_secret_key.as_tensor().par_iter())
326 .zip(gen_iter)
327 .for_each(|((mut rgsw, sk_scalar), mut generator)| {
328 let encoded = Plaintext(*sk_scalar);
329 glwe_secret_key.par_encrypt_constant_ggsw(
330 &mut rgsw,
331 &encoded,
332 noise_parameters,
333 &mut generator,
334 );
335 });
336 }
337
338 /// Generate a new bootstrap key from the input parameters, and fills the current container
339 /// with it.
340 ///
341 /// # Example
342 ///
343 /// ```
344 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
345 /// use concrete_core::commons::crypto::secret::generators::{
346 /// EncryptionRandomGenerator, SecretRandomGenerator,
347 /// };
348 /// use concrete_core::commons::crypto::secret::{GlweSecretKey, LweSecretKey};
349 /// use concrete_core::prelude::{
350 /// DecompositionBaseLog, DecompositionLevelCount, GlweDimension, LogStandardDev, LweDimension,
351 /// PolynomialSize,
352 /// };
353 /// use concrete_csprng::generators::SoftwareRandomGenerator;
354 /// use concrete_csprng::seeders::{Seed, UnixSeeder};
355 ///
356 /// let (lwe_dim, glwe_dim, poly_size) = (LweDimension(4), GlweDimension(6), PolynomialSize(9));
357 /// let (dec_lc, dec_bl) = (DecompositionLevelCount(3), DecompositionBaseLog(5));
358 /// let mut secret_generator = SecretRandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
359 /// let mut encryption_generator =
360 /// EncryptionRandomGenerator::<SoftwareRandomGenerator>::new(Seed(0), &mut UnixSeeder::new(0));
361 /// let mut bsk = StandardBootstrapKey::allocate(
362 /// 9u32,
363 /// glwe_dim.to_glwe_size(),
364 /// poly_size,
365 /// dec_lc,
366 /// dec_bl,
367 /// lwe_dim,
368 /// );
369 /// let lwe_sk = LweSecretKey::generate_binary(lwe_dim, &mut secret_generator);
370 /// let glwe_sk = GlweSecretKey::generate_binary(glwe_dim, poly_size, &mut secret_generator);
371 /// bsk.fill_with_new_trivial_key(
372 /// &lwe_sk,
373 /// &glwe_sk,
374 /// LogStandardDev::from_log_standard_dev(-15.),
375 /// &mut encryption_generator,
376 /// );
377 /// ```
378 pub fn fill_with_new_trivial_key<LweCont, RlweCont, Scalar, Gen>(
379 &mut self,
380 lwe_secret_key: &LweSecretKey<BinaryKeyKind, LweCont>,
381 rlwe_secret_key: &GlweSecretKey<BinaryKeyKind, RlweCont>,
382 noise_parameters: impl DispersionParameter,
383 generator: &mut EncryptionRandomGenerator<Gen>,
384 ) where
385 Self: AsMutTensor<Element = Scalar>,
386 LweSecretKey<BinaryKeyKind, LweCont>: AsRefTensor<Element = Scalar>,
387 GlweSecretKey<BinaryKeyKind, RlweCont>: AsRefTensor<Element = Scalar>,
388 Scalar: UnsignedTorus,
389 Gen: ByteRandomGenerator,
390 {
391 ck_dim_eq!(self.key_size().0 => lwe_secret_key.key_size().0);
392 for (mut rgsw, sk_scalar) in self.ggsw_iter_mut().zip(lwe_secret_key.as_tensor().iter()) {
393 let encoded = Plaintext(*sk_scalar);
394 rlwe_secret_key.trivial_encrypt_constant_ggsw(
395 &mut rgsw,
396 &encoded,
397 noise_parameters,
398 generator,
399 );
400 }
401 }
402
403 /// Returns the size of the polynomials used in the bootstrapping key.
404 ///
405 /// # Example
406 ///
407 /// ```
408 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
409 /// use concrete_core::prelude::{
410 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
411 /// };
412 /// let bsk = StandardBootstrapKey::allocate(
413 /// 9u32,
414 /// GlweSize(7),
415 /// PolynomialSize(9),
416 /// DecompositionLevelCount(3),
417 /// DecompositionBaseLog(5),
418 /// LweDimension(4),
419 /// );
420 /// assert_eq!(bsk.polynomial_size(), PolynomialSize(9));
421 /// ```
422 pub fn polynomial_size(&self) -> PolynomialSize {
423 self.poly_size
424 }
425
426 /// Returns the size of the GLWE ciphertexts used in the bootstrapping key.
427 ///
428 /// # Example
429 ///
430 /// ```
431 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
432 /// use concrete_core::prelude::{
433 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
434 /// };
435 /// let bsk = StandardBootstrapKey::allocate(
436 /// 9u32,
437 /// GlweSize(7),
438 /// PolynomialSize(9),
439 /// DecompositionLevelCount(3),
440 /// DecompositionBaseLog(5),
441 /// LweDimension(4),
442 /// );
443 /// assert_eq!(bsk.glwe_size(), GlweSize(7));
444 /// ```
445 pub fn glwe_size(&self) -> GlweSize {
446 self.rlwe_size
447 }
448
449 /// Returns the number of levels used to decompose the key bits.
450 ///
451 /// # Example
452 ///
453 /// ```
454 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
455 /// use concrete_core::prelude::{
456 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
457 /// };
458 /// let bsk = StandardBootstrapKey::allocate(
459 /// 9u32,
460 /// GlweSize(7),
461 /// PolynomialSize(9),
462 /// DecompositionLevelCount(3),
463 /// DecompositionBaseLog(5),
464 /// LweDimension(4),
465 /// );
466 /// assert_eq!(bsk.level_count(), DecompositionLevelCount(3));
467 /// ```
468 pub fn level_count(&self) -> DecompositionLevelCount {
469 self.decomp_level
470 }
471
472 /// Returns the logarithm of the base used to decompose the key bits.
473 ///
474 /// # Example
475 ///
476 /// ```
477 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
478 /// use concrete_core::prelude::{
479 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
480 /// };
481 /// let bsk = StandardBootstrapKey::allocate(
482 /// 9u32,
483 /// GlweSize(7),
484 /// PolynomialSize(9),
485 /// DecompositionLevelCount(3),
486 /// DecompositionBaseLog(5),
487 /// LweDimension(4),
488 /// );
489 /// assert_eq!(bsk.base_log(), DecompositionBaseLog(5));
490 /// ```
491 pub fn base_log(&self) -> DecompositionBaseLog {
492 self.decomp_base_log
493 }
494
495 /// Returns the size of the LWE encrypted key.
496 ///
497 /// # Example
498 ///
499 /// ```
500 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
501 /// use concrete_core::prelude::{
502 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
503 /// };
504 /// let bsk = StandardBootstrapKey::allocate(
505 /// 9u32,
506 /// GlweSize(7),
507 /// PolynomialSize(9),
508 /// DecompositionLevelCount(3),
509 /// DecompositionBaseLog(5),
510 /// LweDimension(4),
511 /// );
512 /// assert_eq!(bsk.key_size(), LweDimension(4));
513 /// ```
514 pub fn key_size(&self) -> LweDimension
515 where
516 Self: AsRefTensor,
517 {
518 ck_dim_div!(self.as_tensor().len() =>
519 self.poly_size.0,
520 self.rlwe_size.0 * self.rlwe_size.0,
521 self.decomp_level.0
522 );
523 LweDimension(
524 self.as_tensor().len()
525 / (self.rlwe_size.0 * self.rlwe_size.0 * self.poly_size.0 * self.decomp_level.0),
526 )
527 }
528
529 /// Returns an iterator over the borrowed GGSW ciphertext composing the key.
530 ///
531 /// # Example
532 ///
533 /// ```
534 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
535 /// use concrete_core::prelude::{
536 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
537 /// };
538 /// let bsk = StandardBootstrapKey::allocate(
539 /// 9u32,
540 /// GlweSize(7),
541 /// PolynomialSize(9),
542 /// DecompositionLevelCount(3),
543 /// DecompositionBaseLog(5),
544 /// LweDimension(4),
545 /// );
546 /// for ggsw in bsk.ggsw_iter() {
547 /// assert_eq!(ggsw.polynomial_size(), PolynomialSize(9));
548 /// assert_eq!(ggsw.glwe_size(), GlweSize(7));
549 /// assert_eq!(ggsw.decomposition_level_count(), DecompositionLevelCount(3));
550 /// }
551 /// assert_eq!(bsk.ggsw_iter().count(), 4);
552 /// ```
553 pub fn ggsw_iter(
554 &self,
555 ) -> impl Iterator<Item = StandardGgswCiphertext<&[<Self as AsRefTensor>::Element]>>
556 where
557 Self: AsRefTensor,
558 {
559 let chunks_size =
560 self.rlwe_size.0 * self.rlwe_size.0 * self.poly_size.0 * self.decomp_level.0;
561 let rlwe_size = self.rlwe_size;
562 let poly_size = self.poly_size;
563 let base_log = self.decomp_base_log;
564 self.as_tensor()
565 .subtensor_iter(chunks_size)
566 .map(move |tensor| {
567 StandardGgswCiphertext::from_container(
568 tensor.into_container(),
569 rlwe_size,
570 poly_size,
571 base_log,
572 )
573 })
574 }
575
576 /// Returns a parallel iterator over the mutably borrowed GGSW ciphertext composing the
577 /// key.
578 ///
579 /// # Notes
580 ///
581 /// This iterator is hidden behind the "__commons_parallel" feature gate.
582 ///
583 /// # Example
584 ///
585 /// ```
586 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
587 /// use concrete_core::commons::math::tensor::{AsMutTensor, AsRefTensor};
588 /// use concrete_core::prelude::{
589 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
590 /// };
591 /// use rayon::iter::ParallelIterator;
592 /// let mut bsk = StandardBootstrapKey::allocate(
593 /// 9u32,
594 /// GlweSize(7),
595 /// PolynomialSize(9),
596 /// DecompositionLevelCount(3),
597 /// DecompositionBaseLog(5),
598 /// LweDimension(4),
599 /// );
600 /// bsk.par_ggsw_iter_mut().for_each(|mut ggsw| {
601 /// ggsw.as_mut_tensor().fill_with_element(0);
602 /// });
603 /// assert!(bsk.as_tensor().iter().all(|a| *a == 0));
604 /// assert_eq!(bsk.ggsw_iter_mut().count(), 4);
605 /// ```
606 #[cfg(feature = "__commons_parallel")]
607 pub fn par_ggsw_iter_mut(
608 &mut self,
609 ) -> impl IndexedParallelIterator<Item = StandardGgswCiphertext<&mut [<Self as AsRefTensor>::Element]>>
610 where
611 Self: AsMutTensor,
612 <Self as AsRefTensor>::Element: Sync + Send,
613 {
614 let chunks_size =
615 self.rlwe_size.0 * self.rlwe_size.0 * self.poly_size.0 * self.decomp_level.0;
616 let rlwe_size = self.rlwe_size;
617 let poly_size = self.poly_size;
618 let base_log = self.decomp_base_log;
619
620 self.as_mut_tensor()
621 .par_subtensor_iter_mut(chunks_size)
622 .map(move |tensor| {
623 StandardGgswCiphertext::from_container(
624 tensor.into_container(),
625 rlwe_size,
626 poly_size,
627 base_log,
628 )
629 })
630 }
631
632 /// Returns an iterator over the mutably borrowed GGSW ciphertext composing the key.
633 ///
634 /// # Example
635 ///
636 /// ```
637 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
638 /// use concrete_core::commons::math::tensor::{AsMutTensor, AsRefTensor};
639 /// use concrete_core::prelude::{
640 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
641 /// };
642 /// let mut bsk = StandardBootstrapKey::allocate(
643 /// 9u32,
644 /// GlweSize(7),
645 /// PolynomialSize(9),
646 /// DecompositionLevelCount(3),
647 /// DecompositionBaseLog(5),
648 /// LweDimension(4),
649 /// );
650 /// for mut ggsw in bsk.ggsw_iter_mut() {
651 /// ggsw.as_mut_tensor().fill_with_element(0);
652 /// }
653 /// assert!(bsk.as_tensor().iter().all(|a| *a == 0));
654 /// assert_eq!(bsk.ggsw_iter_mut().count(), 4);
655 /// ```
656 pub fn ggsw_iter_mut(
657 &mut self,
658 ) -> impl Iterator<Item = StandardGgswCiphertext<&mut [<Self as AsRefTensor>::Element]>>
659 where
660 Self: AsMutTensor,
661 {
662 let chunks_size =
663 self.rlwe_size.0 * self.rlwe_size.0 * self.poly_size.0 * self.decomp_level.0;
664 let rlwe_size = self.rlwe_size;
665 let poly_size = self.poly_size;
666 let base_log = self.decomp_base_log;
667 self.as_mut_tensor()
668 .subtensor_iter_mut(chunks_size)
669 .map(move |tensor| {
670 StandardGgswCiphertext::from_container(
671 tensor.into_container(),
672 rlwe_size,
673 poly_size,
674 base_log,
675 )
676 })
677 }
678
679 /// Returns an iterator over borrowed polynomials composing the key.
680 ///
681 /// # Example
682 ///
683 /// ```
684 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
685 /// use concrete_core::commons::math::tensor::{AsMutTensor, AsRefTensor};
686 /// use concrete_core::prelude::{
687 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
688 /// };
689 /// let bsk = StandardBootstrapKey::allocate(
690 /// 9u32,
691 /// GlweSize(7),
692 /// PolynomialSize(256),
693 /// DecompositionLevelCount(3),
694 /// DecompositionBaseLog(5),
695 /// LweDimension(4),
696 /// );
697 /// for poly in bsk.poly_iter() {
698 /// assert_eq!(poly.polynomial_size(), PolynomialSize(256));
699 /// }
700 /// assert_eq!(bsk.poly_iter().count(), 7 * 7 * 3 * 4)
701 /// ```
702 pub fn poly_iter(&self) -> impl Iterator<Item = Polynomial<&[<Self as AsRefTensor>::Element]>>
703 where
704 Self: AsRefTensor,
705 <Self as AsRefTensor>::Element: UnsignedTorus,
706 {
707 let poly_size = self.poly_size.0;
708 self.as_tensor()
709 .subtensor_iter(poly_size)
710 .map(|chunk| Polynomial::from_container(chunk.into_container()))
711 }
712
713 /// Returns an iterator over mutably borrowed polynomials composing the key.
714 ///
715 /// # Example
716 ///
717 /// ```
718 /// use concrete_core::commons::crypto::bootstrap::StandardBootstrapKey;
719 /// use concrete_core::commons::math::tensor::{AsMutTensor, AsRefTensor};
720 /// use concrete_core::prelude::{
721 /// DecompositionBaseLog, DecompositionLevelCount, GlweSize, LweDimension, PolynomialSize,
722 /// };
723 /// let mut bsk = StandardBootstrapKey::allocate(
724 /// 9u32,
725 /// GlweSize(7),
726 /// PolynomialSize(256),
727 /// DecompositionLevelCount(3),
728 /// DecompositionBaseLog(5),
729 /// LweDimension(4),
730 /// );
731 /// for mut poly in bsk.poly_iter_mut() {
732 /// poly.as_mut_tensor().fill_with_element(0u32);
733 /// }
734 /// assert!(bsk.as_tensor().iter().all(|a| *a == 0));
735 /// assert_eq!(bsk.poly_iter_mut().count(), 7 * 7 * 3 * 4)
736 /// ```
737 pub fn poly_iter_mut(
738 &mut self,
739 ) -> impl Iterator<Item = Polynomial<&mut [<Self as AsMutTensor>::Element]>>
740 where
741 Self: AsMutTensor,
742 <Self as AsMutTensor>::Element: UnsignedTorus,
743 {
744 let poly_size = self.poly_size.0;
745 self.as_mut_tensor()
746 .subtensor_iter_mut(poly_size)
747 .map(|chunk| Polynomial::from_container(chunk.into_container()))
748 }
749}