use tfhe_versionable::Versionize;
use crate::core_crypto::backward_compatibility::entities::ggsw_ciphertext::GgswCiphertextVersions;
use crate::core_crypto::commons::generators::EncryptionRandomGeneratorForkConfig;
use crate::core_crypto::commons::math::random::{Distribution, RandomGenerable};
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Versionize)]
#[versionize(GgswCiphertextVersions)]
pub struct GgswCiphertext<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
decomp_base_log: DecompositionBaseLog,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for GgswCiphertext<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for GgswCiphertext<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
}
pub fn ggsw_ciphertext_size(
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
decomp_level_count: DecompositionLevelCount,
) -> usize {
decomp_level_count.0 * ggsw_level_matrix_size(glwe_size, polynomial_size)
}
pub fn ggsw_level_matrix_size(glwe_size: GlweSize, polynomial_size: PolynomialSize) -> usize {
glwe_size.0 * glwe_size.0 * polynomial_size.0
}
pub fn fourier_ggsw_ciphertext_size(
glwe_size: GlweSize,
fourier_polynomial_size: FourierPolynomialSize,
decomp_level_count: DecompositionLevelCount,
) -> usize {
decomp_level_count.0 * fourier_ggsw_level_matrix_size(glwe_size, fourier_polynomial_size)
}
pub fn fourier_ggsw_level_matrix_size(
glwe_size: GlweSize,
fourier_polynomial_size: FourierPolynomialSize,
) -> usize {
glwe_size.0 * glwe_size.0 * fourier_polynomial_size.0
}
pub fn ggsw_ciphertext_encryption_mask_sample_count(
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
decomp_level_count: DecompositionLevelCount,
) -> EncryptionMaskSampleCount {
decomp_level_count.0
* ggsw_level_matrix_encryption_mask_sample_count(glwe_size, polynomial_size)
}
pub fn ggsw_level_matrix_encryption_mask_sample_count(
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
) -> EncryptionMaskSampleCount {
glwe_size.0
* glwe_ciphertext_encryption_mask_sample_count(
glwe_size.to_glwe_dimension(),
polynomial_size,
)
}
pub fn ggsw_ciphertext_encryption_noise_sample_count(
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
decomp_level_count: DecompositionLevelCount,
) -> EncryptionNoiseSampleCount {
decomp_level_count.0
* ggsw_level_matrix_encryption_noise_sample_count(glwe_size, polynomial_size)
}
pub fn ggsw_level_matrix_encryption_noise_sample_count(
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
) -> EncryptionNoiseSampleCount {
glwe_size.0 * glwe_ciphertext_encryption_noise_sample_count(polynomial_size)
}
pub fn ggsw_ciphertext_encryption_fork_config<Scalar, MaskDistribution, NoiseDistribution>(
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
decomposition_level_count: DecompositionLevelCount,
mask_distribution: MaskDistribution,
noise_distribution: NoiseDistribution,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> EncryptionRandomGeneratorForkConfig
where
Scalar: UnsignedInteger
+ RandomGenerable<MaskDistribution, CustomModulus = Scalar>
+ RandomGenerable<NoiseDistribution, CustomModulus = Scalar>,
MaskDistribution: Distribution,
NoiseDistribution: Distribution,
{
let ggsw_level_matrix_mask_sample_count =
ggsw_level_matrix_encryption_mask_sample_count(glwe_size, polynomial_size);
let ggsw_level_matrix_noise_sample_count =
ggsw_level_matrix_encryption_noise_sample_count(glwe_size, polynomial_size);
let modulus = ciphertext_modulus.get_custom_modulus_as_optional_scalar();
EncryptionRandomGeneratorForkConfig::new(
decomposition_level_count.0,
ggsw_level_matrix_mask_sample_count,
mask_distribution,
ggsw_level_matrix_noise_sample_count,
noise_distribution,
modulus,
)
}
pub fn ggsw_level_matrix_encryption_fork_config<Scalar, MaskDistribution, NoiseDistribution>(
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
mask_distribution: MaskDistribution,
noise_distribution: NoiseDistribution,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> EncryptionRandomGeneratorForkConfig
where
Scalar: UnsignedInteger
+ RandomGenerable<MaskDistribution, CustomModulus = Scalar>
+ RandomGenerable<NoiseDistribution, CustomModulus = Scalar>,
MaskDistribution: Distribution,
NoiseDistribution: Distribution,
{
let glwe_ciphertext_mask_sample_count = glwe_ciphertext_encryption_mask_sample_count(
glwe_size.to_glwe_dimension(),
polynomial_size,
);
let glwe_ciphertext_noise_sample_count =
glwe_ciphertext_encryption_noise_sample_count(polynomial_size);
let modulus = ciphertext_modulus.get_custom_modulus_as_optional_scalar();
EncryptionRandomGeneratorForkConfig::new(
glwe_size.0,
glwe_ciphertext_mask_sample_count,
mask_distribution,
glwe_ciphertext_noise_sample_count,
noise_distribution,
modulus,
)
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> GgswCiphertext<C> {
pub fn from_container(
container: C,
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
decomp_base_log: DecompositionBaseLog,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> Self {
assert!(
container.container_len() > 0,
"Got an empty container to create a GgswCiphertext"
);
assert!(
container
.container_len()
.is_multiple_of(glwe_size.0 * glwe_size.0 * polynomial_size.0),
"The provided container length is not valid. \
It needs to be dividable by glwe_size * glwe_size * polynomial_size: {}. \
Got container length: {} and glwe_size: {glwe_size:?}, \
polynomial_size: {polynomial_size:?}.",
glwe_size.0 * glwe_size.0 * polynomial_size.0,
container.container_len()
);
Self {
data: container,
glwe_size,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
}
}
pub fn polynomial_size(&self) -> PolynomialSize {
self.polynomial_size
}
pub fn glwe_size(&self) -> GlweSize {
self.glwe_size
}
pub fn decomposition_base_log(&self) -> DecompositionBaseLog {
self.decomp_base_log
}
pub fn decomposition_level_count(&self) -> DecompositionLevelCount {
DecompositionLevelCount(self.data.container_len() / self.ggsw_level_matrix_size())
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
pub fn ggsw_level_matrix_size(&self) -> usize {
ggsw_level_matrix_size(self.glwe_size, self.polynomial_size)
}
pub fn as_polynomial_list(&self) -> PolynomialListView<'_, Scalar> {
PolynomialListView::from_container(self.as_ref(), self.polynomial_size)
}
pub fn as_glwe_list(&self) -> GlweCiphertextListView<'_, Scalar> {
GlweCiphertextListView::from_container(
self.as_ref(),
self.glwe_size,
self.polynomial_size,
self.ciphertext_modulus,
)
}
pub fn as_view(&self) -> GgswCiphertextView<'_, Scalar> {
GgswCiphertextView::from_container(
self.as_ref(),
self.glwe_size(),
self.polynomial_size(),
self.decomposition_base_log(),
self.ciphertext_modulus(),
)
}
pub fn into_container(self) -> C {
self.data
}
pub fn encryption_fork_config<MaskDistribution, NoiseDistribution>(
&self,
mask_distribution: MaskDistribution,
noise_distribution: NoiseDistribution,
) -> EncryptionRandomGeneratorForkConfig
where
MaskDistribution: Distribution,
NoiseDistribution: Distribution,
Scalar: RandomGenerable<MaskDistribution, CustomModulus = Scalar>
+ RandomGenerable<NoiseDistribution, CustomModulus = Scalar>,
{
ggsw_ciphertext_encryption_fork_config(
self.glwe_size(),
self.polynomial_size(),
self.decomposition_level_count(),
mask_distribution,
noise_distribution,
self.ciphertext_modulus(),
)
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> GgswCiphertext<C> {
pub fn as_mut_polynomial_list(&mut self) -> PolynomialListMutView<'_, Scalar> {
let polynomial_size = self.polynomial_size;
PolynomialListMutView::from_container(self.as_mut(), polynomial_size)
}
pub fn as_mut_glwe_list(&mut self) -> GlweCiphertextListMutView<'_, Scalar> {
let polynomial_size = self.polynomial_size;
let glwe_size = self.glwe_size;
let ciphertext_modulus = self.ciphertext_modulus;
GlweCiphertextListMutView::from_container(
self.as_mut(),
glwe_size,
polynomial_size,
ciphertext_modulus,
)
}
pub fn as_mut_view(&mut self) -> GgswCiphertextMutView<'_, Scalar> {
let glwe_size = self.glwe_size();
let polynomial_size = self.polynomial_size();
let decomp_base_log = self.decomposition_base_log();
let ciphertext_modulus = self.ciphertext_modulus;
GgswCiphertextMutView::from_container(
self.as_mut(),
glwe_size,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
)
}
}
pub type GgswCiphertextOwned<Scalar> = GgswCiphertext<Vec<Scalar>>;
pub type GgswCiphertextView<'data, Scalar> = GgswCiphertext<&'data [Scalar]>;
pub type GgswCiphertextMutView<'data, Scalar> = GgswCiphertext<&'data mut [Scalar]>;
impl<Scalar: UnsignedInteger> GgswCiphertextOwned<Scalar> {
pub fn new(
fill_with: Scalar,
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> Self {
Self::from_container(
vec![fill_with; ggsw_ciphertext_size(glwe_size, polynomial_size, decomp_level_count)],
glwe_size,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
)
}
}
#[derive(Clone, Copy)]
pub struct GgswCiphertextCreationMetadata<Scalar: UnsignedInteger> {
pub glwe_size: GlweSize,
pub polynomial_size: PolynomialSize,
pub decomp_base_log: DecompositionBaseLog,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> CreateFrom<C> for GgswCiphertext<C> {
type Metadata = GgswCiphertextCreationMetadata<Scalar>;
#[inline]
fn create_from(from: C, meta: Self::Metadata) -> Self {
let GgswCiphertextCreationMetadata {
glwe_size,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
} = meta;
Self::from_container(
from,
glwe_size,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
)
}
}
pub struct GgswLevelMatrix<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> GgswLevelMatrix<C> {
pub fn from_container(
container: C,
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> Self {
assert!(
container.container_len() == ggsw_level_matrix_size(glwe_size, polynomial_size),
"The provided container length is not valid. \
Expected length of {} (glwe_size * glwe_size * polynomial_size), got {}",
ggsw_level_matrix_size(glwe_size, polynomial_size),
container.container_len(),
);
Self {
data: container,
glwe_size,
polynomial_size,
ciphertext_modulus,
}
}
pub fn glwe_size(&self) -> GlweSize {
self.glwe_size
}
pub fn polynomial_size(&self) -> PolynomialSize {
self.polynomial_size
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
pub fn as_glwe_list(&self) -> GlweCiphertextListView<'_, C::Element> {
GlweCiphertextListView::from_container(
self.data.as_ref(),
self.glwe_size,
self.polynomial_size,
self.ciphertext_modulus,
)
}
pub fn encryption_fork_config<MaskDistribution, NoiseDistribution>(
&self,
mask_distribution: MaskDistribution,
noise_distribution: NoiseDistribution,
) -> EncryptionRandomGeneratorForkConfig
where
MaskDistribution: Distribution,
NoiseDistribution: Distribution,
Scalar: RandomGenerable<MaskDistribution, CustomModulus = Scalar>
+ RandomGenerable<NoiseDistribution, CustomModulus = Scalar>,
{
ggsw_level_matrix_encryption_fork_config(
self.glwe_size(),
self.polynomial_size(),
mask_distribution,
noise_distribution,
self.ciphertext_modulus(),
)
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> GgswLevelMatrix<C> {
pub fn as_mut_glwe_list(&mut self) -> GlweCiphertextListMutView<'_, C::Element> {
GlweCiphertextListMutView::from_container(
self.data.as_mut(),
self.glwe_size,
self.polynomial_size,
self.ciphertext_modulus,
)
}
}
#[derive(Clone, Copy)]
pub struct GgswLevelMatrixCreationMetadata<Scalar: UnsignedInteger> {
pub glwe_size: GlweSize,
pub polynomial_size: PolynomialSize,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> CreateFrom<C> for GgswLevelMatrix<C> {
type Metadata = GgswLevelMatrixCreationMetadata<C::Element>;
#[inline]
fn create_from(from: C, meta: Self::Metadata) -> Self {
let GgswLevelMatrixCreationMetadata {
glwe_size,
polynomial_size,
ciphertext_modulus,
} = meta;
Self::from_container(from, glwe_size, polynomial_size, ciphertext_modulus)
}
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> ContiguousEntityContainer
for GgswCiphertext<C>
{
type Element = C::Element;
type EntityViewMetadata = GgswLevelMatrixCreationMetadata<Self::Element>;
type EntityView<'this>
= GgswLevelMatrix<&'this [Self::Element]>
where
Self: 'this;
type SelfViewMetadata = ();
type SelfView<'this>
= DummyCreateFrom
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) -> Self::EntityViewMetadata {
GgswLevelMatrixCreationMetadata {
glwe_size: self.glwe_size,
polynomial_size: self.polynomial_size,
ciphertext_modulus: self.ciphertext_modulus,
}
}
fn get_entity_view_pod_size(&self) -> usize {
self.ggsw_level_matrix_size()
}
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {
unimplemented!(
"This function is not supported for GgswCiphertext. \
At the moment it does not make sense to return 'sub' GgswCiphertext."
)
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> ContiguousEntityContainerMut
for GgswCiphertext<C>
{
type EntityMutView<'this>
= GgswLevelMatrix<&'this mut [Self::Element]>
where
Self: 'this;
type SelfMutView<'this>
= DummyCreateFrom
where
Self: 'this;
}