diff --git a/tfhe/benches/integer/zk_pke.rs b/tfhe/benches/integer/zk_pke.rs index 1df1f61e80..50eb69872e 100644 --- a/tfhe/benches/integer/zk_pke.rs +++ b/tfhe/benches/integer/zk_pke.rs @@ -64,7 +64,7 @@ fn pke_zk_proof(c: &mut Criterion) { let crs = CompactPkeCrs::from_shortint_params(param_pke, num_block * fhe_uint_count).unwrap(); - let public_params = crs.public_params(); + for compute_load in [ZkComputeLoad::Proof, ZkComputeLoad::Verify] { let zk_load = match compute_load { ZkComputeLoad::Proof => "compute_load_proof", @@ -78,7 +78,7 @@ fn pke_zk_proof(c: &mut Criterion) { b.iter(|| { let _ct1 = tfhe::integer::ProvenCompactCiphertextList::builder(&pk) .extend(messages.iter().copied()) - .build_with_proof_packed(public_params, &metadata, compute_load) + .build_with_proof_packed(&crs, &metadata, compute_load) .unwrap(); }) }); @@ -150,11 +150,10 @@ fn pke_zk_verify(c: &mut Criterion, results_file: &Path) { println!("Generating CRS... "); let crs = CompactPkeCrs::from_shortint_params(param_pke, num_block * fhe_uint_count).unwrap(); - let public_params = crs.public_params(); let shortint_params: PBSParameters = param_fhe.into(); - let crs_data = bincode::serialize(&public_params).unwrap(); + let crs_data = bincode::serialize(&crs).unwrap(); println!("CRS size: {}", crs_data.len()); @@ -187,7 +186,7 @@ fn pke_zk_verify(c: &mut Criterion, results_file: &Path) { println!("Generating proven ciphertext ({zk_load})... "); let ct1 = tfhe::integer::ProvenCompactCiphertextList::builder(&pk) .extend(messages.iter().copied()) - .build_with_proof_packed(public_params, &metadata, compute_load) + .build_with_proof_packed(&crs, &metadata, compute_load) .unwrap(); let proven_ciphertext_list_serialized = bincode::serialize(&ct1).unwrap(); @@ -234,7 +233,7 @@ fn pke_zk_verify(c: &mut Criterion, results_file: &Path) { bench_group.bench_function(&bench_id_verify, |b| { b.iter(|| { - let _ret = ct1.verify(public_params, &pk, &metadata); + let _ret = ct1.verify(&crs, &pk, &metadata); }); }); @@ -242,7 +241,7 @@ fn pke_zk_verify(c: &mut Criterion, results_file: &Path) { b.iter(|| { let _ret = ct1 .verify_and_expand( - public_params, + &crs, &pk, &metadata, IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary( diff --git a/tfhe/c_api_tests/test_high_level_zk.c b/tfhe/c_api_tests/test_high_level_zk.c index 77e6da56af..53dfbabd23 100644 --- a/tfhe/c_api_tests/test_high_level_zk.c +++ b/tfhe/c_api_tests/test_high_level_zk.c @@ -31,10 +31,6 @@ int main(void) { status = compact_pke_crs_from_config(config, max_num_bits, &crs); assert(status == 0); - CompactPkePublicParams *public_params; - status = compact_pke_crs_public_params(crs, &public_params); - assert(status == 0); - #define METADATA_LEN 5 uint8_t metadata[METADATA_LEN] = {'c', '-', 'a', 'p', 'i'}; @@ -71,7 +67,7 @@ int main(void) { assert(status == 0); status = compact_ciphertext_list_builder_build_with_proof_packed( - builder, public_params, metadata, METADATA_LEN, ZkComputeLoadProof, &compact_list); + builder, crs, metadata, METADATA_LEN, ZkComputeLoadProof, &compact_list); assert(status == 0); // Don't forget to destroy the builder @@ -85,7 +81,7 @@ int main(void) { FheUint2 *d = NULL; { CompactCiphertextListExpander *expander = NULL; - status = proven_compact_ciphertext_list_verify_and_expand(compact_list, public_params, pk, + status = proven_compact_ciphertext_list_verify_and_expand(compact_list, crs, pk, metadata, METADATA_LEN, &expander); assert(status == 0); @@ -132,7 +128,6 @@ int main(void) { client_key_destroy(client_key); server_key_destroy(server_key); compact_public_key_destroy(pk); - compact_pke_public_params_destroy(public_params); compact_pke_crs_destroy(crs); return EXIT_SUCCESS; diff --git a/tfhe/docs/guides/zk-pok.md b/tfhe/docs/guides/zk-pok.md index eb588c2057..321719e743 100644 --- a/tfhe/docs/guides/zk-pok.md +++ b/tfhe/docs/guides/zk-pok.md @@ -25,7 +25,6 @@ pub fn main() -> Result<(), Box> { let client_key = tfhe::ClientKey::generate(config.clone()); // This is done in an offline phase and the CRS is shared to all clients and the server let crs = CompactPkeCrs::from_config(config.into(), 64).unwrap(); - let public_zk_params = crs.public_params(); let server_key = tfhe::ServerKey::new(&client_key); let public_key = tfhe::CompactPublicKey::try_new(&client_key).unwrap(); // This can be left empty, but if provided allows to tie the proof to arbitrary data @@ -37,14 +36,14 @@ pub fn main() -> Result<(), Box> { let proven_compact_list = tfhe::ProvenCompactCiphertextList::builder(&public_key) .push(clear_a) .push(clear_b) - .build_with_proof_packed(public_zk_params, &metadata, ZkComputeLoad::Proof)?; + .build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof)?; // Server side let result = { set_server_key(server_key); // Verify the ciphertexts - let expander = proven_compact_list.verify_and_expand(public_zk_params, &public_key, &metadata)?; + let expander = proven_compact_list.verify_and_expand(&crs, &public_key, &metadata)?; let a: tfhe::FheUint64 = expander.get(0)?.unwrap(); let b: tfhe::FheUint64 = expander.get(1)?.unwrap(); @@ -99,7 +98,6 @@ pub fn main() -> Result<(), Box> { let client_key = tfhe::ClientKey::generate(config.clone()); // This is done in an offline phase and the CRS is shared to all clients and the server let crs = CompactPkeCrs::from_config(config.into(), 64).unwrap(); - let public_zk_params = crs.public_params(); let server_key = tfhe::ServerKey::new(&client_key); let public_key = tfhe::CompactPublicKey::try_new(&client_key).unwrap(); // This can be left empty, but if provided allows to tie the proof to arbitrary data @@ -111,7 +109,7 @@ pub fn main() -> Result<(), Box> { let proven_compact_list = tfhe::ProvenCompactCiphertextList::builder(&public_key) .push(clear_a) .push(clear_b) - .build_with_proof_packed(public_zk_params, &metadata, ZkComputeLoad::Verify)?; + .build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Verify)?; // Server side let result = { @@ -119,7 +117,7 @@ pub fn main() -> Result<(), Box> { // Verify the ciphertexts let expander = - proven_compact_list.verify_and_expand(public_zk_params, &public_key, &metadata)?; + proven_compact_list.verify_and_expand(&crs, &public_key, &metadata)?; let a: tfhe::FheUint64 = expander.get(0)?.unwrap(); let b: tfhe::FheUint64 = expander.get(1)?.unwrap(); diff --git a/tfhe/js_on_wasm_tests/test-hlapi-signed.js b/tfhe/js_on_wasm_tests/test-hlapi-signed.js index d9ec5b3642..cd5bd53fef 100644 --- a/tfhe/js_on_wasm_tests/test-hlapi-signed.js +++ b/tfhe/js_on_wasm_tests/test-hlapi-signed.js @@ -23,7 +23,6 @@ const { FheInt256, CompactCiphertextList, ProvenCompactCiphertextList, - CompactPkePublicParams, CompactPkeCrs, ZkComputeLoad, Shortint, @@ -509,12 +508,11 @@ test('hlapi_compact_ciphertext_list_with_proof', (t) => { let publicKey = TfheCompactPublicKey.new(clientKey); let crs = CompactPkeCrs.from_parameters(block_params, 2 + 32 + 1 + 256); - let public_params = crs.public_params(); const compress = false; // We don't compress as it's too slow on wasm - let serialized_pke_params = public_params.serialize(compress); + let serialized_pke_crs = crs.serialize(compress); let validate = false; // Also too slow on wasm - public_params = CompactPkePublicParams.deserialize(serialized_pke_params, compress, validate); + crs = CompactPkeCrs.deserialize(serialized_pke_crs, compress, validate); let clear_u2 = 3; let clear_i32 = -3284; @@ -526,7 +524,7 @@ test('hlapi_compact_ciphertext_list_with_proof', (t) => { builder.push_i32(clear_i32); builder.push_boolean(clear_bool); builder.push_u256(clear_u256); - let list = builder.build_with_proof_packed(public_params, ZkComputeLoad.Proof); + let list = builder.build_with_proof_packed(crs, ZkComputeLoad.Proof); let serialized = list.safe_serialize(BigInt(10000000)); let deserialized = ProvenCompactCiphertextList.safe_deserialize(serialized, BigInt(10000000)); diff --git a/tfhe/src/c_api/high_level_api/compact_list.rs b/tfhe/src/c_api/high_level_api/compact_list.rs index 7e0f0ffeb5..ce2474e79f 100644 --- a/tfhe/src/c_api/high_level_api/compact_list.rs +++ b/tfhe/src/c_api/high_level_api/compact_list.rs @@ -13,7 +13,7 @@ use crate::c_api::high_level_api::utils::{ impl_destroy_on_type, impl_serialize_deserialize_on_type, CApiIntegerType, }; #[cfg(feature = "zk-pok")] -use crate::c_api::high_level_api::zk::{CompactPkePublicParams, ZkComputeLoad}; +use crate::c_api::high_level_api::zk::{CompactPkeCrs, ZkComputeLoad}; use crate::c_api::utils::{catch_panic, get_mut_checked, get_ref_checked}; use crate::prelude::CiphertextList; use std::ffi::c_int; @@ -78,7 +78,7 @@ pub unsafe extern "C" fn compact_ciphertext_list_builder_build_packed( #[no_mangle] pub unsafe extern "C" fn compact_ciphertext_list_builder_build_with_proof_packed( builder: *const CompactCiphertextListBuilder, - public_params: *const CompactPkePublicParams, + crs: *const CompactPkeCrs, metadata: *const u8, metadata_len: usize, compute_load: ZkComputeLoad, @@ -86,7 +86,7 @@ pub unsafe extern "C" fn compact_ciphertext_list_builder_build_with_proof_packed ) -> c_int { catch_panic(|| { let builder = get_ref_checked(builder).unwrap(); - let public_params = get_ref_checked(public_params).unwrap(); + let crs = get_ref_checked(crs).unwrap(); let metadata = if metadata.is_null() { &[] @@ -97,7 +97,7 @@ pub unsafe extern "C" fn compact_ciphertext_list_builder_build_with_proof_packed let inner = builder .0 - .build_with_proof_packed(&public_params.0, metadata, compute_load.into()) + .build_with_proof_packed(&crs.0, metadata, compute_load.into()) .unwrap(); *list = Box::into_raw(Box::new(ProvenCompactCiphertextList(inner))); @@ -182,7 +182,7 @@ pub unsafe extern "C" fn compact_ciphertext_list_expand( #[no_mangle] pub unsafe extern "C" fn proven_compact_ciphertext_list_verify_and_expand( compact_list: *const ProvenCompactCiphertextList, - public_params: *const CompactPkePublicParams, + crs: *const CompactPkeCrs, public_key: *const CompactPublicKey, metadata: *const u8, metadata_len: usize, @@ -190,7 +190,7 @@ pub unsafe extern "C" fn proven_compact_ciphertext_list_verify_and_expand( ) -> c_int { catch_panic(|| { let list = get_ref_checked(compact_list).unwrap(); - let public_params = get_ref_checked(public_params).unwrap(); + let crs = get_ref_checked(crs).unwrap(); let public_key = get_ref_checked(public_key).unwrap(); let metadata = if metadata.is_null() { @@ -202,7 +202,7 @@ pub unsafe extern "C" fn proven_compact_ciphertext_list_verify_and_expand( let inner = list .0 - .verify_and_expand(&public_params.0, &public_key.0, metadata) + .verify_and_expand(&crs.0, &public_key.0, metadata) .unwrap(); *expander = Box::into_raw(Box::new(CompactCiphertextListExpander(inner))); diff --git a/tfhe/src/c_api/high_level_api/zk.rs b/tfhe/src/c_api/high_level_api/zk.rs index 52d8f01b0e..868d025ba9 100644 --- a/tfhe/src/c_api/high_level_api/zk.rs +++ b/tfhe/src/c_api/high_level_api/zk.rs @@ -20,16 +20,23 @@ impl From for crate::zk::ZkComputeLoad { } } +pub struct CompactPkeCrs(pub(crate) crate::core_crypto::entities::CompactPkeCrs); +impl_destroy_on_type!(CompactPkeCrs); + +// Because we use a repr(transparent) for the CompactPkeCrs, cbindgen will define CompactPkeCrs as +// an alias for CompactPkePublicParams. We need to define this struct even if it will not actually +// be used in the C api. +#[allow(unused)] pub struct CompactPkePublicParams(pub(crate) crate::core_crypto::entities::CompactPkePublicParams); impl_destroy_on_type!(CompactPkePublicParams); -/// Serializes the public params +/// Serializes the CRS /// /// If compress is true, the data will be compressed (less serialized bytes), however, this makes /// the deserialization process slower. #[no_mangle] -pub unsafe extern "C" fn compact_pke_public_params_serialize( - sself: *const CompactPkePublicParams, +pub unsafe extern "C" fn compact_pke_crs_serialize( + sself: *const CompactPkeCrs, compress: bool, result: *mut crate::c_api::buffer::DynamicBuffer, ) -> ::std::os::raw::c_int { @@ -48,13 +55,11 @@ pub unsafe extern "C" fn compact_pke_public_params_serialize( }) } -/// Deserializes the public params -/// -/// If the data comes from compressed public params, then `is_compressed` must be true. +/// Deserializes the CRS #[no_mangle] -pub unsafe extern "C" fn compact_pke_public_params_deserialize( +pub unsafe extern "C" fn compact_pke_crs_deserialize( buffer_view: crate::c_api::buffer::DynamicBufferView, - result: *mut *mut CompactPkePublicParams, + result: *mut *mut CompactPkeCrs, ) -> ::std::os::raw::c_int { crate::c_api::utils::catch_panic(|| { crate::c_api::utils::check_ptr_is_non_null_and_aligned(result).unwrap(); @@ -63,19 +68,19 @@ pub unsafe extern "C" fn compact_pke_public_params_deserialize( let deserialized = bincode::deserialize(buffer_view.as_slice()).unwrap(); - let heap_allocated_object = Box::new(CompactPkePublicParams(deserialized)); + let heap_allocated_object = Box::new(CompactPkeCrs(deserialized)); *result = Box::into_raw(heap_allocated_object); }) } -/// Serializes the public params +/// Serializes the CRS /// /// If compress is true, the data will be compressed (less serialized bytes), however, this makes /// the deserialization process slower. #[no_mangle] -pub unsafe extern "C" fn compact_pke_public_params_safe_serialize( - sself: *const CompactPkePublicParams, +pub unsafe extern "C" fn compact_pke_crs_safe_serialize( + sself: *const CompactPkeCrs, compress: bool, serialized_size_limit: u64, result: *mut crate::c_api::buffer::DynamicBuffer, @@ -100,14 +105,12 @@ pub unsafe extern "C" fn compact_pke_public_params_safe_serialize( }) } -/// Deserializes the public params -/// -/// If the data comes from compressed public params, then `is_compressed` must be true. +/// Deserializes the CRS #[no_mangle] -pub unsafe extern "C" fn compact_pke_public_params_safe_deserialize( +pub unsafe extern "C" fn compact_pke_crs_safe_deserialize( buffer_view: crate::c_api::buffer::DynamicBufferView, serialized_size_limit: u64, - result: *mut *mut CompactPkePublicParams, + result: *mut *mut CompactPkeCrs, ) -> ::std::os::raw::c_int { crate::c_api::utils::catch_panic(|| { crate::c_api::utils::check_ptr_is_non_null_and_aligned(result).unwrap(); @@ -122,16 +125,65 @@ pub unsafe extern "C" fn compact_pke_public_params_safe_deserialize( .deserialize_from(buffer_view) .unwrap(); - let heap_allocated_object = Box::new(CompactPkePublicParams(deserialized)); + let heap_allocated_object = Box::new(CompactPkeCrs(deserialized)); *result = Box::into_raw(heap_allocated_object); }) } -pub struct CompactPkeCrs(pub(crate) crate::core_crypto::entities::CompactPkeCrs); +/// Deserializes the CRS from a CompactPkePublicParams object that comes from a previous version of +/// TFHE-rs. This function is kept for backward compatibility, new code should directly use the +/// CompactPkeCrs object. +#[no_mangle] +pub unsafe extern "C" fn compact_pke_crs_deserialize_from_params( + buffer_view: crate::c_api::buffer::DynamicBufferView, + result: *mut *mut CompactPkeCrs, +) -> ::std::os::raw::c_int { + crate::c_api::utils::catch_panic(|| { + crate::c_api::utils::check_ptr_is_non_null_and_aligned(result).unwrap(); -impl_destroy_on_type!(CompactPkeCrs); + *result = std::ptr::null_mut(); + + let deserialized: crate::core_crypto::entities::CompactPkePublicParams = + bincode::deserialize(buffer_view.as_slice()).unwrap(); + let crs = deserialized.into(); + + let heap_allocated_object = Box::new(CompactPkeCrs(crs)); + + *result = Box::into_raw(heap_allocated_object); + }) +} +/// Deserializes the CRS from a CompactPkePublicParams object that comes from a previous version of +/// TFHE-rs. This function is kept for backward compatibility, new code should directly use the +/// CompactPkeCrs object. +#[no_mangle] +pub unsafe extern "C" fn compact_pke_crs_safe_deserialize_from_params( + buffer_view: crate::c_api::buffer::DynamicBufferView, + serialized_size_limit: u64, + result: *mut *mut CompactPkeCrs, +) -> ::std::os::raw::c_int { + crate::c_api::utils::catch_panic(|| { + crate::c_api::utils::check_ptr_is_non_null_and_aligned(result).unwrap(); + + *result = std::ptr::null_mut(); + + let buffer_view: &[u8] = buffer_view.as_slice(); + + let deserialized: crate::core_crypto::entities::CompactPkePublicParams = + crate::safe_serialization::DeserializationConfig::new(serialized_size_limit) + .disable_conformance() + .deserialize_from(buffer_view) + .unwrap(); + let crs = deserialized.into(); + + let heap_allocated_object = Box::new(CompactPkeCrs(crs)); + + *result = Box::into_raw(heap_allocated_object); + }) +} + +/// Creates a new CRS to generate zk pke proofs based on a config object. #[no_mangle] pub unsafe extern "C" fn compact_pke_crs_from_config( config: *const Config, @@ -147,17 +199,3 @@ pub unsafe extern "C" fn compact_pke_crs_from_config( *out_result = Box::into_raw(Box::new(CompactPkeCrs(crs))); }) } - -#[no_mangle] -pub unsafe extern "C" fn compact_pke_crs_public_params( - crs: *const CompactPkeCrs, - out_public_params: *mut *mut CompactPkePublicParams, -) -> c_int { - crate::c_api::utils::catch_panic(|| { - let crs = get_ref_checked(crs).unwrap(); - - *out_public_params = Box::into_raw(Box::new(CompactPkePublicParams( - crs.0.public_params().clone(), - ))); - }) -} diff --git a/tfhe/src/core_crypto/algorithms/lwe_encryption.rs b/tfhe/src/core_crypto/algorithms/lwe_encryption.rs index 330bcd5a7a..579c920796 100644 --- a/tfhe/src/core_crypto/algorithms/lwe_encryption.rs +++ b/tfhe/src/core_crypto/algorithms/lwe_encryption.rs @@ -1847,7 +1847,7 @@ fn verify_zero_knowledge_preconditions crate::Result<()> where Scalar: UnsignedInteger + CastFrom, @@ -1858,6 +1858,7 @@ where BodyDistribution: BoundedDistribution, KeyCont: Container, { + let public_params = crs.public_params(); let exclusive_max = public_params.exclusive_max_noise(); if Scalar::BITS < 64 && (1u64 << Scalar::BITS) >= exclusive_max { return Err( @@ -2200,21 +2201,16 @@ pub fn encrypt_lwe_ciphertext_with_compact_public_key< /// &mut secret_generator, /// &mut encryption_generator, /// &mut random_generator, -/// crs.public_params(), +/// &crs, /// &metadata, /// ZkComputeLoad::Proof, /// ) /// .unwrap(); /// /// // verify the ciphertext list with the proof -/// assert!(verify_lwe_ciphertext( -/// &lwe, -/// &lwe_compact_public_key, -/// &proof, -/// crs.public_params(), -/// &metadata -/// ) -/// .is_valid()); +/// assert!( +/// verify_lwe_ciphertext(&lwe, &lwe_compact_public_key, &proof, &crs, &metadata).is_valid() +/// ); /// /// let decrypted_plaintext = decrypt_lwe_ciphertext(&lwe_secret_key, &lwe); /// @@ -2254,7 +2250,7 @@ pub fn encrypt_and_prove_lwe_ciphertext_with_compact_public_key< secret_generator: &mut SecretRandomGenerator, encryption_generator: &mut EncryptionRandomGenerator, random_generator: &mut RandomGenerator, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], load: ZkComputeLoad, ) -> crate::Result @@ -2280,7 +2276,7 @@ where delta, mask_noise_distribution, body_noise_distribution, - public_params, + crs, )?; let CompactPublicKeyRandomVectors { @@ -2336,12 +2332,12 @@ where .copied() .map(CastFrom::cast_from) .collect::>(), - public_params, + crs.public_params(), random_generator, ); Ok(prove( - (public_params, &public_commit), + (crs.public_params(), &public_commit), &private_commit, metadata, load, @@ -2698,7 +2694,7 @@ pub fn encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// &mut secret_generator, /// &mut encryption_generator, /// &mut random_generator, -/// crs.public_params(), +/// &crs, /// &metadata, /// ZkComputeLoad::Proof, /// ) @@ -2709,7 +2705,7 @@ pub fn encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// &output_compact_ct_list, /// &lwe_compact_public_key, /// &proof, -/// crs.public_params(), +/// &crs, /// &metadata, /// ) /// .is_valid()); @@ -2760,7 +2756,7 @@ pub fn encrypt_and_prove_lwe_compact_ciphertext_list_with_compact_public_key< secret_generator: &mut SecretRandomGenerator, encryption_generator: &mut EncryptionRandomGenerator, random_generator: &mut RandomGenerator, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], load: ZkComputeLoad, ) -> crate::Result @@ -2787,7 +2783,7 @@ where delta, mask_noise_distribution, body_noise_distribution, - public_params, + crs, )?; let encoded = PlaintextList::from_container( @@ -2861,12 +2857,12 @@ where .copied() .map(CastFrom::cast_from) .collect::>(), - public_params, + crs.public_params(), random_generator, ); Ok(prove( - (public_params, &public_commit), + (crs.public_params(), &public_commit), &private_commit, metadata, load, @@ -3232,7 +3228,7 @@ pub fn par_encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// &mut secret_generator, /// &mut encryption_generator, /// &mut random_generator, -/// crs.public_params(), +/// &crs, /// &metadata, /// ZkComputeLoad::Proof, /// ) @@ -3243,7 +3239,7 @@ pub fn par_encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// &output_compact_ct_list, /// &lwe_compact_public_key, /// &proof, -/// crs.public_params(), +/// &crs, /// &metadata, /// ) /// .is_valid()); @@ -3294,7 +3290,7 @@ pub fn par_encrypt_and_prove_lwe_compact_ciphertext_list_with_compact_public_key secret_generator: &mut SecretRandomGenerator, encryption_generator: &mut EncryptionRandomGenerator, random_generator: &mut RandomGenerator, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], load: ZkComputeLoad, ) -> crate::Result @@ -3321,7 +3317,7 @@ where delta, mask_noise_distribution, body_noise_distribution, - public_params, + crs, )?; let encoded = PlaintextList::from_container( @@ -3395,12 +3391,12 @@ where .copied() .map(CastFrom::cast_from) .collect::>(), - public_params, + crs.public_params(), random_generator, ); Ok(prove( - (public_params, &public_commit), + (crs.public_params(), &public_commit), &private_commit, metadata, load, diff --git a/tfhe/src/core_crypto/algorithms/lwe_zero_knowledge_verification.rs b/tfhe/src/core_crypto/algorithms/lwe_zero_knowledge_verification.rs index 2ba365aa8a..529ad681ae 100644 --- a/tfhe/src/core_crypto/algorithms/lwe_zero_knowledge_verification.rs +++ b/tfhe/src/core_crypto/algorithms/lwe_zero_knowledge_verification.rs @@ -1,6 +1,6 @@ use crate::core_crypto::entities::{LweCompactCiphertextList, LweCompactPublicKey}; use crate::core_crypto::prelude::{CastFrom, Container, LweCiphertext, UnsignedInteger}; -use crate::zk::{CompactPkeProof, CompactPkePublicParams, ZkVerificationOutCome}; +use crate::zk::{CompactPkeCrs, CompactPkeProof, ZkVerificationOutCome}; use tfhe_zk_pok::proofs::pke::{verify, PublicCommit}; /// Verifies with the given proof that a [`LweCompactCiphertextList`] @@ -9,7 +9,7 @@ pub fn verify_lwe_compact_ciphertext_list( lwe_compact_list: &LweCompactCiphertextList, compact_public_key: &LweCompactPublicKey, proof: &CompactPkeProof, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], ) -> ZkVerificationOutCome where @@ -51,7 +51,7 @@ where .map(|x| i64::cast_from(x)) .collect(), ); - match verify(proof, (public_params, &public_commit), metadata) { + match verify(proof, (crs.public_params(), &public_commit), metadata) { Ok(_) => ZkVerificationOutCome::Valid, Err(_) => ZkVerificationOutCome::Invalid, } @@ -61,7 +61,7 @@ pub fn verify_lwe_ciphertext( lwe_ciphertext: &LweCiphertext, compact_public_key: &LweCompactPublicKey, proof: &CompactPkeProof, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], ) -> ZkVerificationOutCome where @@ -97,7 +97,7 @@ where .collect(), vec![i64::cast_from(*lwe_ciphertext.get_body().data); 1], ); - match verify(proof, (public_params, &public_commit), metadata) { + match verify(proof, (crs.public_params(), &public_commit), metadata) { Ok(_) => ZkVerificationOutCome::Valid, Err(_) => ZkVerificationOutCome::Invalid, } diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs b/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs index af7f7b79c7..9dd774719d 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs @@ -1064,7 +1064,7 @@ fn lwe_compact_public_encrypt_prove_verify_decrypt_custom_mod( &mut rsc.secret_random_generator, &mut rsc.encryption_random_generator, &mut random_generator, - crs.public_params(), + &crs, &metadata, ZkComputeLoad::Proof, ) @@ -1082,18 +1082,13 @@ fn lwe_compact_public_encrypt_prove_verify_decrypt_custom_mod( assert_eq!(msg, decoded); // Verify the proof - assert!( - verify_lwe_ciphertext(&ct, &pk, &proof, crs.public_params(), &metadata).is_valid() - ); + assert!(verify_lwe_ciphertext(&ct, &pk, &proof, &crs, &metadata).is_valid()); // verify proof with invalid ciphertext let index = random_generator.gen::() % ct.as_ref().len(); let value_to_add = random_generator.gen::(); ct.as_mut()[index] = ct.as_mut()[index].wrapping_add(value_to_add); - assert!( - verify_lwe_ciphertext(&ct, &pk, &proof, crs.public_params(), &metadata) - .is_invalid() - ); + assert!(verify_lwe_ciphertext(&ct, &pk, &proof, &crs, &metadata).is_invalid()); } // In coverage, we break after one while loop iteration, changing message values does not @@ -1193,7 +1188,7 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &mut secret_random_generator, &mut encryption_random_generator, &mut random_generator, - crs.public_params(), + &crs, &metadata, ZkComputeLoad::Proof, ) @@ -1203,7 +1198,7 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &output_compact_ct_list, &compact_lwe_pk, &proof, - crs.public_params(), + &crs, &metadata ) .is_valid()); @@ -1234,7 +1229,7 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &output_compact_ct_list, &compact_lwe_pk, &proof, - crs.public_params(), + &crs, &metadata ) .is_invalid()); @@ -1285,7 +1280,7 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &mut secret_random_generator, &mut encryption_random_generator, &mut random_generator, - crs.public_params(), + &crs, &metadata, ZkComputeLoad::Proof, ) @@ -1295,7 +1290,7 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &output_compact_ct_list, &compact_lwe_pk, &proof, - crs.public_params(), + &crs, &metadata ) .is_valid()); @@ -1326,7 +1321,7 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &output_compact_ct_list, &compact_lwe_pk, &proof, - crs.public_params(), + &crs, &metadata ) .is_invalid()); diff --git a/tfhe/src/high_level_api/compact_list.rs b/tfhe/src/high_level_api/compact_list.rs index 5aded5d62f..e7ff1a640c 100644 --- a/tfhe/src/high_level_api/compact_list.rs +++ b/tfhe/src/high_level_api/compact_list.rs @@ -21,7 +21,7 @@ use crate::shortint::MessageModulus; pub use zk::ProvenCompactCiphertextList; #[cfg(feature = "zk-pok")] -use crate::zk::{CompactPkePublicParams, ZkComputeLoad}; +use crate::zk::{CompactPkeCrs, ZkComputeLoad}; use crate::{CompactPublicKey, Tag}; impl crate::FheTypes { @@ -172,6 +172,7 @@ mod zk { use super::*; use crate::conformance::ParameterSetConformant; use crate::integer::ciphertext::IntegerProvenCompactCiphertextListConformanceParams; + use crate::zk::CompactPkeCrs; #[derive(Clone, Serialize, Deserialize, Versionize)] #[versionize(ProvenCompactCiphertextListVersions)] @@ -214,16 +215,16 @@ mod zk { pub fn verify( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, pk: &CompactPublicKey, metadata: &[u8], ) -> crate::zk::ZkVerificationOutCome { - self.inner.verify(public_params, &pk.key.key, metadata) + self.inner.verify(crs, &pk.key.key, metadata) } pub fn verify_and_expand( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, pk: &CompactPublicKey, metadata: &[u8], ) -> crate::Result { @@ -232,7 +233,7 @@ mod zk { // No ServerKey required, short circuit to avoid the global state call return Ok(CompactCiphertextListExpander { inner: self.inner.verify_and_expand( - public_params, + crs, &pk.key.key, metadata, IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking, @@ -246,7 +247,7 @@ mod zk { Some(InternalServerKey::Cpu(cpu_key)) => self .inner .verify_and_expand( - public_params, + crs, &pk.key.key, metadata, cpu_key.integer_compact_ciphertext_list_expansion_mode(), @@ -321,7 +322,6 @@ mod zk { let client_key = crate::ClientKey::generate(config.clone()); // This is done in an offline phase and the CRS is shared to all clients and the server let crs = CompactPkeCrs::from_config(config.into(), 64).unwrap(); - let public_zk_params = crs.public_params(); let public_key = crate::CompactPublicKey::try_new(&client_key).unwrap(); // This can be left empty, but if provided allows to tie the proof to arbitrary data let metadata = [b'T', b'F', b'H', b'E', b'-', b'r', b's']; @@ -332,7 +332,7 @@ mod zk { let proven_compact_list = crate::ProvenCompactCiphertextList::builder(&public_key) .push(clear_a) .push(clear_b) - .build_with_proof_packed(public_zk_params, &metadata, ZkComputeLoad::Proof) + .build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof) .unwrap(); let params = @@ -360,7 +360,6 @@ mod zk { let client_key = crate::ClientKey::generate(config.clone()); let crs = CompactPkeCrs::from_config(config.into(), 64).unwrap(); - let public_zk_params = crs.public_params(); let public_key = crate::CompactPublicKey::try_new(&client_key).unwrap(); let metadata = [b'T', b'F', b'H', b'E', b'-', b'r', b's']; @@ -371,7 +370,7 @@ mod zk { let proven_compact_list = crate::ProvenCompactCiphertextList::builder(&public_key) .push(clear_a) .push(clear_b) - .build_with_proof_packed(public_zk_params, &metadata, ZkComputeLoad::Proof) + .build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof) .unwrap(); let params = @@ -501,12 +500,12 @@ impl CompactCiphertextListBuilder { #[cfg(feature = "zk-pok")] pub fn build_with_proof_packed( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], compute_load: ZkComputeLoad, ) -> crate::Result { self.inner - .build_with_proof_packed(public_params, metadata, compute_load) + .build_with_proof_packed(crs, metadata, compute_load) .map(|proved_list| ProvenCompactCiphertextList { inner: proved_list, tag: self.tag.clone(), @@ -518,8 +517,6 @@ impl CompactCiphertextListBuilder { mod tests { use super::*; use crate::prelude::*; - #[cfg(feature = "zk-pok")] - use crate::zk::CompactPkeCrs; use crate::{set_server_key, FheBool, FheInt64, FheUint16, FheUint2, FheUint32}; #[test] @@ -664,13 +661,13 @@ mod tests { .push(false) .push_with_num_bits(3u32, 2) .unwrap() - .build_with_proof_packed(crs.public_params(), &metadata, ZkComputeLoad::Proof) + .build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof) .unwrap(); let serialized = bincode::serialize(&compact_list).unwrap(); let compact_list: ProvenCompactCiphertextList = bincode::deserialize(&serialized).unwrap(); let expander = compact_list - .verify_and_expand(crs.public_params(), &pk, &metadata) + .verify_and_expand(&crs, &pk, &metadata) .unwrap(); { @@ -753,13 +750,13 @@ mod tests { .push(false) .push_with_num_bits(3u32, 2) .unwrap() - .build_with_proof_packed(crs.public_params(), &metadata, ZkComputeLoad::Proof) + .build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof) .unwrap(); let serialized = bincode::serialize(&compact_list).unwrap(); let compact_list: ProvenCompactCiphertextList = bincode::deserialize(&serialized).unwrap(); let expander = compact_list - .verify_and_expand(crs.public_params(), &pk, &metadata) + .verify_and_expand(&crs, &pk, &metadata) .unwrap(); { diff --git a/tfhe/src/high_level_api/tests/tags_on_entities.rs b/tfhe/src/high_level_api/tests/tags_on_entities.rs index 457df1740c..a7e45ad7d2 100644 --- a/tfhe/src/high_level_api/tests/tags_on_entities.rs +++ b/tfhe/src/high_level_api/tests/tags_on_entities.rs @@ -58,18 +58,14 @@ fn test_tag_propagation_zk_pok() { .push(i64::MIN) .push(false) .push(true) - .build_with_proof_packed( - crs.public_params(), - &metadata, - crate::zk::ZkComputeLoad::Proof, - ) + .build_with_proof_packed(&crs, &metadata, crate::zk::ZkComputeLoad::Proof) .unwrap(); let list_packed: ProvenCompactCiphertextList = serialize_then_deserialize(list_packed); assert_eq!(list_packed.tag(), cks.tag()); let expander = list_packed - .verify_and_expand(crs.public_params(), &cpk, &metadata) + .verify_and_expand(&crs, &cpk, &metadata) .unwrap(); { diff --git a/tfhe/src/integer/ciphertext/compact_list.rs b/tfhe/src/integer/ciphertext/compact_list.rs index 0684cc1faa..eadca3fe6e 100644 --- a/tfhe/src/integer/ciphertext/compact_list.rs +++ b/tfhe/src/integer/ciphertext/compact_list.rs @@ -21,7 +21,7 @@ use crate::shortint::parameters::{ }; use crate::shortint::{CarryModulus, Ciphertext, MessageModulus}; #[cfg(feature = "zk-pok")] -use crate::zk::{CompactPkeCrs, CompactPkePublicParams, ZkComputeLoad, ZkVerificationOutCome}; +use crate::zk::{CompactPkeCrs, ZkComputeLoad, ZkVerificationOutCome}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -312,13 +312,13 @@ impl CompactCiphertextListBuilder { #[cfg(feature = "zk-pok")] pub fn build_with_proof( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], load: ZkComputeLoad, ) -> crate::Result { let ct_list = self.pk.key.encrypt_and_prove_slice( self.messages.as_slice(), - public_params, + crs, metadata, load, self.pk.key.parameters.message_modulus.0 as u64, @@ -332,7 +332,7 @@ impl CompactCiphertextListBuilder { #[cfg(feature = "zk-pok")] pub fn build_with_proof_packed( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], load: ZkComputeLoad, ) -> crate::Result { @@ -352,7 +352,7 @@ impl CompactCiphertextListBuilder { .collect::>(); let ct_list = self.pk.key.encrypt_and_prove_slice( packed_messages.as_slice(), - public_params, + crs, metadata, load, msg_mod * msg_mod, @@ -780,17 +780,16 @@ impl ProvenCompactCiphertextList { pub fn verify( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, public_key: &CompactPublicKey, metadata: &[u8], ) -> ZkVerificationOutCome { - self.ct_list - .verify(public_params, &public_key.key, metadata) + self.ct_list.verify(crs, &public_key.key, metadata) } pub fn verify_and_expand( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, public_key: &CompactPublicKey, metadata: &[u8], expansion_mode: IntegerCompactCiphertextListExpansionMode<'_>, @@ -826,7 +825,7 @@ impl ProvenCompactCiphertextList { None }; self.ct_list.verify_and_expand( - public_params, + crs, &public_key.key, metadata, ShortintCompactCiphertextListCastingMode::CastIfNecessary { @@ -837,7 +836,7 @@ impl ProvenCompactCiphertextList { } IntegerCompactCiphertextListExpansionMode::UnpackAndSanitizeIfNecessary(sks) => { let expanded_blocks = self.ct_list.verify_and_expand( - public_params, + crs, &public_key.key, metadata, ShortintCompactCiphertextListCastingMode::NoCasting, @@ -864,7 +863,7 @@ impl ProvenCompactCiphertextList { } IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking => { self.ct_list.verify_and_expand( - public_params, + crs, &public_key.key, metadata, ShortintCompactCiphertextListCastingMode::NoCasting, @@ -1007,17 +1006,14 @@ pub struct IntegerProvenCompactCiphertextListConformanceParams { impl IntegerProvenCompactCiphertextListConformanceParams { pub fn from_crs_and_parameters( value: CompactPublicKeyEncryptionParameters, - crs_params: &CompactPkeCrs, + crs: &CompactPkeCrs, ) -> Self { - Self::from_public_key_encryption_parameters_and_crs_parameters( - value, - crs_params.public_params(), - ) + Self::from_public_key_encryption_parameters_and_crs_parameters(value, crs) } pub fn from_public_key_encryption_parameters_and_crs_parameters( value: CompactPublicKeyEncryptionParameters, - crs_params: &crate::zk::CompactPkePublicParams, + crs: &CompactPkeCrs, ) -> Self { Self { encryption_lwe_dimension: value.encryption_lwe_dimension, @@ -1025,7 +1021,7 @@ impl IntegerProvenCompactCiphertextListConformanceParams { carry_modulus: value.carry_modulus, ciphertext_modulus: value.ciphertext_modulus, expansion_kind: value.expansion_kind, - max_elements_per_compact_list: crs_params.k, + max_elements_per_compact_list: crs.max_num_messages(), } } } @@ -1104,12 +1100,12 @@ mod tests { let proven_ct = CompactCiphertextList::builder(&pk) .extend_with_num_blocks(msgs.iter().copied(), num_blocks) - .build_with_proof_packed(crs.public_params(), &metadata, ZkComputeLoad::Proof) + .build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof) .unwrap(); let expander = proven_ct .verify_and_expand( - crs.public_params(), + &crs, &pk, &metadata, IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary(ksk.as_view()), @@ -1161,12 +1157,12 @@ mod tests { let proven_ct = CompactCiphertextList::builder(&pk) .extend_with_num_blocks(msgs.iter().copied(), encryption_num_blocks) - .build_with_proof_packed(crs.public_params(), &metadata, ZkComputeLoad::Proof) + .build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof) .unwrap(); let expander = proven_ct .verify_and_expand( - crs.public_params(), + &crs, &pk, &metadata, IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary(ksk.as_view()), @@ -1220,7 +1216,7 @@ mod tests { let proven_ct = CompactCiphertextList::builder(&pk) .extend_with_num_blocks(msgs.iter().copied(), encryption_num_blocks) - .build_with_proof_packed(crs.public_params(), &metadata, ZkComputeLoad::Proof) + .build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof) .unwrap(); let infos_block_count = { @@ -1272,7 +1268,7 @@ mod tests { let expander = proven_ct .verify_and_expand( - crs.public_params(), + &crs, &pk, &metadata, IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary(ksk.as_view()), diff --git a/tfhe/src/js_on_wasm_api/js_high_level_api/integers.rs b/tfhe/src/js_on_wasm_api/js_high_level_api/integers.rs index 5a58c9a2a7..2f3f4cb85b 100644 --- a/tfhe/src/js_on_wasm_api/js_high_level_api/integers.rs +++ b/tfhe/src/js_on_wasm_api/js_high_level_api/integers.rs @@ -4,7 +4,7 @@ use crate::integer::bigint::{StaticUnsignedBigInt, U1024, U2048, U512}; use crate::integer::{I256, U256}; use crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey; #[cfg(feature = "zk-pok")] -use crate::js_on_wasm_api::js_high_level_api::zk::{CompactPkePublicParams, ZkComputeLoad}; +use crate::js_on_wasm_api::js_high_level_api::zk::{CompactPkeCrs, ZkComputeLoad}; use crate::js_on_wasm_api::js_high_level_api::{catch_panic, catch_panic_result, into_js_error}; use js_sys::BigInt; use wasm_bindgen::prelude::*; @@ -794,14 +794,14 @@ impl ProvenCompactCiphertextList { #[wasm_bindgen] pub fn verify_and_expand( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, public_key: &TfheCompactPublicKey, metadata: &[u8], ) -> Result { catch_panic_result(|| { let inner = self .0 - .verify_and_expand(&public_params.0, &public_key.0, metadata) + .verify_and_expand(&crs.0, &public_key.0, metadata) .map_err(into_js_error)?; Ok(CompactCiphertextListExpander(inner)) }) @@ -1040,13 +1040,13 @@ impl CompactCiphertextListBuilder { #[cfg(feature = "zk-pok")] pub fn build_with_proof_packed( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], compute_load: ZkComputeLoad, ) -> Result { catch_panic_result(|| { self.0 - .build_with_proof_packed(&public_params.0, metadata, compute_load.into()) + .build_with_proof_packed(&crs.0, metadata, compute_load.into()) .map_err(into_js_error) .map(ProvenCompactCiphertextList) }) diff --git a/tfhe/src/js_on_wasm_api/js_high_level_api/zk.rs b/tfhe/src/js_on_wasm_api/js_high_level_api/zk.rs index 6a43251890..839afaa64f 100644 --- a/tfhe/src/js_on_wasm_api/js_high_level_api/zk.rs +++ b/tfhe/src/js_on_wasm_api/js_high_level_api/zk.rs @@ -25,13 +25,10 @@ impl From for crate::zk::ZkComputeLoad { #[wasm_bindgen] pub struct CompactPkeCrs(pub(crate) crate::core_crypto::entities::CompactPkeCrs); -#[wasm_bindgen] -pub struct CompactPkePublicParams(pub(crate) crate::zk::CompactPkePublicParams); - // "wasm bindgen is fragile and prefers the actual type vs. Self" #[allow(clippy::use_self)] #[wasm_bindgen] -impl CompactPkePublicParams { +impl CompactPkeCrs { #[wasm_bindgen] pub fn serialize(&self, compress: bool) -> Result, JsError> { catch_panic_result(|| { @@ -45,12 +42,12 @@ impl CompactPkePublicParams { } #[wasm_bindgen] - pub fn deserialize(buffer: &[u8]) -> Result { + pub fn deserialize(buffer: &[u8]) -> Result { // If buffer is compressed it is automatically detected and uncompressed. // TODO: handle validation catch_panic_result(|| { bincode::deserialize(buffer) - .map(CompactPkePublicParams) + .map(CompactPkeCrs) .map_err(into_js_error) }) } @@ -71,7 +68,7 @@ impl CompactPkePublicParams { pub fn safe_deserialize( buffer: &[u8], serialized_size_limit: u64, - ) -> Result { + ) -> Result { catch_panic_result(|| { crate::safe_serialization::DeserializationConfig::new(serialized_size_limit) .disable_conformance() @@ -80,12 +77,7 @@ impl CompactPkePublicParams { .map_err(into_js_error) }) } -} -// "wasm bindgen is fragile and prefers the actual type vs. Self" -#[allow(clippy::use_self)] -#[wasm_bindgen] -impl CompactPkeCrs { #[wasm_bindgen] pub fn from_parameters( parameters: &ShortintParameters, @@ -111,7 +103,28 @@ impl CompactPkeCrs { } #[wasm_bindgen] - pub fn public_params(&self) -> CompactPkePublicParams { - CompactPkePublicParams(self.0.public_params().clone()) + pub fn deserialize_from_public_params(buffer: &[u8]) -> Result { + // If buffer is compressed it is automatically detected and uncompressed. + catch_panic_result(|| { + bincode::deserialize(buffer) + .map(crate::zk::CompactPkePublicParams::into) + .map(CompactPkeCrs) + .map_err(into_js_error) + }) + } + + #[wasm_bindgen] + pub fn safe_deserialize_from_public_params( + buffer: &[u8], + serialized_size_limit: u64, + ) -> Result { + catch_panic_result(|| { + crate::safe_serialization::DeserializationConfig::new(serialized_size_limit) + .disable_conformance() + .deserialize_from(buffer) + .map(crate::zk::CompactPkePublicParams::into) + .map(CompactPkeCrs) + .map_err(into_js_error) + }) } } diff --git a/tfhe/src/shortint/ciphertext/zk.rs b/tfhe/src/shortint/ciphertext/zk.rs index 8446742d55..b1fc6196dd 100644 --- a/tfhe/src/shortint/ciphertext/zk.rs +++ b/tfhe/src/shortint/ciphertext/zk.rs @@ -10,10 +10,7 @@ use crate::shortint::parameters::{ MessageModulus, ShortintCompactCiphertextListCastingMode, }; use crate::shortint::{Ciphertext, CompactPublicKey}; -use crate::zk::{ - CompactPkeCrs, CompactPkeProof, CompactPkePublicParams, ZkMSBZeroPaddingBitCount, - ZkVerificationOutCome, -}; +use crate::zk::{CompactPkeCrs, CompactPkeProof, ZkMSBZeroPaddingBitCount, ZkVerificationOutCome}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use tfhe_versionable::Versionize; @@ -72,7 +69,7 @@ impl ProvenCompactCiphertextList { pub fn verify_and_expand( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, public_key: &CompactPublicKey, metadata: &[u8], casting_mode: ShortintCompactCiphertextListCastingMode<'_>, @@ -82,7 +79,7 @@ impl ProvenCompactCiphertextList { &ct_list.ct_list, &public_key.key, proof, - public_params, + crs, metadata, ) .is_invalid() @@ -166,7 +163,7 @@ impl ProvenCompactCiphertextList { pub fn verify( &self, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, public_key: &CompactPublicKey, metadata: &[u8], ) -> ZkVerificationOutCome { @@ -175,7 +172,7 @@ impl ProvenCompactCiphertextList { &ct_list.ct_list, &public_key.key, proof, - public_params, + crs, metadata, ) .is_valid() @@ -299,7 +296,7 @@ mod tests { let proven_ct = pk .encrypt_and_prove( msg, - crs.public_params(), + &crs, &metadata, ZkComputeLoad::Proof, encryption_modulus, @@ -317,7 +314,7 @@ mod tests { } let proven_ct = proven_ct.verify_and_expand( - crs.public_params(), + &crs, &pk, &metadata, ShortintCompactCiphertextListCastingMode::NoCasting, @@ -346,19 +343,17 @@ mod tests { let proven_ct = pk .encrypt_and_prove_slice( &msgs, - crs.public_params(), + &crs, &metadata, ZkComputeLoad::Proof, params.message_modulus.0 as u64, ) .unwrap(); - assert!(proven_ct - .verify(crs.public_params(), &pk, &metadata) - .is_valid()); + assert!(proven_ct.verify(&crs, &pk, &metadata).is_valid()); let expanded = proven_ct .verify_and_expand( - crs.public_params(), + &crs, &pk, &metadata, ShortintCompactCiphertextListCastingMode::NoCasting, diff --git a/tfhe/src/shortint/public_key/compact.rs b/tfhe/src/shortint/public_key/compact.rs index 7621960165..eaae438a2e 100644 --- a/tfhe/src/shortint/public_key/compact.rs +++ b/tfhe/src/shortint/public_key/compact.rs @@ -17,7 +17,7 @@ use crate::shortint::engine::ShortintEngine; use crate::shortint::parameters::compact_public_key_only::CompactPublicKeyEncryptionParameters; use crate::shortint::{CarryModulus, ClientKey, MessageModulus}; #[cfg(feature = "zk-pok")] -use crate::zk::{CompactPkePublicParams, ZkComputeLoad}; +use crate::zk::{CompactPkeCrs, ZkComputeLoad}; use crate::Error; use serde::{Deserialize, Serialize}; use tfhe_versionable::Versionize; @@ -256,18 +256,12 @@ impl CompactPublicKey { pub fn encrypt_and_prove( &self, message: u64, - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], load: ZkComputeLoad, encryption_modulus: u64, ) -> crate::Result { - self.encrypt_and_prove_slice( - &[message], - public_params, - metadata, - load, - encryption_modulus, - ) + self.encrypt_and_prove_slice(&[message], crs, metadata, load, encryption_modulus) } /// Encrypts the messages contained in the slice into a compact ciphertext list @@ -376,7 +370,7 @@ impl CompactPublicKey { pub fn encrypt_and_prove_slice( &self, messages: &[u64], - public_params: &CompactPkePublicParams, + crs: &CompactPkeCrs, metadata: &[u8], load: ZkComputeLoad, encryption_modulus: u64, @@ -390,9 +384,9 @@ impl CompactPublicKey { // encryption let max_ciphertext_per_bin = self.key.lwe_dimension().0; // This is the maximum of lwe message a single proof can prove - let max_num_message = public_params.k; + let max_num_messages = crs.max_num_messages(); // One of the two is the limiting factor for how much we can pack messages - let message_chunk_size = max_num_message.min(max_ciphertext_per_bin); + let message_chunk_size = max_num_messages.min(max_ciphertext_per_bin); let num_lists = messages.len().div_ceil(message_chunk_size); let mut proved_lists = Vec::with_capacity(num_lists); @@ -421,7 +415,7 @@ impl CompactPublicKey { &mut engine.secret_generator, &mut engine.encryption_generator, &mut engine.random_generator, - public_params, + crs, metadata, load, ) @@ -443,7 +437,7 @@ impl CompactPublicKey { &mut engine.secret_generator, &mut engine.encryption_generator, &mut engine.random_generator, - public_params, + crs, metadata, load, ) diff --git a/tfhe/src/zk.rs b/tfhe/src/zk.rs index 679c16a01f..b998d0a447 100644 --- a/tfhe/src/zk.rs +++ b/tfhe/src/zk.rs @@ -5,9 +5,11 @@ use crate::named::Named; #[cfg(feature = "shortint")] use crate::shortint::parameters::CompactPublicKeyEncryptionParameters; use rand_core::RngCore; +use serde::{Deserialize, Serialize}; use std::cmp::Ordering; use std::collections::Bound; use std::fmt::Debug; +use tfhe_versionable::Versionize; use tfhe_zk_pok::proofs::pke::crs_gen; pub use tfhe_zk_pok::curve_api::Compressible; @@ -35,7 +37,7 @@ impl Named for CompactPkePublicParams { const NAME: &'static str = "zk::CompactPkePublicParams"; } -pub struct CompactPkePublicParamsConformanceParams { +pub struct CompactPkeCrsConformanceParams { lwe_dim: LweDimension, max_num_message: usize, noise_bound: u64, @@ -44,8 +46,8 @@ pub struct CompactPkePublicParamsConformanceParams { msbs_zero_padding_bit_count: ZkMSBZeroPaddingBitCount, } -impl CompactPkePublicParamsConformanceParams { - #[cfg(feature = "shortint")] +#[cfg(feature = "shortint")] +impl CompactPkeCrsConformanceParams { pub fn new>( value: P, max_num_message: usize, @@ -82,7 +84,7 @@ impl CompactPkePublicParamsConformanceParams { } impl ParameterSetConformant for CompactPkePublicParams { - type ParameterSet = CompactPkePublicParamsConformanceParams; + type ParameterSet = CompactPkeCrsConformanceParams; fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool { self.k <= self.d @@ -123,12 +125,30 @@ impl ZkVerificationOutCome { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct ZkMSBZeroPaddingBitCount(pub u64); + +/// The CRS (Common Reference String) of a ZK scheme is a set of values shared between the prover +/// and the verifier. +/// +/// The same CRS should be used at the prove and verify steps. +#[derive(Clone, Debug, Serialize, Deserialize, Versionize)] +#[repr(transparent)] pub struct CompactPkeCrs { public_params: CompactPkePublicParams, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct ZkMSBZeroPaddingBitCount(pub u64); +impl Named for CompactPkeCrs { + const NAME: &'static str = "zk::CompactPkeCrs"; +} + +impl From for CompactPkeCrs { + fn from(value: CompactPkePublicParams) -> Self { + Self { + public_params: value, + } + } +} impl CompactPkeCrs { /// Prepare and check the CRS parameters. @@ -263,19 +283,64 @@ impl CompactPkeCrs { Ok(Self { public_params }) } + /// Maximum number of messages that can be proven in a single list using this CRS + pub fn max_num_messages(&self) -> usize { + self.public_params().k + } + pub fn public_params(&self) -> &CompactPkePublicParams { &self.public_params } } +impl ParameterSetConformant for CompactPkeCrs { + type ParameterSet = CompactPkeCrsConformanceParams; + + fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool { + self.public_params.is_conformant(parameter_set) + } +} + +/// The CRS can be compressed by only storing the `x` part of the elliptic curve coordinates. +#[derive(Serialize, Deserialize, Versionize)] +#[repr(transparent)] +pub struct CompressedCompactPkeCrs { + public_params: ::Compressed, +} + +// The NAME impl is the same as CompactPkeCrs because once serialized they are represented with the +// same object. Decompression is done automatically during deserialization. +impl Named for CompressedCompactPkeCrs { + const NAME: &'static str = CompactPkeCrs::NAME; +} + +impl Compressible for CompactPkeCrs { + type Compressed = CompressedCompactPkeCrs; + + type UncompressError = ::UncompressError; + + fn compress(&self) -> Self::Compressed { + CompressedCompactPkeCrs { + public_params: self.public_params.compress(), + } + } + + fn uncompress(compressed: Self::Compressed) -> Result { + Ok(Self { + public_params: Compressible::uncompress(compressed.public_params)?, + }) + } +} + #[cfg(all(test, feature = "shortint"))] mod test { use super::*; + use crate::safe_serialization::{safe_deserialize_conformant, safe_serialize}; use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; use crate::shortint::{CarryModulus, MessageModulus}; #[test] - fn test_public_params_conformance() { + fn test_crs_conformance() { let params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let mut bad_params = params; bad_params.carry_modulus = CarryModulus(8); @@ -294,17 +359,59 @@ mod test { ) .unwrap(); - let conformance_params = CompactPkePublicParamsConformanceParams::new(params, 4).unwrap(); + let conformance_params = CompactPkeCrsConformanceParams::new(params, 4).unwrap(); + + assert!(crs.is_conformant(&conformance_params)); + + let conformance_params = CompactPkeCrsConformanceParams::new(bad_params, 4).unwrap(); + + assert!(!crs.is_conformant(&conformance_params)); + + let conformance_params = CompactPkeCrsConformanceParams::new(params, 2).unwrap(); + + assert!(!crs.is_conformant(&conformance_params)); + } + + #[test] + fn test_crs_serialization() { + let params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + + let mut rng = rand::thread_rng(); + + let crs = CompactPkeCrs::new( + params.encryption_lwe_dimension, + 4, + params.encryption_noise_distribution, + params.ciphertext_modulus, + (params.message_modulus.0 * params.carry_modulus.0 * 2) as u64, + ZkMSBZeroPaddingBitCount(1), + &mut rng, + ) + .unwrap(); + + let conformance_params = CompactPkeCrsConformanceParams::new(params, 4).unwrap(); + + let mut serialized = Vec::new(); + safe_serialize(&crs, &mut serialized, 1 << 30).unwrap(); - assert!(crs.public_params().is_conformant(&conformance_params)); + let _crs_deser: CompactPkeCrs = + safe_deserialize_conformant(serialized.as_slice(), 1 << 30, &conformance_params) + .unwrap(); - let conformance_params = - CompactPkePublicParamsConformanceParams::new(bad_params, 4).unwrap(); + // Check that we are able to load public params + let mut serialized = Vec::new(); + safe_serialize(crs.public_params(), &mut serialized, 1 << 30).unwrap(); - assert!(!crs.public_params().is_conformant(&conformance_params)); + let _params_deser: CompactPkePublicParams = + safe_deserialize_conformant(serialized.as_slice(), 1 << 30, &conformance_params) + .unwrap(); - let conformance_params = CompactPkePublicParamsConformanceParams::new(params, 2).unwrap(); + // Check with compression + let mut serialized = Vec::new(); + safe_serialize(&crs.compress(), &mut serialized, 1 << 30).unwrap(); - assert!(!crs.public_params().is_conformant(&conformance_params)); + let _crs_deser: CompactPkeCrs = + safe_deserialize_conformant(serialized.as_slice(), 1 << 30, &conformance_params) + .unwrap(); } } diff --git a/tfhe/tests/backward_compatibility/high_level_api.rs b/tfhe/tests/backward_compatibility/high_level_api.rs index 9a74682d97..d74ef85d5a 100644 --- a/tfhe/tests/backward_compatibility/high_level_api.rs +++ b/tfhe/tests/backward_compatibility/high_level_api.rs @@ -4,6 +4,8 @@ use std::path::Path; use tfhe::prelude::{CiphertextList, FheDecrypt, FheEncrypt}; use tfhe::shortint::PBSParameters; #[cfg(feature = "zk-pok")] +use tfhe::zk::CompactPkeCrs; +#[cfg(feature = "zk-pok")] use tfhe::zk::CompactPkePublicParams; use tfhe::{ set_server_key, ClientKey, CompactCiphertextList, CompressedCiphertextList, @@ -148,9 +150,14 @@ pub fn test_zk_params( test: &ZkPkePublicParamsTest, format: DataFormat, ) -> Result { + // Since CompactPkeCrs is a repr(transparent) of a CompactPkePublicParams, both can be loaded + // from the same data, so we check this. #[cfg(feature = "zk-pok")] let _loaded_params: CompactPkePublicParams = load_and_unversionize(dir, test, format)?; + #[cfg(feature = "zk-pok")] + let _loaded_crs: CompactPkeCrs = load_and_unversionize(dir, test, format)?; + #[cfg(not(feature = "zk-pok"))] let _ = dir; @@ -180,10 +187,11 @@ pub fn test_hl_heterogeneous_ciphertext_list( #[cfg(feature = "zk-pok")] { let crs_file = dir.join(&*zk_info.params_filename); - let crs = CompactPkePublicParams::unversionize( + let public_params = CompactPkePublicParams::unversionize( load_versioned_auxiliary(crs_file).map_err(|e| test.failure(e, format))?, ) .map_err(|e| test.failure(e, format))?; + let crs = CompactPkeCrs::from(public_params); let pubkey_file = dir.join(&*zk_info.public_key_filename); let pubkey = CompactPublicKey::unversionize( diff --git a/tfhe/tests/zk_wasm_x86_test.rs b/tfhe/tests/zk_wasm_x86_test.rs index 9b1a601192..6d48a4274b 100644 --- a/tfhe/tests/zk_wasm_x86_test.rs +++ b/tfhe/tests/zk_wasm_x86_test.rs @@ -14,7 +14,7 @@ use tfhe::safe_serialization::{safe_deserialize, safe_serialize}; use tfhe::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; use tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use tfhe::zk::{CompactPkeCrs, CompactPkePublicParams}; +use tfhe::zk::CompactPkeCrs; use tfhe::{ClientKey, CompactPublicKey, ConfigBuilder, ProvenCompactCiphertextList}; const SIZE_LIMIT: u64 = 1024 * 1024 * 1024; @@ -59,7 +59,7 @@ fn gen_proven_ct_in_wasm(path: &Path) { fn verify_proof( public_key: &CompactPublicKey, - crs: &CompactPkePublicParams, + crs: &CompactPkeCrs, proven_ct: &ProvenCompactCiphertextList, ) { println!("Verifying proof"); @@ -86,12 +86,12 @@ fn test_proof_compat_with_wasm() { safe_serialize(&pub_key, &mut f_pubkey, SIZE_LIMIT).unwrap(); let mut f_crs = File::create(test_path.join("crs.bin")).unwrap(); - safe_serialize(crs.public_params(), &mut f_crs, SIZE_LIMIT).unwrap(); + safe_serialize(&crs, &mut f_crs, SIZE_LIMIT).unwrap(); gen_proven_ct_in_wasm(&test_path); let mut f_ct = File::open(test_path.join("proof.bin")).unwrap(); let proven_ct: ProvenCompactCiphertextList = safe_deserialize(&mut f_ct, SIZE_LIMIT).unwrap(); - verify_proof(&pub_key, crs.public_params(), &proven_ct); + verify_proof(&pub_key, &crs, &proven_ct); } diff --git a/tfhe/tests/zk_wasm_x86_test/index.js b/tfhe/tests/zk_wasm_x86_test/index.js index 3f708002a4..fc0001f47b 100644 --- a/tfhe/tests/zk_wasm_x86_test/index.js +++ b/tfhe/tests/zk_wasm_x86_test/index.js @@ -1,7 +1,7 @@ const { TfheCompactPublicKey, CompactCiphertextList, - CompactPkePublicParams, + CompactPkeCrs, ZkComputeLoad, } = require('node-tfhe'); @@ -14,7 +14,7 @@ const tfhe_proof = async () => { const publicKeyBuf = fs.readFileSync(`${__dirname}/public_key.bin`); const publicParamsBuf = fs.readFileSync(`${__dirname}/crs.bin`); const publicKey = TfheCompactPublicKey.safe_deserialize(publicKeyBuf, SIZE_LIMIT); - const publicParams = CompactPkePublicParams.safe_deserialize(publicParamsBuf, SIZE_LIMIT); + const publicParams = CompactPkeCrs.safe_deserialize(publicParamsBuf, SIZE_LIMIT); const builder = CompactCiphertextList.builder(publicKey); builder.push_u4(1); diff --git a/tfhe/web_wasm_parallel_tests/worker.js b/tfhe/web_wasm_parallel_tests/worker.js index 09190ee021..78b6db9f21 100644 --- a/tfhe/web_wasm_parallel_tests/worker.js +++ b/tfhe/web_wasm_parallel_tests/worker.js @@ -16,7 +16,6 @@ import init, { FheUint8, ZkComputeLoad, CompactPkeCrs, - CompactPkePublicParams, CompactCiphertextList, ProvenCompactCiphertextList, ShortintCompactPublicKeyEncryptionParameters, @@ -383,11 +382,10 @@ async function compactPublicKeyZeroKnowledgeTest() { console.time("CRS generation"); let crs = CompactPkeCrs.from_config(config, 4 * 64); console.timeEnd("CRS generation"); - let public_params = crs.public_params(); - let serialized = public_params.safe_serialize(BigInt(1000000000)); - console.log("CompactPkePublicParams size:", serialized.length); - let deserialized = CompactPkePublicParams.safe_deserialize( + let serialized = crs.safe_serialize(BigInt(1000000000)); + console.log("CompactPkeCrs size:", serialized.length); + let deserialized = CompactPkeCrs.safe_deserialize( serialized, BigInt(1000000000), ); @@ -403,7 +401,7 @@ async function compactPublicKeyZeroKnowledgeTest() { let builder = CompactCiphertextList.builder(publicKey); builder.push_u64(input); let list = builder.build_with_proof_packed( - public_params, + crs, metadata, ZkComputeLoad.Proof, ); @@ -421,11 +419,7 @@ async function compactPublicKeyZeroKnowledgeTest() { BigInt(10000000), ); - let expander = deserialized.verify_and_expand( - public_params, - publicKey, - metadata, - ); + let expander = deserialized.verify_and_expand(crs, publicKey, metadata); assert_eq(expander.get_uint64(0).decrypt(clientKey), input); @@ -447,7 +441,7 @@ async function compactPublicKeyZeroKnowledgeTest() { builder.push_u64(input); } let encrypted = builder.build_with_proof_packed( - public_params, + crs, metadata, ZkComputeLoad.Proof, ); @@ -458,11 +452,7 @@ async function compactPublicKeyZeroKnowledgeTest() { " ms", ); - let expander = encrypted.verify_and_expand( - public_params, - publicKey, - metadata, - ); + let expander = encrypted.verify_and_expand(crs, publicKey, metadata); assert_eq(expander.get_uint64(0).decrypt(clientKey), inputs[0]); @@ -700,7 +690,6 @@ async function compactPublicKeyZeroKnowledgeBench() { const metadata = new Uint8Array(320 / 8); crypto.getRandomValues(metadata); - let public_params = crs.public_params(); let inputs = Array.from(Array(encrypt_count).keys()).map((_) => U64_MAX); for (const loadChoice of load_choices) { let serialized_size = 0; @@ -714,7 +703,7 @@ async function compactPublicKeyZeroKnowledgeBench() { } const start = performance.now(); let list = compact_list_builder.build_with_proof_packed( - public_params, + crs, metadata, loadChoice, );