diff --git a/tests/backward_compatibility/high_level_api.rs b/tests/backward_compatibility/high_level_api.rs index 4f5e6494d..3372b75b5 100644 --- a/tests/backward_compatibility/high_level_api.rs +++ b/tests/backward_compatibility/high_level_api.rs @@ -18,8 +18,9 @@ use tfhe::zk::{CompactPkeCrs, CompactPkeCrsConformanceParams}; use tfhe::{ set_server_key, ClientKey, CompactCiphertextList, CompressedCiphertextList, CompressedCompactPublicKey, CompressedFheBool, CompressedFheInt8, CompressedFheUint8, - CompressedPublicKey, CompressedServerKey, CompressedSquashedNoiseCiphertextList, FheBool, - FheInt8, FheUint8, ReRandomizationContext, SquashedNoiseFheBool, SquashedNoiseFheInt, + CompressedKVStore, CompressedPublicKey, CompressedServerKey, + CompressedSquashedNoiseCiphertextList, FheBool, FheInt8, FheUint64, FheUint8, + ReRandomizationContext, ServerKey, SquashedNoiseFheBool, SquashedNoiseFheInt, SquashedNoiseFheUint, }; #[cfg(feature = "zk-pok")] @@ -28,7 +29,7 @@ use tfhe_backward_compat_data::load::{ load_versioned_auxiliary, DataFormat, TestFailure, TestResult, TestSuccess, }; use tfhe_backward_compat_data::{ - DataKind, HlBoolCiphertextTest, HlCiphertextTest, HlClientKeyTest, + DataKind, HlBoolCiphertextTest, HlCiphertextTest, HlClientKeyTest, HlCompressedKVStoreTest, HlCompressedSquashedNoiseCiphertextListTest, HlHeterogeneousCiphertextListTest, HlPublicKeyTest, HlServerKeyTest, HlSignedCiphertextTest, HlSquashedNoiseBoolCiphertextTest, HlSquashedNoiseSignedCiphertextTest, HlSquashedNoiseUnsignedCiphertextTest, TestMetadata, @@ -616,6 +617,54 @@ pub fn test_hl_compressed_squashed_noise_ciphertext_list( Ok(test.success(format)) } +fn test_hl_compressed_kv_store_test( + dir: &Path, + test: &HlCompressedKVStoreTest, + format: DataFormat, +) -> Result { + let client_key_file = dir.join(&*test.client_key_file_name); + let client_key = ClientKey::unversionize( + load_versioned_auxiliary(client_key_file).map_err(|e| test.failure(e, format))?, + ) + .map_err(|e| test.failure(format!("Failed to load client key file: {e}"), format))?; + + let server_key_file = dir.join(&*test.server_key_file_name); + let server_key = ServerKey::unversionize( + load_versioned_auxiliary(server_key_file).map_err(|e| test.failure(e, format))?, + ) + .map_err(|e| test.failure(format!("Failed to load server key file: {e}"), format))?; + + let file = dir.join(&*test.kv_store_file_name); + let compressed_kv_store = CompressedKVStore::::unversionize( + load_versioned_auxiliary(file).map_err(|e| test.failure(e, format))?, + ) + .map_err(|e| { + test.failure( + format!("Failed to load compressed kvstore file: {e}"), + format, + ) + })?; + + set_server_key(server_key); + let kv_store = compressed_kv_store.decompress().unwrap(); + for key in 0..test.num_elements as u32 { + if let Some(encrypted_value) = kv_store.get_with_clear_key(&key) { + let value: u64 = encrypted_value.decrypt(&client_key); + let expected = u64::MAX - u64::from(key); + if value != expected { + return Err(test.failure( + format!("Expected value for key {key} to be {expected}, got {value} instead"), + format, + )); + } + } else { + return Err(test.failure(format!("Expected an entry for key {key}"), format)); + } + } + + Ok(test.success(format)) +} + pub struct Hl; impl TestedModule for Hl { @@ -665,6 +714,9 @@ impl TestedModule for Hl { test_hl_compressed_squashed_noise_ciphertext_list(test_dir.as_ref(), test, format) .into() } + TestMetadata::HlCompressedKVStoreTest(test) => { + test_hl_compressed_kv_store_test(test_dir.as_ref(), test, format).into() + } _ => { println!("WARNING: missing test: {:?}", testcase.metadata); TestResult::Skipped(testcase.skip()) diff --git a/utils/tfhe-backward-compat-data/data/1_4/high_level_api/client_key_for_kv_store.cbor b/utils/tfhe-backward-compat-data/data/1_4/high_level_api/client_key_for_kv_store.cbor new file mode 100644 index 000000000..b278c1386 --- /dev/null +++ b/utils/tfhe-backward-compat-data/data/1_4/high_level_api/client_key_for_kv_store.cbor @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:42ebcf6ae83b4e99b80e09923ace8dbf13aecb075d41862aa70732673d35803a +size 5136 diff --git a/utils/tfhe-backward-compat-data/data/1_4/high_level_api/compressed_kv_store.bcode b/utils/tfhe-backward-compat-data/data/1_4/high_level_api/compressed_kv_store.bcode new file mode 100644 index 000000000..e437102e1 --- /dev/null +++ b/utils/tfhe-backward-compat-data/data/1_4/high_level_api/compressed_kv_store.bcode @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:508539be5551049798837bc576b2e81388b851a2c633be9df24a9e93700818a6 +size 139646 diff --git a/utils/tfhe-backward-compat-data/data/1_4/high_level_api/compressed_kv_store.cbor b/utils/tfhe-backward-compat-data/data/1_4/high_level_api/compressed_kv_store.cbor new file mode 100644 index 000000000..4f61f72f7 --- /dev/null +++ b/utils/tfhe-backward-compat-data/data/1_4/high_level_api/compressed_kv_store.cbor @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e22ffb92b3cbb0ae11bb6ae6126e956fe6431e3aee2a4bf959d7fcb6b0e2dd5d +size 160646 diff --git a/utils/tfhe-backward-compat-data/data/1_4/high_level_api/server_key_for_kv_store.cbor b/utils/tfhe-backward-compat-data/data/1_4/high_level_api/server_key_for_kv_store.cbor new file mode 100644 index 000000000..94a5a0da1 --- /dev/null +++ b/utils/tfhe-backward-compat-data/data/1_4/high_level_api/server_key_for_kv_store.cbor @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa2fe07e64812c288da355f1d379c9fe36f64139d884cddecba81b76a8f07761 +size 324955712 diff --git a/utils/tfhe-backward-compat-data/data/high_level_api.ron b/utils/tfhe-backward-compat-data/data/high_level_api.ron index 9fe546a0d..cd27df9a3 100644 --- a/utils/tfhe-backward-compat-data/data/high_level_api.ron +++ b/utils/tfhe-backward-compat-data/data/high_level_api.ron @@ -702,4 +702,14 @@ compressed: false, )), ), + ( + tfhe_version_min: "1.4", + tfhe_module: "high_level_api", + metadata: HlCompressedKVStoreTest(( + kv_store_file_name: "compressed_kv_store", + client_key_file_name: "client_key_for_kv_store", + server_key_file_name: "server_key_for_kv_store", + num_elements: 512, + )), + ), ] \ No newline at end of file diff --git a/utils/tfhe-backward-compat-data/src/data_1_4.rs b/utils/tfhe-backward-compat-data/src/data_1_4.rs index 1b9512f2c..394bf39f7 100644 --- a/utils/tfhe-backward-compat-data/src/data_1_4.rs +++ b/utils/tfhe-backward-compat-data/src/data_1_4.rs @@ -2,16 +2,19 @@ use crate::generate::{ store_versioned_auxiliary_tfhe_1_4, store_versioned_test_tfhe_1_4, TfhersVersion, INSECURE_DEDICATED_CPK_TEST_PARAMS, INSECURE_SMALL_TEST_NOISE_SQUASHING_PARAMS_MULTI_BIT, INSECURE_SMALL_TEST_PARAMS_MS_MEAN_COMPENSATION, INSECURE_SMALL_TEST_PARAMS_MULTI_BIT, - KS_TO_BIG_TEST_PARAMS, KS_TO_SMALL_TEST_PARAMS, + KS_TO_BIG_TEST_PARAMS, KS_TO_SMALL_TEST_PARAMS, VALID_TEST_PARAMS_TUNIFORM, + VALID_TEST_PARAMS_TUNIFORM_COMPRESSION, }; use crate::{ - HlClientKeyTest, HlServerKeyTest, HlSquashedNoiseUnsignedCiphertextTest, - TestClassicParameterSet, TestCompactPublicKeyEncryptionParameters, TestDistribution, + HlClientKeyTest, HlCompressedKVStoreTest, HlServerKeyTest, + HlSquashedNoiseUnsignedCiphertextTest, TestClassicParameterSet, + TestCompactPublicKeyEncryptionParameters, TestCompressionParameterSet, TestDistribution, TestKeySwitchingParams, TestMetadata, TestModulusSwitchNoiseReductionParams, TestModulusSwitchType, TestMultiBitParameterSet, TestNoiseSquashingParamsMultiBit, TestParameterSet, HL_MODULE_NAME, }; use std::borrow::Cow; +use std::collections::HashMap; use std::fs::create_dir_all; use tfhe_1_4::boolean::engine::BooleanEngine; @@ -22,18 +25,18 @@ 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, CompactCiphertextListExpansionKind, - CompactPublicKeyEncryptionParameters, CoreCiphertextModulus, DecompositionBaseLog, - DecompositionLevelCount, DynamicDistribution, EncryptionKeyChoice, GlweDimension, - LweBskGroupingFactor, LweCiphertextCount, LweDimension, MaxNoiseLevel, MessageModulus, - ModulusSwitchNoiseReductionParams, ModulusSwitchType, NoiseEstimationMeasureBound, - NoiseSquashingParameters, PolynomialSize, RSigmaFactor, ShortintKeySwitchingParameters, - StandardDev, SupportedCompactPkeZkScheme, Variance, + CarryModulus, CiphertextModulus, CiphertextModulusLog, CompactCiphertextListExpansionKind, + CompactPublicKeyEncryptionParameters, CompressionParameters, CoreCiphertextModulus, + DecompositionBaseLog, DecompositionLevelCount, DynamicDistribution, EncryptionKeyChoice, + GlweDimension, LweBskGroupingFactor, LweCiphertextCount, LweDimension, MaxNoiseLevel, + MessageModulus, ModulusSwitchNoiseReductionParams, ModulusSwitchType, + NoiseEstimationMeasureBound, NoiseSquashingParameters, PolynomialSize, RSigmaFactor, + ShortintKeySwitchingParameters, StandardDev, SupportedCompactPkeZkScheme, Variance, }; use tfhe_1_4::shortint::{AtomicPatternParameters, ClassicPBSParameters, MultiBitPBSParameters}; use tfhe_1_4::{ - set_server_key, ClientKey, CompressedCompactPublicKey, ConfigBuilder, FheUint32, Seed, - ServerKey, + set_server_key, ClientKey, CompressedCompactPublicKey, ConfigBuilder, FheUint32, FheUint64, + KVStore, Seed, ServerKey, }; macro_rules! store_versioned_test { @@ -269,6 +272,33 @@ impl From for CompactPublicKeyEncrypti } } +impl From for CompressionParameters { + fn from(value: TestCompressionParameterSet) -> Self { + let TestCompressionParameterSet { + br_level, + br_base_log, + packing_ks_level, + packing_ks_base_log, + packing_ks_polynomial_size, + packing_ks_glwe_dimension, + lwe_per_glwe, + storage_log_modulus, + packing_ks_key_noise_distribution, + } = value; + Self { + br_level: DecompositionLevelCount(br_level), + br_base_log: DecompositionBaseLog(br_base_log), + packing_ks_level: DecompositionLevelCount(packing_ks_level), + packing_ks_base_log: DecompositionBaseLog(packing_ks_base_log), + packing_ks_polynomial_size: PolynomialSize(packing_ks_polynomial_size), + packing_ks_glwe_dimension: GlweDimension(packing_ks_glwe_dimension), + lwe_per_glwe: LweCiphertextCount(lwe_per_glwe), + storage_log_modulus: CiphertextModulusLog(storage_log_modulus), + packing_ks_key_noise_distribution: packing_ks_key_noise_distribution.into(), + } + } +} + const TEST_FILENAME: Cow<'static, str> = Cow::Borrowed("client_key_with_noise_squashing"); const HL_CLIENTKEY_WITH_NOISE_SQUASHING_TEST: HlClientKeyTest = HlClientKeyTest { @@ -297,6 +327,13 @@ const HL_SERVERKEY_RERAND_TEST: HlServerKeyTest = HlServerKeyTest { compressed: false, }; +const HL_COMPRESSED_KV_STORE_TEST: HlCompressedKVStoreTest = HlCompressedKVStoreTest { + kv_store_file_name: Cow::Borrowed("compressed_kv_store"), + client_key_file_name: Cow::Borrowed("client_key_for_kv_store"), + server_key_file_name: Cow::Borrowed("server_key_for_kv_store"), + num_elements: 512, +}; + pub struct V1_4; impl TfhersVersion for V1_4 { @@ -390,6 +427,47 @@ impl TfhersVersion for V1_4 { ); } + // Test CompressedKVStore + { + let config = ConfigBuilder::with_custom_parameters(VALID_TEST_PARAMS_TUNIFORM) + .enable_compression(VALID_TEST_PARAMS_TUNIFORM_COMPRESSION.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 mut clear_store = HashMap::new(); + let mut store = KVStore::new(); + for key in 0..HL_COMPRESSED_KV_STORE_TEST.num_elements as u32 { + let value = u64::MAX - u64::from(key); + + let encrypted = FheUint64::encrypt(value, &hl_client_key); + + let _ = clear_store.insert(key, value); + let _ = store.insert_with_clear_key(key, encrypted); + } + + let compressed_kv_store = store.compress().unwrap(); + + store_versioned_auxiliary!( + &hl_client_key, + &dir, + &HL_COMPRESSED_KV_STORE_TEST.client_key_file_name + ); + + store_versioned_auxiliary!( + &hl_server_key, + &dir, + &HL_COMPRESSED_KV_STORE_TEST.server_key_file_name + ); + + store_versioned_test!( + &compressed_kv_store, + &dir, + &HL_COMPRESSED_KV_STORE_TEST.kv_store_file_name, + ); + } + vec![ TestMetadata::HlClientKey(HL_CLIENTKEY_WITH_NOISE_SQUASHING_TEST), TestMetadata::HlServerKey(HL_SERVERKEY_TEST), @@ -397,6 +475,7 @@ impl TfhersVersion for V1_4 { HL_SQUASHED_NOISE_UNSIGNED_CIPHERTEXT_TEST, ), TestMetadata::HlServerKey(HL_SERVERKEY_RERAND_TEST), + TestMetadata::HlCompressedKVStoreTest(HL_COMPRESSED_KV_STORE_TEST), ] } } diff --git a/utils/tfhe-backward-compat-data/src/lib.rs b/utils/tfhe-backward-compat-data/src/lib.rs index 153ab3e29..dc1c24059 100644 --- a/utils/tfhe-backward-compat-data/src/lib.rs +++ b/utils/tfhe-backward-compat-data/src/lib.rs @@ -624,6 +624,28 @@ impl TestType for ZkPkePublicParamsTest { } } +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct HlCompressedKVStoreTest { + pub kv_store_file_name: Cow<'static, str>, + pub client_key_file_name: Cow<'static, str>, + pub server_key_file_name: Cow<'static, str>, + pub num_elements: usize, +} + +impl TestType for HlCompressedKVStoreTest { + fn module(&self) -> String { + HL_MODULE_NAME.to_string() + } + + fn target_type(&self) -> String { + "CompressedKVStore".to_string() + } + + fn test_filename(&self) -> String { + self.kv_store_file_name.to_string() + } +} + #[derive(Serialize, Deserialize, Clone, Debug, Display)] pub enum TestMetadata { // Shortint @@ -644,6 +666,7 @@ pub enum TestMetadata { HlSquashedNoiseSignedCiphertext(HlSquashedNoiseSignedCiphertextTest), HlSquashedNoiseBoolCiphertext(HlSquashedNoiseBoolCiphertextTest), HlCompressedSquashedNoiseCiphertextList(HlCompressedSquashedNoiseCiphertextListTest), + HlCompressedKVStoreTest(HlCompressedKVStoreTest), } #[derive(Serialize, Deserialize, Clone, Debug)]