diff --git a/tfhe/src/c_api/high_level_api/booleans.rs b/tfhe/src/c_api/high_level_api/booleans.rs index 2241067d6..753be12c9 100644 --- a/tfhe/src/c_api/high_level_api/booleans.rs +++ b/tfhe/src/c_api/high_level_api/booleans.rs @@ -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] diff --git a/tfhe/src/c_api/high_level_api/integers.rs b/tfhe/src/c_api/high_level_api/integers.rs index ba58f08c7..0d1a55e16 100644 --- a/tfhe/src/c_api/high_level_api/integers.rs +++ b/tfhe/src/c_api/high_level_api/integers.rs @@ -359,7 +359,7 @@ macro_rules! create_integer_wrapper_type { impl_safe_serialize_on_type!([]); - impl_safe_deserialize_conformant_on_type!([], [<$name ConformanceParams>]); + impl_safe_deserialize_conformant_on_type!([], []); #[no_mangle] pub unsafe extern "C" fn []( diff --git a/tfhe/src/core_crypto/entities/compressed_modulus_switched_lwe_ciphertext.rs b/tfhe/src/core_crypto/entities/compressed_modulus_switched_lwe_ciphertext.rs index b7ed70bc0..bf9230cac 100644 --- a/tfhe/src/core_crypto/entities/compressed_modulus_switched_lwe_ciphertext.rs +++ b/tfhe/src/core_crypto/entities/compressed_modulus_switched_lwe_ciphertext.rs @@ -135,17 +135,45 @@ impl CompressedModulusSwitchedLweCiphertext +where + Scalar: UnsignedInteger, +{ + pub ct_params: LweCiphertextConformanceParams, + pub ms_decompression_type: MsDecompressionType, +} + impl ParameterSetConformant for CompressedModulusSwitchedLweCiphertext { - type ParameterSet = LweCiphertextConformanceParams; + type ParameterSet = CompressedModulusSwitchedLweCiphertextConformanceParams; - fn is_conformant(&self, lwe_ct_parameters: &LweCiphertextConformanceParams) -> bool { + fn is_conformant( + &self, + compressed_ct_parameters: &CompressedModulusSwitchedLweCiphertextConformanceParams, + ) -> 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 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) } } diff --git a/tfhe/src/core_crypto/entities/compressed_modulus_switched_multi_bit_lwe_ciphertext.rs b/tfhe/src/core_crypto/entities/compressed_modulus_switched_multi_bit_lwe_ciphertext.rs index ae6270b60..2c9c34da0 100644 --- a/tfhe/src/core_crypto/entities/compressed_modulus_switched_multi_bit_lwe_ciphertext.rs +++ b/tfhe/src/core_crypto/entities/compressed_modulus_switched_multi_bit_lwe_ciphertext.rs @@ -511,9 +511,12 @@ impl MultiBitModulusSwitchedLweCiphertext for FromCompressionMultiBitModulusSwit impl + CastFrom> ParameterSetConformant for CompressedModulusSwitchedMultiBitLweCiphertext { - type ParameterSet = LweCiphertextConformanceParams; + type ParameterSet = CompressedModulusSwitchedLweCiphertextConformanceParams; - fn is_conformant(&self, lwe_ct_parameters: &LweCiphertextConformanceParams) -> bool { + fn is_conformant( + &self, + compressed_ct_parameters: &CompressedModulusSwitchedLweCiphertextConformanceParams, + ) -> bool { let Self { body, packed_mask, @@ -523,22 +526,30 @@ impl + CastFrom> 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 } } diff --git a/tfhe/src/core_crypto/entities/lwe_ciphertext.rs b/tfhe/src/core_crypto/entities/lwe_ciphertext.rs index 168e6848a..514c7d117 100644 --- a/tfhe/src/core_crypto/entities/lwe_ciphertext.rs +++ b/tfhe/src/core_crypto/entities/lwe_ciphertext.rs @@ -753,13 +753,6 @@ pub type LweCiphertextMutView<'data, Scalar> = LweCiphertext<&'data mut [Scalar] pub struct LweCiphertextConformanceParams { pub lwe_dim: LweDimension, pub ct_modulus: CiphertextModulus, - pub ms_decompression_method: MsDecompressionType, -} - -#[derive(Copy, Clone)] -pub enum MsDecompressionType { - ClassicPbs, - MultiBitPbs(LweBskGroupingFactor), } impl ParameterSetConformant for LweCiphertext @@ -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 } } diff --git a/tfhe/src/high_level_api/booleans/compressed.rs b/tfhe/src/high_level_api/booleans/compressed.rs index 3f20903d4..07e3ebcc1 100644 --- a/tfhe/src/high_level_api/booleans/compressed.rs +++ b/tfhe/src/high_level_api/booleans/compressed.rs @@ -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 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> From

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(¶ms.0), + InnerCompressedFheBool::Seeded(seeded) => seeded.is_conformant(¶ms.0.into()), InnerCompressedFheBool::ModulusSwitched(ct) => ct.is_conformant(¶ms.0), } } diff --git a/tfhe/src/high_level_api/booleans/mod.rs b/tfhe/src/high_level_api/booleans/mod.rs index 87d8c2058..f6edec4d3 100644 --- a/tfhe/src/high_level_api/booleans/mod.rs +++ b/tfhe/src/high_level_api/booleans/mod.rs @@ -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; diff --git a/tfhe/src/high_level_api/booleans/tests.rs b/tfhe/src/high_level_api/booleans/tests.rs index 47097c463..37cc6949f 100644 --- a/tfhe/src/high_level_api/booleans/tests.rs +++ b/tfhe/src/high_level_api/booleans/tests.rs @@ -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::(serialized.as_slice(), ¶ms) .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); diff --git a/tfhe/src/high_level_api/integers/signed/compressed.rs b/tfhe/src/high_level_api/integers/signed/compressed.rs index 83714b9fa..f927e986c 100644 --- a/tfhe/src/high_level_api/integers/signed/compressed.rs +++ b/tfhe/src/high_level_api/integers/signed/compressed.rs @@ -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 ParameterSetConformant for CompressedFheInt { - type ParameterSet = FheIntConformanceParams; +#[derive(Copy, Clone)] +pub struct CompressedFheIntConformanceParams { + pub(crate) params: CompressedSignedRadixCiphertextConformanceParams, + pub(crate) id: PhantomData, +} - fn is_conformant(&self, params: &FheIntConformanceParams) -> bool { +impl> From

+ for CompressedFheIntConformanceParams +{ + 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 From<&ServerKey> for CompressedFheIntConformanceParams { + 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 ParameterSetConformant for CompressedFheInt { + type ParameterSet = CompressedFheIntConformanceParams; + + fn is_conformant(&self, params: &CompressedFheIntConformanceParams) -> 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(¶ms.0.into()), + Self::ModulusSwitched(ct) => ct.is_conformant(¶ms.0), } } } diff --git a/tfhe/src/high_level_api/integers/signed/static_.rs b/tfhe/src/high_level_api/integers/signed/static_.rs index 7f1695721..55566bbab 100644 --- a/tfhe/src/high_level_api/integers/signed/static_.rs +++ b/tfhe/src/high_level_api/integers/signed/static_.rs @@ -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 [] = FheIntConformanceParams<[]>; + pub type [] = CompressedFheIntConformanceParams<[]>; } }; } diff --git a/tfhe/src/high_level_api/integers/signed/tests/cpu.rs b/tfhe/src/high_level_api/integers/signed/tests/cpu.rs index 92c3d8ece..f59288757 100644 --- a/tfhe/src/high_level_api/integers/signed/tests/cpu.rs +++ b/tfhe/src/high_level_api/integers/signed/tests/cpu.rs @@ -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::(serialized.as_slice(), ¶ms) .unwrap(); - let params = FheInt32ConformanceParams::from(block_params); + let params = CompressedFheInt32ConformanceParams::from(block_params); assert!(deserialized_a.is_conformant(¶ms)); let decrypted: i32 = deserialized_a.decompress().decrypt(&client_key); diff --git a/tfhe/src/high_level_api/integers/unsigned/compressed.rs b/tfhe/src/high_level_api/integers/unsigned/compressed.rs index b97830289..ed64aba9e 100644 --- a/tfhe/src/high_level_api/integers/unsigned/compressed.rs +++ b/tfhe/src/high_level_api/integers/unsigned/compressed.rs @@ -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 ParameterSetConformant for CompressedFheUint { - type ParameterSet = FheUintConformanceParams; +#[derive(Copy, Clone)] +pub struct CompressedFheUintConformanceParams { + pub(crate) params: CompressedRadixCiphertextConformanceParams, + pub(crate) id: PhantomData, +} - fn is_conformant(&self, params: &FheUintConformanceParams) -> bool { +impl> From

+ for CompressedFheUintConformanceParams +{ + 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 From<&ServerKey> for CompressedFheUintConformanceParams { + 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 ParameterSetConformant for CompressedFheUint { + type ParameterSet = CompressedFheUintConformanceParams; + + fn is_conformant(&self, params: &CompressedFheUintConformanceParams) -> 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(¶ms.0.into()), + Self::ModulusSwitched(ct) => ct.is_conformant(¶ms.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::(); } - 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(); diff --git a/tfhe/src/high_level_api/integers/unsigned/static_.rs b/tfhe/src/high_level_api/integers/unsigned/static_.rs index b14cbca94..bfd60f14e 100644 --- a/tfhe/src/high_level_api/integers/unsigned/static_.rs +++ b/tfhe/src/high_level_api/integers/unsigned/static_.rs @@ -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 [] = FheUintConformanceParams<[]>; + pub type [] = CompressedFheUintConformanceParams<[]>; } }; } diff --git a/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs b/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs index 94cc7b22f..f68086e99 100644 --- a/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs +++ b/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs @@ -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::(serialized.as_slice(), ¶ms) .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); diff --git a/tfhe/src/high_level_api/integers/unsigned/tests/gpu.rs b/tfhe/src/high_level_api/integers/unsigned/tests/gpu.rs index 938ec6f2a..d610c6b7c 100644 --- a/tfhe/src/high_level_api/integers/unsigned/tests/gpu.rs +++ b/tfhe/src/high_level_api/integers/unsigned/tests/gpu.rs @@ -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 { diff --git a/tfhe/src/high_level_api/mod.rs b/tfhe/src/high_level_api/mod.rs index b4047c3ab..f3ca30059 100644 --- a/tfhe/src/high_level_api/mod.rs +++ b/tfhe/src/high_level_api/mod.rs @@ -17,6 +17,7 @@ macro_rules! expand_pub_use_fhe_type( // ConformanceParams [<$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")] diff --git a/tfhe/src/integer/ciphertext/compressed_modulus_switched_ciphertext.rs b/tfhe/src/integer/ciphertext/compressed_modulus_switched_ciphertext.rs index 25e68f3af..19ab20910 100644 --- a/tfhe/src/integer/ciphertext/compressed_modulus_switched_ciphertext.rs +++ b/tfhe/src/integer/ciphertext/compressed_modulus_switched_ciphertext.rs @@ -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, } -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 + 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, diff --git a/tfhe/src/shortint/atomic_pattern/mod.rs b/tfhe/src/shortint/atomic_pattern/mod.rs index 15bb8fc1b..ab0c21a47 100644 --- a/tfhe/src/shortint/atomic_pattern/mod.rs +++ b/tfhe/src/shortint/atomic_pattern/mod.rs @@ -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 { diff --git a/tfhe/src/shortint/ciphertext/compressed_modulus_switched_ciphertext.rs b/tfhe/src/shortint/ciphertext/compressed_modulus_switched_ciphertext.rs index 1bad1f667..730e7f0b7 100644 --- a/tfhe/src/shortint/ciphertext/compressed_modulus_switched_ciphertext.rs +++ b/tfhe/src/shortint/ciphertext/compressed_modulus_switched_ciphertext.rs @@ -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, + pub message_modulus: MessageModulus, + pub carry_modulus: CarryModulus, + pub degree: Degree, + pub atomic_pattern: AtomicPatternKind, +} - fn is_conformant(&self, param: &CiphertextConformanceParams) -> bool { +impl From 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(¶m.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; + type ParameterSet = CompressedModulusSwitchedLweCiphertextConformanceParams; - fn is_conformant(&self, param: &LweCiphertextConformanceParams) -> bool { + fn is_conformant( + &self, + param: &CompressedModulusSwitchedLweCiphertextConformanceParams, + ) -> bool { match self { Self::Classic(a) => a.is_conformant(param), Self::MultiBit(a) => a.is_conformant(param), diff --git a/tfhe/src/shortint/parameters/classic.rs b/tfhe/src/shortint/parameters/classic.rs index c0bcde1b9..a74daa70a 100644 --- a/tfhe/src/shortint/parameters/classic.rs +++ b/tfhe/src/shortint/parameters/classic.rs @@ -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, + } + } } diff --git a/tfhe/src/shortint/parameters/ks32.rs b/tfhe/src/shortint/parameters/ks32.rs index 95a013b49..6ac89b5bf 100644 --- a/tfhe/src/shortint/parameters/ks32.rs +++ b/tfhe/src/shortint/parameters/ks32.rs @@ -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, diff --git a/tfhe/src/shortint/parameters/mod.rs b/tfhe/src/shortint/parameters/mod.rs index dc31fb387..45a8b5889 100644 --- a/tfhe/src/shortint/parameters/mod.rs +++ b/tfhe/src/shortint/parameters/mod.rs @@ -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)] diff --git a/tfhe/src/shortint/parameters/multi_bit.rs b/tfhe/src/shortint/parameters/multi_bit.rs index 5b489cb96..ae615af83 100644 --- a/tfhe/src/shortint/parameters/multi_bit.rs +++ b/tfhe/src/shortint/parameters/multi_bit.rs @@ -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 { diff --git a/tfhe/src/shortint/server_key/mod.rs b/tfhe/src/shortint/server_key/mod.rs index abe7b4ef6..f626a047b 100644 --- a/tfhe/src/shortint/server_key/mod.rs +++ b/tfhe/src/shortint/server_key/mod.rs @@ -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 GenericServerKey { 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 GenericServerKey { } } + 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 { ShortintEncoding { ciphertext_modulus: self.ciphertext_modulus,