Merge pull request #948 from Zokrates/gm17-stdlib-verify
Add gm17 verifier to stdlib
This commit is contained in:
commit
0f2e3f5881
11 changed files with 324 additions and 27 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2490,6 +2490,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"zokrates_abi",
|
||||
"zokrates_core",
|
||||
"zokrates_field",
|
||||
"zokrates_fs_resolver",
|
||||
|
|
1
changelogs/unreleased/948-schaeff
Normal file
1
changelogs/unreleased/948-schaeff
Normal file
|
@ -0,0 +1 @@
|
|||
Add gm17 verifier to stdlib for bw6_761
|
|
@ -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::*;
|
||||
|
|
15
zokrates_cli/examples/compile_errors/wrong_member_type.zok
Normal file
15
zokrates_cli/examples/compile_errors/wrong_member_type.zok
Normal file
|
@ -0,0 +1,15 @@
|
|||
struct B {
|
||||
field a
|
||||
}
|
||||
|
||||
struct A {
|
||||
B a
|
||||
}
|
||||
|
||||
def main():
|
||||
A a = A {
|
||||
a: B {
|
||||
a: false
|
||||
}
|
||||
}
|
||||
return
|
20
zokrates_core_test/tests/tests/structs/member_order.json
Normal file
20
zokrates_core_test/tests/tests/structs/member_order.json
Normal 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": []
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
9
zokrates_core_test/tests/tests/structs/member_order.zok
Normal file
9
zokrates_core_test/tests/tests/structs/member_order.zok
Normal 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
|
52
zokrates_stdlib/stdlib/snark/gm17.zok
Normal file
52
zokrates_stdlib/stdlib/snark/gm17.zok
Normal 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)
|
103
zokrates_stdlib/tests/tests/snark/gm17.json
Normal file
103
zokrates_stdlib/tests/tests/snark/gm17.json
Normal 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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
57
zokrates_stdlib/tests/tests/snark/gm17.zok
Normal file
57
zokrates_stdlib/tests/tests/snark/gm17.zok
Normal 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)
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue