Skip to content

Commit

Permalink
zkutils: cli tool to work with zero knowledge on GGX
Browse files Browse the repository at this point in the history
Adds a command `solidity verifier` to  generate snarkjs like solidity
verifier contract which calls groth16 precompile under the hood.
  • Loading branch information
rikysya committed Sep 19, 2023
1 parent fde40ce commit 681d073
Show file tree
Hide file tree
Showing 10 changed files with 1,039 additions and 0 deletions.
58 changes: 58 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"runtime/sydney",
"runtime/brooklyn",
"runtime/runtime-common",
"zkutils",
]
exclude = [
"examples/cross-vm-communication/evm-to-wasm/flipper",
Expand Down Expand Up @@ -227,6 +228,9 @@ ark-relations = { version = "0.4.0", default-features = false }
ark-serialize = { version = "0.4.1", default-features = false }
ark-std = { version = "0.4.0", default-features = false }

# zk utils
sailfish = "0.8.0"

# Temporary, leaks the std feature in the non-std env. Until https://github.com/AstarNetwork/frontier/pull/84 is merged.
[patch."https://github.com/AstarNetwork/frontier.git"]
fp-account = { git = "https://github.com/GoldenGateGGX/frontier.git", branch = "polkadot-v0.9.40" }
18 changes: 18 additions & 0 deletions zkutils/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "zkutils"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sailfish = { workspace = true }

[dev-dependencies]
assert_cmd = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["macros", "time", "parking_lot", "rt"] }
ethers = { workspace = true }
32 changes: 32 additions & 0 deletions zkutils/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
mod solidity;

use clap::Parser;

#[derive(Debug, clap::Parser)]
#[clap(about, version)]
pub struct CLI {
#[clap(subcommand)]
command: Commands,
}

#[derive(Debug, clap::Subcommand)]
pub enum Commands {
#[clap(subcommand)]
Solidity(solidity::Commands),
}

fn main() {
let cli = CLI::parse();

match cli.command {
Commands::Solidity(cmd) => match cmd {
solidity::Commands::Verifier(cmd) => {
let r = cmd.run();
match r {
Err(e) => eprintln!("{}", e),
_ => {}
}
}
},
}
}
61 changes: 61 additions & 0 deletions zkutils/src/solidity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use sailfish::TemplateOnce;
use std::{error::Error, fs, fs::File, io::Write, path::PathBuf};

#[derive(Debug, clap::Subcommand)]
pub enum Commands {
Verifier(VerifierCMD),
}

#[derive(Debug, clap::Args)]
pub struct VerifierCMD {
#[arg(required = true)]
verification_key: PathBuf,
#[arg(required = false)]
#[clap(default_value = "verifier.sol")]
output: PathBuf,
}

impl VerifierCMD {
pub fn run(&self) -> Result<(), Box<dyn Error>> {
let b = fs::read(self.verification_key.clone())?;
let vk: VerificationKey = serde_json::from_slice(&b)?;

let ctx = TemplateContext {
vk_alpha_1: vk.vk_alpha_1,
vk_beta_2: vk.vk_beta_2,
vk_gamma_2: vk.vk_gamma_2,
vk_delta_2: vk.vk_delta_2,
ic: vk.ic,
};
let rendered = ctx.render_once()?;

let mut file = File::create(self.output.clone())?;
file.write_all(rendered.as_bytes())?;
Ok(())
}
}

#[derive(TemplateOnce)]
#[template(path = "verifier_groth16.sol.stpl")]
struct TemplateContext {
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, serde::Deserialize, serde::Serialize)]
pub struct VerificationKey {
protocol: String,
curve: String,
#[serde(rename = "nPublic")]
n_public: i128,
vk_alpha_1: [String; 3],
vk_beta_2: [[String; 2]; 3],
vk_gamma_2: [[String; 2]; 3],
vk_delta_2: [[String; 2]; 3],
vk_alphabeta_12: [[[String; 2]; 3]; 2],
#[serde(rename = "IC")]
ic: Vec<[String; 3]>,
}
125 changes: 125 additions & 0 deletions zkutils/templates/verifier_groth16.sol.stpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// SPDX-License-Identifier: GPL-3.0
/*
Copyright 2021 0KIMS association.

This file is generated with [snarkJS](https://github.com/iden3/snarkjs).

snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.

You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/

pragma solidity >=0.7.0 <0.9.0;

/**
* @title ZKGroth16Verify Interface
*
* The interface through which solidity contracts will interact with ZKGroth16Verify
* Address : 0x0000000000000000000000000000000000008888
*/
interface IZKGroth16Verify {
/**
* @notice Verifies a Groth16 zkSNARK proof.
*
* @param proof_a The first element of the zkSNARK proof.
* @param proof_b The second element of the zkSNARK proof.
* @param proof_c The third element of the zkSNARK proof.
* @param vk_alpha The first element of the verification key.
* @param vk_beta The second element of the verification key.
* @param vk_gamma The third element of the verification key.
* @param vk_delta The fourth element of the verification key.
* @param vk_ic The array of the rest of the elements of the verification key.
* @param input The array of public inputs to the zkSNARK.
*
* @return valid A boolean value representing whether the proof is valid or not.
*/
function verify(
uint[2] memory proof_a,
uint[2][2] memory proof_b,
uint[2] memory proof_c,
uint[2] memory vk_alpha,
uint[2][2] memory vk_beta,
uint[2][2] memory vk_gamma,
uint[2][2] memory vk_delta,
uint[2][] memory vk_ic,
uint[] memory input
) external view returns (bool valid);
}

contract Groth16Verifier {
// Verification Key data
uint256[2] vk_alpha = [
<%=vk_alpha_1[0]%>,
<%=vk_alpha_1[1]%>
];

uint256[2][2] vk_beta = [
[
<%=vk_beta_2[0][0]%>,
<%=vk_beta_2[0][1]%>
],
[
<%=vk_beta_2[1][0]%>,
<%=vk_beta_2[1][1]%>
]
];
uint256[2][2] vk_gamma = [
[
<%=vk_gamma_2[0][0]%>,
<%=vk_gamma_2[0][1]%>
],
[
<%=vk_gamma_2[1][0]%>,
<%=vk_gamma_2[1][1]%>
]
];
uint256[2][2] vk_delta = [
[
<%=vk_delta_2[0][0]%>,
<%=vk_delta_2[0][1]%>
],
[
<%=vk_delta_2[1][0]%>,
<%=vk_delta_2[1][1]%>
]
];

uint256[2][] vk_ic = [<% for i in 0..ic.len() { %>
[
<%=ic[i][0]%>,
<%=ic[i][1]%>
]<% if i != ic.len()-1 {%>,<% } %><% } %>
];

function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[<%=ic.len()-1%>] calldata _pubSignals) public view returns (bool) {
uint[] memory input = new uint[](_pubSignals.length);
<% for i in 0..ic.len()-1 { %>input[<%=i%>] = _pubSignals[<%=i%>];<% } %>

uint[2][2] memory pB;
pB[0][0] = _pB[0][1];
pB[0][1] = _pB[0][0];
pB[1][0] = _pB[1][1];
pB[1][1] = _pB[1][0];

return IZKGroth16Verify(0x0000000000000000000000000000000000008888).verify(
_pA,
pB,
_pC,
vk_alpha,
vk_beta,
vk_gamma,
vk_delta,
vk_ic,
input
);
}
}
Loading

0 comments on commit 681d073

Please sign in to comment.