concrete-core 1.0.2

Concrete is a fully homomorphic encryption (FHE) library that implements Zama's variant of TFHE.
Documentation
use super::GlweCiphertext;
use crate::commons::crypto::encoding::PlaintextList;
use crate::commons::math::tensor::{
    ck_dim_div, tensor_traits, AsMutTensor, AsRefSlice, AsRefTensor, Tensor,
};
use crate::commons::numeric::Numeric;
use crate::prelude::{CiphertextCount, GlweDimension, GlweSize, PlaintextCount, PolynomialSize};
#[cfg(feature = "__commons_serialization")]
use serde::{Deserialize, Serialize};

/// A list of ciphertexts encoded with the GLWE scheme.
#[cfg_attr(feature = "__commons_serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GlweList<Cont> {
    pub(crate) tensor: Tensor<Cont>,
    pub(crate) rlwe_size: GlweSize,
    pub(crate) poly_size: PolynomialSize,
}

tensor_traits!(GlweList);

impl<Scalar> GlweList<Vec<Scalar>>
where
    Scalar: Copy,
{
    /// Allocates storage for an owned [`GlweList`].
    ///
    /// # Example
    ///
    /// ```rust
    /// use concrete_core::commons::crypto::glwe::GlweList;
    /// use concrete_core::prelude::{CiphertextCount, GlweDimension, GlweSize, PolynomialSize};
    /// let list = GlweList::allocate(
    ///     0 as u8,
    ///     PolynomialSize(10),
    ///     GlweDimension(20),
    ///     CiphertextCount(30),
    /// );
    /// assert_eq!(list.ciphertext_count(), CiphertextCount(30));
    /// assert_eq!(list.polynomial_size(), PolynomialSize(10));
    /// assert_eq!(list.glwe_size(), GlweSize(21));
    /// assert_eq!(list.glwe_dimension(), GlweDimension(20));
    /// ```
    pub fn allocate(
        value: Scalar,
        poly_size: PolynomialSize,
        glwe_dimension: GlweDimension,
        ciphertext_number: CiphertextCount,
    ) -> Self {
        GlweList {
            tensor: Tensor::from_container(vec![
                value;
                poly_size.0
                    * (glwe_dimension.0 + 1)
                    * ciphertext_number.0
            ]),
            rlwe_size: GlweSize(glwe_dimension.0 + 1),
            poly_size,
        }
    }
}

impl<Cont> GlweList<Cont> {
    /// Creates a list from a container of values.
    ///
    /// ```rust
    /// use concrete_core::commons::crypto::glwe::GlweList;
    /// use concrete_core::prelude::{CiphertextCount, GlweDimension, GlweSize, PolynomialSize};
    /// let list = GlweList::from_container(
    ///     vec![0 as u8; 10 * 21 * 30],
    ///     GlweDimension(20),
    ///     PolynomialSize(10),
    /// );
    /// assert_eq!(list.ciphertext_count(), CiphertextCount(30));
    /// assert_eq!(list.polynomial_size(), PolynomialSize(10));
    /// assert_eq!(list.glwe_size(), GlweSize(21));
    /// assert_eq!(list.glwe_dimension(), GlweDimension(20));
    /// ```
    pub fn from_container(
        cont: Cont,
        rlwe_dimension: GlweDimension,
        poly_size: PolynomialSize,
    ) -> Self
    where
        Cont: AsRefSlice,
    {
        let tensor = Tensor::from_container(cont);
        ck_dim_div!(tensor.len() => rlwe_dimension.0 + 1, poly_size.0);
        GlweList {
            tensor,
            rlwe_size: GlweSize(rlwe_dimension.0 + 1),
            poly_size,
        }
    }

    /// Returns the number of ciphertexts in the list.
    ///
    /// # Example
    ///
    /// ```rust
    /// use concrete_core::commons::crypto::glwe::GlweList;
    /// use concrete_core::prelude::{CiphertextCount, GlweDimension, PolynomialSize};
    /// let list = GlweList::allocate(
    ///     0 as u8,
    ///     PolynomialSize(10),
    ///     GlweDimension(20),
    ///     CiphertextCount(30),
    /// );
    /// assert_eq!(list.ciphertext_count(), CiphertextCount(30));
    /// ```
    pub fn ciphertext_count(&self) -> CiphertextCount
    where
        Self: AsRefTensor,
    {
        ck_dim_div!(self.as_tensor().len() => self.rlwe_size.0, self.poly_size.0);
        CiphertextCount(self.as_tensor().len() / (self.rlwe_size.0 * self.polynomial_size().0))
    }

    /// Returns the size of the glwe ciphertexts contained in the list.
    ///
    /// # Example
    ///
    /// ```rust
    /// use concrete_core::commons::crypto::glwe::GlweList;
    /// use concrete_core::prelude::{CiphertextCount, GlweDimension, GlweSize, PolynomialSize};
    /// let list = GlweList::allocate(
    ///     0 as u8,
    ///     PolynomialSize(10),
    ///     GlweDimension(20),
    ///     CiphertextCount(30),
    /// );
    /// assert_eq!(list.glwe_size(), GlweSize(21));
    /// ```
    pub fn glwe_size(&self) -> GlweSize
    where
        Self: AsRefTensor,
    {
        self.rlwe_size
    }

    /// Returns the number of coefficients of the polynomials used for the list ciphertexts.
    ///
    /// # Example
    ///
    /// ```rust
    /// use concrete_core::commons::crypto::glwe::GlweList;
    /// use concrete_core::prelude::{CiphertextCount, GlweDimension, PolynomialSize};
    /// let list = GlweList::allocate(
    ///     0 as u8,
    ///     PolynomialSize(10),
    ///     GlweDimension(20),
    ///     CiphertextCount(30),
    /// );
    /// assert_eq!(list.polynomial_size(), PolynomialSize(10));
    /// ```
    pub fn polynomial_size(&self) -> PolynomialSize {
        self.poly_size
    }

    /// Returns the number of masks of the ciphertexts in the list.
    ///
    /// # Example
    ///
    /// ```rust
    /// use concrete_core::commons::crypto::glwe::GlweList;
    /// use concrete_core::prelude::{CiphertextCount, GlweDimension, PolynomialSize};
    /// let list = GlweList::allocate(
    ///     0 as u8,
    ///     PolynomialSize(10),
    ///     GlweDimension(20),
    ///     CiphertextCount(30),
    /// );
    /// assert_eq!(list.glwe_dimension(), GlweDimension(20));
    /// ```
    pub fn glwe_dimension(&self) -> GlweDimension
    where
        Self: AsRefTensor,
    {
        GlweDimension(self.rlwe_size.0 - 1)
    }

    /// Returns an iterator over ciphertexts borrowed from the list.
    ///
    /// # Example
    ///
    /// ```rust
    /// use concrete_core::commons::crypto::glwe::{GlweBody, GlweList};
    /// use concrete_core::commons::math::tensor::AsRefTensor;
    /// use concrete_core::prelude::{CiphertextCount, GlweDimension, PolynomialSize};
    /// let list = GlweList::allocate(
    ///     0 as u8,
    ///     PolynomialSize(10),
    ///     GlweDimension(20),
    ///     CiphertextCount(30),
    /// );
    /// for ciphertext in list.ciphertext_iter() {
    ///     let (body, masks) = ciphertext.get_body_and_mask();
    ///     assert_eq!(body.as_polynomial().polynomial_size(), PolynomialSize(10));
    /// }
    /// assert_eq!(list.ciphertext_iter().count(), 30);
    /// ```
    pub fn ciphertext_iter(
        &self,
    ) -> impl Iterator<Item = GlweCiphertext<&[<Self as AsRefTensor>::Element]>>
    where
        Self: AsRefTensor,
    {
        ck_dim_div!(self.as_tensor().len() => self.rlwe_size.0, self.poly_size.0);
        let poly_size = self.poly_size;
        let size = self.rlwe_size.0 * self.polynomial_size().0;
        self.as_tensor()
            .subtensor_iter(size)
            .map(move |sub| GlweCiphertext::from_container(sub.into_container(), poly_size))
    }

    /// Returns an iterator over ciphertexts borrowed from the list.
    ///
    /// # Example
    ///
    /// ```rust
    /// use concrete_core::commons::crypto::glwe::{GlweBody, GlweList};
    /// use concrete_core::commons::math::tensor::{AsMutTensor, AsRefTensor};
    /// use concrete_core::prelude::{CiphertextCount, GlweDimension, PolynomialSize};
    /// let mut list = GlweList::allocate(
    ///     0 as u8,
    ///     PolynomialSize(10),
    ///     GlweDimension(20),
    ///     CiphertextCount(30),
    /// );
    /// for mut ciphertext in list.ciphertext_iter_mut() {
    ///     let mut body = ciphertext.get_mut_body();
    ///     body.as_mut_tensor().fill_with_element(9);
    /// }
    /// for ciphertext in list.ciphertext_iter() {
    ///     let body = ciphertext.get_body();
    ///     assert!(body.as_tensor().iter().all(|a| *a == 9));
    /// }
    /// assert_eq!(list.ciphertext_iter_mut().count(), 30);
    /// ```
    pub fn ciphertext_iter_mut(
        &mut self,
    ) -> impl Iterator<Item = GlweCiphertext<&mut [<Self as AsMutTensor>::Element]>>
    where
        Self: AsMutTensor,
    {
        ck_dim_div!(self.as_tensor().len() => self.rlwe_size.0, self.poly_size.0);
        let poly_size = self.poly_size;
        let chunks_size = self.rlwe_size.0 * self.polynomial_size().0;
        self.as_mut_tensor()
            .subtensor_iter_mut(chunks_size)
            .map(move |sub| GlweCiphertext::from_container(sub.into_container(), poly_size))
    }

    pub fn fill_with_trivial_encryption<PlaintextContainer, Scalar>(
        &mut self,
        plaintexts: &PlaintextList<PlaintextContainer>,
    ) where
        PlaintextList<PlaintextContainer>: AsRefTensor<Element = Scalar>,
        for<'a> PlaintextList<&'a [Scalar]>: AsRefTensor<Element = Scalar>,
        Self: AsMutTensor<Element = Scalar>,
        Scalar: Numeric,
    {
        debug_assert_eq!(
            plaintexts.count().0,
            self.poly_size.0 * self.ciphertext_count().0
        );
        let plaintext_count = PlaintextCount(self.poly_size.0);
        for (mut ciphertext, plaintext) in self
            .ciphertext_iter_mut()
            .zip(plaintexts.sublist_iter(plaintext_count))
        {
            ciphertext.fill_with_trivial_encryption(&plaintext);
        }
    }
}