Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,10 +534,10 @@ fn test_safe_deserialize_conformant_compact_fhe_uint32() {
.serialize_into(&a, &mut serialized)
.unwrap();

let params = CompactCiphertextListConformanceParams {
shortint_params: block_params.to_shortint_conformance_param(),
num_elements_constraint: ListSizeConstraint::exact_size(clears.len()),
};
let params = CompactCiphertextListConformanceParams::from_parameters_and_size_constraint(
pk.parameters(),
ListSizeConstraint::exact_size(clears.len()),
);
let deserialized_a = DeserializationConfig::new(1 << 20)
.deserialize_from::<CompactCiphertextList>(serialized.as_slice(), &params)
.unwrap();
Expand Down
81 changes: 45 additions & 36 deletions tfhe/src/integer/ciphertext/compact_list.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{DataKind, Expandable};
use crate::conformance::{ListSizeConstraint, ParameterSetConformant};
use crate::core_crypto::prelude::Numeric;
use crate::core_crypto::prelude::{LweCiphertextListConformanceParams, Numeric};
use crate::integer::backward_compatibility::ciphertext::CompactCiphertextListVersions;
#[cfg(feature = "zk-pok")]
use crate::integer::backward_compatibility::ciphertext::ProvenCompactCiphertextListVersions;
Expand All @@ -13,7 +13,8 @@ use crate::shortint::ciphertext::Degree;
#[cfg(feature = "zk-pok")]
use crate::shortint::ciphertext::ProvenCompactCiphertextListConformanceParams;
use crate::shortint::parameters::{
CastingFunctionsOwned, CiphertextConformanceParams, ShortintCompactCiphertextListCastingMode,
CastingFunctionsOwned, CiphertextListConformanceParams,
ShortintCompactCiphertextListCastingMode,
};
#[cfg(feature = "zk-pok")]
use crate::shortint::parameters::{
Expand Down Expand Up @@ -405,13 +406,52 @@ impl ParameterSetConformant for CompactCiphertextList {
type ParameterSet = CompactCiphertextListConformanceParams;

fn is_conformant(&self, params: &CompactCiphertextListConformanceParams) -> bool {
let Self { ct_list: _, info } = self;
let Self { ct_list, info } = self;

let CompactCiphertextListConformanceParams {
encryption_lwe_dimension,
message_modulus,
carry_modulus,
ciphertext_modulus,
expansion_kind,
num_elements_constraint,
} = params;

if !params.num_elements_constraint.is_valid(info.len()) {
if !num_elements_constraint.is_valid(info.len()) {
return false;
}

self.is_conformant_with_shortint_params(params.shortint_params)
let is_packed = self.is_packed();

let total_expected_num_blocks: usize = info
.iter()
.map(|a| a.num_blocks(self.message_modulus()))
.sum();

let total_expected_lwe_count =
total_expected_num_blocks.div_ceil(if is_packed { 2 } else { 1 });

let degree = if is_packed {
Degree::new(message_modulus.0 * message_modulus.0 - 1)
} else {
Degree::new(message_modulus.0 - 1)
};

let shortint_params = CiphertextListConformanceParams {
expansion_kind: *expansion_kind,
message_modulus: *message_modulus,
carry_modulus: *carry_modulus,
ct_list_params: LweCiphertextListConformanceParams {
lwe_dim: *encryption_lwe_dimension,
lwe_ciphertext_count_constraint: ListSizeConstraint::exact_size(
total_expected_lwe_count,
),
ct_modulus: *ciphertext_modulus,
},
degree,
};

ct_list.is_conformant(&shortint_params)
}
}

Expand Down Expand Up @@ -951,28 +991,6 @@ impl CompactCiphertextList {
pub fn message_modulus(&self) -> MessageModulus {
self.ct_list.message_modulus
}

fn is_conformant_with_shortint_params(
&self,
shortint_params: CiphertextConformanceParams,
) -> bool {
let Self { ct_list, info } = self;

let mut num_blocks: usize = info
.iter()
.copied()
.map(|kind| kind.num_blocks(self.message_modulus()))
.sum();
// This expects packing, halve the number of blocks with enough capacity
if shortint_params.degree.get()
== (shortint_params.message_modulus.0 * shortint_params.carry_modulus.0) - 1
{
num_blocks = num_blocks.div_ceil(2);
}
let shortint_list_params = shortint_params
.to_ct_list_conformance_parameters(ListSizeConstraint::exact_size(num_blocks));
ct_list.is_conformant(&shortint_list_params)
}
}

#[cfg(feature = "zk-pok")]
Expand Down Expand Up @@ -1168,15 +1186,6 @@ impl ParameterSetConformant for ProvenCompactCiphertextList {

let is_packed = self.is_packed();

let all_have_same_packing = ct_list
.proved_lists
.iter()
.all(|(list, _)| list.is_packed() == is_packed);

if !all_have_same_packing {
return false;
}

let total_expected_num_blocks: usize = info
.iter()
.map(|a| a.num_blocks(self.message_modulus()))
Expand Down
35 changes: 23 additions & 12 deletions tfhe/src/integer/parameters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use crate::conformance::ListSizeConstraint;
use crate::integer::key_switching_key::KeySwitchingKeyView;
use crate::integer::server_key::ServerKey;
use crate::shortint::parameters::{
CarryModulus, CiphertextConformanceParams, EncryptionKeyChoice, MessageModulus,
CarryModulus, CiphertextConformanceParams, CompactCiphertextListExpansionKind,
CompactPublicKeyEncryptionParameters, EncryptionKeyChoice, MessageModulus,
};
pub use crate::shortint::parameters::{
DecompositionBaseLog, DecompositionLevelCount, DynamicDistribution, GlweDimension,
Expand Down Expand Up @@ -171,16 +172,6 @@ pub struct RadixCiphertextConformanceParams {
/// Can be used on a server to check if client inputs are well formed
/// before running a computation on them
impl RadixCiphertextConformanceParams {
pub fn to_ct_list_conformance_parameters(
&self,
list_constraint: ListSizeConstraint,
) -> CompactCiphertextListConformanceParams {
CompactCiphertextListConformanceParams {
shortint_params: self.shortint_params,
num_elements_constraint: list_constraint,
}
}

pub fn from_pbs_parameters<P: Into<PBSParameters>>(
params: P,
num_blocks_per_integer: usize,
Expand All @@ -198,6 +189,26 @@ impl RadixCiphertextConformanceParams {
/// before running a computation on them
#[derive(Copy, Clone)]
pub struct CompactCiphertextListConformanceParams {
pub shortint_params: CiphertextConformanceParams,
pub encryption_lwe_dimension: LweDimension,
pub message_modulus: MessageModulus,
pub carry_modulus: CarryModulus,
pub ciphertext_modulus: CiphertextModulus,
pub expansion_kind: CompactCiphertextListExpansionKind,
pub num_elements_constraint: ListSizeConstraint,
}

impl CompactCiphertextListConformanceParams {
pub fn from_parameters_and_size_constraint(
value: CompactPublicKeyEncryptionParameters,
num_elements_constraint: ListSizeConstraint,
) -> Self {
Self {
encryption_lwe_dimension: value.encryption_lwe_dimension,
message_modulus: value.message_modulus,
carry_modulus: value.carry_modulus,
ciphertext_modulus: value.ciphertext_modulus,
expansion_kind: value.expansion_kind,
num_elements_constraint,
}
}
}
144 changes: 103 additions & 41 deletions tfhe/src/safe_serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,10 +718,7 @@ mod test_integer {
use crate::high_level_api::{generate_keys, ConfigBuilder};
use crate::prelude::*;
use crate::safe_serialization::{DeserializationConfig, SerializationConfig};
use crate::shortint::parameters::{
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
};
use crate::shortint::parameters::PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128;
use crate::{
set_server_key, CompactCiphertextList, CompactCiphertextListConformanceParams,
CompactPublicKey, FheUint8,
Expand Down Expand Up @@ -751,18 +748,20 @@ mod test_integer {

assert_eq!(size as usize, buffer.len());

let to_param_set = |list_size_constraint| CompactCiphertextListConformanceParams {
shortint_params: PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
.to_shortint_conformance_param(),
num_elements_constraint: list_size_constraint,
let to_param_set = |list_size_constraint| {
CompactCiphertextListConformanceParams::from_parameters_and_size_constraint(
public_key.parameters(),
list_size_constraint,
)
};

for param_set in [
CompactCiphertextListConformanceParams {
shortint_params: PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128
.to_shortint_conformance_param(),
num_elements_constraint: ListSizeConstraint::exact_size(3),
},
CompactCiphertextListConformanceParams::from_parameters_and_size_constraint(
PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128
.try_into()
.unwrap(),
ListSizeConstraint::exact_size(3),
),
to_param_set(ListSizeConstraint::exact_size(2)),
to_param_set(ListSizeConstraint::exact_size(4)),
to_param_set(ListSizeConstraint::try_size_in_range(1, 2).unwrap()),
Expand All @@ -779,22 +778,91 @@ mod test_integer {
ListSizeConstraint::try_size_in_range(3, 4).unwrap(),
ListSizeConstraint::try_size_in_range(2, 4).unwrap(),
] {
let params = CompactCiphertextListConformanceParams {
shortint_params: PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
.to_shortint_conformance_param(),
num_elements_constraint: len_constraint,
};
let params = to_param_set(len_constraint);

DeserializationConfig::new(1 << 20)
.deserialize_from::<CompactCiphertextList>(buffer.as_slice(), &params)
.unwrap();
}

let params = CompactCiphertextListConformanceParams {
shortint_params: PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
.to_shortint_conformance_param(),
num_elements_constraint: ListSizeConstraint::exact_size(3),
let params = to_param_set(ListSizeConstraint::exact_size(3));
let ct2 = DeserializationConfig::new(1 << 20)
.deserialize_from::<CompactCiphertextList>(buffer.as_slice(), &params)
.unwrap();

let mut cts = Vec::with_capacity(3);
let expander = ct2.expand().unwrap();
for i in 0..3 {
cts.push(expander.get::<FheUint8>(i).unwrap().unwrap());
}

let dec: Vec<u8> = cts.iter().map(|a| a.decrypt(&client_key)).collect();

assert_eq!(&msg[..], &dec);
}

#[test]
fn safe_deserialization_ct_list_packed() {
let (client_key, sks) = generate_keys(ConfigBuilder::default().build());
set_server_key(sks);

let public_key = CompactPublicKey::new(&client_key);

let msg = [27u8, 10, 3];

let ct_list = CompactCiphertextList::builder(&public_key)
.push(27u8)
.push(10u8)
.push(3u8)
.build_packed();

let mut buffer = vec![];

let config = SerializationConfig::new(1 << 20).disable_versioning();

let size = config.serialized_size(&ct_list).unwrap();
config.serialize_into(&ct_list, &mut buffer).unwrap();

assert_eq!(size as usize, buffer.len());

let to_param_set = |list_size_constraint| {
CompactCiphertextListConformanceParams::from_parameters_and_size_constraint(
public_key.parameters(),
list_size_constraint,
)
};

for param_set in [
CompactCiphertextListConformanceParams::from_parameters_and_size_constraint(
PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128
.try_into()
.unwrap(),
ListSizeConstraint::exact_size(3),
),
to_param_set(ListSizeConstraint::exact_size(2)),
to_param_set(ListSizeConstraint::exact_size(4)),
to_param_set(ListSizeConstraint::try_size_in_range(1, 2).unwrap()),
to_param_set(ListSizeConstraint::try_size_in_range(4, 5).unwrap()),
] {
assert!(DeserializationConfig::new(1 << 20)
.deserialize_from::<CompactCiphertextList>(buffer.as_slice(), &param_set)
.is_err());
}

for len_constraint in [
ListSizeConstraint::exact_size(3),
ListSizeConstraint::try_size_in_range(2, 3).unwrap(),
ListSizeConstraint::try_size_in_range(3, 4).unwrap(),
ListSizeConstraint::try_size_in_range(2, 4).unwrap(),
] {
let params = to_param_set(len_constraint);

DeserializationConfig::new(1 << 20)
.deserialize_from::<CompactCiphertextList>(buffer.as_slice(), &params)
.unwrap();
}

let params = to_param_set(ListSizeConstraint::exact_size(3));
let ct2 = DeserializationConfig::new(1 << 20)
.deserialize_from::<CompactCiphertextList>(buffer.as_slice(), &params)
.unwrap();
Expand Down Expand Up @@ -834,18 +902,20 @@ mod test_integer {

assert_eq!(size as usize, buffer.len());

let to_param_set = |list_size_constraint| CompactCiphertextListConformanceParams {
shortint_params: PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
.to_shortint_conformance_param(),
num_elements_constraint: list_size_constraint,
let to_param_set = |list_size_constraint| {
CompactCiphertextListConformanceParams::from_parameters_and_size_constraint(
public_key.parameters(),
list_size_constraint,
)
};

for param_set in [
CompactCiphertextListConformanceParams {
shortint_params: PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128
.to_shortint_conformance_param(),
num_elements_constraint: ListSizeConstraint::exact_size(3),
},
CompactCiphertextListConformanceParams::from_parameters_and_size_constraint(
PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128
.try_into()
.unwrap(),
ListSizeConstraint::exact_size(3),
),
to_param_set(ListSizeConstraint::exact_size(2)),
to_param_set(ListSizeConstraint::exact_size(4)),
to_param_set(ListSizeConstraint::try_size_in_range(1, 2).unwrap()),
Expand All @@ -862,22 +932,14 @@ mod test_integer {
ListSizeConstraint::try_size_in_range(3, 4).unwrap(),
ListSizeConstraint::try_size_in_range(2, 4).unwrap(),
] {
let params = CompactCiphertextListConformanceParams {
shortint_params: PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
.to_shortint_conformance_param(),
num_elements_constraint: len_constraint,
};
let params = to_param_set(len_constraint);

DeserializationConfig::new(1 << 20)
.deserialize_from::<CompactCiphertextList>(buffer.as_slice(), &params)
.unwrap();
}

let params = CompactCiphertextListConformanceParams {
shortint_params: PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
.to_shortint_conformance_param(),
num_elements_constraint: ListSizeConstraint::exact_size(3),
};
let params = to_param_set(ListSizeConstraint::exact_size(3));
let ct2 = DeserializationConfig::new(1 << 20)
.deserialize_from::<CompactCiphertextList>(buffer.as_slice(), &params)
.unwrap();
Expand Down
Loading
Loading