chore(backward): add data for multibit noise squashing

This commit is contained in:
Mayeul@Zama
2025-08-08 11:46:55 +02:00
committed by Nicolas Sarlin
parent c8a9105953
commit 4909a8ef0e
12 changed files with 424 additions and 1 deletions

View File

@@ -55,6 +55,13 @@ tfhe_1_3 = { git = "https://github.com/zama-ai/tfhe-rs.git", features = [
"zk-pok",
"experimental-force_fft_algo_dif4",
], package = "tfhe", tag = "tfhe-rs-1.3.0", optional = true }
tfhe_1_4 = { path = "../../tfhe", features = [
"boolean",
"integer",
"shortint",
"zk-pok",
"experimental-force_fft_algo_dif4",
], package = "tfhe", optional = true }
# TFHE-rs 0.8 and 0.10 use the same version of versionable
@@ -63,6 +70,7 @@ tfhe_0_11-versionable = { version = "0.4.0", optional = true, package = "tfhe-ve
tfhe_1_0-versionable = { version = "0.5.0", optional = true, package = "tfhe-versionable" }
tfhe_1_1-versionable = { git = "https://github.com/zama-ai/tfhe-rs.git", tag = "tfhe-rs-1.1.0", optional = true, package = "tfhe-versionable" }
tfhe_1_3-versionable = { git = "https://github.com/zama-ai/tfhe-rs.git", tag = "tfhe-rs-1.3.0", optional = true, package = "tfhe-versionable" }
tfhe_1_4-versionable = { path = "../../utils/tfhe-versionable", optional = true, package = "tfhe-versionable" }
# other deps
@@ -87,10 +95,12 @@ generate = [
"dep:tfhe_1_0",
"dep:tfhe_1_1",
"dep:tfhe_1_3",
"dep:tfhe_1_4",
"dep:tfhe-versionable",
"dep:tfhe_0_11-versionable",
"dep:tfhe_1_0-versionable",
"dep:tfhe_1_1-versionable",
"dep:tfhe_1_3-versionable",
"dep:tfhe_1_4-versionable",
]
load = ["dep:semver"]

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4fde99e29edfc15e5f7c9693940706cc6ff3f1ecdc56a759265ff58c46a06265
size 16718

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0c6cb8493b0e32785a3c0aa809434e59c0aa6bd7395a4b8acd47f9dbbe97dd0d
size 2845

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3c2f4f5defbb7e80e1eb0c879c997727da7dedc83bc606f4442ab7720855ad25
size 1458994

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:090343d3114d5de87990cd496f07ce32a23e6906d86968f2c077d5e8bb414770
size 1706898

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a275ecba88781266620ed5a6c447f214bb6c271f458a4c0d3d6a4652604b21f7
size 525104

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3700ccf4058c5f453a3e44d446d20fb7c3f849fa689ddb1023b3b035bd16bd63
size 590873

View File

@@ -638,4 +638,51 @@
],
)),
),
(
tfhe_version_min: "1.4",
tfhe_module: "high_level_api",
metadata: HlClientKey((
test_filename: "client_key_with_noise_squashing",
parameters: TestMultiBitParameterSet((
lwe_dimension: 4,
glwe_dimension: 1,
polynomial_size: 2048,
lwe_noise_distribution: TUniform(
bound_log2: 45,
),
glwe_noise_distribution: TUniform(
bound_log2: 17,
),
pbs_base_log: 22,
pbs_level: 1,
ks_base_log: 3,
ks_level: 5,
message_modulus: 4,
ciphertext_modulus: 18446744073709551616,
carry_modulus: 4,
max_noise_level: 5,
log2_p_fail: -134.345,
encryption_key_choice: "big",
grouping_factor: 4,
)),
)),
),
(
tfhe_version_min: "1.4",
tfhe_module: "high_level_api",
metadata: HlServerKey((
test_filename: "server_key_with_noise_squashing",
client_key_filename: "client_key_with_noise_squashing",
compressed: false,
)),
),
(
tfhe_version_min: "1.4",
tfhe_module: "high_level_api",
metadata: HlSquashedNoiseUnsignedCiphertext((
test_filename: "squashed_noise_unsigned_ciphertext",
key_filename: "client_key_with_noise_squashing",
clear_value: 42,
)),
),
]

View File

@@ -0,0 +1,304 @@
use crate::generate::{
store_versioned_test_tfhe_1_4, TfhersVersion,
INSECURE_SMALL_TEST_NOISE_SQUASHING_PARAMS_MULTI_BIT, INSECURE_SMALL_TEST_PARAMS_MULTI_BIT,
};
use crate::{
HlClientKeyTest, HlServerKeyTest, HlSquashedNoiseUnsignedCiphertextTest,
TestClassicParameterSet, TestDistribution, TestMetadata, TestModulusSwitchNoiseReductionParams,
TestModulusSwitchType, TestMultiBitParameterSet, TestNoiseSquashingParamsMultiBit,
TestParameterSet, HL_MODULE_NAME,
};
use std::borrow::Cow;
use std::fs::create_dir_all;
use tfhe_1_4::boolean::engine::BooleanEngine;
use tfhe_1_4::core_crypto::commons::generators::DeterministicSeeder;
use tfhe_1_4::core_crypto::prelude::DefaultRandomGenerator;
use tfhe_1_4::prelude::*;
use tfhe_1_4::shortint::engine::ShortintEngine;
use tfhe_1_4::shortint::parameters::noise_squashing::NoiseSquashingMultiBitParameters;
use tfhe_1_4::shortint::parameters::{
CarryModulus, CiphertextModulus, CoreCiphertextModulus, DecompositionBaseLog,
DecompositionLevelCount, DynamicDistribution, EncryptionKeyChoice, GlweDimension,
LweBskGroupingFactor, LweCiphertextCount, LweDimension, MaxNoiseLevel, MessageModulus,
ModulusSwitchNoiseReductionParams, ModulusSwitchType, NoiseEstimationMeasureBound,
NoiseSquashingParameters, PolynomialSize, RSigmaFactor, StandardDev, Variance,
};
use tfhe_1_4::shortint::{AtomicPatternParameters, ClassicPBSParameters, MultiBitPBSParameters};
use tfhe_1_4::{set_server_key, ClientKey, FheUint32, Seed, ServerKey};
macro_rules! store_versioned_test {
($msg:expr, $dir:expr, $test_filename:expr $(,)? ) => {
store_versioned_test_tfhe_1_4($msg, $dir, $test_filename)
};
}
impl From<TestDistribution> for DynamicDistribution<u64> {
fn from(value: TestDistribution) -> Self {
match value {
TestDistribution::Gaussian { stddev } => {
DynamicDistribution::new_gaussian_from_std_dev(StandardDev(stddev))
}
TestDistribution::TUniform { bound_log2 } => {
DynamicDistribution::new_t_uniform(bound_log2)
}
}
}
}
impl From<TestDistribution> for DynamicDistribution<u128> {
fn from(value: TestDistribution) -> Self {
match value {
TestDistribution::Gaussian { stddev } => {
DynamicDistribution::new_gaussian_from_std_dev(StandardDev(stddev))
}
TestDistribution::TUniform { bound_log2 } => {
DynamicDistribution::new_t_uniform(bound_log2)
}
}
}
}
impl From<TestModulusSwitchNoiseReductionParams> for ModulusSwitchNoiseReductionParams {
fn from(value: TestModulusSwitchNoiseReductionParams) -> Self {
let TestModulusSwitchNoiseReductionParams {
modulus_switch_zeros_count,
ms_bound,
ms_r_sigma_factor,
ms_input_variance,
} = value;
ModulusSwitchNoiseReductionParams {
modulus_switch_zeros_count: LweCiphertextCount(modulus_switch_zeros_count),
ms_bound: NoiseEstimationMeasureBound(ms_bound),
ms_r_sigma_factor: RSigmaFactor(ms_r_sigma_factor),
ms_input_variance: Variance(ms_input_variance),
}
}
}
impl From<TestModulusSwitchType> for ModulusSwitchType {
fn from(value: TestModulusSwitchType) -> Self {
match value {
TestModulusSwitchType::Standard => ModulusSwitchType::Standard,
TestModulusSwitchType::DriftTechniqueNoiseReduction(
test_modulus_switch_noise_reduction_params,
) => ModulusSwitchType::DriftTechniqueNoiseReduction(
test_modulus_switch_noise_reduction_params.into(),
),
TestModulusSwitchType::CenteredMeanNoiseReduction => {
ModulusSwitchType::CenteredMeanNoiseReduction
}
}
}
}
impl From<TestClassicParameterSet> for ClassicPBSParameters {
fn from(value: TestClassicParameterSet) -> Self {
ClassicPBSParameters {
lwe_dimension: LweDimension(value.lwe_dimension),
glwe_dimension: GlweDimension(value.glwe_dimension),
polynomial_size: PolynomialSize(value.polynomial_size),
lwe_noise_distribution: value.lwe_noise_distribution.into(),
glwe_noise_distribution: value.glwe_noise_distribution.into(),
pbs_base_log: DecompositionBaseLog(value.pbs_base_log),
pbs_level: DecompositionLevelCount(value.pbs_level),
ks_base_log: DecompositionBaseLog(value.ks_base_log),
ks_level: DecompositionLevelCount(value.ks_level),
message_modulus: MessageModulus(value.message_modulus as u64),
carry_modulus: CarryModulus(value.carry_modulus as u64),
max_noise_level: MaxNoiseLevel::new(value.max_noise_level as u64),
log2_p_fail: value.log2_p_fail,
ciphertext_modulus: CiphertextModulus::try_new(value.ciphertext_modulus).unwrap(),
encryption_key_choice: {
match &*value.encryption_key_choice {
"big" => EncryptionKeyChoice::Big,
"small" => EncryptionKeyChoice::Small,
_ => panic!("Invalid encryption key choice"),
}
},
modulus_switch_noise_reduction_params: value
.modulus_switch_noise_reduction_params
.into(),
}
}
}
impl From<TestMultiBitParameterSet> for MultiBitPBSParameters {
fn from(value: TestMultiBitParameterSet) -> Self {
let TestMultiBitParameterSet {
lwe_dimension,
glwe_dimension,
polynomial_size,
lwe_noise_distribution,
glwe_noise_distribution,
pbs_base_log,
pbs_level,
ks_base_log,
ks_level,
message_modulus,
ciphertext_modulus,
carry_modulus,
max_noise_level,
log2_p_fail,
encryption_key_choice,
grouping_factor,
} = value;
MultiBitPBSParameters {
lwe_dimension: LweDimension(lwe_dimension),
glwe_dimension: GlweDimension(glwe_dimension),
polynomial_size: PolynomialSize(polynomial_size),
lwe_noise_distribution: lwe_noise_distribution.into(),
glwe_noise_distribution: glwe_noise_distribution.into(),
pbs_base_log: DecompositionBaseLog(pbs_base_log),
pbs_level: DecompositionLevelCount(pbs_level),
ks_base_log: DecompositionBaseLog(ks_base_log),
ks_level: DecompositionLevelCount(ks_level),
message_modulus: MessageModulus(message_modulus as u64),
carry_modulus: CarryModulus(carry_modulus as u64),
max_noise_level: MaxNoiseLevel::new(max_noise_level as u64),
log2_p_fail,
ciphertext_modulus: CiphertextModulus::try_new(ciphertext_modulus).unwrap(),
encryption_key_choice: {
match &*encryption_key_choice {
"big" => EncryptionKeyChoice::Big,
"small" => EncryptionKeyChoice::Small,
_ => panic!("Invalid encryption key choice"),
}
},
grouping_factor: LweBskGroupingFactor(grouping_factor),
deterministic_execution: false,
}
}
}
impl From<TestParameterSet> for AtomicPatternParameters {
fn from(value: TestParameterSet) -> Self {
match value {
TestParameterSet::TestClassicParameterSet(test_classic_parameter_set) => {
let classic = ClassicPBSParameters::from(test_classic_parameter_set);
classic.into()
}
TestParameterSet::TestMultiBitParameterSet(test_parameter_set_multi_bit) => {
let classic = MultiBitPBSParameters::from(test_parameter_set_multi_bit);
classic.into()
}
}
}
}
impl From<TestNoiseSquashingParamsMultiBit> for NoiseSquashingParameters {
fn from(value: TestNoiseSquashingParamsMultiBit) -> Self {
let TestNoiseSquashingParamsMultiBit {
glwe_dimension,
polynomial_size,
glwe_noise_distribution,
decomp_base_log,
decomp_level_count,
grouping_factor,
message_modulus,
carry_modulus,
ciphertext_modulus,
} = value;
Self::MultiBit(NoiseSquashingMultiBitParameters {
glwe_dimension: GlweDimension(glwe_dimension),
polynomial_size: PolynomialSize(polynomial_size),
glwe_noise_distribution: glwe_noise_distribution.into(),
decomp_base_log: DecompositionBaseLog(decomp_base_log),
decomp_level_count: DecompositionLevelCount(decomp_level_count),
grouping_factor: LweBskGroupingFactor(grouping_factor),
message_modulus: MessageModulus(message_modulus as u64),
carry_modulus: CarryModulus(carry_modulus as u64),
ciphertext_modulus: CoreCiphertextModulus::try_new(ciphertext_modulus).unwrap(),
deterministic_execution: false,
})
}
}
const TEST_FILENAME: Cow<'static, str> = Cow::Borrowed("client_key_with_noise_squashing");
const HL_CLIENTKEY_WITH_NOISE_SQUASHING_TEST: HlClientKeyTest = HlClientKeyTest {
test_filename: TEST_FILENAME,
parameters: INSECURE_SMALL_TEST_PARAMS_MULTI_BIT,
};
const HL_SERVERKEY_TEST: HlServerKeyTest = HlServerKeyTest {
test_filename: Cow::Borrowed("server_key_with_noise_squashing"),
client_key_filename: TEST_FILENAME,
compressed: false,
};
const HL_SQUASHED_NOISE_UNSIGNED_CIPHERTEXT_TEST: HlSquashedNoiseUnsignedCiphertextTest =
HlSquashedNoiseUnsignedCiphertextTest {
test_filename: Cow::Borrowed("squashed_noise_unsigned_ciphertext"),
key_filename: TEST_FILENAME,
clear_value: 42,
};
pub struct V1_4;
impl TfhersVersion for V1_4 {
const VERSION_NUMBER: &'static str = "1.4";
fn seed_prng(seed: u128) {
let mut seeder = DeterministicSeeder::<DefaultRandomGenerator>::new(Seed(seed));
let shortint_engine = ShortintEngine::new_from_seeder(&mut seeder);
ShortintEngine::with_thread_local_mut(|local_engine| {
let _ = std::mem::replace(local_engine, shortint_engine);
});
let boolean_engine = BooleanEngine::new_from_seeder(&mut seeder);
BooleanEngine::replace_thread_local(boolean_engine);
}
fn gen_shortint_data() -> Vec<TestMetadata> {
Vec::new()
}
fn gen_hl_data() -> Vec<TestMetadata> {
let dir = Self::data_dir().join(HL_MODULE_NAME);
create_dir_all(&dir).unwrap();
let config = tfhe_1_4::ConfigBuilder::with_custom_parameters(
HL_CLIENTKEY_WITH_NOISE_SQUASHING_TEST.parameters,
)
.enable_noise_squashing(INSECURE_SMALL_TEST_NOISE_SQUASHING_PARAMS_MULTI_BIT.into())
.build();
let hl_client_key = ClientKey::generate(config);
let hl_server_key = ServerKey::new(&hl_client_key);
set_server_key(hl_server_key.clone());
let input = FheUint32::encrypt(
HL_SQUASHED_NOISE_UNSIGNED_CIPHERTEXT_TEST.clear_value as u32,
&hl_client_key,
);
let ns = input.squash_noise().unwrap();
store_versioned_test!(
&hl_client_key,
&dir,
&HL_CLIENTKEY_WITH_NOISE_SQUASHING_TEST.test_filename
);
store_versioned_test!(&hl_server_key, &dir, &HL_SERVERKEY_TEST.test_filename,);
store_versioned_test!(
&ns,
&dir,
&HL_SQUASHED_NOISE_UNSIGNED_CIPHERTEXT_TEST.test_filename,
);
vec![
TestMetadata::HlClientKey(HL_CLIENTKEY_WITH_NOISE_SQUASHING_TEST),
TestMetadata::HlServerKey(HL_SERVERKEY_TEST),
TestMetadata::HlSquashedNoiseUnsignedCiphertext(
HL_SQUASHED_NOISE_UNSIGNED_CIPHERTEXT_TEST,
),
]
}
}

View File

@@ -8,12 +8,14 @@ use tfhe_0_11_versionable::Versionize as VersionizeTfhe_0_11;
use tfhe_1_0_versionable::Versionize as VersionizeTfhe_1_0;
use tfhe_1_1_versionable::Versionize as VersionizeTfhe_1_1;
use tfhe_1_3_versionable::Versionize as VersionizeTfhe_1_3;
use tfhe_1_4_versionable::Versionize as VersionizeTfhe_1_4;
use tfhe_versionable::{Versionize as VersionizeTfhe_0_10, Versionize as VersionizeTfhe_0_8};
use crate::{
data_dir, dir_for_version, TestClassicParameterSet, TestCompressionParameterSet,
TestDistribution, TestMetadata, TestModulusSwitchNoiseReductionParams, TestModulusSwitchType,
TestNoiseSquashingCompressionParameters, TestNoiseSquashingParams, TestParameterSet,
TestMultiBitParameterSet, TestNoiseSquashingCompressionParameters, TestNoiseSquashingParams,
TestNoiseSquashingParamsMultiBit, TestParameterSet,
};
pub const PRNG_SEED: u128 = 0xdeadbeef;
@@ -137,6 +139,27 @@ pub const INSECURE_SMALL_TEST_PARAMS_MS_MEAN_COMPENSATION: TestParameterSet =
modulus_switch_noise_reduction_params: TestModulusSwitchType::CenteredMeanNoiseReduction,
});
/// Those parameters are insecure and are used to generate small legacy public keys
pub const INSECURE_SMALL_TEST_PARAMS_MULTI_BIT: TestParameterSet =
TestParameterSet::from_multi(TestMultiBitParameterSet {
lwe_dimension: 4,
glwe_dimension: 1,
polynomial_size: 2048,
lwe_noise_distribution: TestDistribution::TUniform { bound_log2: 45 },
glwe_noise_distribution: TestDistribution::TUniform { bound_log2: 17 },
pbs_base_log: 22,
pbs_level: 1,
ks_base_log: 3,
ks_level: 5,
message_modulus: 4,
carry_modulus: 4,
max_noise_level: 5,
log2_p_fail: -134.345,
ciphertext_modulus: 1 << 64,
encryption_key_choice: Cow::Borrowed("big"),
grouping_factor: 4,
});
/// Those parameters are insecure and are used to generate small legacy public keys
/// Got with the above parameters for noise squashing
pub const INSECURE_SMALL_TEST_NOISE_SQUASHING_PARAMS_MS_NOISE_REDUCTION: TestNoiseSquashingParams =
@@ -171,6 +194,20 @@ pub const TEST_PRAMS_NOISE_SQUASHING_COMPRESSION: TestNoiseSquashingCompressionP
ciphertext_modulus: 0, // native modulus for u128
};
pub const INSECURE_SMALL_TEST_NOISE_SQUASHING_PARAMS_MULTI_BIT: TestNoiseSquashingParamsMultiBit =
TestNoiseSquashingParamsMultiBit {
glwe_dimension: 2,
polynomial_size: 2048,
glwe_noise_distribution: TestDistribution::TUniform { bound_log2: 30 },
decomp_base_log: 23,
decomp_level_count: 3,
grouping_factor: 4,
message_modulus: 4,
carry_modulus: 4,
// 0 interpreted as native modulus for u128
ciphertext_modulus: 0,
};
// Compression parameters for 2_2 TUniform
pub const VALID_TEST_PARAMS_TUNIFORM_COMPRESSION: TestCompressionParameterSet =
TestCompressionParameterSet {
@@ -260,6 +297,7 @@ define_store_versioned_test_fn!(store_versioned_test_tfhe_0_11, VersionizeTfhe_0
define_store_versioned_test_fn!(store_versioned_test_tfhe_1_0, VersionizeTfhe_1_0);
define_store_versioned_test_fn!(store_versioned_test_tfhe_1_1, VersionizeTfhe_1_1);
define_store_versioned_test_fn!(store_versioned_test_tfhe_1_3, VersionizeTfhe_1_3);
define_store_versioned_test_fn!(store_versioned_test_tfhe_1_4, VersionizeTfhe_1_4);
/// Stores the auxiliary data in `dir`, encoded in cbor, using the right tfhe-versionable version
macro_rules! define_store_versioned_auxiliary_fn {
@@ -281,6 +319,7 @@ define_store_versioned_auxiliary_fn!(store_versioned_auxiliary_tfhe_0_8, Version
define_store_versioned_auxiliary_fn!(store_versioned_auxiliary_tfhe_0_10, VersionizeTfhe_0_10);
define_store_versioned_auxiliary_fn!(store_versioned_auxiliary_tfhe_0_11, VersionizeTfhe_0_11);
define_store_versioned_auxiliary_fn!(store_versioned_auxiliary_tfhe_1_3, VersionizeTfhe_1_3);
define_store_versioned_auxiliary_fn!(store_versioned_auxiliary_tfhe_1_4, VersionizeTfhe_1_4);
pub fn store_metadata<Meta: Serialize, P: AsRef<Path>>(value: &Meta, path: P) {
let serialized = ron::ser::to_string_pretty(value, ron::ser::PrettyConfig::default()).unwrap();

View File

@@ -23,6 +23,8 @@ pub mod data_1_1;
#[cfg(feature = "generate")]
pub mod data_1_3;
#[cfg(feature = "generate")]
pub mod data_1_4;
#[cfg(feature = "generate")]
pub mod generate;
#[cfg(feature = "load")]
pub mod load;

View File

@@ -6,6 +6,7 @@ use tfhe_backward_compat_data::data_0_8::V0_8;
use tfhe_backward_compat_data::data_1_0::V1_0;
use tfhe_backward_compat_data::data_1_1::V1_1;
use tfhe_backward_compat_data::data_1_3::V1_3;
use tfhe_backward_compat_data::data_1_4::V1_4;
use tfhe_backward_compat_data::generate::{store_metadata, TfhersVersion, PRNG_SEED};
use tfhe_backward_compat_data::{data_dir, Testcase, HL_MODULE_NAME, SHORTINT_MODULE_NAME};
@@ -45,6 +46,7 @@ fn main() {
let handler_v1_0 = thread::spawn(gen_all_data::<V1_0>);
let handler_v1_1 = thread::spawn(gen_all_data::<V1_1>);
let handler_v1_3 = thread::spawn(gen_all_data::<V1_3>);
let handler_v1_4 = thread::spawn(gen_all_data::<V1_4>);
let mut testcases = vec![];
@@ -54,6 +56,7 @@ fn main() {
testcases.extend_from_slice(&handler_v1_0.join().unwrap());
testcases.extend_from_slice(&handler_v1_1.join().unwrap());
testcases.extend_from_slice(&handler_v1_3.join().unwrap());
testcases.extend_from_slice(&handler_v1_4.join().unwrap());
let shortint_testcases: Vec<Testcase> = testcases
.iter()