Deterministic proof generation

This commit is contained in:
Remco Bloemen 2022-03-18 18:23:38 -07:00
parent f89a4e399f
commit 16d2c02545
3 changed files with 91 additions and 27 deletions

View File

@ -42,6 +42,7 @@ once_cell = "1.8"
poseidon-rs = "0.0.8" poseidon-rs = "0.0.8"
primitive-types = "0.11.1" primitive-types = "0.11.1"
proptest = { version = "1.0", optional = true } proptest = { version = "1.0", optional = true }
rand = "0.8.4"
rayon = "1.5.1" rayon = "1.5.1"
serde = "1.0" serde = "1.0"
sha2 = "0.10.1" sha2 = "0.10.1"
@ -57,6 +58,7 @@ ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features =
[dev-dependencies] [dev-dependencies]
bincode = "1.3.3" bincode = "1.3.3"
proptest = "1.0" proptest = "1.0"
rand_chacha = "0.3.1"
serde_json = "1.0.79" serde_json = "1.0.79"
tempfile = "3.0" tempfile = "3.0"
tiny-keccak = "2.0.2" tiny-keccak = "2.0.2"

View File

@ -4,9 +4,11 @@ use ark_groth16::ProvingKey;
use ark_relations::r1cs::ConstraintMatrices; use ark_relations::r1cs::ConstraintMatrices;
use core::include_bytes; use core::include_bytes;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::io::{Cursor, Write}; use std::{
io::{Cursor, Write},
sync::Mutex,
};
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
use std::sync::Mutex;
const ZKEY_BYTES: &[u8] = include_bytes!("../semaphore/build/snark/semaphore_final.zkey"); const ZKEY_BYTES: &[u8] = include_bytes!("../semaphore/build/snark/semaphore_final.zkey");
const WASM: &[u8] = include_bytes!("../semaphore/build/snark/semaphore.wasm"); const WASM: &[u8] = include_bytes!("../semaphore/build/snark/semaphore.wasm");

View File

@ -13,9 +13,10 @@ use ark_groth16::{
create_proof_with_reduction_and_matrices, prepare_verifying_key, Proof as ArkProof, create_proof_with_reduction_and_matrices, prepare_verifying_key, Proof as ArkProof,
}; };
use ark_relations::r1cs::SynthesisError; use ark_relations::r1cs::SynthesisError;
use ark_std::{rand::thread_rng, UniformRand}; use ark_std::UniformRand;
use color_eyre::Result; use color_eyre::Result;
use primitive_types::U256; use primitive_types::U256;
use rand::{thread_rng, Rng};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Instant; use std::time::Instant;
use thiserror::Error; use thiserror::Error;
@ -98,6 +99,40 @@ pub fn generate_proof(
merkle_proof: &merkle_tree::Proof<PoseidonHash>, merkle_proof: &merkle_tree::Proof<PoseidonHash>,
external_nullifier_hash: Field, external_nullifier_hash: Field,
signal_hash: Field, signal_hash: Field,
) -> Result<Proof, ProofError> {
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<PoseidonHash>,
external_nullifier_hash: Field,
signal_hash: Field,
rng: &mut impl Rng,
) -> Result<Proof, ProofError> {
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<PoseidonHash>,
external_nullifier_hash: Field,
signal_hash: Field,
r: ark_bn254::Fr,
s: ark_bn254::Fr,
) -> Result<Proof, ProofError> { ) -> Result<Proof, ProofError> {
let inputs = [ let inputs = [
("identityNullifier", vec![identity.nullifier]), ("identityNullifier", vec![identity.nullifier]),
@ -116,8 +151,7 @@ pub fn generate_proof(
let now = Instant::now(); let now = Instant::now();
let full_assignment = let full_assignment = WITNESS_CALCULATOR
WITNESS_CALCULATOR
.lock() .lock()
.expect("witness_calculator mutex should not get poisoned") .expect("witness_calculator mutex should not get poisoned")
.calculate_witness_element::<Bn254, _>(inputs, false) .calculate_witness_element::<Bn254, _>(inputs, false)
@ -125,14 +159,7 @@ pub fn generate_proof(
println!("witness generation took: {:.2?}", now.elapsed()); 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 now = Instant::now();
let ark_proof = create_proof_with_reduction_and_matrices::<_, CircomReduction>( let ark_proof = create_proof_with_reduction_and_matrices::<_, CircomReduction>(
&ZKEY.0, &ZKEY.0,
r, r,
@ -143,7 +170,6 @@ pub fn generate_proof(
full_assignment.as_slice(), full_assignment.as_slice(),
)?; )?;
let proof = ark_proof.into(); let proof = ark_proof.into();
println!("proof generation took: {:.2?}", now.elapsed()); println!("proof generation took: {:.2?}", now.elapsed());
Ok(proof) Ok(proof)
@ -179,10 +205,17 @@ pub fn verify_proof(
mod test { mod test {
use super::*; use super::*;
use crate::{hash_to_field, poseidon_tree::PoseidonTree}; 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 // generate identity
let id = Identity::from_seed(b"secret"); let seed: [u8; 16] = rng.gen();
let id = Identity::from_seed(&seed);
// generate merkle tree // generate merkle tree
let leaf = Field::from(0); let leaf = Field::from(0);
@ -191,16 +224,25 @@ mod test {
let merkle_proof = tree.proof(0).expect("proof should exist"); let merkle_proof = tree.proof(0).expect("proof should exist");
// change signal and external_nullifier here let external_nullifier: [u8; 16] = rng.gen();
let signal_hash = hash_to_field(b"xxx"); let external_nullifier_hash = hash_to_field(&external_nullifier);
let external_nullifier_hash = hash_to_field(b"appId");
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] #[test]
fn test_proof_cast_roundtrip() { fn test_proof_cast_roundtrip() {
let proof = arb_proof(); let proof = arb_proof(123);
let ark_proof: ArkProof<Bn<Parameters>> = proof.into(); let ark_proof: ArkProof<Bn<Parameters>> = proof.into();
let result: Proof = ark_proof.into(); let result: Proof = ark_proof.into();
assert_eq!(proof, result); assert_eq!(proof, result);
@ -208,12 +250,30 @@ mod test {
#[test] #[test]
fn test_proof_serialize() { fn test_proof_serialize() {
let proof = arb_proof(); let proof = arb_proof(456);
let _json = serde_json::to_value(&proof).unwrap(); let json = serde_json::to_value(&proof).unwrap();
assert_eq!(
// TODO: Ideally we would check the output against an expected value, json,
// but proof generation is non-deterministic (to achieve json!([
// zero-knowledge) and there's currently no mechanism to make it [
// deterministic for testing purposes. "0x249ae469686987ee9368da60dd177a8c42891c02f5760e955e590c79d55cfab2",
"0xf22e25870f49388459d388afb24dcf6ec11bb2d4def1e2ec26d6e42f373aad8"
],
[
[
"0x17bd25dbd7436c30ea5b8a3a47aadf11ed646c4b25cc14a84ff8cbe0252ff1f8",
"0x1c140668c56688367416534d57b4a14e5a825efdd5e121a6a2099f6dc4cd277b"
],
[
"0x26a8524759d969ea0682a092cf7a551697d81962d6c998f543f81e52d83e05e1",
"0x273eb3f796fd1807b9df9c6d769d983e3dabdc61677b75d48bb7691303b2c8dd"
]
],
[
"0x62715c53a0eb4c46dbb5f73f1fd7449b9c63d37c1ece65debc39b472065a90f",
"0x114f7becc66f1cd7a8b01c89db8233622372fc0b6fc037c4313bca41e2377fd9"
]
])
);
} }
} }