Deterministic proof generation
This commit is contained in:
parent
f89a4e399f
commit
16d2c02545
|
@ -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"
|
||||
|
|
|
@ -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");
|
||||
|
|
110
src/protocol.rs
110
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<PoseidonHash>,
|
||||
external_nullifier_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> {
|
||||
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::<Bn254, _>(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<Bn<Parameters>> = 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"
|
||||
]
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue