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"
|
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"
|
||||||
|
|
|
@ -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");
|
||||||
|
|
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,
|
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"
|
||||||
|
]
|
||||||
|
])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue