diff --git a/Cargo.lock b/Cargo.lock index ebc143d8..83adf1bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,6 +80,12 @@ dependencies = [ "libc", ] +[[package]] +name = "base64" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5ca2cd0adc3f48f9e9ea5a6bbdf9ccc0bfade884847e484d452414c7ccffb3" + [[package]] name = "bellman_ce" version = "0.3.1" @@ -384,21 +390,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "curl-sys" -version = "0.4.30+curl-7.69.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923b38e423a8f47a4058e96f2a1fa2865a6231097ee860debd678d244277d50c" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "winapi", -] - [[package]] name = "difference" version = "1.0.0" @@ -559,9 +550,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.8.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7339329bfa14a00223244311560d11f8f489b453fb90092af97f267a6090ab0" +checksum = "ef222034f2069cfc5af01ce423574d3d9a3925bd4052912a14e5bcfd7ca9e47a" dependencies = [ "bitflags", "libc", @@ -607,9 +598,9 @@ checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" [[package]] name = "idna" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" dependencies = [ "matches", "unicode-bidi", @@ -663,12 +654,11 @@ checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" [[package]] name = "libgit2-sys" -version = "0.7.11" +version = "0.12.2+1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48441cb35dc255da8ae72825689a95368bf510659ae1ad55dc4aa88cb1789bf1" +checksum = "a12c878ccc1a49ff71e264233a66d2114cdcc7fdc44c0ebe2b54075240831238" dependencies = [ "cc", - "curl-sys", "libc", "libssh2-sys", "libz-sys", @@ -870,9 +860,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "1.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pest" @@ -1439,9 +1429,9 @@ checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "url" -version = "1.7.2" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" dependencies = [ "idna", "matches", @@ -1664,6 +1654,7 @@ name = "zokrates_core" version = "0.4.2" dependencies = [ "assert_cli", + "base64", "bellman_ce 0.3.1 (git+https://github.com/matter-labs/bellman?rev=9e35737)", "bincode", "cc", diff --git a/zokrates_cli/src/bin.rs b/zokrates_cli/src/bin.rs index e113f4e7..12959cae 100644 --- a/zokrates_cli/src/bin.rs +++ b/zokrates_cli/src/bin.rs @@ -687,7 +687,13 @@ fn cli() -> Result<(), String> { .map_err(|why| format!("couldn't read {}: {}", proof_path.display(), why))?; println!("Performing verification..."); - println!("Verified: {}", scheme.verify(vk, proof)); + println!( + "The verification result is: {}", + match scheme.verify(vk, proof) { + true => "PASS", + false => "FAIL", + } + ); } _ => unreachable!(), } diff --git a/zokrates_core/Cargo.toml b/zokrates_core/Cargo.toml index 528aaae1..34cdbf49 100644 --- a/zokrates_core/Cargo.toml +++ b/zokrates_core/Cargo.toml @@ -7,7 +7,7 @@ readme = "README.md" build = "build.rs" [features] -default = [] +default = ["libsnark"] libsnark = ["cc", "cmake", "git2"] wasm = ["bellman_ce/wasm", "zokrates_embed/wasm"] multicore = ["bellman_ce/multicore"] @@ -25,6 +25,7 @@ serde_json = "1.0" serde_bytes = "0.10" bincode = "0.8.0" hex = "0.4.2" +base64 = "0.12.0" regex = "0.2" pairing_ce = "0.18" ff_ce = "0.7" @@ -44,4 +45,4 @@ wasm-bindgen-test = "0.3.0" [build-dependencies] cc = { version = "1.0", features = ["parallel"], optional = true } cmake = { version = "0.1.31", optional = true } -git2 = { version = "0.8.0", optional = true } \ No newline at end of file +git2 = { version = "0.13.1", optional = true } \ No newline at end of file diff --git a/zokrates_core/lib/ffi.cpp b/zokrates_core/lib/ffi.cpp index 2ff535aa..3ea355bb 100644 --- a/zokrates_core/lib/ffi.cpp +++ b/zokrates_core/lib/ffi.cpp @@ -1,5 +1,6 @@ #include "ffi.hpp" -void __free(uint8_t* ptr) { - free(ptr); +void __free(uint8_t* ptr) +{ + free(ptr); } \ No newline at end of file diff --git a/zokrates_core/lib/ffi.hpp b/zokrates_core/lib/ffi.hpp index 50a33264..98335cc7 100644 --- a/zokrates_core/lib/ffi.hpp +++ b/zokrates_core/lib/ffi.hpp @@ -1,26 +1,33 @@ #pragma once -#include #include +#include #ifdef __cplusplus extern "C" { #endif struct buffer_t { - uint8_t* data; - int32_t length; + uint8_t* data; + int32_t length; }; struct setup_result_t { buffer_t vk; buffer_t pk; - setup_result_t(buffer_t& vk_buf, buffer_t& pk_buf) : vk(vk_buf), pk(pk_buf) { } + setup_result_t(buffer_t& vk_buf, buffer_t& pk_buf) + : vk(vk_buf) + , pk(pk_buf) + { + } }; struct proof_result_t { buffer_t proof; - proof_result_t(buffer_t& proof_buf) : proof(proof_buf) { } + proof_result_t(buffer_t& proof_buf) + : proof(proof_buf) + { + } }; void __free(uint8_t* ptr); @@ -29,7 +36,8 @@ void __free(uint8_t* ptr); } // extern "C" #endif -static inline void __alloc(buffer_t* buffer, size_t length) { +static inline void make_buffer(buffer_t* buffer, size_t length) +{ buffer->data = (uint8_t*)malloc(length); buffer->length = length; } \ No newline at end of file diff --git a/zokrates_core/lib/gm17.cpp b/zokrates_core/lib/gm17.cpp index c364f6fd..f6f44797 100644 --- a/zokrates_core/lib/gm17.cpp +++ b/zokrates_core/lib/gm17.cpp @@ -5,11 +5,12 @@ * @date 2017 */ -#include "util.hpp" #include "gm17.hpp" +#include "util.hpp" #include -#include +#include #include +#include // contains definition of alt_bn128 ec public parameters #include "libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp" @@ -23,111 +24,125 @@ using namespace libsnark; using std::cout; using std::endl; -namespace gm17 +namespace gm17 { +r1cs_se_ppzksnark_constraint_system createConstraintSystem(const uint8_t* a, const uint8_t* b, const uint8_t* c, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs) { - r1cs_se_ppzksnark_constraint_system createConstraintSystem(const uint8_t* a, const uint8_t* b, const uint8_t* c, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs) - { - r1cs_se_ppzksnark_constraint_system cs; - cs.primary_input_size = inputs; - cs.auxiliary_input_size = variables - inputs - 1; // ~one not included + r1cs_se_ppzksnark_constraint_system cs; + cs.primary_input_size = inputs; + cs.auxiliary_input_size = variables - inputs - 1; // ~one not included - cout << "num variables: " << variables < > lin_comb_A, lin_comb_B, lin_comb_C; - while (a_id < a_len && a_vvmap[a_id].constraint_id == row) { - libff::bigint value = libsnarkBigintFromBytes(a_vvmap[a_id].variable_value); - if (!value.is_zero()) { - lin_comb_A.add_term(a_vvmap[a_id].variable_id, value); - } - a_id++; + for (int row = 0; row < constraints; row++) { + linear_combination> lin_comb_a, lin_comb_b, lin_comb_c; + while (a_id < a_len && a_vvmap[a_id].constraint_id == row) { + libff::bigint value = libsnarkBigintFromBytes(a_vvmap[a_id].variable_value); + if (!value.is_zero()) { + lin_comb_a.add_term(a_vvmap[a_id].variable_id, value); } - while (b_id < b_len && b_vvmap[b_id].constraint_id == row) { - libff::bigint value = libsnarkBigintFromBytes(b_vvmap[b_id].variable_value); - if (!value.is_zero()) { - lin_comb_B.add_term(b_vvmap[b_id].variable_id, value); - } - b_id++; - } - while (c_id < c_len && c_vvmap[c_id].constraint_id == row) { - libff::bigint value = libsnarkBigintFromBytes(c_vvmap[c_id].variable_value); - if (!value.is_zero()) { - lin_comb_C.add_term(c_vvmap[c_id].variable_id, value); - } - c_id++; - } - cs.add_constraint(r1cs_constraint >(lin_comb_A, lin_comb_B, lin_comb_C)); + a_id++; } - return cs; - } - - r1cs_se_ppzksnark_keypair generateKeypair(const r1cs_se_ppzksnark_constraint_system &cs) { - return r1cs_se_ppzksnark_generator(cs); //from r1cs_se_ppzksnark.hpp - } - - std::string serializeVerificationKey(r1cs_se_ppzksnark_verification_key* vk) - { - std::stringstream ss; - unsigned queryLength = vk->query.size(); - - ss << "vk.h = " << outputPointG2AffineAsHex(vk->H) << endl; - ss << "vk.g_alpha = " << outputPointG1AffineAsHex(vk->G_alpha) << endl; - ss << "vk.h_beta = " << outputPointG2AffineAsHex(vk->H_beta) << endl; - ss << "vk.g_gamma = " << outputPointG1AffineAsHex(vk->G_gamma) << endl; - ss << "vk.h_gamma = " << outputPointG2AffineAsHex(vk->H_gamma) << endl; - ss << "vk.query.len() = " << queryLength << endl; - for (size_t i = 0; i < queryLength; ++i) - { - auto vk_query_i = outputPointG1AffineAsHex(vk->query[i]); - ss << "vk.query[" << i << "] = " << vk_query_i << endl; - } - return ss.str(); - } - - std::string serializeProof(r1cs_se_ppzksnark_proof* proof, const uint8_t* public_inputs, int32_t public_inputs_length) - { - std::stringstream ss; - ss << "{" << "\n"; - ss << "\t\"proof\": {" << "\n"; - ss << "\t\t\"a\": " << outputPointG1AffineAsHexJson(proof->A) << ",\n"; - ss << "\t\t\"b\": " << outputPointG2AffineAsHexJson(proof->B) << ",\n"; - ss << "\t\t\"c\": " << outputPointG1AffineAsHexJson(proof->C) << "\n"; - ss << "\t}," << "\n"; - ss << "\t\"inputs\": " << "["; - for (int i = 1; i < public_inputs_length; i++) { - if (i != 1) { - ss << ","; + while (b_id < b_len && b_vvmap[b_id].constraint_id == row) { + libff::bigint value = libsnarkBigintFromBytes(b_vvmap[b_id].variable_value); + if (!value.is_zero()) { + lin_comb_b.add_term(b_vvmap[b_id].variable_id, value); } - ss << outputInputAsHex(libsnarkBigintFromBytes(public_inputs + i * 32)); + b_id++; } - ss << "]" << "\n"; - ss << "}" << "\n"; - std::string str = ss.str(); - return str; + while (c_id < c_len && c_vvmap[c_id].constraint_id == row) { + libff::bigint value = libsnarkBigintFromBytes(c_vvmap[c_id].variable_value); + if (!value.is_zero()) { + lin_comb_c.add_term(c_vvmap[c_id].variable_id, value); + } + c_id++; + } + cs.add_constraint(r1cs_constraint>(lin_comb_a, lin_comb_b, lin_comb_c)); } + return cs; } -setup_result_t gm17_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs) +r1cs_se_ppzksnark_keypair generateKeypair(const r1cs_se_ppzksnark_constraint_system& cs) +{ + return r1cs_se_ppzksnark_generator(cs); //from r1cs_se_ppzksnark.hpp +} + +std::string serializeVerificationKey(r1cs_se_ppzksnark_verification_key* vk, bool include_raw) +{ + std::stringstream ss; + unsigned queryLength = vk->query.size(); + + ss << "vk.h=" << outputPointG2AffineAsHex(vk->H) << endl; + ss << "vk.g_alpha=" << outputPointG1AffineAsHex(vk->G_alpha) << endl; + ss << "vk.h_beta=" << outputPointG2AffineAsHex(vk->H_beta) << endl; + ss << "vk.g_gamma=" << outputPointG1AffineAsHex(vk->G_gamma) << endl; + ss << "vk.h_gamma=" << outputPointG2AffineAsHex(vk->H_gamma) << endl; + ss << "vk.query.len()=" << queryLength << endl; + for (size_t i = 0; i < queryLength; ++i) { + auto vk_query_i = outputPointG1AffineAsHex(vk->query[i]); + ss << "vk.query[" << i << "]=" << vk_query_i << endl; + } + if (include_raw) { + std::stringstream ss_; + ss_ << *vk; + ss << "vk.raw=" << toHex(ss_.str()) << endl; + } + std::string str = ss.str(); + return str; +} + +std::string serializeProof(r1cs_se_ppzksnark_proof* proof, const uint8_t* public_inputs, int32_t public_inputs_length, bool include_raw) +{ + std::stringstream ss; + ss << "{" + << "\n"; + ss << "\t\"proof\": {" + << "\n"; + ss << "\t\t\"a\": " << outputPointG1AffineAsHexJson(proof->A) << ",\n"; + ss << "\t\t\"b\": " << outputPointG2AffineAsHexJson(proof->B) << ",\n"; + ss << "\t\t\"c\": " << outputPointG1AffineAsHexJson(proof->C) << "\n"; + ss << "\t}," + << "\n"; + ss << "\t\"inputs\": " + << "["; + for (int i = 1; i < public_inputs_length; i++) { + if (i != 1) { + ss << ","; + } + ss << outputInputAsHex(libsnarkBigintFromBytes(public_inputs + i * 32)); + } + ss << "]"; + if (include_raw) { + std::stringstream ss_; + ss_ << *proof; + ss << ",\n\t\"raw\": \"" << toHex(ss_.str()) << "\""; + } + ss << "\n}" + << "\n"; + std::string str = ss.str(); + return str; +} +} + +setup_result_t gm17_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs, bool include_raw) { libff::inhibit_profiling_info = true; libff::inhibit_profiling_counters = true; @@ -142,37 +157,25 @@ setup_result_t gm17_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, // create keypair auto keypair = r1cs_se_ppzksnark_generator(cs); - auto vk = gm17::serializeVerificationKey(&keypair.vk); + auto vk = gm17::serializeVerificationKey(&keypair.vk, include_raw); - std::stringstream ss; - ss << keypair.pk; - - std::string pk = ss.str(); - - buffer_t vk_buf, pk_buf; - __alloc(&vk_buf, vk.size()); - __alloc(&pk_buf, pk.size()); - - vk.copy(reinterpret_cast(vk_buf.data), vk_buf.length); - pk.copy(reinterpret_cast(pk_buf.data), pk_buf.length); + buffer_t vk_buf = create_buffer(vk); + buffer_t pk_buf = create_buffer(keypair.pk); setup_result_t result(vk_buf, pk_buf); return result; } -proof_result_t gm17_generate_proof(buffer_t* pk_buf, const uint8_t* public_inputs, int32_t public_inputs_length, const uint8_t* private_inputs, int32_t private_inputs_length) +proof_result_t gm17_generate_proof(buffer_t* pk_buf, const uint8_t* public_inputs, int32_t public_inputs_length, const uint8_t* private_inputs, int32_t private_inputs_length, bool include_raw) { libff::inhibit_profiling_info = true; libff::inhibit_profiling_counters = true; //initialize curve parameters libff::alt_bn128_pp::init_public_params(); - r1cs_se_ppzksnark_proving_key proving_key; - std::stringstream ss; - ss.write(reinterpret_cast(pk_buf->data), pk_buf->length); - ss.rdbuf()->pubseekpos(0, std::ios_base::in); - ss >> proving_key; + r1cs_se_ppzksnark_proving_key proving_key; + from_buffer>(pk_buf, proving_key); // assign variables based on witness values, excludes ~one r1cs_variable_assignment> full_variable_assignment; @@ -195,12 +198,31 @@ proof_result_t gm17_generate_proof(buffer_t* pk_buf, const uint8_t* public_input // Proof Generation auto proof = r1cs_se_ppzksnark_prover(proving_key, primary_input, auxiliary_input); - auto proof_json = gm17::serializeProof(&proof, public_inputs, public_inputs_length); + auto proof_json = gm17::serializeProof(&proof, public_inputs, public_inputs_length, include_raw); - buffer_t proof_buf; - __alloc(&proof_buf, proof_json.size()); - - proof_json.copy(reinterpret_cast(proof_buf.data), proof_buf.length); + buffer_t proof_buf = create_buffer(proof_json); proof_result_t result(proof_buf); return result; +} + +bool gm17_verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length) +{ + libff::inhibit_profiling_info = true; + libff::inhibit_profiling_counters = true; + + // initialize curve parameters + libff::alt_bn128_pp::init_public_params(); + + r1cs_se_ppzksnark_verification_key vk; + r1cs_se_ppzksnark_proof proof; + + from_buffer>(vk_buf, vk); + from_buffer>(proof_buf, proof); + + r1cs_primary_input> primary_input; + for (int i = 0; i < public_inputs_length; i++) { + primary_input.push_back(libff::Fr(libsnarkBigintFromBytes(public_inputs + i * 32))); + } + + return r1cs_se_ppzksnark_verifier_strong_IC(vk, primary_input, proof); } \ No newline at end of file diff --git a/zokrates_core/lib/gm17.hpp b/zokrates_core/lib/gm17.hpp index adafa63d..10a6cbd7 100644 --- a/zokrates_core/lib/gm17.hpp +++ b/zokrates_core/lib/gm17.hpp @@ -22,16 +22,22 @@ setup_result_t gm17_setup( int32_t c_len, int32_t constraints, int32_t variables, - int32_t inputs -); + int32_t inputs, + bool include_raw); proof_result_t gm17_generate_proof( buffer_t* pk_buf, const uint8_t* public_inputs, int32_t public_inputs_length, const uint8_t* private_inputs, - int32_t private_inputs_length -); + int32_t private_inputs_length, + bool include_raw); + +bool gm17_verify( + buffer_t* vk_buf, + buffer_t* proof_buf, + const uint8_t* public_inputs, + int32_t public_inputs_length); #ifdef __cplusplus } // extern "C" diff --git a/zokrates_core/lib/pghr13.cpp b/zokrates_core/lib/pghr13.cpp index 5633442b..673fc434 100644 --- a/zokrates_core/lib/pghr13.cpp +++ b/zokrates_core/lib/pghr13.cpp @@ -5,11 +5,11 @@ * @date 2017 */ -#include "util.hpp" #include "pghr13.hpp" +#include "util.hpp" #include -#include #include +#include // contains definitions of alt_bn128 ec public parameters #include "libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp" @@ -23,119 +23,133 @@ using namespace libsnark; using std::cout; using std::endl; -namespace pghr13 +namespace pghr13 { +r1cs_ppzksnark_constraint_system createConstraintSystem(const uint8_t* a, const uint8_t* b, const uint8_t* c, int a_len, int b_len, int c_len, int constraints, int variables, int inputs) { - r1cs_ppzksnark_constraint_system createConstraintSystem(const uint8_t* a, const uint8_t* b, const uint8_t* c, int a_len, int b_len, int c_len, int constraints, int variables, int inputs) - { - r1cs_ppzksnark_constraint_system cs; - cs.primary_input_size = inputs; - cs.auxiliary_input_size = variables - inputs - 1; // ~one not included + r1cs_ppzksnark_constraint_system cs; + cs.primary_input_size = inputs; + cs.auxiliary_input_size = variables - inputs - 1; // ~one not included - cout << "num variables: " << variables <> lin_comb_a, lin_comb_b, lin_comb_c; - while (a_id < a_len && a_vvmap[a_id].constraint_id == row) { - libff::bigint value = libsnarkBigintFromBytes(a_vvmap[a_id].variable_value); - if (!value.is_zero()) { - lin_comb_a.add_term(a_vvmap[a_id].variable_id, value); - } - a_id++; + for (int row = 0; row < constraints; row++) { + linear_combination> lin_comb_a, lin_comb_b, lin_comb_c; + while (a_id < a_len && a_vvmap[a_id].constraint_id == row) { + libff::bigint value = libsnarkBigintFromBytes(a_vvmap[a_id].variable_value); + if (!value.is_zero()) { + lin_comb_a.add_term(a_vvmap[a_id].variable_id, value); } - while (b_id < b_len && b_vvmap[b_id].constraint_id == row) { - libff::bigint value = libsnarkBigintFromBytes(b_vvmap[b_id].variable_value); - if (!value.is_zero()) { - lin_comb_b.add_term(b_vvmap[b_id].variable_id, value); - } - b_id++; - } - while (c_id < c_len && c_vvmap[c_id].constraint_id == row) { - libff::bigint value = libsnarkBigintFromBytes(c_vvmap[c_id].variable_value); - if (!value.is_zero()) { - lin_comb_c.add_term(c_vvmap[c_id].variable_id, value); - } - c_id++; - } - cs.add_constraint(r1cs_constraint>(lin_comb_a, lin_comb_b, lin_comb_c)); + a_id++; } - return cs; - } - - r1cs_ppzksnark_keypair generateKeypair(const r1cs_ppzksnark_constraint_system &cs) { - return r1cs_ppzksnark_generator(cs); // from r1cs_ppzksnark.hpp - } - - std::string serializeVerificationKey(r1cs_ppzksnark_verification_key* vk) - { - std::stringstream ss; - unsigned icLength = vk->encoded_IC_query.rest.indices.size() + 1; - - ss << "vk.a = " << outputPointG2AffineAsHex(vk->alphaA_g2) << endl; - ss << "vk.b = " << outputPointG1AffineAsHex(vk->alphaB_g1) << endl; - ss << "vk.c = " << outputPointG2AffineAsHex(vk->alphaC_g2) << endl; - ss << "vk.gamma = " << outputPointG2AffineAsHex(vk->gamma_g2) << endl; - ss << "vk.gamma_beta_1 = " << outputPointG1AffineAsHex(vk->gamma_beta_g1) << endl; - ss << "vk.gamma_beta_2 = " << outputPointG2AffineAsHex(vk->gamma_beta_g2) << endl; - ss << "vk.z = " << outputPointG2AffineAsHex(vk->rC_Z_g2) << endl; - ss << "vk.ic.len() = " << icLength << endl; - ss << "vk.ic[0] = " << outputPointG1AffineAsHex(vk->encoded_IC_query.first) << endl; - for (size_t i = 1; i < icLength; ++i) - { - auto vk_ic_i = outputPointG1AffineAsHex(vk->encoded_IC_query.rest.values[i - 1]); - ss << "vk.ic[" << i << "] = " << vk_ic_i << endl; - } - std::string str = ss.str(); - return str; - } - - std::string serializeProof(r1cs_ppzksnark_proof* proof, const uint8_t* public_inputs, int public_inputs_length) - { - std::stringstream ss; - ss << "{" << "\n"; - ss << "\t\"proof\": {" << "\n"; - ss << "\t\t\"a\": " << outputPointG1AffineAsHexJson(proof->g_A.g) << ",\n"; - ss << "\t\t\"a_p\": " << outputPointG1AffineAsHexJson(proof->g_A.h) << ",\n"; - ss << "\t\t\"b\": " << outputPointG2AffineAsHexJson(proof->g_B.g) << ",\n"; - ss << "\t\t\"b_p\": " << outputPointG1AffineAsHexJson(proof->g_B.h) << ",\n"; - ss << "\t\t\"c\": " << outputPointG1AffineAsHexJson(proof->g_C.g) << ",\n"; - ss << "\t\t\"c_p\": " << outputPointG1AffineAsHexJson(proof->g_C.h) << ",\n"; - ss << "\t\t\"h\": " << outputPointG1AffineAsHexJson(proof->g_H) << ",\n"; - ss << "\t\t\"k\": " << outputPointG1AffineAsHexJson(proof->g_K) << "\n"; - ss << "\t}," << "\n"; - ss << "\t\"inputs\": " << "["; - for (int i = 1; i < public_inputs_length; i++) { - if (i != 1) { - ss << ","; + while (b_id < b_len && b_vvmap[b_id].constraint_id == row) { + libff::bigint value = libsnarkBigintFromBytes(b_vvmap[b_id].variable_value); + if (!value.is_zero()) { + lin_comb_b.add_term(b_vvmap[b_id].variable_id, value); } - ss << outputInputAsHex(libsnarkBigintFromBytes(public_inputs + i * 32)); + b_id++; } - ss << "]" << "\n"; - ss << "}" << "\n"; - std::string str = ss.str(); - return str; + while (c_id < c_len && c_vvmap[c_id].constraint_id == row) { + libff::bigint value = libsnarkBigintFromBytes(c_vvmap[c_id].variable_value); + if (!value.is_zero()) { + lin_comb_c.add_term(c_vvmap[c_id].variable_id, value); + } + c_id++; + } + cs.add_constraint(r1cs_constraint>(lin_comb_a, lin_comb_b, lin_comb_c)); } + return cs; } -setup_result_t pghr13_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs) +r1cs_ppzksnark_keypair generateKeypair(const r1cs_ppzksnark_constraint_system& cs) +{ + return r1cs_ppzksnark_generator(cs); // from r1cs_ppzksnark.hpp +} + +std::string serializeVerificationKey(r1cs_ppzksnark_verification_key* vk, bool include_raw) +{ + std::stringstream ss; + unsigned icLength = vk->encoded_IC_query.rest.indices.size() + 1; + + ss << "vk.a=" << outputPointG2AffineAsHex(vk->alphaA_g2) << endl; + ss << "vk.b=" << outputPointG1AffineAsHex(vk->alphaB_g1) << endl; + ss << "vk.c=" << outputPointG2AffineAsHex(vk->alphaC_g2) << endl; + ss << "vk.gamma=" << outputPointG2AffineAsHex(vk->gamma_g2) << endl; + ss << "vk.gamma_beta_1=" << outputPointG1AffineAsHex(vk->gamma_beta_g1) << endl; + ss << "vk.gamma_beta_2=" << outputPointG2AffineAsHex(vk->gamma_beta_g2) << endl; + ss << "vk.z=" << outputPointG2AffineAsHex(vk->rC_Z_g2) << endl; + ss << "vk.ic.len()=" << icLength << endl; + ss << "vk.ic[0]=" << outputPointG1AffineAsHex(vk->encoded_IC_query.first) << endl; + for (size_t i = 1; i < icLength; ++i) { + auto vk_ic_i = outputPointG1AffineAsHex(vk->encoded_IC_query.rest.values[i - 1]); + ss << "vk.ic[" << i << "]=" << vk_ic_i << endl; + } + if (include_raw) { + std::stringstream ss_; + ss_ << *vk; + ss << "vk.raw=" << toHex(ss_.str()) << endl; + } + std::string str = ss.str(); + return str; +} + +std::string serializeProof(r1cs_ppzksnark_proof* proof, const uint8_t* public_inputs, int public_inputs_length, bool include_raw) +{ + std::stringstream ss; + ss << "{" + << "\n"; + ss << "\t\"proof\": {" + << "\n"; + ss << "\t\t\"a\": " << outputPointG1AffineAsHexJson(proof->g_A.g) << ",\n"; + ss << "\t\t\"a_p\": " << outputPointG1AffineAsHexJson(proof->g_A.h) << ",\n"; + ss << "\t\t\"b\": " << outputPointG2AffineAsHexJson(proof->g_B.g) << ",\n"; + ss << "\t\t\"b_p\": " << outputPointG1AffineAsHexJson(proof->g_B.h) << ",\n"; + ss << "\t\t\"c\": " << outputPointG1AffineAsHexJson(proof->g_C.g) << ",\n"; + ss << "\t\t\"c_p\": " << outputPointG1AffineAsHexJson(proof->g_C.h) << ",\n"; + ss << "\t\t\"h\": " << outputPointG1AffineAsHexJson(proof->g_H) << ",\n"; + ss << "\t\t\"k\": " << outputPointG1AffineAsHexJson(proof->g_K) << "\n"; + ss << "\t}," + << "\n"; + ss << "\t\"inputs\": " + << "["; + for (int i = 1; i < public_inputs_length; i++) { + if (i != 1) { + ss << ","; + } + ss << outputInputAsHex(libsnarkBigintFromBytes(public_inputs + i * 32)); + } + ss << "]"; + if (include_raw) { + std::stringstream ss_; + ss_ << *proof; + ss << ",\n\t\"raw\": \"" << toHex(ss_.str()) << "\""; + } + ss << "\n}" + << "\n"; + std::string str = ss.str(); + return str; +} +} + +setup_result_t pghr13_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs, bool include_raw) { libff::inhibit_profiling_info = true; libff::inhibit_profiling_counters = true; @@ -151,37 +165,25 @@ setup_result_t pghr13_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C // create keypair auto keypair = r1cs_ppzksnark_generator(cs); - auto vk = pghr13::serializeVerificationKey(&keypair.vk); + auto vk = pghr13::serializeVerificationKey(&keypair.vk, include_raw); - std::stringstream ss; - ss << keypair.pk; - - std::string pk = ss.str(); - - buffer_t vk_buf, pk_buf; - __alloc(&vk_buf, vk.size()); - __alloc(&pk_buf, pk.size()); - - vk.copy(reinterpret_cast(vk_buf.data), vk_buf.length); - pk.copy(reinterpret_cast(pk_buf.data), pk_buf.length); + buffer_t vk_buf = create_buffer(vk); + buffer_t pk_buf = create_buffer(keypair.pk); setup_result_t result(vk_buf, pk_buf); return result; } -proof_result_t pghr13_generate_proof(buffer_t* pk_buf, const uint8_t* public_inputs, int32_t public_inputs_length, const uint8_t* private_inputs, int32_t private_inputs_length) +proof_result_t pghr13_generate_proof(buffer_t* pk_buf, const uint8_t* public_inputs, int32_t public_inputs_length, const uint8_t* private_inputs, int32_t private_inputs_length, bool include_raw) { libff::inhibit_profiling_info = true; libff::inhibit_profiling_counters = true; // initialize curve parameters libff::alt_bn128_pp::init_public_params(); - r1cs_ppzksnark_proving_key proving_key; - std::stringstream ss; - ss.write(reinterpret_cast(pk_buf->data), pk_buf->length); - ss.rdbuf()->pubseekpos(0, std::ios_base::in); - ss >> proving_key; + r1cs_ppzksnark_proving_key proving_key; + from_buffer>(pk_buf, proving_key); // assign variables based on witness values, excludes ~one r1cs_variable_assignment> full_variable_assignment; @@ -204,12 +206,31 @@ proof_result_t pghr13_generate_proof(buffer_t* pk_buf, const uint8_t* public_inp // Proof Generation auto proof = r1cs_ppzksnark_prover(proving_key, primary_input, auxiliary_input); - auto proof_json = pghr13::serializeProof(&proof, public_inputs, public_inputs_length); + auto proof_json = pghr13::serializeProof(&proof, public_inputs, public_inputs_length, include_raw); - buffer_t proof_buf; - __alloc(&proof_buf, proof_json.size()); - - proof_json.copy(reinterpret_cast(proof_buf.data), proof_buf.length); + buffer_t proof_buf = create_buffer(proof_json); proof_result_t result(proof_buf); return result; } + +bool pghr13_verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length) +{ + libff::inhibit_profiling_info = true; + libff::inhibit_profiling_counters = true; + + // initialize curve parameters + libff::alt_bn128_pp::init_public_params(); + + r1cs_ppzksnark_verification_key vk; + r1cs_ppzksnark_proof proof; + + from_buffer>(vk_buf, vk); + from_buffer>(proof_buf, proof); + + r1cs_primary_input> primary_input; + for (int i = 0; i < public_inputs_length; i++) { + primary_input.push_back(libff::Fr(libsnarkBigintFromBytes(public_inputs + i * 32))); + } + + return r1cs_ppzksnark_verifier_strong_IC(vk, primary_input, proof); +} diff --git a/zokrates_core/lib/pghr13.hpp b/zokrates_core/lib/pghr13.hpp index 4457a2f8..20960888 100644 --- a/zokrates_core/lib/pghr13.hpp +++ b/zokrates_core/lib/pghr13.hpp @@ -22,16 +22,22 @@ setup_result_t pghr13_setup( int32_t c_len, int32_t constraints, int32_t variables, - int32_t inputs -); + int32_t inputs, + bool include_raw); proof_result_t pghr13_generate_proof( buffer_t* pk_buf, const uint8_t* public_inputs, int32_t public_inputs_length, const uint8_t* private_inputs, - int32_t private_inputs_length -); + int32_t private_inputs_length, + bool include_raw); + +bool pghr13_verify( + buffer_t* vk_buf, + buffer_t* proof_buf, + const uint8_t* public_inputs, + int32_t public_inputs_length); #ifdef __cplusplus } // extern "C" diff --git a/zokrates_core/lib/util.cpp b/zokrates_core/lib/util.cpp index 5ab8b30c..aea546da 100644 --- a/zokrates_core/lib/util.cpp +++ b/zokrates_core/lib/util.cpp @@ -16,10 +16,21 @@ libff::bigint libsnarkBigintFromBytes(const uint8_t* _ x.data[3 - i] |= uint64_t(_x[i * 8 + j]) << (8 * (7 - j)); } } - return x; } +std::string toHex(const std::string& in) +{ + std::ostringstream out; + out << std::setfill('0'); + + for (unsigned char const& c : in) { + out << std::hex << std::setw(2) << static_cast(c); + } + + return out.str(); +} + std::string HexStringFromLibsnarkBigint(libff::bigint _x) { uint8_t x[32]; @@ -28,15 +39,12 @@ std::string HexStringFromLibsnarkBigint(libff::bigint x[i * 8 + j] = uint8_t(uint64_t(_x.data[3 - i]) >> (8 * (7 - j))); } } - std::stringstream ss; - ss << std::setfill('0'); - for (unsigned i = 0; i < 32; i++) { - ss << std::hex << std::setw(2) << (int)x[i]; - } - return ss.str(); + std::string tmp((char*)x, 32); + return toHex(tmp); } -std::string outputInputAsHex(libff::bigint _x) { +std::string outputInputAsHex(libff::bigint _x) +{ return "\"0x" + HexStringFromLibsnarkBigint(_x) + "\""; } @@ -44,38 +52,26 @@ std::string outputPointG1AffineAsHex(libff::alt_bn128_G1 _p) { libff::alt_bn128_G1 aff = _p; aff.to_affine_coordinates(); - return "0x" + - HexStringFromLibsnarkBigint(aff.X.as_bigint()) + ", 0x" + - HexStringFromLibsnarkBigint(aff.Y.as_bigint()); + return "0x" + HexStringFromLibsnarkBigint(aff.X.as_bigint()) + ", 0x" + HexStringFromLibsnarkBigint(aff.Y.as_bigint()); } std::string outputPointG1AffineAsHexJson(libff::alt_bn128_G1 _p) { libff::alt_bn128_G1 aff = _p; aff.to_affine_coordinates(); - return "[\"0x" + - HexStringFromLibsnarkBigint(aff.X.as_bigint()) + "\", \"0x" + - HexStringFromLibsnarkBigint(aff.Y.as_bigint())+"\"]"; + return "[\"0x" + HexStringFromLibsnarkBigint(aff.X.as_bigint()) + "\", \"0x" + HexStringFromLibsnarkBigint(aff.Y.as_bigint()) + "\"]"; } std::string outputPointG2AffineAsHex(libff::alt_bn128_G2 _p) { libff::alt_bn128_G2 aff = _p; aff.to_affine_coordinates(); - return "[0x" + - HexStringFromLibsnarkBigint(aff.X.c1.as_bigint()) + ", 0x" + - HexStringFromLibsnarkBigint(aff.X.c0.as_bigint()) + "], [0x" + - HexStringFromLibsnarkBigint(aff.Y.c1.as_bigint()) + ", 0x" + - HexStringFromLibsnarkBigint(aff.Y.c0.as_bigint()) + "]"; + return "[0x" + HexStringFromLibsnarkBigint(aff.X.c1.as_bigint()) + ", 0x" + HexStringFromLibsnarkBigint(aff.X.c0.as_bigint()) + "], [0x" + HexStringFromLibsnarkBigint(aff.Y.c1.as_bigint()) + ", 0x" + HexStringFromLibsnarkBigint(aff.Y.c0.as_bigint()) + "]"; } std::string outputPointG2AffineAsHexJson(libff::alt_bn128_G2 _p) { libff::alt_bn128_G2 aff = _p; aff.to_affine_coordinates(); - return "[[\"0x" + - HexStringFromLibsnarkBigint(aff.X.c1.as_bigint()) + "\", \"0x" + - HexStringFromLibsnarkBigint(aff.X.c0.as_bigint()) + "\"], [\"0x" + - HexStringFromLibsnarkBigint(aff.Y.c1.as_bigint()) + "\", \"0x" + - HexStringFromLibsnarkBigint(aff.Y.c0.as_bigint()) + "\"]]"; -} + return "[[\"0x" + HexStringFromLibsnarkBigint(aff.X.c1.as_bigint()) + "\", \"0x" + HexStringFromLibsnarkBigint(aff.X.c0.as_bigint()) + "\"], [\"0x" + HexStringFromLibsnarkBigint(aff.Y.c1.as_bigint()) + "\", \"0x" + HexStringFromLibsnarkBigint(aff.Y.c0.as_bigint()) + "\"]]"; +} \ No newline at end of file diff --git a/zokrates_core/lib/util.hpp b/zokrates_core/lib/util.hpp index c23d43c0..c9f7c00f 100644 --- a/zokrates_core/lib/util.hpp +++ b/zokrates_core/lib/util.hpp @@ -1,18 +1,43 @@ #pragma once // contains definitions of alt_bn128 ec public parameters +#include "ffi.hpp" #include "libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp" #include -#include -#include -#include #include +#include +#include +#include libff::bigint libsnarkBigintFromBytes(const uint8_t* _x); +std::string toHex(const std::string& s); std::string HexStringFromLibsnarkBigint(libff::bigint _x); std::string outputInputAsHex(libff::bigint _x); std::string outputPointG1AffineAsHex(libff::alt_bn128_G1 _p); std::string outputPointG1AffineAsHexJson(libff::alt_bn128_G1 _p); std::string outputPointG2AffineAsHex(libff::alt_bn128_G2 _p); -std::string outputPointG2AffineAsHexJson(libff::alt_bn128_G2 _p); \ No newline at end of file +std::string outputPointG2AffineAsHexJson(libff::alt_bn128_G2 _p); + +template +inline void from_buffer(buffer_t* buffer, T& t) +{ + std::string tmp((char*)buffer->data, buffer->length); + std::stringstream ss(tmp); + ss >> t; +} + +template +inline buffer_t create_buffer(T& t) +{ + std::stringstream ss; + ss << t; + + std::string tmp = ss.str(); + + buffer_t buffer; + make_buffer(&buffer, tmp.length()); + + tmp.copy(reinterpret_cast(buffer.data), buffer.length); + return buffer; +} \ No newline at end of file diff --git a/zokrates_core/src/proof_system/bn128/g16.rs b/zokrates_core/src/proof_system/bn128/g16.rs index a58e9ea7..5fc370c7 100644 --- a/zokrates_core/src/proof_system/bn128/g16.rs +++ b/zokrates_core/src/proof_system/bn128/g16.rs @@ -1,4 +1,7 @@ -use bellman::groth16::*; +use bellman::groth16::{ + prepare_verifying_key, verify_proof, Parameters, PreparedVerifyingKey, Proof as BellmanProof, + VerifyingKey, +}; use bellman::pairing::bn256::{Bn256, Fr}; use regex::Regex; @@ -14,6 +17,7 @@ use crate::proof_system::bn128::utils::solidity::{ SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB, SOLIDITY_PAIRING_LIB_V2, }; use crate::proof_system::{ProofSystem, SetupKeypair}; +use proof_system::bn128::{G1PairingPoint, G2PairingPoint, Proof}; 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."; @@ -25,9 +29,6 @@ impl G16 { } } -type G1PairingPoint = (String, String); -type G2PairingPoint = (G1PairingPoint, G1PairingPoint); - #[derive(Serialize, Deserialize)] struct G16ProofPoints { a: G1PairingPoint, @@ -35,24 +36,13 @@ struct G16ProofPoints { c: G1PairingPoint, } -#[derive(Serialize, Deserialize)] -struct G16Proof { - proof: G16ProofPoints, - inputs: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - raw: Option, -} - impl G16ProofPoints { fn new(a: G1PairingPoint, b: G2PairingPoint, c: G1PairingPoint) -> Self { G16ProofPoints { a, b, c } } } -impl G16Proof { - fn new(proof: G16ProofPoints, inputs: Vec, raw: Option) -> Self { - G16Proof { proof, inputs, raw } - } +impl Proof { fn from_json(str: &str) -> Self { serde_json::from_str(str).unwrap() } @@ -106,9 +96,10 @@ impl ProofSystem for G16 { let mut raw: Vec = Vec::new(); proof.write(&mut raw).unwrap(); - G16Proof::new(proof_points, inputs, Some(hex::encode(&raw))).to_json_pretty() + Proof::::new(proof_points, inputs, Some(base64::encode(&raw))) + .to_json_pretty() } else { - G16Proof::new(proof_points, inputs, None).to_json_pretty() + Proof::::new(proof_points, inputs, None).to_json_pretty() } } @@ -185,26 +176,11 @@ impl ProofSystem for G16 { } fn verify(&self, vk: String, proof: String) -> bool { - let vk_map = parse_vk(vk); - let vk_raw = vk_map.get("vk.raw"); - assert!( - vk_raw.is_some(), - "Missing \"vk.raw\" key; pass \"--raw\" flag when running setup" - ); - - let vk_raw = hex::decode(vk_raw.unwrap()).unwrap(); - - let vk: VerifyingKey = VerifyingKey::read(vk_raw.as_slice()).unwrap(); + let vk: VerifyingKey = get_raw_vk(vk); let pvk: PreparedVerifyingKey = prepare_verifying_key(&vk); - let g16_proof = G16Proof::from_json(proof.as_str()); - assert!( - g16_proof.raw.is_some(), - "Missing \"raw\" field in proof; pass \"--raw\" flag when generating proof" - ); - - let raw_proof = hex::decode(g16_proof.raw.unwrap()).unwrap(); - let bellman_proof: Proof = Proof::read(raw_proof.as_slice()).unwrap(); + let g16_proof: Proof = Proof::from_json(proof.as_str()); + let proof: BellmanProof = get_raw_proof(&g16_proof); let public_inputs: Vec = g16_proof .inputs @@ -216,10 +192,30 @@ impl ProofSystem for G16 { }) .collect::>(); - verify_proof(&pvk, &bellman_proof, &public_inputs).unwrap() + verify_proof(&pvk, &proof, &public_inputs).unwrap() } } +fn get_raw_proof(proof: &Proof) -> BellmanProof { + assert!( + proof.raw.is_some(), + "Missing \"raw\" field in proof: pass \"--raw\" flag when generating proof" + ); + let proof = base64::decode(proof.raw.as_ref().unwrap()).unwrap(); + BellmanProof::read(proof.as_slice()).unwrap() +} + +fn get_raw_vk(vk: String) -> VerifyingKey { + let map = parse_vk(vk); + let raw = map.get("vk.raw"); + assert!( + raw.is_some(), + "Missing \"vk.raw\" key: pass \"--raw\" flag when running setup" + ); + let raw = base64::decode(raw.unwrap()).unwrap(); + VerifyingKey::read(raw.as_slice()).unwrap() +} + fn serialize_vk(vk: VerifyingKey, include_raw: bool) -> String { let mut writer = csv::WriterBuilder::new() .delimiter(b'=') @@ -256,7 +252,7 @@ fn serialize_vk(vk: VerifyingKey, include_raw: bool) -> String { vk.write(&mut raw).unwrap(); writer - .write_record(&["vk.raw", hex::encode(&raw).as_str()]) + .write_record(&["vk.raw", base64::encode(&raw).as_str()]) .unwrap(); } diff --git a/zokrates_core/src/proof_system/bn128/gm17.rs b/zokrates_core/src/proof_system/bn128/gm17.rs index f13fdaab..623b0474 100644 --- a/zokrates_core/src/proof_system/bn128/gm17.rs +++ b/zokrates_core/src/proof_system/bn128/gm17.rs @@ -2,11 +2,14 @@ use regex::Regex; use ir; use proof_system::bn128::utils::ffi::{Buffer, ProofResult, SetupResult}; -use proof_system::bn128::utils::libsnark::{prepare_generate_proof, prepare_setup}; +use proof_system::bn128::utils::libsnark::{ + prepare_generate_proof, prepare_public_inputs, prepare_setup, +}; use proof_system::bn128::utils::parser::parse_vk; 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; @@ -18,6 +21,19 @@ impl GM17 { } } +#[derive(Serialize, Deserialize)] +struct GM17ProofPoints { + a: G1PairingPoint, + b: G2PairingPoint, + c: G1PairingPoint, +} + +impl Proof { + fn from_json(str: &str) -> Self { + serde_json::from_str(str).unwrap() + } +} + extern "C" { fn gm17_setup( a: *const u8, @@ -29,6 +45,7 @@ extern "C" { constraints: i32, variables: i32, inputs: i32, + include_raw: bool, ) -> SetupResult; fn gm17_generate_proof( @@ -37,11 +54,19 @@ extern "C" { public_query_inputs_length: i32, private_inputs: *const u8, private_inputs_length: i32, + include_raw: bool, ) -> ProofResult; + + fn gm17_verify( + vk_buf: *mut Buffer, + proof_buf: *mut Buffer, + public_inputs: *const u8, + public_inputs_length: i32, + ) -> bool; } impl ProofSystem for GM17 { - fn setup(&self, program: ir::Prog, _include_raw: bool) -> SetupKeypair { + fn setup(&self, program: ir::Prog, include_raw: bool) -> SetupKeypair { let (a_arr, b_arr, c_arr, a_vec, b_vec, c_vec, num_constraints, num_variables, num_inputs) = prepare_setup(program); @@ -56,6 +81,7 @@ impl ProofSystem for GM17 { num_constraints as i32, num_variables as i32, num_inputs as i32, + include_raw, ); let vk: Vec = @@ -79,34 +105,36 @@ impl ProofSystem for GM17 { program: ir::Prog, witness: ir::Witness, proving_key: Vec, - _include_raw: bool, + include_raw: bool, ) -> String { let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) = prepare_generate_proof(program, witness); - let mut pk = proving_key.clone(); - let mut pk_buf = Buffer::from_vec(pk.as_mut()); - - let proof_vec = unsafe { + let proof = unsafe { + let mut pk_buffer = Buffer::from_vec(&proving_key); let result = gm17_generate_proof( - &mut pk_buf as *mut _, + &mut pk_buffer as *mut _, public_inputs_arr[0].as_ptr(), public_inputs_length as i32, private_inputs_arr[0].as_ptr(), private_inputs_length as i32, + include_raw, ); + pk_buffer.drop(); // drop the buffer manually + + let proof: Vec = + std::slice::from_raw_parts(result.proof.data, result.proof.length as usize) + .to_vec(); + // Memory is allocated in C and raw pointers are returned to Rust. The caller has to manually // free the memory. - let proof_vec: Vec = - std::slice::from_raw_parts(result.proof.data, result.proof.length as usize) - .to_vec(); result.proof.free(); - proof_vec + proof }; - String::from_utf8(proof_vec).unwrap() + String::from_utf8(proof).unwrap() } fn export_solidity_verifier(&self, vk: String, abi_v2: bool) -> String { @@ -186,8 +214,43 @@ impl ProofSystem for GM17 { ) } - fn verify(&self, _vk: String, _proof: String) -> bool { - unimplemented!() + fn verify(&self, vk: String, proof: String) -> bool { + let map = parse_vk(vk); + let vk_raw = map.get("vk.raw"); + assert!( + vk_raw.is_some(), + "Missing \"vk.raw\" key: pass \"--raw\" flag when running setup" + ); + + let proof: Proof = Proof::from_json(proof.as_str()); + assert!( + proof.raw.is_some(), + "Missing \"raw\" field in proof: pass \"--raw\" flag when generating proof" + ); + + let vk_raw = hex::decode(vk_raw.unwrap().clone()).unwrap(); + let proof_raw = hex::decode(proof.raw.unwrap().clone()).unwrap(); + + let public_inputs: Vec<&str> = proof.inputs.iter().map(|v| v.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 ans = gm17_verify( + &mut vk_buffer as *mut _, + &mut proof_buffer as *mut _, + public_inputs_arr[0].as_ptr(), + public_inputs_length as i32, + ); + + vk_buffer.drop(); + proof_buffer.drop(); + + ans + } } } diff --git a/zokrates_core/src/proof_system/bn128/mod.rs b/zokrates_core/src/proof_system/bn128/mod.rs index 421406a6..672b3dfb 100644 --- a/zokrates_core/src/proof_system/bn128/mod.rs +++ b/zokrates_core/src/proof_system/bn128/mod.rs @@ -11,3 +11,20 @@ pub use self::g16::G16; pub use self::gm17::GM17; #[cfg(feature = "libsnark")] pub use self::pghr13::PGHR13; + +type G1PairingPoint = (String, String); +type G2PairingPoint = (G1PairingPoint, G1PairingPoint); + +#[derive(Serialize, Deserialize)] +struct Proof { + proof: T, + inputs: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + raw: Option, +} + +impl Proof { + fn new(proof: T, inputs: Vec, raw: Option) -> Self { + Proof { proof, inputs, raw } + } +} diff --git a/zokrates_core/src/proof_system/bn128/pghr13.rs b/zokrates_core/src/proof_system/bn128/pghr13.rs index 13288ff3..f96a793d 100644 --- a/zokrates_core/src/proof_system/bn128/pghr13.rs +++ b/zokrates_core/src/proof_system/bn128/pghr13.rs @@ -1,10 +1,13 @@ use ir; use proof_system::bn128::utils::ffi::{Buffer, ProofResult, SetupResult}; -use proof_system::bn128::utils::libsnark::{prepare_generate_proof, prepare_setup}; +use proof_system::bn128::utils::libsnark::{ + prepare_generate_proof, prepare_public_inputs, prepare_setup, +}; use proof_system::bn128::utils::parser::parse_vk; 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 regex::Regex; use zokrates_field::field::FieldPrime; @@ -17,6 +20,24 @@ impl PGHR13 { } } +#[derive(Serialize, Deserialize)] +struct PGHR13ProofPoints { + a: G1PairingPoint, + a_p: G1PairingPoint, + b: G2PairingPoint, + b_p: G1PairingPoint, + c: G1PairingPoint, + c_p: G1PairingPoint, + h: G1PairingPoint, + k: G1PairingPoint, +} + +impl Proof { + fn from_json(str: &str) -> Self { + serde_json::from_str(str).unwrap() + } +} + extern "C" { fn pghr13_setup( a: *const u8, @@ -28,6 +49,7 @@ extern "C" { constraints: i32, variables: i32, inputs: i32, + include_raw: bool, ) -> SetupResult; fn pghr13_generate_proof( @@ -36,11 +58,19 @@ extern "C" { public_query_inputs_length: i32, private_inputs: *const u8, private_inputs_length: i32, + include_raw: bool, ) -> ProofResult; + + fn pghr13_verify( + vk_buf: *mut Buffer, + proof_buf: *mut Buffer, + public_inputs: *const u8, + public_inputs_length: i32, + ) -> bool; } impl ProofSystem for PGHR13 { - fn setup(&self, program: ir::Prog, _include_raw: bool) -> SetupKeypair { + fn setup(&self, program: ir::Prog, include_raw: bool) -> SetupKeypair { let (a_arr, b_arr, c_arr, a_vec, b_vec, c_vec, num_constraints, num_variables, num_inputs) = prepare_setup(program); @@ -55,6 +85,7 @@ impl ProofSystem for PGHR13 { num_constraints as i32, num_variables as i32, num_inputs as i32, + include_raw, ); let vk: Vec = @@ -78,23 +109,25 @@ impl ProofSystem for PGHR13 { program: ir::Prog, witness: ir::Witness, proving_key: Vec, - _include_raw: bool, + include_raw: bool, ) -> String { let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) = prepare_generate_proof(program, witness); - let mut pk = proving_key.clone(); - let mut pk_buf = Buffer::from_vec(pk.as_mut()); - let proof_vec = unsafe { + let mut pk_buf = Buffer::from_vec(&proving_key); + let result = pghr13_generate_proof( &mut pk_buf as *mut _, public_inputs_arr[0].as_ptr(), public_inputs_length as i32, private_inputs_arr[0].as_ptr(), private_inputs_length as i32, + include_raw, ); + pk_buf.drop(); // drop the buffer manually + let proof_vec: Vec = std::slice::from_raw_parts(result.proof.data, result.proof.length as usize) .to_vec(); @@ -185,8 +218,43 @@ impl ProofSystem for PGHR13 { ) } - fn verify(&self, _vk: String, _proof: String) -> bool { - unimplemented!() + fn verify(&self, vk: String, proof: String) -> bool { + let map = parse_vk(vk); + let vk_raw = map.get("vk.raw"); + assert!( + vk_raw.is_some(), + "Missing \"vk.raw\" key: pass \"--raw\" flag when running setup" + ); + + let proof: Proof = Proof::from_json(proof.as_str()); + assert!( + proof.raw.is_some(), + "Missing \"raw\" field in proof: pass \"--raw\" flag when generating proof" + ); + + let vk_raw = hex::decode(vk_raw.unwrap().clone()).unwrap(); + let proof_raw = hex::decode(proof.raw.unwrap().clone()).unwrap(); + + let public_inputs: Vec<&str> = proof.inputs.iter().map(|v| v.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 ans = pghr13_verify( + &mut vk_buffer as *mut _, + &mut proof_buffer as *mut _, + public_inputs_arr[0].as_ptr(), + public_inputs_length as i32, + ); + + vk_buffer.drop(); + proof_buffer.drop(); + + ans + } } } diff --git a/zokrates_core/src/proof_system/bn128/utils/ffi.rs b/zokrates_core/src/proof_system/bn128/utils/ffi.rs index 5dd0fc51..1ccc201e 100644 --- a/zokrates_core/src/proof_system/bn128/utils/ffi.rs +++ b/zokrates_core/src/proof_system/bn128/utils/ffi.rs @@ -20,14 +20,27 @@ extern "C" { } impl Buffer { - pub fn from_vec(v: &mut Vec) -> Buffer { - let length = v.len() as i32; + pub unsafe fn from_vec(v: &Vec) -> Buffer { + let mut buf = vec![0; v.len()].into_boxed_slice(); + buf.copy_from_slice(v.as_slice()); + + let data = buf.as_mut_ptr(); + let len = buf.len(); + + std::mem::forget(buf); + Buffer { - data: v.as_mut_ptr(), - length, + data, + length: len as i32, } } + pub unsafe fn drop(&self) { + let s = std::slice::from_raw_parts_mut(self.data, self.length as usize); + let s = s.as_mut_ptr(); + Box::from_raw(s); + } + /// The purpose of this function is to free memory previously allocated by "malloc" /// from C standard library. Do not use otherwise. pub fn free(self) { diff --git a/zokrates_core/src/proof_system/bn128/utils/libsnark.rs b/zokrates_core/src/proof_system/bn128/utils/libsnark.rs index ae472207..e6ac4388 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; +use zokrates_field::field::{Field, FieldPrime}; // 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,6 +14,19 @@ fn vec_as_u8_32_array(vec: &Vec) -> [u8; 32] { array } +pub fn prepare_public_inputs(public_inputs: Vec<&str>) -> (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, public_inputs_length) +} + // proof-system-independent preparation for the setup phase pub fn prepare_setup( program: ir::Prog,