From 16d2c02545e4270bd39275ee3c7922e3bd004bcc Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 18 Mar 2022 18:23:38 -0700 Subject: [PATCH] Deterministic proof generation --- Cargo.toml | 2 + src/circuit.rs | 6 ++- src/protocol.rs | 110 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 91 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 909ff63..44dac89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ once_cell = "1.8" poseidon-rs = "0.0.8" primitive-types = "0.11.1" proptest = { version = "1.0", optional = true } +rand = "0.8.4" rayon = "1.5.1" serde = "1.0" sha2 = "0.10.1" @@ -57,6 +58,7 @@ ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = [dev-dependencies] bincode = "1.3.3" proptest = "1.0" +rand_chacha = "0.3.1" serde_json = "1.0.79" tempfile = "3.0" tiny-keccak = "2.0.2" diff --git a/src/circuit.rs b/src/circuit.rs index 274b9ba..455c49f 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -4,9 +4,11 @@ use ark_groth16::ProvingKey; use ark_relations::r1cs::ConstraintMatrices; use core::include_bytes; use once_cell::sync::Lazy; -use std::io::{Cursor, Write}; +use std::{ + io::{Cursor, Write}, + sync::Mutex, +}; use tempfile::NamedTempFile; -use std::sync::Mutex; const ZKEY_BYTES: &[u8] = include_bytes!("../semaphore/build/snark/semaphore_final.zkey"); const WASM: &[u8] = include_bytes!("../semaphore/build/snark/semaphore.wasm"); diff --git a/src/protocol.rs b/src/protocol.rs index a75eb67..bad5974 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -13,9 +13,10 @@ use ark_groth16::{ create_proof_with_reduction_and_matrices, prepare_verifying_key, Proof as ArkProof, }; use ark_relations::r1cs::SynthesisError; -use ark_std::{rand::thread_rng, UniformRand}; +use ark_std::UniformRand; use color_eyre::Result; use primitive_types::U256; +use rand::{thread_rng, Rng}; use serde::{Deserialize, Serialize}; use std::time::Instant; use thiserror::Error; @@ -98,6 +99,40 @@ pub fn generate_proof( merkle_proof: &merkle_tree::Proof, external_nullifier_hash: Field, signal_hash: Field, +) -> Result { + generate_proof_rng( + identity, + merkle_proof, + external_nullifier_hash, + signal_hash, + &mut thread_rng(), + ) +} + +pub fn generate_proof_rng( + identity: &Identity, + merkle_proof: &merkle_tree::Proof, + external_nullifier_hash: Field, + signal_hash: Field, + rng: &mut impl Rng, +) -> Result { + generate_proof_rs( + identity, + merkle_proof, + external_nullifier_hash, + signal_hash, + ark_bn254::Fr::rand(rng), + ark_bn254::Fr::rand(rng), + ) +} + +fn generate_proof_rs( + identity: &Identity, + merkle_proof: &merkle_tree::Proof, + external_nullifier_hash: Field, + signal_hash: Field, + r: ark_bn254::Fr, + s: ark_bn254::Fr, ) -> Result { let inputs = [ ("identityNullifier", vec![identity.nullifier]), @@ -116,8 +151,7 @@ pub fn generate_proof( let now = Instant::now(); - let full_assignment = - WITNESS_CALCULATOR + let full_assignment = WITNESS_CALCULATOR .lock() .expect("witness_calculator mutex should not get poisoned") .calculate_witness_element::(inputs, false) @@ -125,14 +159,7 @@ pub fn generate_proof( println!("witness generation took: {:.2?}", now.elapsed()); - let mut rng = thread_rng(); - let rng = &mut rng; - - let r = ark_bn254::Fr::rand(rng); - let s = ark_bn254::Fr::rand(rng); - let now = Instant::now(); - let ark_proof = create_proof_with_reduction_and_matrices::<_, CircomReduction>( &ZKEY.0, r, @@ -143,7 +170,6 @@ pub fn generate_proof( full_assignment.as_slice(), )?; let proof = ark_proof.into(); - println!("proof generation took: {:.2?}", now.elapsed()); Ok(proof) @@ -179,10 +205,17 @@ pub fn verify_proof( mod test { use super::*; use crate::{hash_to_field, poseidon_tree::PoseidonTree}; + use rand::SeedableRng as _; + use rand_chacha::ChaChaRng; + use serde_json::json; + + fn arb_proof(seed: u64) -> Proof { + // Deterministic randomness for testing + let mut rng = ChaChaRng::seed_from_u64(seed); - fn arb_proof() -> Proof { // generate identity - let id = Identity::from_seed(b"secret"); + let seed: [u8; 16] = rng.gen(); + let id = Identity::from_seed(&seed); // generate merkle tree let leaf = Field::from(0); @@ -191,16 +224,25 @@ mod test { let merkle_proof = tree.proof(0).expect("proof should exist"); - // change signal and external_nullifier here - let signal_hash = hash_to_field(b"xxx"); - let external_nullifier_hash = hash_to_field(b"appId"); + let external_nullifier: [u8; 16] = rng.gen(); + let external_nullifier_hash = hash_to_field(&external_nullifier); - generate_proof(&id, &merkle_proof, external_nullifier_hash, signal_hash).unwrap() + let signal: [u8; 16] = rng.gen(); + let signal_hash = hash_to_field(&signal); + + generate_proof_rng( + &id, + &merkle_proof, + external_nullifier_hash, + signal_hash, + &mut rng, + ) + .unwrap() } #[test] fn test_proof_cast_roundtrip() { - let proof = arb_proof(); + let proof = arb_proof(123); let ark_proof: ArkProof> = proof.into(); let result: Proof = ark_proof.into(); assert_eq!(proof, result); @@ -208,12 +250,30 @@ mod test { #[test] fn test_proof_serialize() { - let proof = arb_proof(); - let _json = serde_json::to_value(&proof).unwrap(); - - // TODO: Ideally we would check the output against an expected value, - // but proof generation is non-deterministic (to achieve - // zero-knowledge) and there's currently no mechanism to make it - // deterministic for testing purposes. + let proof = arb_proof(456); + let json = serde_json::to_value(&proof).unwrap(); + assert_eq!( + json, + json!([ + [ + "0x249ae469686987ee9368da60dd177a8c42891c02f5760e955e590c79d55cfab2", + "0xf22e25870f49388459d388afb24dcf6ec11bb2d4def1e2ec26d6e42f373aad8" + ], + [ + [ + "0x17bd25dbd7436c30ea5b8a3a47aadf11ed646c4b25cc14a84ff8cbe0252ff1f8", + "0x1c140668c56688367416534d57b4a14e5a825efdd5e121a6a2099f6dc4cd277b" + ], + [ + "0x26a8524759d969ea0682a092cf7a551697d81962d6c998f543f81e52d83e05e1", + "0x273eb3f796fd1807b9df9c6d769d983e3dabdc61677b75d48bb7691303b2c8dd" + ] + ], + [ + "0x62715c53a0eb4c46dbb5f73f1fd7449b9c63d37c1ece65debc39b472065a90f", + "0x114f7becc66f1cd7a8b01c89db8233622372fc0b6fc037c4313bca41e2377fd9" + ] + ]) + ); } }