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}