1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00

Merge pull request #948 from Zokrates/gm17-stdlib-verify

Add gm17 verifier to stdlib
This commit is contained in:
Darko Macesic 2021-08-05 16:34:59 +02:00 committed by GitHub
commit 0f2e3f5881
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 324 additions and 27 deletions

1
Cargo.lock generated
View file

@ -2490,6 +2490,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"zokrates_abi",
"zokrates_core",
"zokrates_field",
"zokrates_fs_resolver",

View file

@ -0,0 +1 @@
Add gm17 verifier to stdlib for bw6_761

View file

@ -299,22 +299,7 @@ pub fn parse_strict<T: Field>(s: &str, types: Vec<ConcreteType>) -> Result<Value
serde_json::from_str(s).map_err(|e| Error::Json(e.to_string()))?;
match values {
serde_json::Value::Array(values) => {
if values.len() != types.len() {
return Err(Error::Type(format!(
"Expected {} inputs, found {}",
types.len(),
values.len()
)));
}
Ok(Values(
types
.into_iter()
.zip(values.into_iter())
.map(|(ty, v)| parse_value(v, ty))
.collect::<Result<_, _>>()?,
))
}
serde_json::Value::Array(values) => parse_strict_json(values, types),
_ => Err(Error::Type(format!(
"Expected an array of values, found `{}`",
values
@ -322,6 +307,27 @@ pub fn parse_strict<T: Field>(s: &str, types: Vec<ConcreteType>) -> Result<Value
}
}
pub fn parse_strict_json<T: Field>(
values: Vec<serde_json::Value>,
types: Vec<ConcreteType>,
) -> Result<Values<T>, Error> {
if values.len() != types.len() {
return Err(Error::Type(format!(
"Expected {} inputs, found {}",
types.len(),
values.len()
)));
}
Ok(Values(
types
.into_iter()
.zip(values.into_iter())
.map(|(ty, v)| parse_value(v, ty))
.collect::<Result<_, _>>()?,
))
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -0,0 +1,15 @@
struct B {
field a
}
struct A {
B a
}
def main():
A a = A {
a: B {
a: false
}
}
return

View file

@ -0,0 +1,20 @@
{
"entry_point": "./tests/tests/structs/member_order.zok",
"curves": ["Bn128"],
"tests": [
{
"abi": true,
"input": {
"values": [{
"a":true,
"b": "3"
}]
},
"output": {
"Ok": {
"values": []
}
}
}
]
}

View file

@ -0,0 +1,9 @@
struct Foo {
field b
bool a
}
// this tests the abi, checking that the fields of a `Foo` instance get encoded in the right order
// if the the encoder reverses `a` and `b`, the boolean check ends up being done on the field value, which would fail
def main(Foo f):
return

View file

@ -0,0 +1,52 @@
#pragma curve bw6_761
from "EMBED" import snark_verify_bls12_377 as verify
struct ProofInner {
field[2] a
field[2][2] b
field[2] c
}
struct Proof<N> {
ProofInner proof
field[N] inputs
}
struct VerificationKey<N> {
field[2][2] h
field[2] g_alpha
field[2][2] h_beta
field[2] g_gamma
field[2][2] h_gamma
field[N][2] query // input length + 1
}
def flat<N, F>(field[N][2] input) -> field[F]:
assert(F == N * 2)
field[F] out = [0; F]
for u32 i in 0..N do
for u32 j in 0..2 do
out[(i * 2) + j] = input[i][j]
endfor
endfor
return out
def main<N, Q>(Proof<N> proof, VerificationKey<Q> vk) -> bool:
assert(Q == N + 1) // query length (Q) should be N + 1
field[8] flat_proof = [
...proof.proof.a,
...flat::<2, 4>(proof.proof.b),
...proof.proof.c
]
u32 two_Q = 2 * Q
field[16 + (2 * Q)] flat_vk = [
...flat::<2, 4>(vk.h),
...vk.g_alpha,
...flat::<2, 4>(vk.h_beta),
...vk.g_gamma,
...flat::<2, 4>(vk.h_gamma),
...flat::<Q, two_Q>(vk.query)
]
return verify(proof.inputs, flat_proof, flat_vk)

View file

@ -0,0 +1,103 @@
{
"entry_point": "./tests/tests/snark/gm17.zok",
"curves": ["Bw6_761"],
"tests": [
{
"abi": true,
"input": {
"values": [
{
"proof": {
"a": [
"0x01441e34fd88112583831de068e3bdf67d7a5b020c9650e4dc8e3dd0cf92f62b32668dd4654ddc63fe5293a542756a27",
"0x013d7b6097a6ae8534909cb2f2ec2e39f3ccbe8858db0285e45619131db37f84b1c88fbb257a7b8e8944a926bb41aa66"
],
"b": [
[
"0x00dcf8242e445213da28281aab32bcf47268bf16624dbca7c828cfbb0e8000bad94926272cba0cd5e9a959cf4e969c7c",
"0x00b570276d40ae06ac3feb5db65b37acf1eabd16e1c588d01c553b1a60e5d007d9202a8ad2b6405e521b3eec84772521"
],
[
"0x00acbeabed6267316420b73b9eba39e8c51080b8b507857478a54c0fc259b17eec2921253a15445e2ec3c130706398b0",
"0x019b579a061cbc4aed64351d87ba96c071118ef3fd645e630c18986e284de5ffc8a48ea94eeb3bdc8807d62d366e223f"
]
],
"c": [
"0x004c93c20cd43f8b7818fcc4ece38243779bedb8b874702df4d6968b75cbe2e6831ab38475e2f0c7bc170171580198df",
"0x0177a560e5f6ae87f07aeff2dcdb1e0737b4810aeba8a5ba1bc4c5d0e89f268aae142ab5327afbde8e8bad869702aad3"
]
},
"inputs": [
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000002",
"0x0000000000000000000000000000000000000000000000000000000000000003"
]
},
{
"h": [
[
"0x000a4c42894d5fd7ac23ca05eac034d82299dd9db5fa493812e4852bcf50cd88faf8f3e97cd292678b292d11e173949b",
"0x001ead78f91728b07146e93ee1f21165f25ad88e0fee997f5527076ca84374d3a6d834b59608226b28ab8b8d5ea9a94f"
],
[
"0x0087b1837c209351af3b67bbfeaea80ed94f690584847b1aa34cc59a2b451f360fc268b2562ea8015f8f4d71c7bf4675",
"0x015c50d51c8ed463a4e9cc76fc0583634b04dc26b36e10bfac9169d0baebf58b45b687a81a0ca60400427889bcbc6b76"
]
],
"g_alpha": [
"0x004b7af9ab6ef9061adb5ed7ba12e9cd41f508ac758c25c5e629d871a1b980e5242149b522b20c57808fae97cb76b971",
"0x0196c16d89a7cccbb8f15775da22c01d5ec45b384829bcaad91b324a482676558d3d6d41f675966b5d22537f4ed77903"
],
"h_beta": [
[
"0x014d2d0bcfa272334efbc589dc263c3f2a5d2711f9a0d5fbb3c2ad1b7eebe93459aeee6e1c8bc02041945313aec93d8a",
"0x0054800f89ebbbd924328a7782fdbb5260b56059901a06e6ad58c4a7df96018e5ea1c5ffd28ed0dd0139dcced6bde7e8"
],
[
"0x00ca4e270e5fe79ff2a5432daf6e9e5aa22aebf6521a7d3c5ef97d981b05ea93043c6307b47e8a3e00ace9c987fb725e",
"0x010cb8f97a5d586777e4f7ca8a0ce4465c0de02951cb8ccca43403b1a669e523c1163ebc9ce7d10edf583894fad70341"
]
],
"g_gamma": [
"0x003fa4d4d1fe1a9bb62e704b5ac76a514e4aaf53cfcbd12cb55aa7afecf2c12ce9346737b5594ee872700178748e9ed1",
"0x018975a2eb9de8a1982d076b56bb86b5214f89cff897d492e16dcdc1eca2a692eb9f0af5183585ba4aee9d78af2ab570"
],
"h_gamma": [
[
"0x000a4c42894d5fd7ac23ca05eac034d82299dd9db5fa493812e4852bcf50cd88faf8f3e97cd292678b292d11e173949b",
"0x001ead78f91728b07146e93ee1f21165f25ad88e0fee997f5527076ca84374d3a6d834b59608226b28ab8b8d5ea9a94f"
],
[
"0x0087b1837c209351af3b67bbfeaea80ed94f690584847b1aa34cc59a2b451f360fc268b2562ea8015f8f4d71c7bf4675",
"0x015c50d51c8ed463a4e9cc76fc0583634b04dc26b36e10bfac9169d0baebf58b45b687a81a0ca60400427889bcbc6b76"
]
],
"query": [
[
"0x00dbcc84391e078ae2fa7b5dc8478651b945e155505332a55e5b7be4de52ce83450bbf94f1da270c012104d394b22fda",
"0x002dc3039f7236d31fceaa6d8e13d33a5850984193f70c0abfe20a1f4540f59987e49cb0cc2722f1dccb47f1012d38c8"
],
[
"0x00db1bc3a431619ca74564c8a734592151a5fc2d8bfa750d4ffb94126bdaed83dce86bcdc8f966dca3066f67c61c897c",
"0x00e97f2f6c94a2676dd3c8646a45684cfd66a644644c1fc8ee5cf2ab4e322a5a82a9f9872ec9e8c7f3f1a9ddf38f2e53"
],
[
"0x008f4c292ba1ae0fa22613e0afaa075796b21a935e591fb8e8b32fa7c0fe0ecda25d5575e1e2b178d5a4bfb8e89f9d36",
"0x017cb6aca4e2d1027ab429a2a7d6b8f6e13dfeb427b7eaf9b6e3ca22554fae39f45ee0854098c9753cca04b46f3388d0"
],
[
"0x0168740e2d9cab168df083dd1d340de23d5055f4eed63c87811e94a5bf9c492658c6c58ccb1a48bb153cbe9aa8d98c8d",
"0x005b7c28b57504562c1d38a5ba9c67a59c696dc2e51b3c50d96e75e2f399f9106f08f6846d553d32e58b8131ad997fc1"
]
]
}
]
},
"output": {
"Ok": {
"values": ["1"]
}
}
}
]
}

View file

@ -0,0 +1,57 @@
// verify a snark
// to reproduce the test cases:
//
// 1. Create a program
// ```zokrates
// def main(field a, field b) -> field:
// return a + b
// ```
//
// 2. Compile it to bls12_377
// ```sh
// zokrates compile -i program.zok --curve bls12_377
// ```
//
// 3. Run a trusted setup for gm17
// ```sh
// zokrates setup --proving-scheme gm17 --backend ark
// ```
//
// 4. Execute the program and generate a proof
// ```sh
// zokrates compute-witness -a 1 2
// zokrates generate-proof --proving-scheme gm17 --backend ark
// ```
//
// 5. Generate the test case
//
// ```sh
// cat > gm17.json << EOT
// {
// "entry_point": "./tests/tests/snark/gm17.zok",
// "curves": ["Bw6_761"],
// "tests": [
// {
// "abi": true,
// "input": {
// "values": [
// $(cat proof.json && echo ", " && cat verification.key)
// ]
// },
// "output": {
// "Ok": {
// "values": ["1"]
// }
// }
// }
// ]
// }
// EOT
// ```
//
// `gm17.json` can then be used as a test for this code file
from "snark/gm17" import main as verify, Proof, VerificationKey
def main(Proof<3> proof, VerificationKey<4> vk) -> bool:
return verify::<3, 4>(proof, vk)

View file

@ -8,6 +8,7 @@ edition = "2018"
zokrates_field = { version = "0.4", path = "../zokrates_field" }
zokrates_core = { version = "0.6", path = "../zokrates_core" }
zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver" }
zokrates_abi = { version = "0.1", path = "../zokrates_abi" }
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"

View file

@ -5,8 +5,11 @@ use std::fs::File;
use std::io::{BufReader, Read};
use std::path::{Path, PathBuf};
use zokrates_core::compile::{compile, CompileConfig};
use zokrates_core::ir;
use zokrates_core::{
compile::{compile, CompileConfig},
typed_absy::ConcreteType,
};
use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field};
use zokrates_fs_resolver::FileSystemResolver;
@ -34,6 +37,7 @@ struct Input {
#[derive(Serialize, Deserialize, Clone)]
struct Test {
pub abi: Option<bool>,
pub input: Input,
pub output: TestResult,
}
@ -48,11 +52,24 @@ struct Output {
values: Vec<Val>,
}
type Val = String;
type Val = serde_json::Value;
fn parse_val<T: Field>(s: String) -> T {
let radix = if s.starts_with("0x") { 16 } else { 10 };
T::try_from_str(s.trim_start_matches("0x"), radix).unwrap()
fn try_parse_raw_val<T: Field>(s: serde_json::Value) -> Result<T, ()> {
match s {
serde_json::Value::String(s) => {
let radix = if s.starts_with("0x") { 16 } else { 10 };
T::try_from_str(s.trim_start_matches("0x"), radix).map_err(|_| ())
}
_ => Err(()),
}
}
fn try_parse_abi_val<T: Field>(
s: Vec<Val>,
types: Vec<ConcreteType>,
) -> Result<Vec<T>, zokrates_abi::Error> {
use zokrates_abi::Encode;
zokrates_abi::parse_strict_json(s, types).map(|v| v.encode())
}
impl<T: Field> From<ir::ExecutionResult<T>> for ComparableResult<T> {
@ -63,7 +80,12 @@ impl<T: Field> From<ir::ExecutionResult<T>> for ComparableResult<T> {
impl<T: Field> From<TestResult> for ComparableResult<T> {
fn from(r: TestResult) -> ComparableResult<T> {
ComparableResult(r.map(|v| v.values.into_iter().map(parse_val).collect()))
ComparableResult(r.map(|v| {
v.values
.into_iter()
.map(|v| try_parse_raw_val(v).unwrap())
.collect()
}))
}
}
@ -130,6 +152,7 @@ fn compile_and_run<T: Field>(t: Tests) {
let artifacts = compile::<T, _>(code, entry_point.clone(), Some(&resolver), &config).unwrap();
let bin = artifacts.prog();
let abi = artifacts.abi();
if let Some(target_count) = t.max_constraint_count {
let count = bin.constraint_count();
@ -148,12 +171,21 @@ fn compile_and_run<T: Field>(t: Tests) {
let interpreter = zokrates_core::ir::Interpreter::default();
for test in t.tests.into_iter() {
let input = &test.input.values;
let with_abi = test.abi.unwrap_or(false);
let output = interpreter.execute(
bin,
&(input.iter().cloned().map(parse_val).collect::<Vec<_>>()),
);
let input = if with_abi {
try_parse_abi_val(test.input.values, abi.signature().inputs).unwrap()
} else {
test.input
.values
.iter()
.cloned()
.map(try_parse_raw_val)
.collect::<Result<Vec<_>, _>>()
.unwrap()
};
let output = interpreter.execute(bin, &input);
if let Err(e) = compare(output, test.output) {
let mut code = File::open(&entry_point).unwrap();