chore: use dedicated types for compressed modswitched conformance

This commit is contained in:
Nicolas Sarlin
2025-11-27 14:35:20 +01:00
committed by Nicolas Sarlin
parent dac999b279
commit f9c2a5d423
24 changed files with 527 additions and 119 deletions

View File

@@ -46,7 +46,7 @@ impl_destroy_on_type!(CompressedFheBool);
impl_clone_on_type!(CompressedFheBool);
impl_serialize_deserialize_on_type!(CompressedFheBool);
impl_safe_serialize_on_type!(CompressedFheBool);
impl_safe_deserialize_conformant_on_type!(CompressedFheBool, FheBoolConformanceParams);
impl_safe_deserialize_conformant_on_type!(CompressedFheBool, CompressedFheBoolConformanceParams);
impl_try_encrypt_with_client_key_on_type!(CompressedFheBool{crate::high_level_api::CompressedFheBool}, bool);
#[no_mangle]

View File

@@ -359,7 +359,7 @@ macro_rules! create_integer_wrapper_type {
impl_safe_serialize_on_type!([<Compressed $name>]);
impl_safe_deserialize_conformant_on_type!([<Compressed $name>], [<$name ConformanceParams>]);
impl_safe_deserialize_conformant_on_type!([<Compressed $name>], [<Compressed $name ConformanceParams>]);
#[no_mangle]
pub unsafe extern "C" fn [<compressed_ $name:snake _decompress>](

View File

@@ -135,17 +135,45 @@ impl<PackingScalar: UnsignedInteger> CompressedModulusSwitchedLweCiphertext<Pack
}
}
#[derive(Copy, Clone)]
pub enum MsDecompressionType {
ClassicPbs,
MultiBitPbs(LweBskGroupingFactor),
}
#[derive(Copy, Clone)]
pub struct CompressedModulusSwitchedLweCiphertextConformanceParams<Scalar>
where
Scalar: UnsignedInteger,
{
pub ct_params: LweCiphertextConformanceParams<Scalar>,
pub ms_decompression_type: MsDecompressionType,
}
impl<Scalar: UnsignedInteger> ParameterSetConformant
for CompressedModulusSwitchedLweCiphertext<Scalar>
{
type ParameterSet = LweCiphertextConformanceParams<Scalar>;
type ParameterSet = CompressedModulusSwitchedLweCiphertextConformanceParams<Scalar>;
fn is_conformant(&self, lwe_ct_parameters: &LweCiphertextConformanceParams<Scalar>) -> bool {
fn is_conformant(
&self,
compressed_ct_parameters: &CompressedModulusSwitchedLweCiphertextConformanceParams<Scalar>,
) -> bool {
let Self {
packed_integers,
lwe_dimension,
} = self;
let CompressedModulusSwitchedLweCiphertextConformanceParams {
ct_params,
ms_decompression_type,
} = compressed_ct_parameters;
let LweCiphertextConformanceParams {
lwe_dim: params_lwe_dim,
ct_modulus,
} = ct_params;
let lwe_size = lwe_dimension.to_lwe_size().0;
let number_bits_to_pack = lwe_size * packed_integers.log_modulus().0;
@@ -153,12 +181,9 @@ impl<Scalar: UnsignedInteger> ParameterSetConformant
let len = number_bits_to_pack.div_ceil(Scalar::BITS);
packed_integers.packed_coeffs().len() == len
&& *lwe_dimension == lwe_ct_parameters.lwe_dim
&& lwe_ct_parameters.ct_modulus.is_power_of_two()
&& matches!(
lwe_ct_parameters.ms_decompression_method,
MsDecompressionType::ClassicPbs
)
&& lwe_dimension == params_lwe_dim
&& ct_modulus.is_power_of_two()
&& matches!(ms_decompression_type, MsDecompressionType::ClassicPbs)
}
}

View File

@@ -511,9 +511,12 @@ impl MultiBitModulusSwitchedLweCiphertext for FromCompressionMultiBitModulusSwit
impl<Scalar: UnsignedInteger + CastInto<usize> + CastFrom<usize>> ParameterSetConformant
for CompressedModulusSwitchedMultiBitLweCiphertext<Scalar>
{
type ParameterSet = LweCiphertextConformanceParams<Scalar>;
type ParameterSet = CompressedModulusSwitchedLweCiphertextConformanceParams<Scalar>;
fn is_conformant(&self, lwe_ct_parameters: &LweCiphertextConformanceParams<Scalar>) -> bool {
fn is_conformant(
&self,
compressed_ct_parameters: &CompressedModulusSwitchedLweCiphertextConformanceParams<Scalar>,
) -> bool {
let Self {
body,
packed_mask,
@@ -523,22 +526,30 @@ impl<Scalar: UnsignedInteger + CastInto<usize> + CastFrom<usize>> ParameterSetCo
grouping_factor,
} = self;
let lwe_dim = lwe_dimension.0;
let CompressedModulusSwitchedLweCiphertextConformanceParams {
ct_params,
ms_decompression_type,
} = compressed_ct_parameters;
let LweCiphertextConformanceParams {
lwe_dim: params_lwe_dim,
ct_modulus,
} = ct_params;
*body >> packed_mask.log_modulus().0 == Scalar::ZERO
&& packed_mask.is_conformant(&lwe_dim)
&& packed_mask.is_conformant(&lwe_dimension.0)
&& packed_diffs
.as_ref()
.is_none_or(|packed_diffs| packed_diffs.is_conformant(&lwe_dim))
&& *lwe_dimension == lwe_ct_parameters.lwe_dim
&& lwe_ct_parameters.ct_modulus.is_power_of_two()
&& match lwe_ct_parameters.ms_decompression_method {
.is_none_or(|packed_diffs| packed_diffs.is_conformant(&lwe_dimension.0))
&& lwe_dimension == params_lwe_dim
&& ct_modulus.is_power_of_two()
&& match ms_decompression_type {
MsDecompressionType::ClassicPbs => false,
MsDecompressionType::MultiBitPbs(expected_grouping_factor) => {
expected_grouping_factor.0 == grouping_factor.0
}
}
&& *uncompressed_ciphertext_modulus == lwe_ct_parameters.ct_modulus
&& uncompressed_ciphertext_modulus == ct_modulus
}
}

View File

@@ -753,13 +753,6 @@ pub type LweCiphertextMutView<'data, Scalar> = LweCiphertext<&'data mut [Scalar]
pub struct LweCiphertextConformanceParams<T: UnsignedInteger> {
pub lwe_dim: LweDimension,
pub ct_modulus: CiphertextModulus<T>,
pub ms_decompression_method: MsDecompressionType,
}
#[derive(Copy, Clone)]
pub enum MsDecompressionType {
ClassicPbs,
MultiBitPbs(LweBskGroupingFactor),
}
impl<C: Container> ParameterSetConformant for LweCiphertext<C>
@@ -777,9 +770,14 @@ where
ciphertext_modulus,
} = self;
check_encrypted_content_respects_mod(data, lwe_ct_parameters.ct_modulus)
&& self.lwe_size() == lwe_ct_parameters.lwe_dim.to_lwe_size()
&& *ciphertext_modulus == lwe_ct_parameters.ct_modulus
let LweCiphertextConformanceParams {
lwe_dim,
ct_modulus,
} = lwe_ct_parameters;
check_encrypted_content_respects_mod(data, *ct_modulus)
&& self.lwe_size() == lwe_dim.to_lwe_size()
&& ciphertext_modulus == ct_modulus
}
}

View File

@@ -9,9 +9,12 @@ use crate::high_level_api::traits::Tagged;
use crate::integer::BooleanBlock;
use crate::named::Named;
use crate::prelude::FheTryEncrypt;
use crate::shortint::ciphertext::{CompressedModulusSwitchedCiphertext, Degree};
use crate::shortint::CompressedCiphertext;
use crate::{ClientKey, FheBool, FheBoolConformanceParams, Tag};
use crate::shortint::ciphertext::{
CompressedModulusSwitchedCiphertext, CompressedModulusSwitchedCiphertextConformanceParams,
Degree,
};
use crate::shortint::{AtomicPatternParameters, CompressedCiphertext};
use crate::{ClientKey, FheBool, ServerKey, Tag};
use serde::{Deserialize, Serialize};
use tfhe_versionable::Versionize;
@@ -111,12 +114,38 @@ impl FheTryEncrypt<bool, ClientKey> for CompressedFheBool {
}
}
impl ParameterSetConformant for CompressedFheBool {
type ParameterSet = FheBoolConformanceParams;
#[derive(Copy, Clone)]
pub struct CompressedFheBoolConformanceParams(
pub(crate) CompressedModulusSwitchedCiphertextConformanceParams,
);
fn is_conformant(&self, params: &FheBoolConformanceParams) -> bool {
impl<P: Into<AtomicPatternParameters>> From<P> for CompressedFheBoolConformanceParams {
fn from(params: P) -> Self {
let mut params = params.into().to_compressed_modswitched_conformance_param();
params.degree = crate::shortint::ciphertext::Degree::new(1);
Self(params)
}
}
impl From<&ServerKey> for CompressedFheBoolConformanceParams {
fn from(sk: &ServerKey) -> Self {
let mut parameter_set = Self(
sk.key
.pbs_key()
.key
.compressed_modswitched_conformance_params(),
);
parameter_set.0.degree = crate::shortint::ciphertext::Degree::new(1);
parameter_set
}
}
impl ParameterSetConformant for CompressedFheBool {
type ParameterSet = CompressedFheBoolConformanceParams;
fn is_conformant(&self, params: &CompressedFheBoolConformanceParams) -> bool {
match &self.inner {
InnerCompressedFheBool::Seeded(seeded) => seeded.is_conformant(&params.0),
InnerCompressedFheBool::Seeded(seeded) => seeded.is_conformant(&params.0.into()),
InnerCompressedFheBool::ModulusSwitched(ct) => ct.is_conformant(&params.0),
}
}

View File

@@ -1,5 +1,5 @@
pub use base::{FheBool, FheBoolConformanceParams};
pub use compressed::CompressedFheBool;
pub use compressed::{CompressedFheBool, CompressedFheBoolConformanceParams};
pub use squashed_noise::SquashedNoiseFheBool;
pub(in crate::high_level_api) use compressed::InnerCompressedFheBool;

View File

@@ -318,6 +318,7 @@ fn compressed_bool_test_case(setup_fn: impl FnOnce() -> (ClientKey, Device)) {
mod cpu {
use super::*;
use crate::high_level_api::booleans::compressed::CompressedFheBoolConformanceParams;
use crate::safe_serialization::{DeserializationConfig, SerializationConfig};
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
use crate::FheBoolConformanceParams;
@@ -707,12 +708,14 @@ mod cpu {
.serialize_into(&a, &mut serialized)
.unwrap();
let params = FheBoolConformanceParams::from(&server_key);
let params = CompressedFheBoolConformanceParams::from(&server_key);
let deserialized_a = DeserializationConfig::new(1 << 20)
.deserialize_from::<CompressedFheBool>(serialized.as_slice(), &params)
.unwrap();
assert!(deserialized_a.is_conformant(&FheBoolConformanceParams::from(block_params)));
assert!(
deserialized_a.is_conformant(&CompressedFheBoolConformanceParams::from(block_params))
);
let decrypted: bool = deserialized_a.decompress().decrypt(&keys);
assert_eq!(decrypted, clear_a);

View File

@@ -1,3 +1,5 @@
use std::marker::PhantomData;
use tfhe_versionable::Versionize;
use crate::backward_compatibility::integers::{
@@ -6,20 +8,20 @@ use crate::backward_compatibility::integers::{
use crate::conformance::ParameterSetConformant;
use crate::core_crypto::prelude::SignedNumeric;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::signed::base::FheIntConformanceParams;
use crate::high_level_api::integers::{FheInt, FheIntId};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::traits::Tagged;
use crate::integer::block_decomposition::DecomposableInto;
use crate::integer::ciphertext::{
CompressedModulusSwitchedRadixCiphertextConformanceParams,
CompressedModulusSwitchedSignedRadixCiphertext,
CompressedSignedRadixCiphertext as IntegerCompressedSignedRadixCiphertext,
};
use crate::integer::parameters::RadixCiphertextConformanceParams;
use crate::named::Named;
use crate::prelude::FheTryEncrypt;
use crate::{ClientKey, Tag};
use crate::shortint::AtomicPatternParameters;
use crate::{ClientKey, ServerKey, Tag};
/// Compressed [FheInt]
///
@@ -153,10 +155,51 @@ where
}
}
impl<Id: FheIntId> ParameterSetConformant for CompressedFheInt<Id> {
type ParameterSet = FheIntConformanceParams<Id>;
#[derive(Copy, Clone)]
pub struct CompressedFheIntConformanceParams<Id: FheIntId> {
pub(crate) params: CompressedSignedRadixCiphertextConformanceParams,
pub(crate) id: PhantomData<Id>,
}
fn is_conformant(&self, params: &FheIntConformanceParams<Id>) -> bool {
impl<Id: FheIntId, P: Into<AtomicPatternParameters>> From<P>
for CompressedFheIntConformanceParams<Id>
{
fn from(params: P) -> Self {
let params = params.into();
Self {
params: CompressedSignedRadixCiphertextConformanceParams(
CompressedModulusSwitchedRadixCiphertextConformanceParams {
shortint_params: params.to_compressed_modswitched_conformance_param(),
num_blocks_per_integer: Id::num_blocks(params.message_modulus()),
},
),
id: PhantomData,
}
}
}
impl<Id: FheIntId> From<&ServerKey> for CompressedFheIntConformanceParams<Id> {
fn from(sk: &ServerKey) -> Self {
Self {
params: CompressedSignedRadixCiphertextConformanceParams(
CompressedModulusSwitchedRadixCiphertextConformanceParams {
shortint_params: sk
.key
.pbs_key()
.key
.compressed_modswitched_conformance_params(),
num_blocks_per_integer: Id::num_blocks(sk.key.pbs_key().message_modulus()),
},
),
id: PhantomData,
}
}
}
impl<Id: FheIntId> ParameterSetConformant for CompressedFheInt<Id> {
type ParameterSet = CompressedFheIntConformanceParams<Id>;
fn is_conformant(&self, params: &CompressedFheIntConformanceParams<Id>) -> bool {
let Self {
ciphertext,
id: _,
@@ -178,12 +221,17 @@ pub enum CompressedSignedRadixCiphertext {
ModulusSwitched(CompressedModulusSwitchedSignedRadixCiphertext),
}
#[derive(Copy, Clone)]
pub struct CompressedSignedRadixCiphertextConformanceParams(
pub(crate) CompressedModulusSwitchedRadixCiphertextConformanceParams,
);
impl ParameterSetConformant for CompressedSignedRadixCiphertext {
type ParameterSet = RadixCiphertextConformanceParams;
fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool {
type ParameterSet = CompressedSignedRadixCiphertextConformanceParams;
fn is_conformant(&self, params: &CompressedSignedRadixCiphertextConformanceParams) -> bool {
match self {
Self::Seeded(ct) => ct.is_conformant(params),
Self::ModulusSwitched(ct) => ct.is_conformant(params),
Self::Seeded(ct) => ct.is_conformant(&params.0.into()),
Self::ModulusSwitched(ct) => ct.is_conformant(&params.0),
}
}
}

View File

@@ -1,5 +1,7 @@
use crate::high_level_api::integers::signed::base::{FheInt, FheIntConformanceParams, FheIntId};
use crate::high_level_api::integers::signed::compressed::CompressedFheInt;
use crate::high_level_api::integers::signed::compressed::{
CompressedFheInt, CompressedFheIntConformanceParams,
};
use crate::high_level_api::{FheId, IntegerId};
use serde::{Deserialize, Serialize};
use tfhe_versionable::NotVersioned;
@@ -52,6 +54,7 @@ macro_rules! static_int_type {
// Conformance Params
pub type [<FheInt $num_bits ConformanceParams>] = FheIntConformanceParams<[<FheInt $num_bits Id>]>;
pub type [<CompressedFheInt $num_bits ConformanceParams>] = CompressedFheIntConformanceParams<[<FheInt $num_bits Id>]>;
}
};
}

View File

@@ -13,8 +13,8 @@ use crate::shortint::parameters::test_params::{
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
use crate::{
generate_keys, set_server_key, CompactCiphertextList, CompactPublicKey, CompressedFheInt16,
CompressedFheInt32, ConfigBuilder, DeserializationConfig, FheInt256, FheInt32,
FheInt32ConformanceParams, FheInt8, SerializationConfig,
CompressedFheInt32, CompressedFheInt32ConformanceParams, ConfigBuilder, DeserializationConfig,
FheInt256, FheInt32, FheInt32ConformanceParams, FheInt8, SerializationConfig,
};
use rand::{random, thread_rng, Rng};
@@ -242,12 +242,12 @@ fn test_safe_deserialize_conformant_compressed_fhe_int32() {
.serialize_into(&a, &mut serialized)
.unwrap();
let params = FheInt32ConformanceParams::from(&server_key);
let params = CompressedFheInt32ConformanceParams::from(&server_key);
let deserialized_a = DeserializationConfig::new(1 << 20)
.deserialize_from::<CompressedFheInt32>(serialized.as_slice(), &params)
.unwrap();
let params = FheInt32ConformanceParams::from(block_params);
let params = CompressedFheInt32ConformanceParams::from(block_params);
assert!(deserialized_a.is_conformant(&params));
let decrypted: i32 = deserialized_a.decompress().decrypt(&client_key);

View File

@@ -1,3 +1,5 @@
use std::marker::PhantomData;
use tfhe_versionable::Versionize;
use crate::backward_compatibility::integers::{
@@ -5,9 +7,7 @@ use crate::backward_compatibility::integers::{
};
use crate::conformance::ParameterSetConformant;
use crate::core_crypto::prelude::UnsignedNumeric;
use crate::high_level_api::integers::unsigned::base::{
FheUint, FheUintConformanceParams, FheUintId,
};
use crate::high_level_api::integers::unsigned::base::{FheUint, FheUintId};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::traits::{FheTryEncrypt, Tagged};
@@ -15,11 +15,12 @@ use crate::high_level_api::{global_state, ClientKey};
use crate::integer::block_decomposition::DecomposableInto;
use crate::integer::ciphertext::{
CompressedModulusSwitchedRadixCiphertext,
CompressedModulusSwitchedRadixCiphertextConformanceParams,
CompressedRadixCiphertext as IntegerCompressedRadixCiphertext,
};
use crate::integer::parameters::RadixCiphertextConformanceParams;
use crate::named::Named;
use crate::Tag;
use crate::shortint::AtomicPatternParameters;
use crate::{ServerKey, Tag};
/// Compressed [FheUint]
///
@@ -151,10 +152,51 @@ where
}
}
impl<Id: FheUintId> ParameterSetConformant for CompressedFheUint<Id> {
type ParameterSet = FheUintConformanceParams<Id>;
#[derive(Copy, Clone)]
pub struct CompressedFheUintConformanceParams<Id: FheUintId> {
pub(crate) params: CompressedRadixCiphertextConformanceParams,
pub(crate) id: PhantomData<Id>,
}
fn is_conformant(&self, params: &FheUintConformanceParams<Id>) -> bool {
impl<Id: FheUintId, P: Into<AtomicPatternParameters>> From<P>
for CompressedFheUintConformanceParams<Id>
{
fn from(params: P) -> Self {
let params = params.into();
Self {
params: CompressedRadixCiphertextConformanceParams(
CompressedModulusSwitchedRadixCiphertextConformanceParams {
shortint_params: params.to_compressed_modswitched_conformance_param(),
num_blocks_per_integer: Id::num_blocks(params.message_modulus()),
},
),
id: PhantomData,
}
}
}
impl<Id: FheUintId> From<&ServerKey> for CompressedFheUintConformanceParams<Id> {
fn from(sk: &ServerKey) -> Self {
Self {
params: CompressedRadixCiphertextConformanceParams(
CompressedModulusSwitchedRadixCiphertextConformanceParams {
shortint_params: sk
.key
.pbs_key()
.key
.compressed_modswitched_conformance_params(),
num_blocks_per_integer: Id::num_blocks(sk.key.pbs_key().message_modulus()),
},
),
id: PhantomData,
}
}
}
impl<Id: FheUintId> ParameterSetConformant for CompressedFheUint<Id> {
type ParameterSet = CompressedFheUintConformanceParams<Id>;
fn is_conformant(&self, params: &CompressedFheUintConformanceParams<Id>) -> bool {
let Self {
ciphertext,
id: _,
@@ -176,12 +218,17 @@ pub enum CompressedRadixCiphertext {
ModulusSwitched(CompressedModulusSwitchedRadixCiphertext),
}
#[derive(Copy, Clone)]
pub struct CompressedRadixCiphertextConformanceParams(
pub(crate) CompressedModulusSwitchedRadixCiphertextConformanceParams,
);
impl ParameterSetConformant for CompressedRadixCiphertext {
type ParameterSet = RadixCiphertextConformanceParams;
fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool {
type ParameterSet = CompressedRadixCiphertextConformanceParams;
fn is_conformant(&self, params: &CompressedRadixCiphertextConformanceParams) -> bool {
match self {
Self::Seeded(ct) => ct.is_conformant(params),
Self::ModulusSwitched(ct) => ct.is_conformant(params),
Self::Seeded(ct) => ct.is_conformant(&params.0.into()),
Self::ModulusSwitched(ct) => ct.is_conformant(&params.0),
}
}
}
@@ -267,7 +314,7 @@ mod test {
let ct = CompressedFheUint8::try_encrypt(0_u64, &client_key).unwrap();
assert!(ct.is_conformant(&FheUintConformanceParams::from(
assert!(ct.is_conformant(&CompressedFheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
)));
@@ -291,9 +338,11 @@ mod test {
breaker(i, &mut ct_clone);
assert!(!ct_clone.is_conformant(&FheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
)));
assert!(
!ct_clone.is_conformant(&CompressedFheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
))
);
}
}
}
@@ -322,9 +371,11 @@ mod test {
breaker(i, &mut ct_clone);
assert!(!ct_clone.is_conformant(&FheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
)));
assert!(
!ct_clone.is_conformant(&CompressedFheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
))
);
}
}
}
@@ -339,7 +390,7 @@ mod test {
let ct = CompressedFheUint8::try_encrypt(0_u64, &client_key).unwrap();
assert!(ct.is_conformant(&FheUintConformanceParams::from(
assert!(ct.is_conformant(&CompressedFheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
)));
@@ -359,9 +410,11 @@ mod test {
.seed
.0 = rng.gen::<u128>();
}
assert!(ct_clone.is_conformant(&FheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
)));
assert!(
ct_clone.is_conformant(&CompressedFheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
))
);
let mut ct_clone_decompressed = ct_clone.decompress();

View File

@@ -1,7 +1,9 @@
use crate::high_level_api::integers::unsigned::base::{
FheUint, FheUintConformanceParams, FheUintId,
};
use crate::high_level_api::integers::unsigned::compressed::CompressedFheUint;
use crate::high_level_api::integers::unsigned::compressed::{
CompressedFheUint, CompressedFheUintConformanceParams,
};
use crate::high_level_api::integers::{FheId, IntegerId};
use serde::{Deserialize, Serialize};
use tfhe_versionable::NotVersioned;
@@ -56,6 +58,7 @@ macro_rules! static_int_type {
// Conformance Params
pub type [<FheUint $num_bits ConformanceParams>] = FheUintConformanceParams<[<FheUint $num_bits Id>]>;
pub type [<CompressedFheUint $num_bits ConformanceParams>] = CompressedFheUintConformanceParams<[<FheUint $num_bits Id>]>;
}
};
}

View File

@@ -9,8 +9,8 @@ use crate::shortint::parameters::*;
use crate::{
ClientKey, CompactCiphertextList, CompactCiphertextListConformanceParams, CompactPublicKey,
CompressedCompactPublicKey, CompressedFheUint16, CompressedFheUint256, CompressedFheUint32,
CompressedPublicKey, CompressedServerKey, FheInt16, FheInt32, FheInt8, FheUint128, FheUint16,
FheUint256, FheUint32, FheUint32ConformanceParams,
CompressedFheUint32ConformanceParams, CompressedPublicKey, CompressedServerKey, FheInt16,
FheInt32, FheInt8, FheUint128, FheUint16, FheUint256, FheUint32, FheUint32ConformanceParams,
};
use rand::prelude::*;
@@ -506,12 +506,12 @@ fn test_safe_deserialize_conformant_compressed_fhe_uint32() {
.serialize_into(&a, &mut serialized)
.unwrap();
let params = FheUint32ConformanceParams::from(&server_key);
let params = CompressedFheUint32ConformanceParams::from(&server_key);
let deserialized_a = DeserializationConfig::new(1 << 20)
.deserialize_from::<CompressedFheUint32>(serialized.as_slice(), &params)
.unwrap();
assert!(deserialized_a.is_conformant(&FheUint32ConformanceParams::from(block_params)));
assert!(deserialized_a.is_conformant(&CompressedFheUint32ConformanceParams::from(block_params)));
let decrypted: u32 = deserialized_a.decompress().decrypt(&client_key);
assert_eq!(decrypted, clear_a);

View File

@@ -18,9 +18,9 @@ use crate::shortint::parameters::{
use crate::{
set_server_key, ClientKey, CompactCiphertextList, CompactCiphertextListConformanceParams,
CompactPublicKey, CompressedCompactPublicKey, CompressedFheUint16, CompressedFheUint256,
CompressedFheUint32, ConfigBuilder, DeserializationConfig, FheBool, FheInt16, FheInt32,
FheInt8, FheUint128, FheUint16, FheUint256, FheUint32, FheUint32ConformanceParams, FheUint8,
GpuIndex, MatchValues, SerializationConfig,
CompressedFheUint32, CompressedFheUint32ConformanceParams, ConfigBuilder,
DeserializationConfig, FheBool, FheInt16, FheInt32, FheInt8, FheUint128, FheUint16, FheUint256,
FheUint32, FheUint32ConformanceParams, FheUint8, GpuIndex, MatchValues, SerializationConfig,
};
use rand::{random, Rng};
@@ -554,9 +554,11 @@ fn test_safe_deserialize_conformant_compressed_fhe_uint32_gpu() {
.unwrap();
let params = if i == 0 {
FheUint32ConformanceParams::from(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128)
CompressedFheUint32ConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
)
} else if i == 1 {
FheUint32ConformanceParams::from(
CompressedFheUint32ConformanceParams::from(
PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
)
} else {

View File

@@ -17,6 +17,7 @@ macro_rules! expand_pub_use_fhe_type(
// ConformanceParams
[<$fhe_type_name ConformanceParams>],
[<Compressed $fhe_type_name ConformanceParams>],
)*
};
}
@@ -74,7 +75,8 @@ use strum::FromRepr;
mod tests;
pub use crate::high_level_api::booleans::{
CompressedFheBool, FheBool, FheBoolConformanceParams, SquashedNoiseFheBool,
CompressedFheBool, CompressedFheBoolConformanceParams, FheBool, FheBoolConformanceParams,
SquashedNoiseFheBool,
};
#[cfg(feature = "extended-types")]

View File

@@ -7,7 +7,10 @@ use crate::integer::backward_compatibility::ciphertext::{
CompressedModulusSwitchedSignedRadixCiphertextVersions,
};
use crate::integer::parameters::RadixCiphertextConformanceParams;
use crate::shortint::ciphertext::{CompressedModulusSwitchedCiphertext, MaxDegree};
use crate::shortint::ciphertext::{
CompressedModulusSwitchedCiphertext, CompressedModulusSwitchedCiphertextConformanceParams,
MaxDegree,
};
use crate::shortint::parameters::Degree;
/// An object to store a ciphertext using less memory.
@@ -44,9 +47,12 @@ pub struct CompressedModulusSwitchedRadixCiphertext(
);
impl ParameterSetConformant for CompressedModulusSwitchedRadixCiphertext {
type ParameterSet = RadixCiphertextConformanceParams;
type ParameterSet = CompressedModulusSwitchedRadixCiphertextConformanceParams;
fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool {
fn is_conformant(
&self,
params: &CompressedModulusSwitchedRadixCiphertextConformanceParams,
) -> bool {
let Self(ct) = self;
ct.is_conformant(params)
@@ -87,9 +93,12 @@ pub struct CompressedModulusSwitchedSignedRadixCiphertext(
);
impl ParameterSetConformant for CompressedModulusSwitchedSignedRadixCiphertext {
type ParameterSet = RadixCiphertextConformanceParams;
type ParameterSet = CompressedModulusSwitchedRadixCiphertextConformanceParams;
fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool {
fn is_conformant(
&self,
params: &CompressedModulusSwitchedRadixCiphertextConformanceParams,
) -> bool {
let Self(ct) = self;
ct.is_conformant(params)
@@ -103,10 +112,30 @@ pub(crate) struct CompressedModulusSwitchedRadixCiphertextGeneric {
pub last_block: Option<CompressedModulusSwitchedCiphertext>,
}
impl ParameterSetConformant for CompressedModulusSwitchedRadixCiphertextGeneric {
type ParameterSet = RadixCiphertextConformanceParams;
#[derive(Copy, Clone)]
pub struct CompressedModulusSwitchedRadixCiphertextConformanceParams {
pub shortint_params: CompressedModulusSwitchedCiphertextConformanceParams,
pub num_blocks_per_integer: usize,
}
fn is_conformant(&self, params: &RadixCiphertextConformanceParams) -> bool {
impl From<CompressedModulusSwitchedRadixCiphertextConformanceParams>
for RadixCiphertextConformanceParams
{
fn from(value: CompressedModulusSwitchedRadixCiphertextConformanceParams) -> Self {
Self {
shortint_params: value.shortint_params.into(),
num_blocks_per_integer: value.num_blocks_per_integer,
}
}
}
impl ParameterSetConformant for CompressedModulusSwitchedRadixCiphertextGeneric {
type ParameterSet = CompressedModulusSwitchedRadixCiphertextConformanceParams;
fn is_conformant(
&self,
params: &CompressedModulusSwitchedRadixCiphertextConformanceParams,
) -> bool {
let Self {
paired_blocks,
last_block,

View File

@@ -20,7 +20,10 @@ use crate::core_crypto::prelude::{
};
use super::backward_compatibility::atomic_pattern::*;
use super::ciphertext::{CompressedModulusSwitchedCiphertext, Degree};
use super::ciphertext::{
CompressedModulusSwitchedCiphertext, CompressedModulusSwitchedCiphertextConformanceParams,
Degree,
};
use super::client_key::atomic_pattern::AtomicPatternClientKey;
use super::engine::ShortintEngine;
use super::parameters::{
@@ -608,6 +611,19 @@ impl AtomicPatternParameters {
}
}
}
pub fn to_compressed_modswitched_conformance_param(
&self,
) -> CompressedModulusSwitchedCiphertextConformanceParams {
match self {
Self::Standard(pbsparameters) => {
pbsparameters.to_compressed_modswitched_conformance_param()
}
Self::KeySwitch32(key_switch32_pbsparameters) => {
key_switch32_pbsparameters.to_compressed_modswitched_conformance_param()
}
}
}
}
impl ParameterSetConformant for AtomicPatternServerKey {

View File

@@ -4,7 +4,7 @@ use super::common::*;
use crate::conformance::ParameterSetConformant;
use crate::core_crypto::prelude::compressed_modulus_switched_lwe_ciphertext::CompressedModulusSwitchedLweCiphertext;
use crate::core_crypto::prelude::compressed_modulus_switched_multi_bit_lwe_ciphertext::CompressedModulusSwitchedMultiBitLweCiphertext;
use crate::core_crypto::prelude::LweCiphertextConformanceParams;
use crate::core_crypto::prelude::CompressedModulusSwitchedLweCiphertextConformanceParams;
use crate::shortint::backward_compatibility::ciphertext::{
CompressedModulusSwitchedCiphertextVersions,
InternalCompressedModulusSwitchedCiphertextVersions,
@@ -48,10 +48,32 @@ pub struct CompressedModulusSwitchedCiphertext {
pub(crate) atomic_pattern: AtomicPatternKind,
}
impl ParameterSetConformant for CompressedModulusSwitchedCiphertext {
type ParameterSet = CiphertextConformanceParams;
#[derive(Copy, Clone)]
pub struct CompressedModulusSwitchedCiphertextConformanceParams {
pub ct_params: CompressedModulusSwitchedLweCiphertextConformanceParams<u64>,
pub message_modulus: MessageModulus,
pub carry_modulus: CarryModulus,
pub degree: Degree,
pub atomic_pattern: AtomicPatternKind,
}
fn is_conformant(&self, param: &CiphertextConformanceParams) -> bool {
impl From<CompressedModulusSwitchedCiphertextConformanceParams> for CiphertextConformanceParams {
fn from(value: CompressedModulusSwitchedCiphertextConformanceParams) -> Self {
Self {
ct_params: value.ct_params.ct_params,
message_modulus: value.message_modulus,
carry_modulus: value.carry_modulus,
degree: value.degree,
noise_level: NoiseLevel::NOMINAL,
atomic_pattern: value.atomic_pattern,
}
}
}
impl ParameterSetConformant for CompressedModulusSwitchedCiphertext {
type ParameterSet = CompressedModulusSwitchedCiphertextConformanceParams;
fn is_conformant(&self, param: &CompressedModulusSwitchedCiphertextConformanceParams) -> bool {
let Self {
compressed_modulus_switched_lwe_ciphertext,
degree,
@@ -60,11 +82,19 @@ impl ParameterSetConformant for CompressedModulusSwitchedCiphertext {
atomic_pattern,
} = self;
compressed_modulus_switched_lwe_ciphertext.is_conformant(&param.ct_params)
&& *message_modulus == param.message_modulus
&& *carry_modulus == param.carry_modulus
&& *atomic_pattern == param.atomic_pattern
&& *degree == param.degree
let CompressedModulusSwitchedCiphertextConformanceParams {
ct_params,
message_modulus: param_message_modulus,
carry_modulus: param_carry_modulus,
degree: param_degree,
atomic_pattern: param_atomic_pattern,
} = param;
compressed_modulus_switched_lwe_ciphertext.is_conformant(ct_params)
&& message_modulus == param_message_modulus
&& carry_modulus == param_carry_modulus
&& atomic_pattern == param_atomic_pattern
&& degree == param_degree
}
}
@@ -76,9 +106,12 @@ pub(crate) enum InternalCompressedModulusSwitchedCiphertext {
}
impl ParameterSetConformant for InternalCompressedModulusSwitchedCiphertext {
type ParameterSet = LweCiphertextConformanceParams<u64>;
type ParameterSet = CompressedModulusSwitchedLweCiphertextConformanceParams<u64>;
fn is_conformant(&self, param: &LweCiphertextConformanceParams<u64>) -> bool {
fn is_conformant(
&self,
param: &CompressedModulusSwitchedLweCiphertextConformanceParams<u64>,
) -> bool {
match self {
Self::Classic(a) => a.is_conformant(param),
Self::MultiBit(a) => a.is_conformant(param),

View File

@@ -1,5 +1,9 @@
use crate::core_crypto::prelude::{LweCiphertextConformanceParams, MsDecompressionType};
use crate::core_crypto::prelude::{
CompressedModulusSwitchedLweCiphertextConformanceParams, LweCiphertextConformanceParams,
MsDecompressionType,
};
use crate::shortint::backward_compatibility::parameters::ClassicPBSParametersVersions;
use crate::shortint::ciphertext::CompressedModulusSwitchedCiphertextConformanceParams;
use crate::shortint::parameters::{
AtomicPatternKind, CarryModulus, CiphertextConformanceParams, CiphertextModulus,
DecompositionBaseLog, DecompositionLevelCount, Degree, DynamicDistribution,
@@ -121,7 +125,6 @@ impl ClassicPBSParameters {
ct_params: LweCiphertextConformanceParams {
lwe_dim: expected_dim,
ct_modulus: ciphertext_modulus,
ms_decompression_method: MsDecompressionType::ClassicPbs,
},
message_modulus,
carry_modulus,
@@ -130,4 +133,44 @@ impl ClassicPBSParameters {
noise_level,
}
}
pub fn to_compressed_modswitched_conformance_param(
&self,
) -> CompressedModulusSwitchedCiphertextConformanceParams {
let (atomic_pattern, expected_dim) = match self.encryption_key_choice {
EncryptionKeyChoice::Big => (
AtomicPatternKind::Standard(PBSOrder::KeyswitchBootstrap),
self.glwe_dimension
.to_equivalent_lwe_dimension(self.polynomial_size),
),
EncryptionKeyChoice::Small => (
AtomicPatternKind::Standard(PBSOrder::BootstrapKeyswitch),
self.lwe_dimension,
),
};
let message_modulus = self.message_modulus;
let ciphertext_modulus = self.ciphertext_modulus;
let carry_modulus = self.carry_modulus;
let degree = Degree::new(message_modulus.0 - 1);
let ct_params = LweCiphertextConformanceParams {
lwe_dim: expected_dim,
ct_modulus: ciphertext_modulus,
};
let compressed_ct_params = CompressedModulusSwitchedLweCiphertextConformanceParams {
ct_params,
ms_decompression_type: MsDecompressionType::ClassicPbs,
};
CompressedModulusSwitchedCiphertextConformanceParams {
ct_params: compressed_ct_params,
message_modulus,
carry_modulus,
atomic_pattern,
degree,
}
}
}

View File

@@ -7,9 +7,11 @@ pub use crate::core_crypto::commons::parameters::{
NoiseEstimationMeasureBound, PolynomialSize, RSigmaFactor,
};
use crate::core_crypto::prelude::{
LweCiphertextConformanceParams, LweKeyswitchKeyConformanceParams, MsDecompressionType,
CompressedModulusSwitchedLweCiphertextConformanceParams, LweCiphertextConformanceParams,
LweKeyswitchKeyConformanceParams, MsDecompressionType,
};
use crate::shortint::backward_compatibility::parameters::KeySwitch32PBSParametersVersions;
use crate::shortint::ciphertext::CompressedModulusSwitchedCiphertextConformanceParams;
use crate::shortint::parameters::ModulusSwitchType;
use super::{
@@ -143,7 +145,6 @@ impl KeySwitch32PBSParameters {
ct_params: LweCiphertextConformanceParams {
lwe_dim: expected_dim,
ct_modulus: ciphertext_modulus,
ms_decompression_method: MsDecompressionType::ClassicPbs,
},
message_modulus,
carry_modulus,
@@ -153,6 +154,38 @@ impl KeySwitch32PBSParameters {
}
}
pub fn to_compressed_modswitched_conformance_param(
&self,
) -> CompressedModulusSwitchedCiphertextConformanceParams {
let expected_dim = self
.glwe_dimension
.to_equivalent_lwe_dimension(self.polynomial_size);
let message_modulus = self.message_modulus;
let ciphertext_modulus = self.ciphertext_modulus;
let carry_modulus = self.carry_modulus;
let degree = Degree::new(message_modulus.0 - 1);
let ct_params = LweCiphertextConformanceParams {
lwe_dim: expected_dim,
ct_modulus: ciphertext_modulus,
};
let compressed_ct_params = CompressedModulusSwitchedLweCiphertextConformanceParams {
ct_params,
ms_decompression_type: MsDecompressionType::ClassicPbs,
};
CompressedModulusSwitchedCiphertextConformanceParams {
ct_params: compressed_ct_params,
message_modulus,
carry_modulus,
atomic_pattern: AtomicPatternKind::KeySwitch32,
degree,
}
}
pub fn ciphertext_modulus_for_key(&self, key_choice: EncryptionKeyChoice) -> CiphertextModulus {
match key_choice {
EncryptionKeyChoice::Big => self.ciphertext_modulus,

View File

@@ -65,6 +65,7 @@ pub use v1_5 as current_params;
pub use super::atomic_pattern::{AtomicPatternKind, AtomicPatternParameters};
use super::backward_compatibility::parameters::modulus_switch_noise_reduction::ModulusSwitchNoiseReductionParamsVersions;
use super::ciphertext::CompressedModulusSwitchedCiphertextConformanceParams;
pub use super::ciphertext::{Degree, MaxNoiseLevel, NoiseLevel};
use super::server_key::PBSConformanceParams;
pub use super::PBSOrder;
@@ -366,6 +367,15 @@ impl PBSParameters {
Self::MultiBitPBS(param) => param.to_shortint_conformance_param(),
}
}
pub fn to_compressed_modswitched_conformance_param(
&self,
) -> CompressedModulusSwitchedCiphertextConformanceParams {
match self {
Self::PBS(param) => param.to_compressed_modswitched_conformance_param(),
Self::MultiBitPBS(param) => param.to_compressed_modswitched_conformance_param(),
}
}
}
#[derive(Serialize, Copy, Clone, Deserialize, Debug, PartialEq, Versionize)]

View File

@@ -1,7 +1,12 @@
use crate::core_crypto::entities::{
LweCiphertextConformanceParams, MsDecompressionType, MultiBitBootstrapKeyConformanceParams,
LweCiphertextConformanceParams, MultiBitBootstrapKeyConformanceParams,
};
use crate::core_crypto::prelude::{
CompressedModulusSwitchedLweCiphertextConformanceParams, MsDecompressionType,
};
use crate::shortint::ciphertext::{
CompressedModulusSwitchedCiphertextConformanceParams, Degree, NoiseLevel,
};
use crate::shortint::ciphertext::{Degree, NoiseLevel};
use crate::shortint::parameters::{
AtomicPatternKind, CarryModulus, CiphertextConformanceParams, CiphertextModulus,
DecompositionBaseLog, DecompositionLevelCount, DynamicDistribution, EncryptionKeyChoice,
@@ -78,7 +83,6 @@ impl MultiBitPBSParameters {
ct_params: LweCiphertextConformanceParams {
lwe_dim: expected_dim,
ct_modulus: ciphertext_modulus,
ms_decompression_method: MsDecompressionType::MultiBitPbs(self.grouping_factor),
},
message_modulus,
carry_modulus,
@@ -87,6 +91,46 @@ impl MultiBitPBSParameters {
noise_level,
}
}
pub fn to_compressed_modswitched_conformance_param(
&self,
) -> CompressedModulusSwitchedCiphertextConformanceParams {
let (atomic_pattern, expected_dim) = match self.encryption_key_choice {
EncryptionKeyChoice::Big => (
AtomicPatternKind::Standard(PBSOrder::KeyswitchBootstrap),
self.glwe_dimension
.to_equivalent_lwe_dimension(self.polynomial_size),
),
EncryptionKeyChoice::Small => (
AtomicPatternKind::Standard(PBSOrder::BootstrapKeyswitch),
self.lwe_dimension,
),
};
let message_modulus = self.message_modulus;
let ciphertext_modulus = self.ciphertext_modulus;
let carry_modulus = self.carry_modulus;
let degree = Degree::new(message_modulus.0 - 1);
let ct_params = LweCiphertextConformanceParams {
lwe_dim: expected_dim,
ct_modulus: ciphertext_modulus,
};
let compressed_ct_params = CompressedModulusSwitchedLweCiphertextConformanceParams {
ct_params,
ms_decompression_type: MsDecompressionType::MultiBitPbs(self.grouping_factor),
};
CompressedModulusSwitchedCiphertextConformanceParams {
ct_params: compressed_ct_params,
message_modulus,
carry_modulus,
atomic_pattern,
degree,
}
}
}
impl TryFrom<&PBSConformanceParams> for MultiBitBootstrapKeyConformanceParams<u64> {

View File

@@ -84,7 +84,9 @@ use super::atomic_pattern::{
use super::backward_compatibility::server_key::{
SerializableShortintBootstrappingKeyVersions, ServerKeyVersions,
};
use super::ciphertext::unchecked_create_trivial_with_lwe_size;
use super::ciphertext::{
unchecked_create_trivial_with_lwe_size, CompressedModulusSwitchedCiphertextConformanceParams,
};
use super::noise_squashing::Shortint128BootstrappingKey;
use super::parameters::KeySwitch32PBSParameters;
use super::PBSParameters;
@@ -728,12 +730,9 @@ impl<AP: AtomicPattern> GenericServerKey<AP> {
pub fn conformance_params(&self) -> CiphertextConformanceParams {
let lwe_dim = self.ciphertext_lwe_dimension();
let ms_decompression_method = self.atomic_pattern.ciphertext_decompression_method();
let ct_params = LweCiphertextConformanceParams {
lwe_dim,
ct_modulus: self.ciphertext_modulus,
ms_decompression_method,
};
CiphertextConformanceParams {
@@ -746,6 +745,30 @@ impl<AP: AtomicPattern> GenericServerKey<AP> {
}
}
pub fn compressed_modswitched_conformance_params(
&self,
) -> CompressedModulusSwitchedCiphertextConformanceParams {
let lwe_dim = self.ciphertext_lwe_dimension();
let ct_params = LweCiphertextConformanceParams {
lwe_dim,
ct_modulus: self.ciphertext_modulus,
};
let compressed_ct = CompressedModulusSwitchedLweCiphertextConformanceParams {
ct_params,
ms_decompression_type: self.atomic_pattern.ciphertext_decompression_method(),
};
CompressedModulusSwitchedCiphertextConformanceParams {
ct_params: compressed_ct,
message_modulus: self.message_modulus,
carry_modulus: self.carry_modulus,
degree: Degree::new(self.message_modulus.0 - 1),
atomic_pattern: self.atomic_pattern.kind(),
}
}
pub(crate) fn encoding(&self, padding_bit: PaddingBit) -> ShortintEncoding<u64> {
ShortintEncoding {
ciphertext_modulus: self.ciphertext_modulus,