From f2ebddb2fc7407c204df9fc94843b18e5506371d Mon Sep 17 00:00:00 2001 From: dark64 Date: Fri, 24 Apr 2020 16:09:03 +0200 Subject: [PATCH] minor refactor and cleanup, add tests to vk parser --- .circleci/config.yml | 6 +- zokrates_cli/src/bin.rs | 57 +++++++++---------- zokrates_core/lib/gm17.cpp | 1 - zokrates_core/src/proof_system/bn128/g16.rs | 41 +++++-------- zokrates_core/src/proof_system/bn128/gm17.rs | 51 +++++++++-------- zokrates_core/src/proof_system/bn128/mod.rs | 9 ++- .../src/proof_system/bn128/pghr13.rs | 54 +++++++++--------- .../src/proof_system/bn128/utils/ffi.rs | 2 +- .../src/proof_system/bn128/utils/libsnark.rs | 8 +-- .../src/proof_system/bn128/utils/parser.rs | 41 +++++++++---- zokrates_core/src/proof_system/mod.rs | 17 +++++- zokrates_core/src/semantics.rs | 53 ++++++++++------- zokrates_js/index.d.ts | 3 +- zokrates_js/index.js | 4 +- zokrates_js/src/lib.rs | 12 ++-- 15 files changed, 200 insertions(+), 159 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ecf45c41..27511643 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -42,9 +42,9 @@ jobs: - restore_cache: keys: - v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }} - # - run: - # name: Check format - # command: rustup component add rustfmt; cargo fmt --all -- --check + - run: + name: Check format + command: rustup component add rustfmt; cargo fmt --all -- --check - run: name: Install libsnark prerequisites command: ./scripts/install_libsnark_prerequisites.sh diff --git a/zokrates_cli/src/bin.rs b/zokrates_cli/src/bin.rs index 426d0c2f..4d075f1d 100644 --- a/zokrates_cli/src/bin.rs +++ b/zokrates_cli/src/bin.rs @@ -264,7 +264,7 @@ fn cli() -> Result<(), String> { ) ) .subcommand(SubCommand::with_name("verify") - .about("Verifies a given proof with the given constraint system and verification key") + .about("Verifies a given proof with the given verification key") .arg(Arg::with_name("proof-path") .short("j") .long("proof-path") @@ -367,7 +367,7 @@ fn cli() -> Result<(), String> { if !light { // write human-readable output file let hr_output_file = File::create(&hr_output_path).map_err(|why| { - format!("couldn't create {}: {}", hr_output_path.display(), why) + format!("Couldn't create {}: {}", hr_output_path.display(), why) })?; let mut hrofb = BufWriter::new(hr_output_file); @@ -397,7 +397,7 @@ fn cli() -> Result<(), String> { // read compiled program let path = Path::new(sub_matches.value_of("input").unwrap()); let file = File::open(&path) - .map_err(|why| format!("couldn't open {}: {}", path.display(), why))?; + .map_err(|why| format!("Couldn't open {}: {}", path.display(), why))?; let mut reader = BufReader::new(file); @@ -422,7 +422,7 @@ fn cli() -> Result<(), String> { true => { let path = Path::new(sub_matches.value_of("abi_spec").unwrap()); let file = File::open(&path) - .map_err(|why| format!("couldn't open {}: {}", path.display(), why))?; + .map_err(|why| format!("Couldn't open {}: {}", path.display(), why))?; let mut reader = BufReader::new(file); let abi: Abi = from_reader(&mut reader).map_err(|why| why.to_string())?; @@ -502,13 +502,13 @@ fn cli() -> Result<(), String> { // write witness to file let output_path = Path::new(sub_matches.value_of("output").unwrap()); let output_file = File::create(&output_path) - .map_err(|why| format!("couldn't create {}: {}", output_path.display(), why))?; + .map_err(|why| format!("Couldn't create {}: {}", output_path.display(), why))?; let writer = BufWriter::new(output_file); witness .write(writer) - .map_err(|why| format!("could not save witness: {:?}", why))?; + .map_err(|why| format!("Could not save witness: {:?}", why))?; } ("setup", Some(sub_matches)) => { let scheme = get_scheme(sub_matches.value_of("proving-scheme").unwrap())?; @@ -517,7 +517,7 @@ fn cli() -> Result<(), String> { let path = Path::new(sub_matches.value_of("input").unwrap()); let file = File::open(&path) - .map_err(|why| format!("couldn't open {}: {}", path.display(), why))?; + .map_err(|why| format!("Couldn't open {}: {}", path.display(), why))?; let mut reader = BufReader::new(file); @@ -538,17 +538,17 @@ fn cli() -> Result<(), String> { // write verification key let mut vk_file = File::create(vk_path) - .map_err(|why| format!("couldn't create {}: {}", vk_path.display(), why))?; + .map_err(|why| format!("Couldn't create {}: {}", vk_path.display(), why))?; vk_file .write(keypair.vk.as_ref()) - .map_err(|why| format!("couldn't write to {}: {}", vk_path.display(), why))?; + .map_err(|why| format!("Couldn't write to {}: {}", vk_path.display(), why))?; // write proving key let mut pk_file = File::create(pk_path) - .map_err(|why| format!("couldn't create {}: {}", pk_path.display(), why))?; + .map_err(|why| format!("Couldn't create {}: {}", pk_path.display(), why))?; pk_file .write(keypair.pk.as_ref()) - .map_err(|why| format!("couldn't write to {}: {}", pk_path.display(), why))?; + .map_err(|why| format!("Couldn't write to {}: {}", pk_path.display(), why))?; println!("Setup completed."); } @@ -556,26 +556,27 @@ fn cli() -> Result<(), String> { { let scheme = get_scheme(sub_matches.value_of("proving-scheme").unwrap())?; - let is_abi_v2 = sub_matches.value_of("solidity-abi").unwrap() == "v2"; + let abi_version = AbiVersion::from(sub_matches.value_of("solidity-abi").unwrap())?; + println!("Exporting verifier..."); // read vk file let vk_path = Path::new(sub_matches.value_of("input").unwrap()); let vk_file = File::open(&vk_path) - .map_err(|why| format!("couldn't open {}: {}", vk_path.display(), why))?; + .map_err(|why| format!("Couldn't open {}: {}", vk_path.display(), why))?; let mut reader = BufReader::new(vk_file); let mut vk = String::new(); reader .read_to_string(&mut vk) - .map_err(|why| format!("couldn't read {}: {}", vk_path.display(), why))?; + .map_err(|why| format!("Couldn't read {}: {}", vk_path.display(), why))?; - let verifier = scheme.export_solidity_verifier(vk, is_abi_v2); + let verifier = scheme.export_solidity_verifier(vk, abi_version); //write output file let output_path = Path::new(sub_matches.value_of("output").unwrap()); let output_file = File::create(&output_path) - .map_err(|why| format!("couldn't create {}: {}", output_path.display(), why))?; + .map_err(|why| format!("Couldn't create {}: {}", output_path.display(), why))?; let mut writer = BufWriter::new(output_file); @@ -592,20 +593,18 @@ fn cli() -> Result<(), String> { // deserialize witness let witness_path = Path::new(sub_matches.value_of("witness").unwrap()); - let witness_file = match File::open(&witness_path) { - Ok(file) => file, - Err(why) => panic!("couldn't open {}: {}", witness_path.display(), why), - }; + let witness_file = File::open(&witness_path) + .map_err(|why| format!("Couldn't open {}: {}", witness_path.display(), why))?; let witness = ir::Witness::read(witness_file) - .map_err(|why| format!("could not load witness: {:?}", why))?; + .map_err(|why| format!("Could not load witness: {:?}", why))?; let pk_path = Path::new(sub_matches.value_of("proving-key-path").unwrap()); let proof_path = Path::new(sub_matches.value_of("proof-path").unwrap()); let program_path = Path::new(sub_matches.value_of("input").unwrap()); let program_file = File::open(&program_path) - .map_err(|why| format!("couldn't open {}: {}", program_path.display(), why))?; + .map_err(|why| format!("Couldn't open {}: {}", program_path.display(), why))?; let mut reader = BufReader::new(program_file); @@ -613,22 +612,22 @@ fn cli() -> Result<(), String> { deserialize_from(&mut reader, Infinite).map_err(|why| format!("{:?}", why))?; let pk_file = File::open(&pk_path) - .map_err(|why| format!("couldn't open {}: {}", pk_path.display(), why))?; + .map_err(|why| format!("Couldn't open {}: {}", pk_path.display(), why))?; let mut pk: Vec = Vec::new(); let mut pk_reader = BufReader::new(pk_file); pk_reader .read_to_end(&mut pk) - .map_err(|why| format!("couldn't read {}: {}", pk_path.display(), why))?; + .map_err(|why| format!("Couldn't read {}: {}", pk_path.display(), why))?; let proof = scheme.generate_proof(program, witness, pk); let mut proof_file = File::create(proof_path).unwrap(); proof_file .write(proof.as_ref()) - .map_err(|why| format!("couldn't write to {}: {}", proof_path.display(), why))?; + .map_err(|why| format!("Couldn't write to {}: {}", proof_path.display(), why))?; - println!("Proof: \n\n{}", format!("{}", proof)); + println!("\nProof:\n{}", format!("{}", proof)); } ("print-proof", Some(sub_matches)) => { let format = sub_matches.value_of("format").unwrap(); @@ -636,7 +635,7 @@ fn cli() -> Result<(), String> { let path = Path::new(sub_matches.value_of("proof-path").unwrap()); let file = File::open(&path) - .map_err(|why| format!("couldn't open {}: {}", path.display(), why))?; + .map_err(|why| format!("Couldn't open {}: {}", path.display(), why))?; let proof_object: Value = serde_json::from_reader(file).map_err(|why| format!("{:?}", why))?; @@ -672,11 +671,11 @@ fn cli() -> Result<(), String> { let vk_path = Path::new(sub_matches.value_of("verification-key-path").unwrap()); let vk = std::fs::read_to_string(vk_path) - .map_err(|why| format!("couldn't read {}: {}", vk_path.display(), why))?; + .map_err(|why| format!("Couldn't read {}: {}", vk_path.display(), why))?; let proof_path = Path::new(sub_matches.value_of("proof-path").unwrap()); let proof = std::fs::read_to_string(proof_path) - .map_err(|why| format!("couldn't read {}: {}", proof_path.display(), why))?; + .map_err(|why| format!("Couldn't read {}: {}", proof_path.display(), why))?; println!("Performing verification..."); println!( diff --git a/zokrates_core/lib/gm17.cpp b/zokrates_core/lib/gm17.cpp index 01a99b44..bda5d1f8 100644 --- a/zokrates_core/lib/gm17.cpp +++ b/zokrates_core/lib/gm17.cpp @@ -8,7 +8,6 @@ #include "gm17.hpp" #include "util.hpp" #include -#include #include #include diff --git a/zokrates_core/src/proof_system/bn128/g16.rs b/zokrates_core/src/proof_system/bn128/g16.rs index 5e22733c..2a5ebf91 100644 --- a/zokrates_core/src/proof_system/bn128/g16.rs +++ b/zokrates_core/src/proof_system/bn128/g16.rs @@ -18,6 +18,7 @@ use crate::proof_system::bn128::utils::solidity::{ }; use crate::proof_system::{ProofSystem, SetupKeypair}; use proof_system::bn128::{G1PairingPoint, G2PairingPoint, Proof}; +use proof_system::AbiVersion; const G16_WARNING: &str = "WARNING: You are using the G16 scheme which is subject to malleability. See zokrates.github.io/reference/proving_schemes.html#g16-malleability for implications."; @@ -42,15 +43,6 @@ impl G16ProofPoints { } } -impl Proof { - fn from_json(str: &str) -> Self { - serde_json::from_str(str).unwrap() - } - fn to_json_pretty(&self) -> String { - serde_json::to_string_pretty(&self).unwrap() - } -} - impl ProofSystem for G16 { fn setup(&self, program: ir::Prog) -> SetupKeypair { #[cfg(not(target_arch = "wasm32"))] @@ -60,9 +52,7 @@ impl ProofSystem for G16 { let parameters = Computation::without_witness(program).setup(); let mut pk: Vec = Vec::new(); - parameters - .write(&mut pk) - .expect("Could not write proving key to buffer"); + parameters.write(&mut pk).unwrap(); SetupKeypair::from(serialize_vk(parameters.vk), pk) } @@ -97,18 +87,17 @@ impl ProofSystem for G16 { Proof::::new(proof_points, inputs, hex::encode(&raw)).to_json_pretty() } - fn export_solidity_verifier(&self, vk: String, abi_v2: bool) -> String { - let vk_map = parse_vk(vk); - let (mut template_text, solidity_pairing_lib) = if abi_v2 { - ( - String::from(CONTRACT_TEMPLATE_V2), - String::from(SOLIDITY_PAIRING_LIB_V2), - ) - } else { - ( + fn export_solidity_verifier(&self, vk: String, abi_version: AbiVersion) -> String { + let vk_map = parse_vk(vk).unwrap(); + let (mut template_text, solidity_pairing_lib) = match abi_version { + AbiVersion::V1 => ( String::from(CONTRACT_TEMPLATE), String::from(SOLIDITY_PAIRING_LIB), - ) + ), + AbiVersion::V2 => ( + String::from(CONTRACT_TEMPLATE_V2), + String::from(SOLIDITY_PAIRING_LIB_V2), + ), }; let vk_regex = Regex::new(r#"(<%vk_[^i%]*%>)"#).unwrap(); @@ -170,15 +159,15 @@ impl ProofSystem for G16 { } fn verify(&self, vk: String, proof: String) -> bool { - let map = parse_vk(vk); + let map = parse_vk(vk).unwrap(); let vk_raw = hex::decode(map.get("vk.raw").unwrap()).unwrap(); let vk: VerifyingKey = VerifyingKey::read(vk_raw.as_slice()).unwrap(); let pvk: PreparedVerifyingKey = prepare_verifying_key(&vk); - let g16_proof: Proof = Proof::from_json(proof.as_str()); - let raw_proof = hex::decode(g16_proof.raw).unwrap(); + let g16_proof = Proof::::from_str(proof.as_str()); + let raw_proof = hex::decode(g16_proof.raw).unwrap(); let proof: BellmanProof = BellmanProof::read(raw_proof.as_slice()).unwrap(); let public_inputs: Vec = g16_proof @@ -186,7 +175,7 @@ impl ProofSystem for G16 { .iter() .map(|s| { FieldPrime::try_from_str(s.trim_start_matches("0x"), 16) - .unwrap() + .expect(format!("Invalid field value: {}", s).as_str()) .into_bellman() }) .collect::>(); diff --git a/zokrates_core/src/proof_system/bn128/gm17.rs b/zokrates_core/src/proof_system/bn128/gm17.rs index db61292e..85d16b33 100644 --- a/zokrates_core/src/proof_system/bn128/gm17.rs +++ b/zokrates_core/src/proof_system/bn128/gm17.rs @@ -10,8 +10,8 @@ use proof_system::bn128::utils::solidity::{ SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB, SOLIDITY_PAIRING_LIB_V2, }; use proof_system::bn128::{G1PairingPoint, G2PairingPoint, Proof}; -use proof_system::{ProofSystem, SetupKeypair}; -use zokrates_field::field::FieldPrime; +use proof_system::{AbiVersion, ProofSystem, SetupKeypair}; +use zokrates_field::field::{Field, FieldPrime}; pub struct GM17 {} @@ -28,12 +28,6 @@ struct GM17ProofPoints { c: G1PairingPoint, } -impl Proof { - fn from_json(str: &str) -> Self { - serde_json::from_str(str).unwrap() - } -} - extern "C" { fn gm17_setup( a: *const u8, @@ -106,8 +100,9 @@ impl ProofSystem for GM17 { let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) = prepare_generate_proof(program, witness); + let mut pk_buffer = Buffer::from_vec(&proving_key); + let proof = unsafe { - let mut pk_buffer = Buffer::from_vec(&proving_key); let result = gm17_generate_proof( &mut pk_buffer as *mut _, public_inputs_arr[0].as_ptr(), @@ -132,18 +127,17 @@ impl ProofSystem for GM17 { String::from_utf8(proof).unwrap() } - fn export_solidity_verifier(&self, vk: String, abi_v2: bool) -> String { - let vk_map = parse_vk(vk); - let (mut template_text, solidity_pairing_lib) = if abi_v2 { - ( - String::from(CONTRACT_TEMPLATE_V2), - String::from(SOLIDITY_PAIRING_LIB_V2), - ) - } else { - ( + fn export_solidity_verifier(&self, vk: String, abi_version: AbiVersion) -> String { + let vk_map = parse_vk(vk).unwrap(); + let (mut template_text, solidity_pairing_lib) = match abi_version { + AbiVersion::V1 => ( String::from(CONTRACT_TEMPLATE), String::from(SOLIDITY_PAIRING_LIB), - ) + ), + AbiVersion::V2 => ( + String::from(CONTRACT_TEMPLATE_V2), + String::from(SOLIDITY_PAIRING_LIB_V2), + ), }; // replace things in template @@ -210,20 +204,27 @@ impl ProofSystem for GM17 { } fn verify(&self, vk: String, proof: String) -> bool { - let map = parse_vk(vk); + let map = parse_vk(vk).unwrap(); let vk_raw = hex::decode(map.get("vk.raw").unwrap()).unwrap(); - let proof: Proof = Proof::from_json(proof.as_str()); + let proof = Proof::::from_str(proof.as_str()); let proof_raw = hex::decode(proof.raw).unwrap(); - let public_inputs: Vec<&str> = proof.inputs.iter().map(|v| v.as_str()).collect(); + let public_inputs: Vec = proof + .inputs + .iter() + .map(|v| { + FieldPrime::try_from_str(v.as_str().trim_start_matches("0x"), 16) + .expect(format!("Invalid field value: {}", v.as_str()).as_str()) + }) + .collect(); let (public_inputs_arr, public_inputs_length) = prepare_public_inputs(public_inputs); - unsafe { - let mut vk_buffer = Buffer::from_vec(&vk_raw); - let mut proof_buffer = Buffer::from_vec(&proof_raw); + let mut vk_buffer = Buffer::from_vec(&vk_raw); + let mut proof_buffer = Buffer::from_vec(&proof_raw); + unsafe { let ans = gm17_verify( &mut vk_buffer as *mut _, &mut proof_buffer as *mut _, diff --git a/zokrates_core/src/proof_system/bn128/mod.rs b/zokrates_core/src/proof_system/bn128/mod.rs index 42350fca..b18ef9ec 100644 --- a/zokrates_core/src/proof_system/bn128/mod.rs +++ b/zokrates_core/src/proof_system/bn128/mod.rs @@ -11,6 +11,7 @@ pub use self::g16::G16; pub use self::gm17::GM17; #[cfg(feature = "libsnark")] pub use self::pghr13::PGHR13; +use serde::{Deserialize, Serialize}; type G1PairingPoint = (String, String); type G2PairingPoint = (G1PairingPoint, G1PairingPoint); @@ -22,8 +23,14 @@ struct Proof { raw: String, } -impl Proof { +impl<'a, T: Serialize + Deserialize<'a>> Proof { fn new(proof: T, inputs: Vec, raw: String) -> Self { Proof { proof, inputs, raw } } + fn from_str(proof: &'a str) -> Proof { + serde_json::from_str(proof).expect("Invalid proof json format") + } + fn to_json_pretty(&self) -> String { + serde_json::to_string_pretty(self).unwrap() + } } diff --git a/zokrates_core/src/proof_system/bn128/pghr13.rs b/zokrates_core/src/proof_system/bn128/pghr13.rs index b95bce42..9fbbe3f8 100644 --- a/zokrates_core/src/proof_system/bn128/pghr13.rs +++ b/zokrates_core/src/proof_system/bn128/pghr13.rs @@ -8,9 +8,9 @@ use proof_system::bn128::utils::solidity::{ SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB, SOLIDITY_PAIRING_LIB_V2, }; use proof_system::bn128::{G1PairingPoint, G2PairingPoint, Proof}; -use proof_system::{ProofSystem, SetupKeypair}; +use proof_system::{AbiVersion, ProofSystem, SetupKeypair}; use regex::Regex; -use zokrates_field::field::FieldPrime; +use zokrates_field::field::{Field, FieldPrime}; pub struct PGHR13 {} @@ -21,7 +21,7 @@ impl PGHR13 { } #[derive(Serialize, Deserialize)] -struct PGHR13ProofPoints { +pub struct PGHR13ProofPoints { a: G1PairingPoint, a_p: G1PairingPoint, b: G2PairingPoint, @@ -32,12 +32,6 @@ struct PGHR13ProofPoints { k: G1PairingPoint, } -impl Proof { - fn from_json(str: &str) -> Self { - serde_json::from_str(str).unwrap() - } -} - extern "C" { fn pghr13_setup( a: *const u8, @@ -110,9 +104,9 @@ impl ProofSystem for PGHR13 { let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) = prepare_generate_proof(program, witness); - let proof_vec = unsafe { - let mut pk_buf = Buffer::from_vec(&proving_key); + let mut pk_buf = Buffer::from_vec(&proving_key); + let proof_vec = unsafe { let result = pghr13_generate_proof( &mut pk_buf as *mut _, public_inputs_arr[0].as_ptr(), @@ -137,18 +131,17 @@ impl ProofSystem for PGHR13 { String::from_utf8(proof_vec).unwrap() } - fn export_solidity_verifier(&self, vk: String, abi_v2: bool) -> String { - let vk_map = parse_vk(vk); - let (mut template_text, solidity_pairing_lib) = if abi_v2 { - ( - String::from(CONTRACT_TEMPLATE_V2), - String::from(SOLIDITY_PAIRING_LIB_V2), - ) - } else { - ( + fn export_solidity_verifier(&self, vk: String, abi_version: AbiVersion) -> String { + let vk_map = parse_vk(vk).unwrap(); + let (mut template_text, solidity_pairing_lib) = match abi_version { + AbiVersion::V1 => ( String::from(CONTRACT_TEMPLATE), String::from(SOLIDITY_PAIRING_LIB), - ) + ), + AbiVersion::V2 => ( + String::from(CONTRACT_TEMPLATE_V2), + String::from(SOLIDITY_PAIRING_LIB_V2), + ), }; // replace things in template @@ -214,20 +207,27 @@ impl ProofSystem for PGHR13 { } fn verify(&self, vk: String, proof: String) -> bool { - let map = parse_vk(vk); + let map = parse_vk(vk).unwrap(); let vk_raw = hex::decode(map.get("vk.raw").unwrap()).unwrap(); - let proof: Proof = Proof::from_json(proof.as_str()); + let proof = Proof::::from_str(proof.as_str()); let proof_raw = hex::decode(proof.raw).unwrap(); - let public_inputs: Vec<&str> = proof.inputs.iter().map(|v| v.as_str()).collect(); + let public_inputs: Vec = proof + .inputs + .iter() + .map(|v| { + FieldPrime::try_from_str(v.as_str().trim_start_matches("0x"), 16) + .expect(format!("Invalid field value: {}", v.as_str()).as_str()) + }) + .collect(); let (public_inputs_arr, public_inputs_length) = prepare_public_inputs(public_inputs); - unsafe { - let mut vk_buffer = Buffer::from_vec(&vk_raw); - let mut proof_buffer = Buffer::from_vec(&proof_raw); + let mut vk_buffer = Buffer::from_vec(&vk_raw); + let mut proof_buffer = Buffer::from_vec(&proof_raw); + unsafe { let ans = pghr13_verify( &mut vk_buffer as *mut _, &mut proof_buffer as *mut _, diff --git a/zokrates_core/src/proof_system/bn128/utils/ffi.rs b/zokrates_core/src/proof_system/bn128/utils/ffi.rs index 1ccc201e..f16b6e90 100644 --- a/zokrates_core/src/proof_system/bn128/utils/ffi.rs +++ b/zokrates_core/src/proof_system/bn128/utils/ffi.rs @@ -20,7 +20,7 @@ extern "C" { } impl Buffer { - pub unsafe fn from_vec(v: &Vec) -> Buffer { + pub fn from_vec(v: &Vec) -> Buffer { let mut buf = vec![0; v.len()].into_boxed_slice(); buf.copy_from_slice(v.as_slice()); diff --git a/zokrates_core/src/proof_system/bn128/utils/libsnark.rs b/zokrates_core/src/proof_system/bn128/utils/libsnark.rs index e6ac4388..52be8110 100644 --- a/zokrates_core/src/proof_system/bn128/utils/libsnark.rs +++ b/zokrates_core/src/proof_system/bn128/utils/libsnark.rs @@ -2,7 +2,7 @@ use flat_absy::FlatVariable; use ir::{self, Statement}; use std::cmp::max; use std::collections::HashMap; -use zokrates_field::field::{Field, FieldPrime}; +use zokrates_field::field::Field; // utility function. Converts a Field's vector-based byte representation to fixed size array. fn vec_as_u8_32_array(vec: &Vec) -> [u8; 32] { @@ -14,14 +14,12 @@ fn vec_as_u8_32_array(vec: &Vec) -> [u8; 32] { array } -pub fn prepare_public_inputs(public_inputs: Vec<&str>) -> (Vec<[u8; 32]>, usize) { +pub fn prepare_public_inputs(public_inputs: Vec) -> (Vec<[u8; 32]>, usize) { let public_inputs_length = public_inputs.len(); let mut public_inputs_arr: Vec<[u8; 32]> = vec![[0u8; 32]; public_inputs_length]; for (index, value) in public_inputs.into_iter().enumerate() { - let field: FieldPrime = - FieldPrime::try_from_str(value.trim_start_matches("0x"), 16).unwrap(); - public_inputs_arr[index] = vec_as_u8_32_array(&field.into_byte_vector()); + public_inputs_arr[index] = vec_as_u8_32_array(&value.into_byte_vector()); } (public_inputs_arr, public_inputs_length) diff --git a/zokrates_core/src/proof_system/bn128/utils/parser.rs b/zokrates_core/src/proof_system/bn128/utils/parser.rs index ba393d4b..3ccad811 100644 --- a/zokrates_core/src/proof_system/bn128/utils/parser.rs +++ b/zokrates_core/src/proof_system/bn128/utils/parser.rs @@ -1,22 +1,21 @@ use std::collections::HashMap; -pub fn parse_vk(vk: String) -> HashMap { +pub fn parse_vk(vk: String) -> Result, csv::Error> { let mut reader = csv::ReaderBuilder::new() .delimiter(b'=') .has_headers(false) .trim(csv::Trim::All) - .from_reader(vk.as_bytes()); + .flexible(false) + .from_reader(vk.trim().as_bytes()); let mut map = HashMap::new(); let mut iterator = reader.deserialize::<(String, String)>(); while let Some(r) = iterator.next() { - if r.is_ok() { - let r = r.unwrap(); - map.insert(r.0, r.1); - } + let r = r?; + map.insert(r.0, r.1); } - map + Ok(map) } #[cfg(test)] @@ -24,20 +23,38 @@ mod tests { use proof_system::bn128::utils::parser::parse_vk; #[test] - fn parse_example() { - let example: &str = r#" + fn parse_valid_input() { + let example: String = r#" a = 1 b = 2 - "#; + "# + .to_string(); - let map = parse_vk(example.to_string()); + let map = parse_vk(example).unwrap(); assert_eq!("1", map.get("a").unwrap()); assert_eq!("2", map.get("b").unwrap()); } + #[test] + #[should_panic] + fn panic_on_invalid_delimiter() { + parse_vk("a , 1".to_string()).unwrap(); + } + + #[test] + #[should_panic] + fn panic_on_unequal_lengths() { + let example: String = r#" + a = 1 + b = 2 = 3 + "# + .to_string(); + parse_vk(example).unwrap(); + } + #[test] fn parse_empty() { - let map = parse_vk(String::new()); + let map = parse_vk(String::new()).unwrap(); assert!(map.is_empty()); } } diff --git a/zokrates_core/src/proof_system/mod.rs b/zokrates_core/src/proof_system/mod.rs index 2f2eb035..fd4e402b 100644 --- a/zokrates_core/src/proof_system/mod.rs +++ b/zokrates_core/src/proof_system/mod.rs @@ -24,6 +24,21 @@ impl SetupKeypair { } } +pub enum AbiVersion { + V1, + V2, +} + +impl AbiVersion { + pub fn from(v: &str) -> Result { + match v { + "v1" => Ok(AbiVersion::V1), + "v2" => Ok(AbiVersion::V2), + _ => Err("Invalid ABI version"), + } + } +} + pub trait ProofSystem { fn setup(&self, program: ir::Prog) -> SetupKeypair; @@ -34,7 +49,7 @@ pub trait ProofSystem { proving_key: Vec, ) -> String; - fn export_solidity_verifier(&self, vk: String, abi_v2: bool) -> String; + fn export_solidity_verifier(&self, vk: String, abi_version: AbiVersion) -> String; fn verify(&self, vk: String, proof: String) -> bool; } diff --git a/zokrates_core/src/semantics.rs b/zokrates_core/src/semantics.rs index 33a4fb11..6a86bbf0 100644 --- a/zokrates_core/src/semantics.rs +++ b/zokrates_core/src/semantics.rs @@ -795,7 +795,6 @@ impl<'ast> Checker<'ast> { module_id: &ModuleId, types: &TypeMap, ) -> Result, Vec> { - let pos = stat.pos(); match stat.value { @@ -3184,9 +3183,7 @@ mod tests { let foo_statements: Vec> = vec![Statement::Return( ExpressionList { - expressions: vec![ - Expression::FieldConstant(FieldPrime::from(1)).mock(), - ], + expressions: vec![Expression::FieldConstant(FieldPrime::from(1)).mock()], } .mock(), ) @@ -3197,20 +3194,36 @@ mod tests { statements: foo_statements, signature: UnresolvedSignature { inputs: vec![], - outputs: vec![ - UnresolvedType::FieldElement.mock(), - ], + outputs: vec![UnresolvedType::FieldElement.mock()], }, } .mock(); let main_statements: Vec> = vec![ - Statement::Declaration(absy::Variable::new("a", UnresolvedType::array(UnresolvedType::FieldElement.mock(), 1).mock()).mock()).mock(), - Statement::Definition(Assignee::Identifier("a".into()).mock(), Expression::InlineArray(vec![absy::SpreadOrExpression::Expression(Expression::FieldConstant(FieldPrime::from(0)).mock())]).mock()).mock(), + Statement::Declaration( + absy::Variable::new( + "a", + UnresolvedType::array(UnresolvedType::FieldElement.mock(), 1).mock(), + ) + .mock(), + ) + .mock(), + Statement::Definition( + Assignee::Identifier("a".into()).mock(), + Expression::InlineArray(vec![absy::SpreadOrExpression::Expression( + Expression::FieldConstant(FieldPrime::from(0)).mock(), + )]) + .mock(), + ) + .mock(), Statement::MultipleDefinition( - vec![ - Assignee::Select(box Assignee::Identifier("a").mock(), box RangeOrExpression::Expression(absy::Expression::FieldConstant(FieldPrime::from(0)).mock())).mock(), - ], + vec![Assignee::Select( + box Assignee::Identifier("a").mock(), + box RangeOrExpression::Expression( + absy::Expression::FieldConstant(FieldPrime::from(0)).mock(), + ), + ) + .mock()], Expression::FunctionCall("foo", vec![]).mock(), ) .mock(), @@ -3254,15 +3267,13 @@ mod tests { let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); assert_eq!( checker.check_module(&"main".into(), &mut state), - Err(vec![ - Error { - inner: ErrorInner { - pos: Some((Position::mock(), Position::mock())), - message: "Only assignment to identifiers is supported, found a[0]".into() - }, - module_id: "main".into() - } - ]) + Err(vec![Error { + inner: ErrorInner { + pos: Some((Position::mock(), Position::mock())), + message: "Only assignment to identifiers is supported, found a[0]".into() + }, + module_id: "main".into() + }]) ); } diff --git a/zokrates_js/index.d.ts b/zokrates_js/index.d.ts index 4661cbce..3426263f 100644 --- a/zokrates_js/index.d.ts +++ b/zokrates_js/index.d.ts @@ -20,13 +20,14 @@ declare module 'zokrates-js' { pk: Uint8Array, } + export type AbiVersion = "v1" | "v2"; export type ResolveCallback = (location: string, path: string) => ResolverResult; export interface ZoKratesProvider { compile(source: string, location: string, callback: ResolveCallback): CompilationArtifacts; setup(program: Uint8Array): SetupKeypair; computeWitness(artifacts: CompilationArtifacts, args: any[]): ComputationResult; - exportSolidityVerifier(verifyingKey: string, isAbiv2: boolean): string + exportSolidityVerifier(verifyingKey: string, abiVersion: AbiVersion): string; generateProof(program: Uint8Array, witness: string, provingKey: Uint8Array): string; } diff --git a/zokrates_js/index.js b/zokrates_js/index.js index e86bb7b9..c83a9b5c 100644 --- a/zokrates_js/index.js +++ b/zokrates_js/index.js @@ -49,8 +49,8 @@ const initialize = async () => { computeWitness: (artifacts, args) => { return zokrates.compute_witness(artifacts, JSON.stringify(Array.from(args))); }, - exportSolidityVerifier: (verifyingKey, isAbiv2) => { - return zokrates.export_solidity_verifier(verifyingKey, isAbiv2); + exportSolidityVerifier: (verifyingKey, abiVersion) => { + return zokrates.export_solidity_verifier(verifyingKey, abiVersion); }, generateProof: (program, witness, provingKey) => { return zokrates.generate_proof(program, witness, provingKey); diff --git a/zokrates_js/src/lib.rs b/zokrates_js/src/lib.rs index 241a6d8a..a085f23f 100644 --- a/zokrates_js/src/lib.rs +++ b/zokrates_js/src/lib.rs @@ -8,7 +8,7 @@ use zokrates_common::Resolver; use zokrates_core::compile::{compile as core_compile, CompilationArtifacts, CompileError}; use zokrates_core::imports::Error; use zokrates_core::ir; -use zokrates_core::proof_system::{self, ProofSystem}; +use zokrates_core::proof_system::{self, ProofSystem, AbiVersion}; use zokrates_core::typed_absy::abi::Abi; use zokrates_core::typed_absy::types::Signature; use zokrates_field::field::FieldPrime; @@ -162,10 +162,14 @@ pub fn setup(program: JsValue) -> Result { } #[wasm_bindgen] -pub fn export_solidity_verifier(vk: JsValue, is_abi_v2: JsValue) -> JsValue { +pub fn export_solidity_verifier(vk: JsValue, abi_version: JsValue) -> Result { + let abi_version = AbiVersion::from(abi_version.as_string().unwrap().as_str()) + .map_err(|err| JsValue::from_str(err))?; + let verifier = proof_system::G16 {} - .export_solidity_verifier(vk.as_string().unwrap(), is_abi_v2.as_bool().unwrap()); - JsValue::from_str(verifier.as_str()) + .export_solidity_verifier(vk.as_string().unwrap(), abi_version); + + Ok(JsValue::from_str(verifier.as_str())) } #[wasm_bindgen]