diff --git a/Makefile b/Makefile index 199c8034d6..9b33b8b123 100644 --- a/Makefile +++ b/Makefile @@ -284,6 +284,9 @@ clippy_c_api: install_rs_check_toolchain .PHONY: clippy_js_wasm_api # Run clippy lints enabling the boolean, shortint, integer and the js wasm API clippy_js_wasm_api: install_rs_check_toolchain + RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \ + --features=boolean-client-js-wasm-api,shortint-client-js-wasm-api,integer-client-js-wasm-api,high-level-client-js-wasm-api,zk-pok \ + -p $(TFHE_SPEC) -- --no-deps -D warnings RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \ --features=boolean-client-js-wasm-api,shortint-client-js-wasm-api,integer-client-js-wasm-api,high-level-client-js-wasm-api \ -p $(TFHE_SPEC) -- --no-deps -D warnings diff --git a/tfhe-zk-pok/Cargo.toml b/tfhe-zk-pok/Cargo.toml index dd53f6c260..6933143a7e 100644 --- a/tfhe-zk-pok/Cargo.toml +++ b/tfhe-zk-pok/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tfhe-zk-pok" -version = "0.3.0-alpha.0" +version = "0.3.0-alpha.1" edition = "2021" keywords = ["zero", "knowledge", "proof", "vector-commitments"] homepage = "https://zama.ai/" @@ -15,7 +15,9 @@ description = "tfhe-zk-pok: An implementation of zero-knowledge proofs of encryp ark-bls12-381 = { package = "tfhe-ark-bls12-381", version = "0.4.0" } ark-ec = { package = "tfhe-ark-ec", version = "0.4.2", features = ["parallel"] } ark-ff = { package = "tfhe-ark-ff", version = "0.4.3", features = ["parallel"] } -ark-poly = { package = "tfhe-ark-poly", version = "0.4.2", features = ["parallel"] } +ark-poly = { package = "tfhe-ark-poly", version = "0.4.2", features = [ + "parallel", +] } ark-serialize = { version = "0.4.2" } rand = "0.8.5" rayon = "1.8.0" @@ -26,3 +28,4 @@ num-bigint = "0.4.5" [dev-dependencies] serde_json = "~1.0" +itertools = "0.11.0" diff --git a/tfhe-zk-pok/src/proofs/pke.rs b/tfhe-zk-pok/src/proofs/pke.rs index 45818a59e0..945de8b417 100644 --- a/tfhe-zk-pok/src/proofs/pke.rs +++ b/tfhe-zk-pok/src/proofs/pke.rs @@ -194,6 +194,7 @@ pub fn commit( pub fn prove( public: (&PublicParams, &PublicCommit), private_commit: &PrivateCommit, + metadata: &[u8], load: ComputeLoad, rng: &mut dyn RngCore, ) -> Proof { @@ -347,7 +348,10 @@ pub fn prove( .collect::>(); let mut y = vec![G::Zp::ZERO; n]; - G::Zp::hash(&mut y, &[hash, x_bytes, c_hat.to_bytes().as_ref()]); + G::Zp::hash( + &mut y, + &[hash, metadata, x_bytes, c_hat.to_bytes().as_ref()], + ); let y = OneBased(y); let scalars = (n + 1 - big_d..n + 1) @@ -360,6 +364,7 @@ pub fn prove( &mut theta, &[ hash_lmap, + metadata, x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref(), @@ -379,6 +384,7 @@ pub fn prove( &mut t, &[ hash_t, + metadata, &(1..n + 1) .flat_map(|i| y[i].to_bytes().as_ref().to_vec()) .collect::>(), @@ -394,6 +400,7 @@ pub fn prove( &mut delta, &[ hash_agg, + metadata, x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref(), @@ -472,6 +479,7 @@ pub fn prove( core::array::from_mut(&mut z), &[ hash_z, + metadata, x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref(), @@ -512,6 +520,7 @@ pub fn prove( core::array::from_mut(&mut w), &[ hash_w, + metadata, x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref(), @@ -698,6 +707,7 @@ fn compute_a_theta( pub fn verify( proof: &Proof, public: (&PublicParams, &PublicCommit), + metadata: &[u8], ) -> Result<(), ()> { let &Proof { c_hat, @@ -760,7 +770,10 @@ pub fn verify( .collect::>(); let mut y = vec![G::Zp::ZERO; n]; - G::Zp::hash(&mut y, &[hash, x_bytes, c_hat.to_bytes().as_ref()]); + G::Zp::hash( + &mut y, + &[hash, metadata, x_bytes, c_hat.to_bytes().as_ref()], + ); let y = OneBased(y); let mut theta = vec![G::Zp::ZERO; d + k + 1]; @@ -768,6 +781,7 @@ pub fn verify( &mut theta, &[ hash_lmap, + metadata, x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref(), @@ -792,6 +806,7 @@ pub fn verify( &mut t, &[ hash_t, + metadata, &(1..n + 1) .flat_map(|i| y[i].to_bytes().as_ref().to_vec()) .collect::>(), @@ -807,6 +822,7 @@ pub fn verify( &mut delta, &[ hash_agg, + metadata, x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref(), @@ -821,6 +837,7 @@ pub fn verify( core::array::from_mut(&mut z), &[ hash_z, + metadata, x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref(), @@ -873,6 +890,7 @@ pub fn verify( core::array::from_mut(&mut w), &[ hash_w, + metadata, x_bytes, c_hat.to_bytes().as_ref(), c_y.to_bytes().as_ref(), @@ -1053,6 +1071,15 @@ mod tests { .wrapping_add((delta * m[i] as u64) as i64); } + // One of our usecases uses 320 bits of additional metadata + const METADATA_LEN: usize = (320 / u8::BITS) as usize; + + let mut metadata = [0u8; METADATA_LEN]; + metadata.fill_with(|| rng.gen::()); + + let mut fake_metadata = [255u8; METADATA_LEN]; + fake_metadata.fill_with(|| rng.gen::()); + let mut m_roundtrip = vec![0i64; k]; for i in 0..k { let mut dot = 0i128; @@ -1093,60 +1120,77 @@ mod tests { let public_param_that_was_not_compressed = serialize_then_deserialize(&original_public_param, Compress::Yes).unwrap(); - for public_param in [ - original_public_param, - public_param_that_was_compressed, - public_param_that_was_not_compressed, - ] { - for use_fake_e1 in [false, true] { - for use_fake_e2 in [false, true] { - for use_fake_m in [false, true] { - for use_fake_r in [false, true] { - let (public_commit, private_commit) = commit( - a.clone(), - b.clone(), - c1.clone(), - c2.clone(), - if use_fake_r { - fake_r.clone() - } else { - r.clone() - }, - if use_fake_e1 { - fake_e1.clone() - } else { - e1.clone() - }, - if use_fake_m { - fake_m.clone() - } else { - m.clone() - }, - if use_fake_e2 { - fake_e2.clone() - } else { - e2.clone() - }, - &public_param, - rng, - ); - - for load in [ComputeLoad::Proof, ComputeLoad::Verify] { - let proof = prove( - (&public_param, &public_commit), - &private_commit, - load, - rng, - ); - - assert_eq!( - verify(&proof, (&public_param, &public_commit)).is_err(), - use_fake_e1 || use_fake_e2 || use_fake_r || use_fake_m - ); - } - } - } - } + for ( + public_param, + use_fake_e1, + use_fake_e2, + use_fake_m, + use_fake_r, + use_fake_metadata_verify, + ) in itertools::iproduct!( + [ + original_public_param, + public_param_that_was_compressed, + public_param_that_was_not_compressed, + ], + [false, true], + [false, true], + [false, true], + [false, true], + [false, true] + ) { + let (public_commit, private_commit) = commit( + a.clone(), + b.clone(), + c1.clone(), + c2.clone(), + if use_fake_r { + fake_r.clone() + } else { + r.clone() + }, + if use_fake_e1 { + fake_e1.clone() + } else { + e1.clone() + }, + if use_fake_m { + fake_m.clone() + } else { + m.clone() + }, + if use_fake_e2 { + fake_e2.clone() + } else { + e2.clone() + }, + &public_param, + rng, + ); + + for load in [ComputeLoad::Proof, ComputeLoad::Verify] { + let proof = prove( + (&public_param, &public_commit), + &private_commit, + &metadata, + load, + rng, + ); + + let verify_metadata = if use_fake_metadata_verify { + &fake_metadata + } else { + &metadata + }; + + assert_eq!( + verify(&proof, (&public_param, &public_commit), verify_metadata).is_err(), + use_fake_e1 + || use_fake_e2 + || use_fake_r + || use_fake_m + || use_fake_metadata_verify + ); } } } diff --git a/tfhe/Cargo.toml b/tfhe/Cargo.toml index 6d2e41152e..7cd22740b5 100644 --- a/tfhe/Cargo.toml +++ b/tfhe/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tfhe" -version = "0.8.0-alpha.4" +version = "0.8.0-alpha.5" edition = "2021" readme = "../README.md" keywords = ["fully", "homomorphic", "encryption", "fhe", "cryptography"] @@ -75,7 +75,7 @@ sha3 = { version = "0.10", optional = true } # While we wait for repeat_n in rust standard library itertools = "0.11.0" rand_core = { version = "0.6.4", features = ["std"] } -tfhe-zk-pok = { version = "0.3.0-alpha.0", path = "../tfhe-zk-pok", optional = true } +tfhe-zk-pok = { version = "0.3.0-alpha.1", path = "../tfhe-zk-pok", optional = true } tfhe-versionable = { version = "0.2.1", path = "../utils/tfhe-versionable" } # wasm deps diff --git a/tfhe/benches/integer/zk_pke.rs b/tfhe/benches/integer/zk_pke.rs index 8ea5f2634f..015f006621 100644 --- a/tfhe/benches/integer/zk_pke.rs +++ b/tfhe/benches/integer/zk_pke.rs @@ -4,6 +4,7 @@ mod utilities; use criterion::{criterion_group, criterion_main, Criterion}; +use rand::prelude::*; use std::fs::{File, OpenOptions}; use std::io::Write; use std::path::Path; @@ -49,6 +50,11 @@ fn pke_zk_proof(c: &mut Criterion) { let _casting_key = KeySwitchingKey::new((&compact_private_key, None), (&cks, &sks), _param_casting); + // We have a use case with 320 bits of metadata + let mut metadata = [0u8; (320 / u8::BITS) as usize]; + let mut rng = rand::thread_rng(); + metadata.fill_with(|| rng.gen()); + for bits in [640usize, 1280, 4096] { assert_eq!(bits % 64, 0); // Packing, so we take the message and carry modulus to compute our block count @@ -77,7 +83,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, compute_load) + .build_with_proof_packed(public_params, &metadata, compute_load) .unwrap(); }) }); @@ -129,6 +135,11 @@ fn pke_zk_verify(c: &mut Criterion, results_file: &Path) { let casting_key = KeySwitchingKey::new((&compact_private_key, None), (&cks, &sks), param_casting); + // We have a use case with 320 bits of metadata + let mut metadata = [0u8; (320 / u8::BITS) as usize]; + let mut rng = rand::thread_rng(); + metadata.fill_with(|| rng.gen()); + for bits in [640usize, 1280, 4096] { assert_eq!(bits % 64, 0); // Packing, so we take the message and carry modulus to compute our block count @@ -184,7 +195,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, compute_load) + .build_with_proof_packed(public_params, &metadata, compute_load) .unwrap(); let proven_ciphertext_list_serialized = bincode::serialize(&ct1).unwrap(); @@ -231,7 +242,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); + let _ret = ct1.verify(public_params, &pk, &metadata); }); }); @@ -241,6 +252,7 @@ fn pke_zk_verify(c: &mut Criterion, results_file: &Path) { .verify_and_expand( public_params, &pk, + &metadata, IntegerCompactCiphertextListUnpackingMode::UnpackIfNecessary(&sks), IntegerCompactCiphertextListCastingMode::CastIfNecessary( casting_key.as_view(), diff --git a/tfhe/c_api_tests/test_high_level_zk.c b/tfhe/c_api_tests/test_high_level_zk.c index 992ad121ac..77e6da56af 100644 --- a/tfhe/c_api_tests/test_high_level_zk.c +++ b/tfhe/c_api_tests/test_high_level_zk.c @@ -35,6 +35,9 @@ int main(void) { 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'}; + ClientKey *client_key; ServerKey *server_key; status = generate_keys(config, &client_key, &server_key); @@ -47,8 +50,6 @@ int main(void) { status = compact_public_key_new(client_key, &pk); assert(status == 0); - - // Then, we create the compact list ProvenCompactCiphertextList *compact_list = NULL; { @@ -69,8 +70,8 @@ int main(void) { status = compact_ciphertext_list_builder_push_u2(builder, 3); assert(status == 0); - status = compact_ciphertext_list_builder_build_with_proof_packed(builder, public_params, - ZkComputeLoadProof, &compact_list); + status = compact_ciphertext_list_builder_build_with_proof_packed( + builder, public_params, metadata, METADATA_LEN, ZkComputeLoadProof, &compact_list); assert(status == 0); // Don't forget to destroy the builder @@ -85,7 +86,7 @@ int main(void) { { CompactCiphertextListExpander *expander = NULL; status = proven_compact_ciphertext_list_verify_and_expand(compact_list, public_params, pk, - &expander); + metadata, METADATA_LEN, &expander); assert(status == 0); status = compact_ciphertext_list_expander_get_fhe_uint32(expander, 0, &a); diff --git a/tfhe/docs/guides/zk-pok.md b/tfhe/docs/guides/zk-pok.md index 5754ebbae4..3a52bf0807 100644 --- a/tfhe/docs/guides/zk-pok.md +++ b/tfhe/docs/guides/zk-pok.md @@ -19,8 +19,7 @@ use tfhe::zk::{CompactPkeCrs, ZkComputeLoad}; pub fn main() -> Result<(), Box> { let mut rng = thread_rng(); - let params = - tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let params = tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let config = tfhe::ConfigBuilder::with_custom_parameters(params); let client_key = tfhe::ClientKey::generate(config.clone()); @@ -29,21 +28,24 @@ pub fn main() -> Result<(), Box> { 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 + let metadata = [b'T', b'F', b'H', b'E', b'-', b'r', b's']; let clear_a = rng.gen::(); let clear_b = rng.gen::(); - + let proven_compact_list = tfhe::ProvenCompactCiphertextList::builder(&public_key) .push(clear_a) .push(clear_b) - .build_with_proof_packed(public_zk_params, ZkComputeLoad::Proof)?; + .build_with_proof_packed(public_zk_params, &metadata, ZkComputeLoad::Proof)?; // Server side let result = { set_server_key(server_key); // Verify the ciphertexts - let mut expander = proven_compact_list.verify_and_expand(public_zk_params, &public_key)?; + let mut expander = + proven_compact_list.verify_and_expand(public_zk_params, &public_key, &metadata)?; let a: tfhe::FheUint64 = expander.get(0).unwrap()?; let b: tfhe::FheUint64 = expander.get(1).unwrap()?; @@ -101,6 +103,8 @@ pub fn main() -> Result<(), Box> { 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 + let metadata = [b'T', b'F', b'H', b'E', b'-', b'r', b's']; let clear_a = rng.gen::(); let clear_b = rng.gen::(); @@ -108,14 +112,15 @@ 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, ZkComputeLoad::Verify)?; + .build_with_proof_packed(public_zk_params, &metadata, ZkComputeLoad::Verify)?; // Server side let result = { set_server_key(server_key); // Verify the ciphertexts - let mut expander = proven_compact_list.verify_and_expand(public_zk_params, &public_key)?; + let mut expander = + proven_compact_list.verify_and_expand(public_zk_params, &public_key, &metadata)?; let a: tfhe::FheUint64 = expander.get(0).unwrap()?; let b: tfhe::FheUint64 = expander.get(1).unwrap()?; 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 67ce1a3fa6..5e0e045593 100644 --- a/tfhe/src/c_api/high_level_api/compact_list.rs +++ b/tfhe/src/c_api/high_level_api/compact_list.rs @@ -78,15 +78,25 @@ pub unsafe extern "C" fn compact_ciphertext_list_builder_build_packed( pub unsafe extern "C" fn compact_ciphertext_list_builder_build_with_proof_packed( builder: *const CompactCiphertextListBuilder, public_params: *const CompactPkePublicParams, + metadata: *const u8, + metadata_len: usize, compute_load: ZkComputeLoad, list: *mut *mut ProvenCompactCiphertextList, ) -> c_int { catch_panic(|| { let builder = get_ref_checked(builder).unwrap(); let public_params = get_ref_checked(public_params).unwrap(); + + let metadata = if metadata.is_null() { + &[] + } else { + let _metadata_check_ptr = get_ref_checked(metadata).unwrap(); + core::slice::from_raw_parts(metadata, metadata_len) + }; + let inner = builder .0 - .build_with_proof_packed(&public_params.0, compute_load.into()) + .build_with_proof_packed(&public_params.0, metadata, compute_load.into()) .unwrap(); *list = Box::into_raw(Box::new(ProvenCompactCiphertextList(inner))); @@ -173,6 +183,8 @@ pub unsafe extern "C" fn proven_compact_ciphertext_list_verify_and_expand( compact_list: *const ProvenCompactCiphertextList, public_params: *const CompactPkePublicParams, public_key: *const CompactPublicKey, + metadata: *const u8, + metadata_len: usize, expander: *mut *mut CompactCiphertextListExpander, ) -> c_int { catch_panic(|| { @@ -180,9 +192,16 @@ pub unsafe extern "C" fn proven_compact_ciphertext_list_verify_and_expand( let public_params = get_ref_checked(public_params).unwrap(); let public_key = get_ref_checked(public_key).unwrap(); + let metadata = if metadata.is_null() { + &[] + } else { + let _metadata_check_ptr = get_ref_checked(metadata).unwrap(); + core::slice::from_raw_parts(metadata, metadata_len) + }; + let inner = list .0 - .verify_and_expand(&public_params.0, &public_key.0) + .verify_and_expand(&public_params.0, &public_key.0, metadata) .unwrap(); *expander = Box::into_raw(Box::new(CompactCiphertextListExpander(inner))); diff --git a/tfhe/src/core_crypto/algorithms/lwe_encryption.rs b/tfhe/src/core_crypto/algorithms/lwe_encryption.rs index 6ae1ce2e89..8ab481f343 100644 --- a/tfhe/src/core_crypto/algorithms/lwe_encryption.rs +++ b/tfhe/src/core_crypto/algorithms/lwe_encryption.rs @@ -2153,6 +2153,10 @@ pub fn encrypt_lwe_ciphertext_with_compact_public_key< /// let delta = 1u64 << delta_log; /// let plaintext_modulus = 1u64 << (64 - delta_log); /// +/// // We can add custom metadata that will be required for verification, allowing to tie the proof +/// // to some arbitrary data. +/// let metadata = [b'T', b'F', b'H', b'E', b'-', b'r', b's']; +/// /// // Create the PRNG /// let mut seeder = new_seeder(); /// let seeder = seeder.as_mut(); @@ -2200,15 +2204,20 @@ pub fn encrypt_lwe_ciphertext_with_compact_public_key< /// &mut encryption_generator, /// &mut random_generator, /// crs.public_params(), +/// &metadata, /// ZkComputeLoad::Proof, /// ) /// .unwrap(); /// /// // verify the ciphertext list with the proof -/// assert!( -/// verify_lwe_ciphertext(&lwe, &lwe_compact_public_key, &proof, crs.public_params()) -/// .is_valid() -/// ); +/// assert!(verify_lwe_ciphertext( +/// &lwe, +/// &lwe_compact_public_key, +/// &proof, +/// crs.public_params(), +/// &metadata +/// ) +/// .is_valid()); /// /// let decrypted_plaintext = decrypt_lwe_ciphertext(&lwe_secret_key, &lwe); /// @@ -2246,6 +2255,7 @@ pub fn encrypt_and_prove_lwe_ciphertext_with_compact_public_key< encryption_generator: &mut EncryptionRandomGenerator, random_generator: &mut RandomGenerator, public_params: &CompactPkePublicParams, + metadata: &[u8], load: ZkComputeLoad, ) -> crate::Result where @@ -2333,6 +2343,7 @@ where Ok(prove( (public_params, &public_commit), &private_commit, + metadata, load, random_generator, )) @@ -2628,6 +2639,10 @@ pub fn encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// let delta = 1u64 << delta_log; /// let plaintext_modulus = 1u64 << (64 - delta_log); /// +/// // We can add custom metadata that will be required for verification, allowing to tie the proof +/// // to some arbitrary data. +/// let metadata = [b'T', b'F', b'H', b'E', b'-', b'r', b's']; +/// /// // Create the PRNG /// let mut seeder = new_seeder(); /// let seeder = seeder.as_mut(); @@ -2679,6 +2694,7 @@ pub fn encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// &mut encryption_generator, /// &mut random_generator, /// crs.public_params(), +/// &metadata, /// ZkComputeLoad::Proof, /// ) /// .unwrap(); @@ -2689,6 +2705,7 @@ pub fn encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// &lwe_compact_public_key, /// &proof, /// crs.public_params(), +/// &metadata, /// ) /// .is_valid()); /// @@ -2737,6 +2754,7 @@ pub fn encrypt_and_prove_lwe_compact_ciphertext_list_with_compact_public_key< encryption_generator: &mut EncryptionRandomGenerator, random_generator: &mut RandomGenerator, public_params: &CompactPkePublicParams, + metadata: &[u8], load: ZkComputeLoad, ) -> crate::Result where @@ -2843,6 +2861,7 @@ where Ok(prove( (public_params, &public_commit), &private_commit, + metadata, load, random_generator, )) @@ -3148,6 +3167,10 @@ pub fn par_encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// let delta = 1u64 << delta_log; /// let plaintext_modulus = 1u64 << (64 - delta_log); /// +/// // We can add custom metadata that will be required for verification, allowing to tie the proof +/// // to some arbitrary data. +/// let metadata = [b'T', b'F', b'H', b'E', b'-', b'r', b's']; +/// /// // Create the PRNG /// let mut seeder = new_seeder(); /// let seeder = seeder.as_mut(); @@ -3199,6 +3222,7 @@ pub fn par_encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// &mut encryption_generator, /// &mut random_generator, /// crs.public_params(), +/// &metadata, /// ZkComputeLoad::Proof, /// ) /// .unwrap(); @@ -3209,6 +3233,7 @@ pub fn par_encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// &lwe_compact_public_key, /// &proof, /// crs.public_params(), +/// &metadata, /// ) /// .is_valid()); /// @@ -3257,6 +3282,7 @@ pub fn par_encrypt_and_prove_lwe_compact_ciphertext_list_with_compact_public_key encryption_generator: &mut EncryptionRandomGenerator, random_generator: &mut RandomGenerator, public_params: &CompactPkePublicParams, + metadata: &[u8], load: ZkComputeLoad, ) -> crate::Result where @@ -3363,6 +3389,7 @@ where Ok(prove( (public_params, &public_commit), &private_commit, + metadata, load, random_generator, )) 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 2f0e2d4a57..2ba365aa8a 100644 --- a/tfhe/src/core_crypto/algorithms/lwe_zero_knowledge_verification.rs +++ b/tfhe/src/core_crypto/algorithms/lwe_zero_knowledge_verification.rs @@ -10,6 +10,7 @@ pub fn verify_lwe_compact_ciphertext_list( compact_public_key: &LweCompactPublicKey, proof: &CompactPkeProof, public_params: &CompactPkePublicParams, + metadata: &[u8], ) -> ZkVerificationOutCome where Scalar: UnsignedInteger, @@ -50,7 +51,7 @@ where .map(|x| i64::cast_from(x)) .collect(), ); - match verify(proof, (public_params, &public_commit)) { + match verify(proof, (public_params, &public_commit), metadata) { Ok(_) => ZkVerificationOutCome::Valid, Err(_) => ZkVerificationOutCome::Invalid, } @@ -61,6 +62,7 @@ pub fn verify_lwe_ciphertext( compact_public_key: &LweCompactPublicKey, proof: &CompactPkeProof, public_params: &CompactPkePublicParams, + metadata: &[u8], ) -> ZkVerificationOutCome where Scalar: UnsignedInteger, @@ -95,7 +97,7 @@ where .collect(), vec![i64::cast_from(*lwe_ciphertext.get_body().data); 1], ); - match verify(proof, (public_params, &public_commit)) { + match verify(proof, (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 a894bbeb6c..98372df29b 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs @@ -1012,6 +1012,8 @@ fn lwe_compact_public_encrypt_prove_verify_decrypt_custom_mod( let message_modulus_log = params.message_modulus_log; let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus); + let metadata = [b'c', b'o', b'r', b'e']; + let mut rsc = TestResources::new(); let mut random_generator = RandomGenerator::::new(rsc.seeder.seed()); @@ -1061,6 +1063,7 @@ fn lwe_compact_public_encrypt_prove_verify_decrypt_custom_mod( &mut rsc.encryption_random_generator, &mut random_generator, crs.public_params(), + &metadata, ZkComputeLoad::Proof, ) .unwrap(); @@ -1077,13 +1080,18 @@ 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()).is_valid()); + assert!( + verify_lwe_ciphertext(&ct, &pk, &proof, crs.public_params(), &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()).is_invalid()); + assert!( + verify_lwe_ciphertext(&ct, &pk, &proof, crs.public_params(), &metadata) + .is_invalid() + ); } // In coverage, we break after one while loop iteration, changing message values does not @@ -1107,6 +1115,8 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { let glwe_noise_distribution = TUniform::new(9); let ciphertext_modulus = CiphertextModulus::new_native(); + let metadata = [b'c', b'o', b'r', b'e']; + let delta_log = 59; let delta = 1u64 << delta_log; let message_modulus = 1u64 << (64 - (delta_log + 1)); @@ -1179,6 +1189,7 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &mut encryption_random_generator, &mut random_generator, crs.public_params(), + &metadata, ZkComputeLoad::Proof, ) .unwrap(); @@ -1187,7 +1198,8 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &output_compact_ct_list, &compact_lwe_pk, &proof, - crs.public_params() + crs.public_params(), + &metadata ) .is_valid()); @@ -1217,7 +1229,8 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &output_compact_ct_list, &compact_lwe_pk, &proof, - crs.public_params() + crs.public_params(), + &metadata ) .is_invalid()); @@ -1268,6 +1281,7 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &mut encryption_random_generator, &mut random_generator, crs.public_params(), + &metadata, ZkComputeLoad::Proof, ) .unwrap(); @@ -1276,7 +1290,8 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &output_compact_ct_list, &compact_lwe_pk, &proof, - crs.public_params() + crs.public_params(), + &metadata ) .is_valid()); @@ -1306,7 +1321,8 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { &output_compact_ct_list, &compact_lwe_pk, &proof, - crs.public_params() + crs.public_params(), + &metadata ) .is_invalid()); diff --git a/tfhe/src/high_level_api/compact_list.rs b/tfhe/src/high_level_api/compact_list.rs index d4d6fdd87d..4c83105918 100644 --- a/tfhe/src/high_level_api/compact_list.rs +++ b/tfhe/src/high_level_api/compact_list.rs @@ -233,6 +233,7 @@ mod zk { &self, public_params: &CompactPkePublicParams, pk: &CompactPublicKey, + metadata: &[u8], ) -> crate::Result { // For WASM if !self.inner.is_packed() && !self.inner.needs_casting() { @@ -241,6 +242,7 @@ mod zk { inner: self.inner.verify_and_expand( public_params, &pk.key.key, + metadata, IntegerCompactCiphertextListUnpackingMode::NoUnpacking, IntegerCompactCiphertextListCastingMode::NoCasting, )?, @@ -274,7 +276,13 @@ mod zk { }; self.inner - .verify_and_expand(public_params, &pk.key.key, unpacking_mode, casting_mode) + .verify_and_expand( + public_params, + &pk.key.key, + metadata, + unpacking_mode, + casting_mode, + ) .map(|expander| CompactCiphertextListExpander { inner: expander, tag: self.tag.clone(), @@ -405,10 +413,11 @@ impl CompactCiphertextListBuilder { pub fn build_with_proof_packed( &self, public_params: &CompactPkePublicParams, + metadata: &[u8], compute_load: ZkComputeLoad, ) -> crate::Result { self.inner - .build_with_proof_packed(public_params, compute_load) + .build_with_proof_packed(public_params, metadata, compute_load) .map(|proved_list| ProvenCompactCiphertextList { inner: proved_list, tag: self.tag.clone(), @@ -496,19 +505,21 @@ mod tests { // Intentionally low to that we test when multiple lists and proofs are needed let crs = CompactPkeCrs::from_config(config, 32).unwrap(); + let metadata = [b'h', b'l', b'a', b'p', b'i']; + let compact_list = ProvenCompactCiphertextList::builder(&pk) .push(17u32) .push(-1i64) .push(false) .push_with_num_bits(3u32, 2) .unwrap() - .build_with_proof_packed(crs.public_params(), ZkComputeLoad::Proof) + .build_with_proof_packed(crs.public_params(), &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) + .verify_and_expand(crs.public_params(), &pk, &metadata) .unwrap(); { @@ -563,19 +574,21 @@ mod tests { // Intentionally low to that we test when multiple lists and proofs are needed let crs = CompactPkeCrs::from_config(config, 32).unwrap(); + let metadata = [b'h', b'l', b'a', b'p', b'i']; + let compact_list = ProvenCompactCiphertextList::builder(&pk) .push(17u32) .push(-1i64) .push(false) .push_with_num_bits(3u32, 2) .unwrap() - .build_with_proof_packed(crs.public_params(), ZkComputeLoad::Proof) + .build_with_proof_packed(crs.public_params(), &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) + .verify_and_expand(crs.public_params(), &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 3075f18f98..43c3d08d89 100644 --- a/tfhe/src/high_level_api/tests/tags_on_entities.rs +++ b/tfhe/src/high_level_api/tests/tags_on_entities.rs @@ -34,6 +34,8 @@ fn test_tag_propagation_zk_pok() { ConfigBuilder::with_custom_parameters(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64).build(); let crs = crate::zk::CompactPkeCrs::from_config(config, (2 * 32) + (2 * 64) + 2).unwrap(); + let metadata = [b'h', b'l', b'a', b'p', b'i']; + let mut cks = ClientKey::generate(config); let tag_value = random(); cks.tag_mut().set_u64(tag_value); @@ -55,14 +57,18 @@ fn test_tag_propagation_zk_pok() { .push(i64::MIN) .push(false) .push(true) - .build_with_proof_packed(crs.public_params(), crate::zk::ZkComputeLoad::Proof) + .build_with_proof_packed( + crs.public_params(), + &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) + .verify_and_expand(crs.public_params(), &cpk, &metadata) .unwrap(); { diff --git a/tfhe/src/integer/ciphertext/compact_list.rs b/tfhe/src/integer/ciphertext/compact_list.rs index 63522fc8e0..cce2dc3441 100644 --- a/tfhe/src/integer/ciphertext/compact_list.rs +++ b/tfhe/src/integer/ciphertext/compact_list.rs @@ -193,11 +193,13 @@ impl CompactCiphertextListBuilder { pub fn build_with_proof( &self, public_params: &CompactPkePublicParams, + metadata: &[u8], load: ZkComputeLoad, ) -> crate::Result { let ct_list = self.pk.key.encrypt_and_prove_slice( self.messages.as_slice(), public_params, + metadata, load, self.pk.key.parameters.message_modulus.0 as u64, )?; @@ -211,6 +213,7 @@ impl CompactCiphertextListBuilder { pub fn build_with_proof_packed( &self, public_params: &CompactPkePublicParams, + metadata: &[u8], load: ZkComputeLoad, ) -> crate::Result { if self.pk.key.parameters.carry_modulus.0 < self.pk.key.parameters.message_modulus.0 { @@ -230,6 +233,7 @@ impl CompactCiphertextListBuilder { let ct_list = self.pk.key.encrypt_and_prove_slice( packed_messages.as_slice(), public_params, + metadata, load, msg_mod * msg_mod, )?; @@ -568,14 +572,17 @@ impl ProvenCompactCiphertextList { &self, public_params: &CompactPkePublicParams, public_key: &CompactPublicKey, + metadata: &[u8], ) -> ZkVerificationOutCome { - self.ct_list.verify(public_params, &public_key.key) + self.ct_list + .verify(public_params, &public_key.key, metadata) } pub fn verify_and_expand( &self, public_params: &CompactPkePublicParams, public_key: &CompactPublicKey, + metadata: &[u8], unpacking_mode: IntegerCompactCiphertextListUnpackingMode<'_>, casting_mode: IntegerCompactCiphertextListCastingMode<'_>, ) -> crate::Result { @@ -592,9 +599,12 @@ impl ProvenCompactCiphertextList { ))); } - let expanded_blocks = - self.ct_list - .verify_and_expand(public_params, &public_key.key, casting_mode.into())?; + let expanded_blocks = self.ct_list.verify_and_expand( + public_params, + &public_key.key, + metadata, + casting_mode.into(), + )?; let expanded_blocks = if is_packed { match unpacking_mode { @@ -643,6 +653,10 @@ impl ProvenCompactCiphertextList { self.ct_list.proof_size() } + pub fn message_modulus(&self) -> MessageModulus { + self.ct_list.message_modulus() + } + pub fn len(&self) -> usize { self.info.len() } @@ -679,6 +693,8 @@ mod tests { let ksk_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let fhe_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let metadata = [b'i', b'n', b't', b'e', b'g', b'e', b'r']; + let num_blocks = 4usize; let modulus = (pke_params.message_modulus.0 as u64) .checked_pow(num_blocks as u32) @@ -697,13 +713,14 @@ mod tests { let proven_ct = CompactCiphertextList::builder(&pk) .extend_with_num_blocks(msgs.iter().copied(), num_blocks) - .build_with_proof_packed(crs.public_params(), ZkComputeLoad::Proof) + .build_with_proof_packed(crs.public_params(), &metadata, ZkComputeLoad::Proof) .unwrap(); let expander = proven_ct .verify_and_expand( crs.public_params(), &pk, + &metadata, IntegerCompactCiphertextListUnpackingMode::UnpackIfNecessary(&sk), IntegerCompactCiphertextListCastingMode::CastIfNecessary(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 33b185fb32..ed370acea2 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 @@ -779,11 +779,12 @@ impl ProvenCompactCiphertextList { &self, public_params: &CompactPkePublicParams, public_key: &TfheCompactPublicKey, + metadata: &[u8], ) -> Result { catch_panic_result(|| { let inner = self .0 - .verify_and_expand(&public_params.0, &public_key.0) + .verify_and_expand(&public_params.0, &public_key.0, metadata) .map_err(into_js_error)?; Ok(CompactCiphertextListExpander(inner)) }) @@ -1009,11 +1010,12 @@ impl CompactCiphertextListBuilder { pub fn build_with_proof_packed( &self, public_params: &CompactPkePublicParams, + metadata: &[u8], compute_load: ZkComputeLoad, ) -> Result { catch_panic_result(|| { self.0 - .build_with_proof_packed(&public_params.0, compute_load.into()) + .build_with_proof_packed(&public_params.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 be95bdeb41..1de4b6ae8f 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 @@ -11,11 +11,11 @@ pub enum ZkComputeLoad { Verify, } -impl Into for ZkComputeLoad { - fn into(self) -> crate::zk::ZkComputeLoad { - match self { - Self::Proof => crate::zk::ZkComputeLoad::Proof, - Self::Verify => crate::zk::ZkComputeLoad::Verify, +impl From for crate::zk::ZkComputeLoad { + fn from(value: ZkComputeLoad) -> Self { + match value { + ZkComputeLoad::Proof => Self::Proof, + ZkComputeLoad::Verify => Self::Verify, } } } @@ -26,6 +26,10 @@ pub struct CompactPkeCrs(pub(crate) crate::core_crypto::entities::CompactPkeCrs) #[wasm_bindgen] pub struct CompactPkePublicParams(pub(crate) crate::zk::CompactPkePublicParams); +#[allow( + clippy::use_self, + reason = "wasm bindgen is fragile and prefers the actual type vs. Self" +)] #[wasm_bindgen] impl CompactPkePublicParams { #[wasm_bindgen] @@ -72,11 +76,15 @@ impl CompactPkePublicParams { } } +#[allow( + clippy::use_self, + reason = "wasm bindgen is fragile and prefers the actual type vs. Self" +)] #[wasm_bindgen] impl CompactPkeCrs { #[wasm_bindgen] pub fn from_parameters( - parameters: ShortintParameters, + parameters: &ShortintParameters, max_num_message: usize, ) -> Result { catch_panic_result(|| { diff --git a/tfhe/src/shortint/ciphertext/zk.rs b/tfhe/src/shortint/ciphertext/zk.rs index 9227cbce86..4e96746513 100644 --- a/tfhe/src/shortint/ciphertext/zk.rs +++ b/tfhe/src/shortint/ciphertext/zk.rs @@ -1,9 +1,9 @@ use crate::core_crypto::algorithms::verify_lwe_compact_ciphertext_list; use crate::shortint::ciphertext::CompactCiphertextList; use crate::shortint::parameters::{ - CompactPublicKeyEncryptionParameters, ShortintCompactCiphertextListCastingMode, + CompactPublicKeyEncryptionParameters, MessageModulus, ShortintCompactCiphertextListCastingMode, }; -use crate::shortint::{Ciphertext, CompactPublicKey, MessageModulus}; +use crate::shortint::{Ciphertext, CompactPublicKey}; use crate::zk::{CompactPkeCrs, CompactPkeProof, CompactPkePublicParams, ZkVerificationOutCome}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -60,6 +60,7 @@ impl ProvenCompactCiphertextList { &self, public_params: &CompactPkePublicParams, public_key: &CompactPublicKey, + metadata: &[u8], casting_mode: ShortintCompactCiphertextListCastingMode<'_>, ) -> crate::Result> { let not_all_valid = self.proved_lists.par_iter().any(|(ct_list, proof)| { @@ -68,6 +69,7 @@ impl ProvenCompactCiphertextList { &public_key.key, proof, public_params, + metadata, ) .is_invalid() }); @@ -92,6 +94,7 @@ impl ProvenCompactCiphertextList { &self, public_params: &CompactPkePublicParams, public_key: &CompactPublicKey, + metadata: &[u8], ) -> ZkVerificationOutCome { let all_valid = self.proved_lists.par_iter().all(|(ct_list, proof)| { verify_lwe_compact_ciphertext_list( @@ -99,6 +102,7 @@ impl ProvenCompactCiphertextList { &public_key.key, proof, public_params, + metadata, ) .is_valid() }); @@ -114,7 +118,7 @@ impl ProvenCompactCiphertextList { self.proved_lists.len() * core::mem::size_of::() } - pub(crate) fn message_modulus(&self) -> MessageModulus { + pub fn message_modulus(&self) -> MessageModulus { self.proved_lists[0].0.message_modulus } } @@ -136,6 +140,8 @@ mod tests { let cks = ClientKey::new(params); let pk = CompactPublicKey::new(&cks); + let metadata = [b's', b'h', b'o', b'r', b't', b'i', b'n', b't']; + let msg = random::() % params.message_modulus.0 as u64; // No packing let encryption_modulus = params.message_modulus.0 as u64; @@ -144,6 +150,7 @@ mod tests { .encrypt_and_prove( msg, crs.public_params(), + &metadata, ZkComputeLoad::Proof, encryption_modulus, ) @@ -151,6 +158,7 @@ mod tests { let proven_ct = proven_ct.verify_and_expand( crs.public_params(), &pk, + &metadata, ShortintCompactCiphertextListCastingMode::NoCasting, ); assert!(proven_ct.is_ok()); @@ -168,6 +176,8 @@ mod tests { let cks = ClientKey::new(params); let pk = CompactPublicKey::new(&cks); + let metadata = [b's', b'h', b'o', b'r', b't', b'i', b'n', b't']; + let msgs = (0..512) .map(|_| random::() % params.message_modulus.0 as u64) .collect::>(); @@ -176,16 +186,20 @@ mod tests { .encrypt_and_prove_slice( &msgs, crs.public_params(), + &metadata, ZkComputeLoad::Proof, params.message_modulus.0 as u64, ) .unwrap(); - assert!(proven_ct.verify(crs.public_params(), &pk).is_valid()); + assert!(proven_ct + .verify(crs.public_params(), &pk, &metadata) + .is_valid()); let expanded = proven_ct .verify_and_expand( crs.public_params(), &pk, + &metadata, ShortintCompactCiphertextListCastingMode::NoCasting, ) .unwrap(); diff --git a/tfhe/src/shortint/public_key/compact.rs b/tfhe/src/shortint/public_key/compact.rs index 210aadb294..34cf4cf82c 100644 --- a/tfhe/src/shortint/public_key/compact.rs +++ b/tfhe/src/shortint/public_key/compact.rs @@ -255,10 +255,17 @@ impl CompactPublicKey { &self, message: u64, public_params: &CompactPkePublicParams, + metadata: &[u8], load: ZkComputeLoad, encryption_modulus: u64, ) -> crate::Result { - self.encrypt_and_prove_slice(&[message], public_params, load, encryption_modulus) + self.encrypt_and_prove_slice( + &[message], + public_params, + metadata, + load, + encryption_modulus, + ) } /// Encrypts the messages contained in the slice into a compact ciphertext list @@ -369,6 +376,7 @@ impl CompactPublicKey { &self, messages: &[u64], public_params: &CompactPkePublicParams, + metadata: &[u8], load: ZkComputeLoad, encryption_modulus: u64, ) -> crate::Result { @@ -413,6 +421,7 @@ impl CompactPublicKey { &mut engine.encryption_generator, &mut engine.random_generator, public_params, + metadata, load, ) }) @@ -434,6 +443,7 @@ impl CompactPublicKey { &mut engine.encryption_generator, &mut engine.random_generator, public_params, + metadata, load, ) }) diff --git a/tfhe/web_wasm_parallel_tests/worker.js b/tfhe/web_wasm_parallel_tests/worker.js index b4ccc9add2..3d3b21596f 100644 --- a/tfhe/web_wasm_parallel_tests/worker.js +++ b/tfhe/web_wasm_parallel_tests/worker.js @@ -378,6 +378,10 @@ async function compactPublicKeyZeroKnowledge() { console.timeEnd("CRS generation"); let public_params = crs.public_params(); + // 320 bits is a use case we have, 8 bits per byte + const metadata = new Uint8Array(320 / 8); + crypto.getRandomValues(metadata); + { let input = generateRandomBigInt(64); let start = performance.now(); @@ -386,6 +390,7 @@ async function compactPublicKeyZeroKnowledge() { builder.push_u64(input); let list = builder.build_with_proof_packed( public_params, + metadata, ZkComputeLoad.Proof, ); let end = performance.now(); @@ -399,7 +404,11 @@ async function compactPublicKeyZeroKnowledge() { console.log("CompactCiphertextList size:", serialized.length); let deserialized = ProvenCompactCiphertextList.deserialize(serialized); - let expander = deserialized.verify_and_expand(public_params, publicKey); + let expander = deserialized.verify_and_expand( + public_params, + publicKey, + metadata, + ); assert_eq(expander.get_uint64(0).decrypt(clientKey), input); } @@ -418,6 +427,7 @@ async function compactPublicKeyZeroKnowledge() { } let encrypted = builder.build_with_proof_packed( public_params, + metadata, ZkComputeLoad.Proof, ); let end = performance.now(); @@ -427,7 +437,11 @@ async function compactPublicKeyZeroKnowledge() { " ms", ); - let expander = encrypted.verify_and_expand(public_params, publicKey); + let expander = encrypted.verify_and_expand( + public_params, + publicKey, + metadata, + ); assert_eq(expander.get_uint64(0).decrypt(clientKey), inputs[0]); @@ -651,6 +665,10 @@ async function compactPublicKeyZeroKnowledgeBench() { let crs = CompactPkeCrs.from_config(config, encrypt_count * 64); console.timeEnd("CRS generation"); + // 320 bits is a use case we have, 8 bits per byte + 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) { @@ -666,6 +684,7 @@ async function compactPublicKeyZeroKnowledgeBench() { const start = performance.now(); let list = compact_list_builder.build_with_proof_packed( public_params, + metadata, loadChoice, ); const end = performance.now();