use crate::conformance::ParameterSetConformant;
use tfhe_versionable::Versionize;
use crate::core_crypto::backward_compatibility::entities::glwe_ciphertext::GlweCiphertextVersions;
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
use crate::core_crypto::prelude::misc::check_encrypted_content_respects_mod;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GlweBody<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> GlweBody<C> {
pub fn from_container(container: C, ciphertext_modulus: CiphertextModulus<C::Element>) -> Self {
assert!(
container.container_len() > 0,
"Got an empty container to create a GlweBody"
);
Self {
data: container,
ciphertext_modulus,
}
}
pub fn polynomial_size(&self) -> PolynomialSize {
PolynomialSize(self.data.container_len())
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
pub fn as_polynomial(&self) -> PolynomialView<'_, C::Element> {
PolynomialView::from_container(self.as_ref())
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> GlweBody<C> {
pub fn as_mut_polynomial(&mut self) -> PolynomialMutView<'_, C::Element> {
PolynomialMutView::from_container(self.as_mut())
}
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> CreateFrom<C> for GlweBody<C> {
type Metadata = GlweCiphertextCreationMetadata<C::Element>;
#[inline]
fn create_from(from: C, meta: Self::Metadata) -> Self {
let GlweCiphertextCreationMetadata {
polynomial_size: _,
ciphertext_modulus,
} = meta;
Self::from_container(from, ciphertext_modulus)
}
}
#[derive(Clone, Debug)]
#[allow(dead_code)]
pub struct GlweMask<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
polynomial_size: PolynomialSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> GlweMask<C> {
pub fn from_container(
container: C,
polynomial_size: PolynomialSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> Self {
assert!(
container.container_len().is_multiple_of(polynomial_size.0),
"The provided container length is not valid. \
It needs to be dividable by polynomial_size. \
Got container length: {} and polynomial_size: {polynomial_size:?}.",
container.container_len()
);
Self {
data: container,
polynomial_size,
ciphertext_modulus,
}
}
pub fn glwe_dimension(&self) -> GlweDimension {
GlweDimension(self.data.container_len() / self.polynomial_size.0)
}
pub fn polynomial_size(&self) -> PolynomialSize {
self.polynomial_size
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
pub fn as_polynomial_list(&self) -> PolynomialListView<'_, C::Element> {
PolynomialListView::from_container(self.as_ref(), self.polynomial_size)
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> GlweMask<C> {
pub fn as_mut_polynomial_list(&mut self) -> PolynomialListMutView<'_, C::Element> {
let polynomial_size = self.polynomial_size;
PolynomialListMutView::from_container(self.as_mut(), polynomial_size)
}
}
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for GlweMask<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for GlweMask<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
}
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for GlweBody<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for GlweBody<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
}
pub fn glwe_ciphertext_size(glwe_size: GlweSize, polynomial_size: PolynomialSize) -> usize {
glwe_size.0 * polynomial_size.0
}
pub fn glwe_mask_size(glwe_dim: GlweDimension, polynomial_size: PolynomialSize) -> usize {
glwe_dim.0 * polynomial_size.0
}
pub fn glwe_ciphertext_mask_size(
glwe_dimension: GlweDimension,
polynomial_size: PolynomialSize,
) -> usize {
glwe_dimension
.to_equivalent_lwe_dimension(polynomial_size)
.0
}
pub fn glwe_ciphertext_encryption_mask_sample_count(
glwe_dimension: GlweDimension,
polynomial_size: PolynomialSize,
) -> EncryptionMaskSampleCount {
EncryptionMaskSampleCount(glwe_ciphertext_mask_size(glwe_dimension, polynomial_size))
}
pub fn glwe_ciphertext_encryption_noise_sample_count(
polynomial_size: PolynomialSize,
) -> EncryptionNoiseSampleCount {
EncryptionNoiseSampleCount(polynomial_size.0)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Versionize)]
#[versionize(GlweCiphertextVersions)]
pub struct GlweCiphertext<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
polynomial_size: PolynomialSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for GlweCiphertext<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for GlweCiphertext<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> GlweCiphertext<C> {
pub fn from_container(
container: C,
polynomial_size: PolynomialSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> Self {
assert!(
container.container_len() > 0,
"Got an empty container to create a GlweCiphertext"
);
assert!(
container.container_len().is_multiple_of(polynomial_size.0),
"The provided container length is not valid. \
It needs to be dividable by polynomial_size. \
Got container length: {} and polynomial_size: {polynomial_size:?}.",
container.container_len()
);
Self {
data: container,
polynomial_size,
ciphertext_modulus,
}
}
pub fn glwe_size(&self) -> GlweSize {
GlweSize(self.as_ref().container_len() / self.polynomial_size.0)
}
pub fn polynomial_size(&self) -> PolynomialSize {
self.polynomial_size
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
pub fn get_mask_and_body(&self) -> (GlweMask<&[Scalar]>, GlweBody<&[Scalar]>) {
let (mask, body) = self.data.as_ref().split_at(glwe_ciphertext_mask_size(
self.glwe_size().to_glwe_dimension(),
self.polynomial_size,
));
(
GlweMask::from_container(mask, self.polynomial_size, self.ciphertext_modulus),
GlweBody::from_container(body, self.ciphertext_modulus),
)
}
pub fn get_body(&self) -> GlweBody<&[Scalar]> {
let body = &self.data.as_ref()[glwe_ciphertext_mask_size(
self.glwe_size().to_glwe_dimension(),
self.polynomial_size,
)..];
GlweBody::from_container(body, self.ciphertext_modulus)
}
pub fn get_mask(&self) -> GlweMask<&[Scalar]> {
GlweMask::from_container(
&self.as_ref()[0..glwe_ciphertext_mask_size(
self.glwe_size().to_glwe_dimension(),
self.polynomial_size,
)],
self.polynomial_size,
self.ciphertext_modulus,
)
}
pub fn as_polynomial_list(&self) -> PolynomialList<&'_ [Scalar]> {
PolynomialList::from_container(self.as_ref(), self.polynomial_size)
}
pub fn as_view(&self) -> GlweCiphertext<&'_ [Scalar]> {
GlweCiphertext {
data: self.data.as_ref(),
polynomial_size: self.polynomial_size,
ciphertext_modulus: self.ciphertext_modulus,
}
}
pub fn into_container(self) -> C {
self.data
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> GlweCiphertext<C> {
pub fn get_mut_mask_and_body(&mut self) -> (GlweMask<&mut [Scalar]>, GlweBody<&mut [Scalar]>) {
let glwe_dimension = self.glwe_size().to_glwe_dimension();
let polynomial_size = self.polynomial_size();
let ciphertext_modulus = self.ciphertext_modulus();
let (mask, body) = self
.data
.as_mut()
.split_at_mut(glwe_ciphertext_mask_size(glwe_dimension, polynomial_size));
(
GlweMask::from_container(mask, polynomial_size, ciphertext_modulus),
GlweBody::from_container(body, ciphertext_modulus),
)
}
pub fn get_mut_body(&mut self) -> GlweBody<&mut [Scalar]> {
let glwe_dimension = self.glwe_size().to_glwe_dimension();
let polynomial_size = self.polynomial_size();
let ciphertext_modulus = self.ciphertext_modulus();
let body =
&mut self.data.as_mut()[glwe_ciphertext_mask_size(glwe_dimension, polynomial_size)..];
GlweBody::from_container(body, ciphertext_modulus)
}
pub fn get_mut_mask(&mut self) -> GlweMask<&mut [Scalar]> {
let polynomial_size = self.polynomial_size();
let glwe_dimension = self.glwe_size().to_glwe_dimension();
let ciphertext_modulus = self.ciphertext_modulus();
GlweMask::from_container(
&mut self.as_mut()[0..glwe_ciphertext_mask_size(glwe_dimension, polynomial_size)],
polynomial_size,
ciphertext_modulus,
)
}
pub fn as_mut_polynomial_list(&mut self) -> PolynomialList<&'_ mut [Scalar]> {
let polynomial_size = self.polynomial_size;
PolynomialList::from_container(self.as_mut(), polynomial_size)
}
pub fn as_mut_view(&mut self) -> GlweCiphertext<&'_ mut [Scalar]> {
GlweCiphertext {
data: self.data.as_mut(),
polynomial_size: self.polynomial_size,
ciphertext_modulus: self.ciphertext_modulus,
}
}
}
pub type GlweCiphertextOwned<Scalar> = GlweCiphertext<Vec<Scalar>>;
pub type GlweCiphertextView<'data, Scalar> = GlweCiphertext<&'data [Scalar]>;
pub type GlweCiphertextMutView<'data, Scalar> = GlweCiphertext<&'data mut [Scalar]>;
impl<Scalar: UnsignedInteger> GlweCiphertextOwned<Scalar> {
pub fn new(
fill_with: Scalar,
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> Self {
Self::from_container(
vec![fill_with; glwe_ciphertext_size(glwe_size, polynomial_size)],
polynomial_size,
ciphertext_modulus,
)
}
}
#[derive(Clone, Copy)]
pub struct GlweCiphertextCreationMetadata<Scalar: UnsignedInteger> {
pub polynomial_size: PolynomialSize,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> CreateFrom<C> for GlweCiphertext<C> {
type Metadata = GlweCiphertextCreationMetadata<Scalar>;
#[inline]
fn create_from(from: C, meta: Self::Metadata) -> Self {
let GlweCiphertextCreationMetadata {
polynomial_size,
ciphertext_modulus,
} = meta;
Self::from_container(from, polynomial_size, ciphertext_modulus)
}
}
#[derive(Copy, Clone)]
pub struct GlweCiphertextConformanceParams<T: UnsignedInteger> {
pub glwe_dim: GlweDimension,
pub polynomial_size: PolynomialSize,
pub ct_modulus: CiphertextModulus<T>,
}
impl<C: Container> ParameterSetConformant for GlweCiphertext<C>
where
C::Element: UnsignedInteger,
{
type ParameterSet = GlweCiphertextConformanceParams<C::Element>;
fn is_conformant(
&self,
glwe_ct_parameters: &GlweCiphertextConformanceParams<C::Element>,
) -> bool {
let Self {
data,
polynomial_size,
ciphertext_modulus,
} = self;
polynomial_size.0.is_power_of_two()
&& check_encrypted_content_respects_mod(self, glwe_ct_parameters.ct_modulus)
&& data.container_len()
== glwe_ciphertext_size(
glwe_ct_parameters.glwe_dim.to_glwe_size(),
glwe_ct_parameters.polynomial_size,
)
&& *polynomial_size == glwe_ct_parameters.polynomial_size
&& *ciphertext_modulus == glwe_ct_parameters.ct_modulus
}
}