mirror of
https://github.com/vacp2p/semaphore-rs.git
synced 2026-01-09 14:58:03 -05:00
Merge pull request #9 from worldcoin/remco/proof-serialize
Add serializable proof type
This commit is contained in:
@@ -40,6 +40,7 @@ hex-literal = "0.3"
|
||||
num-bigint = { version = "0.4", default-features = false, features = ["rand"] }
|
||||
once_cell = "1.8"
|
||||
poseidon-rs = "0.0.8"
|
||||
primitive-types = "0.11.1"
|
||||
proptest = { version = "1.0", optional = true }
|
||||
rayon = "1.5.1"
|
||||
serde = "1.0"
|
||||
|
||||
@@ -9,13 +9,57 @@ use crate::{
|
||||
use ark_bn254::{Bn254, Parameters};
|
||||
use ark_circom::CircomReduction;
|
||||
use ark_ec::bn::Bn;
|
||||
use ark_groth16::{create_proof_with_reduction_and_matrices, prepare_verifying_key, Proof};
|
||||
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 color_eyre::Result;
|
||||
use primitive_types::U256;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Instant;
|
||||
use thiserror::Error;
|
||||
|
||||
// Matches the private G1Tup type in ark-circom.
|
||||
pub type G1 = (U256, U256);
|
||||
|
||||
// Matches the private G2Tup type in ark-circom.
|
||||
pub type G2 = ([U256; 2], [U256; 2]);
|
||||
|
||||
/// Wrap a proof object so we have serde support
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Proof(G1, G2, G1);
|
||||
|
||||
impl From<ArkProof<Bn<Parameters>>> for Proof {
|
||||
fn from(proof: ArkProof<Bn<Parameters>>) -> Self {
|
||||
let proof = ark_circom::ethereum::Proof::from(proof);
|
||||
let (a, b, c) = proof.as_tuple();
|
||||
Self(a, b, c)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Proof> for ArkProof<Bn<Parameters>> {
|
||||
fn from(proof: Proof) -> Self {
|
||||
let eth_proof = ark_circom::ethereum::Proof {
|
||||
a: ark_circom::ethereum::G1 {
|
||||
x: proof.0 .0,
|
||||
y: proof.0 .1,
|
||||
},
|
||||
#[rustfmt::skip] // Rustfmt inserts some confusing spaces
|
||||
b: ark_circom::ethereum::G2 {
|
||||
// The order of coefficients is flipped.
|
||||
x: [proof.1.0[1], proof.1.0[0]],
|
||||
y: [proof.1.1[1], proof.1.1[0]],
|
||||
},
|
||||
c: ark_circom::ethereum::G1 {
|
||||
x: proof.2 .0,
|
||||
y: proof.2 .1,
|
||||
},
|
||||
};
|
||||
eth_proof.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to merkle proof into a bigint vector
|
||||
/// TODO: we should create a From trait for this
|
||||
fn merkle_proof_to_vec(proof: &merkle_tree::Proof<PoseidonHash>) -> Vec<Field> {
|
||||
@@ -54,7 +98,7 @@ pub fn generate_proof(
|
||||
merkle_proof: &merkle_tree::Proof<PoseidonHash>,
|
||||
external_nullifier_hash: Field,
|
||||
signal_hash: Field,
|
||||
) -> Result<Proof<Bn<Parameters>>, ProofError> {
|
||||
) -> Result<Proof, ProofError> {
|
||||
let inputs = [
|
||||
("identityNullifier", vec![identity.nullifier]),
|
||||
("identityTrapdoor", vec![identity.trapdoor]),
|
||||
@@ -87,7 +131,7 @@ pub fn generate_proof(
|
||||
|
||||
let now = Instant::now();
|
||||
|
||||
let proof = create_proof_with_reduction_and_matrices::<_, CircomReduction>(
|
||||
let ark_proof = create_proof_with_reduction_and_matrices::<_, CircomReduction>(
|
||||
&ZKEY.0,
|
||||
r,
|
||||
s,
|
||||
@@ -96,6 +140,7 @@ pub fn generate_proof(
|
||||
ZKEY.1.num_constraints,
|
||||
full_assignment.as_slice(),
|
||||
)?;
|
||||
let proof = ark_proof.into();
|
||||
|
||||
println!("proof generation took: {:.2?}", now.elapsed());
|
||||
|
||||
@@ -113,7 +158,7 @@ pub fn verify_proof(
|
||||
nullifier_hash: Field,
|
||||
signal_hash: Field,
|
||||
external_nullifier_hash: Field,
|
||||
proof: &Proof<Bn<Parameters>>,
|
||||
proof: &Proof,
|
||||
) -> Result<bool, ProofError> {
|
||||
let pvk = prepare_verifying_key(&ZKEY.0.vk);
|
||||
|
||||
@@ -123,6 +168,40 @@ pub fn verify_proof(
|
||||
signal_hash.into(),
|
||||
external_nullifier_hash.into(),
|
||||
];
|
||||
let result = ark_groth16::verify_proof(&pvk, proof, &public_inputs[..])?;
|
||||
let ark_proof = (*proof).into();
|
||||
let result = ark_groth16::verify_proof(&pvk, &ark_proof, &public_inputs[..])?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::{hash_to_field, poseidon_tree::PoseidonTree};
|
||||
|
||||
#[test]
|
||||
fn test_proof_serialize() {
|
||||
// generate identity
|
||||
let id = Identity::from_seed(b"secret");
|
||||
|
||||
// generate merkle tree
|
||||
let leaf = Field::from(0);
|
||||
let mut tree = PoseidonTree::new(21, leaf);
|
||||
tree.set(0, id.commitment());
|
||||
|
||||
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 proof =
|
||||
generate_proof(&id, &merkle_proof, external_nullifier_hash, signal_hash).unwrap();
|
||||
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user