diff --git a/README.md b/README.md index 285011b..1e13ede 100644 --- a/README.md +++ b/README.md @@ -39,14 +39,13 @@ let merkle_proof = tree.proof(0).expect("proof should exist"); let root = tree.root(); // change signal and external_nullifier here -let signal = b"xxx"; -let external_nullifier = b"appId"; +let signal_hash = hash_to_field(b"xxx"); +let external_nullifier_hash = hash_to_field(b"appId"); -let external_nullifier_hash = hash_external_nullifier(external_nullifier); let nullifier_hash = generate_nullifier_hash(&id, external_nullifier_hash); -let proof = generate_proof(&id, &merkle_proof, external_nullifier, signal).unwrap(); -let success = verify_proof(root.into(), nullifier_hash, signal, external_nullifier, &proof).unwrap(); +let proof = generate_proof(&id, &merkle_proof, external_nullifier_hash, signal_hash).unwrap(); +let success = verify_proof(root.into(), nullifier_hash, signal_hash, external_nullifier_hash, &proof).unwrap(); assert!(success); ``` diff --git a/src/lib.rs b/src/lib.rs index 53d38db..be97253 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,9 +32,7 @@ mod test { hash::Hash, identity::Identity, poseidon_tree::PoseidonTree, - protocol::{ - generate_nullifier_hash, generate_proof, hash_external_nullifier, verify_proof, - }, + protocol::{generate_nullifier_hash, generate_proof, hash_to_field, verify_proof}, }; use hex_literal::hex; @@ -58,13 +56,21 @@ mod test { let signal = b"xxx"; let external_nullifier = b"appId"; - let external_nullifier_hash = hash_external_nullifier(external_nullifier); + let signal_hash = hash_to_field(signal); + let external_nullifier_hash = hash_to_field(external_nullifier); let nullifier_hash = generate_nullifier_hash(&id, external_nullifier_hash); - let proof = generate_proof(&id, &merkle_proof, external_nullifier, signal).unwrap(); + let proof = + generate_proof(&id, &merkle_proof, external_nullifier_hash, signal_hash).unwrap(); - let success = - verify_proof(root, nullifier_hash, signal, external_nullifier, &proof).unwrap(); + let success = verify_proof( + root, + nullifier_hash, + signal_hash, + external_nullifier_hash, + &proof, + ) + .unwrap(); assert!(success); } @@ -73,7 +79,10 @@ mod test { #[cfg(feature = "bench")] pub mod bench { use crate::{ - hash::Hash, identity::Identity, poseidon_tree::PoseidonTree, protocol::generate_proof, + hash::Hash, + identity::Identity, + poseidon_tree::PoseidonTree, + protocol::{generate_proof, hash_to_field}, }; use criterion::Criterion; use hex_literal::hex; @@ -98,12 +107,12 @@ pub mod bench { let merkle_proof = tree.proof(0).expect("proof should exist"); // change signal and external_nullifier here - let signal = b"xxx"; - let external_nullifier = b"appId"; + let signal_hash = hash_to_field(b"xxx"); + let external_nullifier_hash = hash_to_field(b"appId"); criterion.bench_function("proof", move |b| { b.iter(|| { - generate_proof(&id, &merkle_proof, external_nullifier, signal).unwrap(); + generate_proof(&id, &merkle_proof, external_nullifier_hash, signal_hash).unwrap(); }); }); } diff --git a/src/protocol.rs b/src/protocol.rs index bd76e47..ba4d1cb 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -9,7 +9,7 @@ use crate::{ use ark_bn254::{Bn254, Parameters}; use ark_circom::CircomReduction; use ark_ec::bn::Bn; -use ark_ff::{Fp256, PrimeField}; +use ark_ff::PrimeField; use ark_groth16::{create_proof_with_reduction_and_matrices, prepare_verifying_key, Proof}; use ark_relations::r1cs::SynthesisError; use ark_std::{rand::thread_rng, UniformRand}; @@ -31,28 +31,18 @@ fn merkle_proof_to_vec(proof: &merkle_tree::Proof) -> Vec { .collect() } -/// Internal helper to hash the signal to make sure it's in the field -fn hash_signal(signal: &[u8]) -> Field { - let hash = keccak256(signal); +/// Hash arbitrary data to a field element. +/// +/// This is used to create `signal_hash` and `external_nullifier_hash`. +#[must_use] +pub fn hash_to_field(data: &[u8]) -> Field { + let hash = keccak256(data); // Shift right one byte to make it fit in the field let mut bytes = [0_u8; 32]; bytes[1..].copy_from_slice(&hash[..31]); Field::from_be_bytes_mod_order(&bytes) } -/// Internal helper to hash the external nullifier -#[must_use] -pub fn hash_external_nullifier(nullifier: &[u8]) -> Field { - // Hash input to 256 bits. - let mut hash = keccak256(nullifier); - // Clear first four bytes to make sure the hash is in the field. - for byte in &mut hash[0..4] { - *byte = 0; - } - // Convert to field element. - Fp256::from_be_bytes_mod_order(&hash) -} - /// Generates the nullifier hash #[must_use] pub fn generate_nullifier_hash(identity: &Identity, external_nullifier: Field) -> Field { @@ -82,18 +72,16 @@ fn ark_to_bigint(n: Field) -> BigInt { pub fn generate_proof( identity: &Identity, merkle_proof: &merkle_tree::Proof, - external_nullifier: &[u8], - signal: &[u8], + external_nullifier_hash: Field, + signal_hash: Field, ) -> Result>, ProofError> { - let external_nullifier = hash_external_nullifier(external_nullifier); - let signal = hash_signal(signal); let inputs = [ ("identityNullifier", vec![identity.nullifier]), ("identityTrapdoor", vec![identity.trapdoor]), ("treePathIndices", merkle_proof.path_index()), ("treeSiblings", merkle_proof_to_vec(merkle_proof)), - ("externalNullifier", vec![external_nullifier]), - ("signalHash", vec![signal]), + ("externalNullifier", vec![external_nullifier_hash]), + ("signalHash", vec![signal_hash]), ]; let inputs = inputs.into_iter().map(|(name, values)| { ( @@ -147,18 +135,13 @@ pub fn generate_proof( pub fn verify_proof( root: Field, nullifier_hash: Field, - signal: &[u8], - external_nullifier: &[u8], + signal_hash: Field, + external_nullifier_hash: Field, proof: &Proof>, ) -> Result { let pvk = prepare_verifying_key(&ZKEY.0.vk); - let public_inputs = vec![ - root, - nullifier_hash, - hash_signal(signal), - hash_external_nullifier(external_nullifier), - ]; + let public_inputs = vec![root, nullifier_hash, signal_hash, external_nullifier_hash]; let result = ark_groth16::verify_proof(&pvk, proof, &public_inputs)?; Ok(result) }