feat: groth16 proof verification in rust with sample proof of twitter test

This commit is contained in:
zkFriendly
2024-07-09 15:33:30 +02:00
parent 804d625881
commit 5390f34421
9 changed files with 325 additions and 5 deletions

View File

@@ -1,5 +1,5 @@
[package]
name = "ark-verifier"
name = "utils"
version = "0.1.0"
edition = "2021"
@@ -55,4 +55,4 @@ default = ["wasmer/default", "circom-2", "ethereum"]
wasm = ["wasmer/js-default"]
bench-complex-all = []
circom-2 = []
ethereum = ["ethers-core"]
ethereum = ["ethers-core"]

View File

@@ -1 +0,0 @@
# rust-verifier

View File

@@ -1,4 +1,6 @@
{
"name": "rust-verifier",
"packageManager": "yarn@3.2.3"
"name": "utils",
"private": true,
"version": "1.0.0",
"description": "utilities to generating bindings for various proving contexts"
}

View File

@@ -0,0 +1 @@
pub mod verifier;

View File

@@ -0,0 +1,178 @@
use ark_bn254::Bn254;
use ark_bn254::Config;
use ark_bn254::Fq2;
use ark_bn254::FrConfig;
use ark_bn254::G1Affine;
use ark_bn254::G2Affine;
use ark_circom::CircomReduction;
use ark_ec::bn::Bn;
use ark_ff::Fp;
use ark_ff::MontBackend;
use ark_groth16::Groth16;
use ark_groth16::Proof;
use ark_groth16::VerifyingKey;
use serde::Deserialize;
use std::fs;
use std::ops::Deref;
use std::str::FromStr;
pub type GrothBn = Groth16<Bn254, CircomReduction>;
pub type GrothBnProof = Proof<Bn<Config>>;
pub type GrothBnVkey = VerifyingKey<Bn254>;
pub type GrothFp = Fp<MontBackend<FrConfig, 4>, 4>;
#[derive(Debug, Deserialize)]
struct SnarkJsProof {
pi_a: [String; 3],
pi_b: [[String; 2]; 3],
pi_c: [String; 3],
}
#[derive(Debug, Deserialize)]
struct SnarkJsVkey {
vk_alpha_1: [String; 3],
vk_beta_2: [[String; 2]; 3],
vk_gamma_2: [[String; 2]; 3],
vk_delta_2: [[String; 2]; 3],
IC: Vec<[String; 3]>,
}
#[derive(Debug)]
pub struct PublicInputs<const N: usize> {
inputs: [GrothFp; N],
}
pub trait JsonDecoder {
fn from_json(json: &str) -> Self;
fn from_json_file(file_path: &str) -> Self
where
Self: Sized,
{
let json = fs::read_to_string(file_path).unwrap();
Self::from_json(&json)
}
}
impl JsonDecoder for GrothBnProof {
fn from_json(json: &str) -> Self {
let snarkjs_proof: SnarkJsProof = serde_json::from_str(json).unwrap();
let a = G1Affine {
x: Fp::from_str(snarkjs_proof.pi_a[0].as_str()).unwrap(),
y: Fp::from_str(snarkjs_proof.pi_a[1].as_str()).unwrap(),
infinity: false,
};
let b = G2Affine {
x: Fq2::new(
Fp::from_str(snarkjs_proof.pi_b[0][0].as_str()).unwrap(),
Fp::from_str(snarkjs_proof.pi_b[0][1].as_str()).unwrap(),
),
y: Fq2::new(
Fp::from_str(snarkjs_proof.pi_b[1][0].as_str()).unwrap(),
Fp::from_str(snarkjs_proof.pi_b[1][1].as_str()).unwrap(),
),
infinity: false,
};
let c = G1Affine {
x: Fp::from_str(snarkjs_proof.pi_c[0].as_str()).unwrap(),
y: Fp::from_str(snarkjs_proof.pi_c[1].as_str()).unwrap(),
infinity: false,
};
Proof { a, b, c }
}
}
impl JsonDecoder for GrothBnVkey {
fn from_json(json: &str) -> Self {
let snarkjs_vkey: SnarkJsVkey = serde_json::from_str(json).unwrap();
let vk_alpha_1 = G1Affine {
x: Fp::from_str(snarkjs_vkey.vk_alpha_1[0].as_str()).unwrap(),
y: Fp::from_str(snarkjs_vkey.vk_alpha_1[1].as_str()).unwrap(),
infinity: false,
};
let vk_beta_2 = G2Affine {
x: Fq2::new(
Fp::from_str(snarkjs_vkey.vk_beta_2[0][0].as_str()).unwrap(),
Fp::from_str(snarkjs_vkey.vk_beta_2[0][1].as_str()).unwrap(),
),
y: Fq2::new(
Fp::from_str(snarkjs_vkey.vk_beta_2[1][0].as_str()).unwrap(),
Fp::from_str(snarkjs_vkey.vk_beta_2[1][1].as_str()).unwrap(),
),
infinity: false,
};
let vk_gamma_2 = G2Affine {
x: Fq2::new(
Fp::from_str(snarkjs_vkey.vk_gamma_2[0][0].as_str()).unwrap(),
Fp::from_str(snarkjs_vkey.vk_gamma_2[0][1].as_str()).unwrap(),
),
y: Fq2::new(
Fp::from_str(snarkjs_vkey.vk_gamma_2[1][0].as_str()).unwrap(),
Fp::from_str(snarkjs_vkey.vk_gamma_2[1][1].as_str()).unwrap(),
),
infinity: false,
};
let vk_delta_2 = G2Affine {
x: Fq2::new(
Fp::from_str(snarkjs_vkey.vk_delta_2[0][0].as_str()).unwrap(),
Fp::from_str(snarkjs_vkey.vk_delta_2[0][1].as_str()).unwrap(),
),
y: Fq2::new(
Fp::from_str(snarkjs_vkey.vk_delta_2[1][0].as_str()).unwrap(),
Fp::from_str(snarkjs_vkey.vk_delta_2[1][1].as_str()).unwrap(),
),
infinity: false,
};
let ic = snarkjs_vkey
.IC
.iter()
.map(|ic| G1Affine {
x: Fp::from_str(ic[0].as_str()).unwrap(),
y: Fp::from_str(ic[1].as_str()).unwrap(),
infinity: false,
})
.collect();
VerifyingKey {
alpha_g1: vk_alpha_1,
beta_g2: vk_beta_2,
gamma_g2: vk_gamma_2,
delta_g2: vk_delta_2,
gamma_abc_g1: ic,
}
}
}
impl<const N: usize> JsonDecoder for PublicInputs<N> {
fn from_json(json: &str) -> Self {
let inputs: Vec<String> = serde_json::from_str(json).unwrap();
let inputs: Vec<GrothFp> = inputs
.iter()
.map(|input| Fp::from_str(input).unwrap())
.collect();
Self {
inputs: inputs.try_into().unwrap(),
}
}
}
impl<const N: usize> PublicInputs<N> {
pub fn from(inputs: [&str; N]) -> Self {
let inputs: Vec<GrothFp> = inputs
.iter()
.map(|input| Fp::from_str(input).unwrap())
.collect();
Self {
inputs: inputs.try_into().unwrap(),
}
}
}
impl<const N: usize> Deref for PublicInputs<N> {
type Target = [GrothFp];
fn deref(&self) -> &Self::Target {
&self.inputs
}
}

View File

@@ -0,0 +1,25 @@
{
"pi_a": [
"7322653719534980528477944398011016647254113886264496434209142915373719728330",
"7628912536907839379514448322649890607492217442803051947968392007164895386635",
"1"
],
"pi_b": [
[
"16234593703961390420744598781852865663725256239282005257881003391155979508175",
"2634938501612343384443797634806019339499759856521176306545002649451701618890"
],
[
"20230573717932313809779793208166930057423046021163352571847229725759748970685",
"3400562595023578951323767846410060663270999913751859309274508041293791416795"
],
["1", "0"]
],
"pi_c": [
"4754500730009341734285764647492628138720619353305414050344261728054146174269",
"15456162944887044317047060179938689904460637264071491912107485866386470848896",
"1"
],
"protocol": "groth16",
"curve": "bn128"
}

View File

@@ -0,0 +1,5 @@
[
"1983664618407009423875829639306275185491946247764487749439145140682408188330",
"131061634216091175196322682",
"663497778919717248086462294001838786758809425003"
]

View File

@@ -0,0 +1,95 @@
{
"protocol": "groth16",
"curve": "bn128",
"nPublic": 3,
"vk_alpha_1": [
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
"1"
],
"vk_beta_2": [
[
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
],
[
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
],
["1", "0"]
],
"vk_gamma_2": [
[
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
],
[
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
],
["1", "0"]
],
"vk_delta_2": [
[
"12766874234600095787343990480146022057791723986357917332831399540581276927233",
"3971642277770342590957506265349105456434855661397513517213431669169235844045"
],
[
"17019878480168149557284885665446758390388295710404486629277107858448704695435",
"8466466441600144089096780116598234208747001808490439031541612931795850272713"
],
["1", "0"]
],
"vk_alphabeta_12": [
[
[
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
],
[
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
],
[
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
]
],
[
[
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
],
[
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
],
[
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
]
]
],
"IC": [
[
"13455031991578888733674312423967185601946065645222957382145186994616611244362",
"14050030878011228297368009518321338442347619972518515173925378569459442994011",
"1"
],
[
"17413305859812487897886068173955193240718176224001852027948255829721305653639",
"20501940977432443854287668104189155029974249999233988371475203832572003103923",
"1"
],
[
"16478835329297149904466221463850128581969676144765895448709484660840830338291",
"18378280162143562209519402347714766029351163075742403485652069083748853436468",
"1"
],
[
"9167194412515699354423101347633274318437697317154678611069229798965044490452",
"14219742127910100142812096423691693747338448854474336725819074409505103543838",
"1"
]
]
}

View File

@@ -0,0 +1,15 @@
#[cfg(test)]
mod tests {
use ark_crypto_primitives::snark::SNARK;
use utils::verifier::{GrothBn, GrothBnProof, GrothBnVkey, JsonDecoder, PublicInputs};
#[test]
fn test_case_1_proof_valid() {
let vkey = GrothBnVkey::from_json_file("tests/data/proof_of_twitter/vkey.json");
let proof = GrothBnProof::from_json_file("tests/data/proof_of_twitter/proof.json");
let public_inputs: PublicInputs<3> =
PublicInputs::from_json_file("tests/data/proof_of_twitter/public.json");
let verified = GrothBn::verify(&vkey, &public_inputs, &proof).unwrap();
assert!(verified);
}
}