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

libsnark refactor

This commit is contained in:
dark64 2020-10-14 18:27:39 +02:00
parent 4b2dd517b7
commit 66438e8610
14 changed files with 606 additions and 241 deletions

View file

@ -24,52 +24,60 @@ using namespace libsnark;
namespace gm17 {
template <mp_size_t Q, typename ppT, typename G1, typename G2>
std::string serializeVerificationKey(r1cs_se_ppzksnark_verification_key<ppT>* vk)
buffer_t serialize_verification_key(r1cs_se_ppzksnark_verification_key<ppT>* vk)
{
std::stringstream ss;
unsigned queryLength = vk->query.size();
const size_t QUERY_COUNT = vk->query.size();
ss << "{";
ss << "\"h\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->H) << ",";
ss << "\"g_alpha\":" << outputPointG1AffineAsHexJson<Q, G1>(vk->G_alpha) << ",";
ss << "\"h_beta\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->H_beta) << ",";
ss << "\"g_gamma\":" << outputPointG1AffineAsHexJson<Q, G1>(vk->G_gamma) << ",";
ss << "\"h_gamma\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->H_gamma) << ",";
ss << "\"query\":[";
for (size_t i = 0; i < queryLength; ++i) {
if (i != 0)
ss << ",";
ss << outputPointG1AffineAsHexJson<Q, G1>(vk->query[i]);
}
ss << "],";
ss << "\"raw\":\"" << encodeToHexString<2>(serialize(*vk)) << "\"";
ss << "}";
std::string str = ss.str();
return str;
const size_t G1_SIZE = Q * sizeof(mp_limb_t) * 2; // [x, y]
const size_t G2_SIZE = Q * sizeof(mp_limb_t) * 4; // [[x0, x1], [y0, y1]]
const size_t LENGTH =
(G1_SIZE * 2) +
(G2_SIZE * 3) +
(QUERY_COUNT * G1_SIZE);
// [ ----------------- LENGTH ------------------ ]
// [ h, G_alpha, H_beta, G_gamma, H_gamma, query ]
buffer_t buffer;
buffer.data = (uint8_t*)malloc(LENGTH);
buffer.length = LENGTH;
uint8_t* ptr = buffer.data;
serialize_g2_affine<Q, G2>(vk->H, ptr);
serialize_g1_affine<Q, G1>(vk->G_alpha, ptr);
serialize_g2_affine<Q, G2>(vk->H_beta, ptr);
serialize_g1_affine<Q, G1>(vk->G_gamma, ptr);
serialize_g2_affine<Q, G2>(vk->H_gamma, ptr);
for (size_t i = 0; i < QUERY_COUNT; ++i)
serialize_g1_affine<Q, G1>(vk->query[i], ptr);
return buffer;
}
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
std::string serializeProof(r1cs_se_ppzksnark_proof<ppT>* proof, const uint8_t* public_inputs, int32_t public_inputs_length)
template <mp_size_t Q, typename ppT, typename G1, typename G2>
buffer_t serialize_proof(r1cs_se_ppzksnark_proof<ppT>* proof)
{
std::stringstream ss;
ss << "{";
ss << "\"proof\":{";
ss << "\"a\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->A) << ",";
ss << "\"b\":" << outputPointG2AffineAsHexJson<Q, G2>(proof->B) << ",";
ss << "\"c\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->C);
ss << "},";
ss << "\"inputs\":[";
for (int i = 1; i < public_inputs_length; i++) {
if (i != 1) {
ss << ",";
}
ss << outputInputAsHex<R>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t))));
}
ss << "],";
ss << "\"raw\":\"" << encodeToHexString<2>(serialize(*proof)) << "\"";
ss << "}";
std::string str = ss.str();
return str;
const size_t G1_SIZE = Q * sizeof(mp_limb_t) * 2; // [x, y]
const size_t G2_SIZE = Q * sizeof(mp_limb_t) * 4; // [[x0, x1], [y0, y1]]
const size_t LENGTH = (G1_SIZE * 2) + G2_SIZE;
// [ ---------- LENGTH ---------- ]
// [ G1_SIZE, G2_SIZE, G1_SIZE ]
// [ a, b, c ]
buffer_t buffer;
buffer.data = (uint8_t*)malloc(LENGTH);
buffer.length = LENGTH;
uint8_t* ptr = buffer.data;
serialize_g1_affine<Q, G1>(proof->A, ptr);
serialize_g2_affine<Q, G2>(proof->B, ptr);
serialize_g1_affine<Q, G1>(proof->C, ptr);
return buffer;
}
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
@ -81,23 +89,22 @@ setup_result_t setup(const uint8_t* a, const uint8_t* b, const uint8_t* c, int32
// initialize curve parameters
ppT::init_public_params();
auto cs = createConstraintSystem<r1cs_se_ppzksnark_constraint_system, R, ppT>(a, b, c, a_len, b_len, c_len, constraints, variables, inputs);
auto cs = create_constraint_system<r1cs_se_ppzksnark_constraint_system, R, ppT>(a, b, c, a_len, b_len, c_len, constraints, variables, inputs);
assert(cs.num_variables() >= (unsigned)inputs);
assert(cs.num_inputs() == (unsigned)inputs);
assert(cs.num_constraints() == (unsigned)constraints);
r1cs_se_ppzksnark_keypair<ppT> keypair = r1cs_se_ppzksnark_generator<ppT>(cs);
auto vk = serializeVerificationKey<Q, ppT, G1, G2>(&keypair.vk);
buffer_t vk_buf = createBuffer(vk);
buffer_t pk_buf = createBuffer(keypair.pk);
buffer_t vk_buf = serialize_verification_key<Q, ppT, G1, G2>(&keypair.vk);
buffer_t pk_buf = create_buffer(keypair.pk);
setup_result_t result(vk_buf, pk_buf);
return result;
}
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
proof_result_t generateProof(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 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)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
@ -106,14 +113,14 @@ proof_result_t generateProof(buffer_t* pk_buf, const uint8_t* public_inputs, int
ppT::init_public_params();
r1cs_se_ppzksnark_proving_key<ppT> proving_key;
fromBuffer<r1cs_se_ppzksnark_proving_key<ppT>>(pk_buf, proving_key);
from_buffer<r1cs_se_ppzksnark_proving_key<ppT>>(pk_buf, proving_key);
r1cs_variable_assignment<libff::Fr<ppT>> full_variable_assignment;
for (int i = 1; i < public_inputs_length; i++) {
full_variable_assignment.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
full_variable_assignment.push_back(libff::Fr<ppT>(to_libff_bigint<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
}
for (int i = 0; i < private_inputs_length; i++) {
full_variable_assignment.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(private_inputs + (i * R * sizeof(mp_limb_t)))));
full_variable_assignment.push_back(libff::Fr<ppT>(to_libff_bigint<R>(private_inputs + (i * R * sizeof(mp_limb_t)))));
}
r1cs_primary_input<libff::Fr<ppT>> primary_input(
@ -125,14 +132,12 @@ proof_result_t generateProof(buffer_t* pk_buf, const uint8_t* public_inputs, int
full_variable_assignment.end());
r1cs_se_ppzksnark_proof<ppT> proof = r1cs_se_ppzksnark_prover<ppT>(proving_key, primary_input, auxiliary_input);
std::string json = serializeProof<Q, R, ppT, G1, G2>(&proof, public_inputs, public_inputs_length);
buffer_t proof_buf = createBuffer(json);
buffer_t proof_buf = serialize_proof<Q, ppT, G1, G2>(&proof);
proof_result_t result(proof_buf);
return result;
}
template <mp_size_t R, typename ppT>
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
bool verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length)
{
libff::inhibit_profiling_info = true;
@ -141,15 +146,36 @@ bool verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs,
// initialize curve parameters
ppT::init_public_params();
r1cs_se_ppzksnark_verification_key<ppT> vk;
r1cs_se_ppzksnark_proof<ppT> proof;
uint8_t *ptr = vk_buf->data;
const G2 H = deserialize_g2_affine<Q, typename ppT::Fqe_type, G2>(ptr);
const G1 G_alpha = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
const G2 H_beta = deserialize_g2_affine<Q, typename ppT::Fqe_type, G2>(ptr);
const G1 G_gamma = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
const G2 H_gamma = deserialize_g2_affine<Q, typename ppT::Fqe_type, G2>(ptr);
libff::G1_vector<ppT> query_G1_vector;
fromBuffer<r1cs_se_ppzksnark_verification_key<ppT>>(vk_buf, vk);
fromBuffer<r1cs_se_ppzksnark_proof<ppT>>(proof_buf, proof);
const size_t query_count = ((vk_buf->data + vk_buf->length) - ptr) / (Q * sizeof(mp_limb_t) * 2);
for (size_t i = 0; i < query_count; i++)
{
auto query = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
query_G1_vector.push_back(query);
}
const r1cs_se_ppzksnark_verification_key<ppT> vk(H, G_alpha, H_beta, G_gamma, H_gamma, std::move(query_G1_vector));
ptr = proof_buf->data;
G1 a = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
G2 b = deserialize_g2_affine<Q, typename ppT::Fqe_type, G2>(ptr);
G1 c = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
r1cs_se_ppzksnark_proof<ppT> proof(
std::move(a),
std::move(b),
std::move(c));
r1cs_primary_input<libff::Fr<ppT>> primary_input;
for (int i = 0; i < public_inputs_length; i++) {
primary_input.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
primary_input.push_back(libff::Fr<ppT>(to_libff_bigint<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
}
return r1cs_se_ppzksnark_verifier_strong_IC<ppT>(vk, primary_input, proof);
@ -171,7 +197,7 @@ proof_result_t gm17_bn128_generate_proof(buffer_t* pk_buf,
const uint8_t* private_inputs,
int32_t private_inputs_length)
{
return gm17::generateProof<libff::alt_bn128_q_limbs,
return gm17::generate_proof<libff::alt_bn128_q_limbs,
libff::alt_bn128_r_limbs,
libff::alt_bn128_pp,
libff::alt_bn128_G1,
@ -184,6 +210,9 @@ proof_result_t gm17_bn128_generate_proof(buffer_t* pk_buf,
bool gm17_bn128_verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length)
{
return gm17::verify<libff::alt_bn128_r_limbs,
libff::alt_bn128_pp>(vk_buf, proof_buf, public_inputs, public_inputs_length);
return gm17::verify<libff::alt_bn128_q_limbs,
libff::alt_bn128_r_limbs,
libff::alt_bn128_pp,
libff::alt_bn128_G1,
libff::alt_bn128_G2>(vk_buf, proof_buf, public_inputs, public_inputs_length);
}

View file

@ -15,6 +15,8 @@
#include "libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp"
// contains required interfaces and types (keypair, proof, generator, prover, verifier)
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libsnark/common/data_structures/accumulation_vector.hpp>
#include <libsnark/knowledge_commitment/knowledge_commitment.hpp>
using namespace libsnark;
@ -23,59 +25,67 @@ using namespace libsnark;
namespace pghr13 {
template <mp_size_t Q, typename ppT, typename G1, typename G2>
std::string serializeVerificationKey(r1cs_ppzksnark_verification_key<ppT>* vk)
buffer_t serialize_verification_key(r1cs_ppzksnark_verification_key<ppT>* vk)
{
std::stringstream ss;
unsigned icLength = vk->encoded_IC_query.rest.indices.size();
const size_t QUERY_COUNT = vk->encoded_IC_query.rest.indices.size();
ss << "{";
ss << "\"a\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->alphaA_g2) << ",";
ss << "\"b\":" << outputPointG1AffineAsHexJson<Q, G1>(vk->alphaB_g1) << ",";
ss << "\"c\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->alphaC_g2) << ",";
ss << "\"gamma\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->gamma_g2) << ",";
ss << "\"gamma_beta_1\":" << outputPointG1AffineAsHexJson<Q, G1>(vk->gamma_beta_g1) << ",";
ss << "\"gamma_beta_2\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->gamma_beta_g2) << ",";
ss << "\"z\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->rC_Z_g2) << ",";
ss << "\"ic\":[";
ss << outputPointG1AffineAsHexJson<Q, G1>(vk->encoded_IC_query.first);
for (size_t i = 0; i < icLength; ++i) {
ss << ",";
ss << outputPointG1AffineAsHexJson<Q, G1>(vk->encoded_IC_query.rest.values[i]);
}
ss << "],";
ss << "\"raw\":\"" << encodeToHexString<2>(serialize(*vk)) << "\"";
ss << "}";
std::string str = ss.str();
return str;
const size_t G1_SIZE = Q * sizeof(mp_limb_t) * 2; // [x, y]
const size_t G2_SIZE = Q * sizeof(mp_limb_t) * 4; // [[x0, x1], [y0, y1]]
const size_t LENGTH =
(G1_SIZE * 3) +
(G2_SIZE * 5) +
(QUERY_COUNT * G1_SIZE);
// [ -------------------- LENGTH --------------------- ]
// [ a, b, c, gamma, gamma_beta_1, gamma_beta_2, z, ic ]
buffer_t buffer;
buffer.data = (uint8_t*)malloc(LENGTH);
buffer.length = LENGTH;
uint8_t* ptr = buffer.data;
serialize_g2_affine<Q, G2>(vk->alphaA_g2, ptr);
serialize_g1_affine<Q, G1>(vk->alphaB_g1, ptr);
serialize_g2_affine<Q, G2>(vk->alphaC_g2, ptr);
serialize_g2_affine<Q, G2>(vk->gamma_g2, ptr);
serialize_g1_affine<Q, G1>(vk->gamma_beta_g1, ptr);
serialize_g2_affine<Q, G2>(vk->gamma_beta_g2, ptr);
serialize_g2_affine<Q, G2>(vk->rC_Z_g2, ptr);
serialize_g1_affine<Q, G1>(vk->encoded_IC_query.first, ptr);
for (size_t i = 0; i < QUERY_COUNT; ++i)
serialize_g1_affine<Q, G1>(vk->encoded_IC_query.rest.values[i], ptr);
return buffer;
}
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
std::string serializeProof(r1cs_ppzksnark_proof<ppT>* proof, const uint8_t* public_inputs, int public_inputs_length)
template <mp_size_t Q, typename ppT, typename G1, typename G2>
buffer_t serialize_proof(r1cs_ppzksnark_proof<ppT>* proof)
{
std::stringstream ss;
ss << "{";
ss << "\"proof\":{";
ss << "\"a\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_A.g) << ",";
ss << "\"a_p\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_A.h) << ",";
ss << "\"b\":" << outputPointG2AffineAsHexJson<Q, G2>(proof->g_B.g) << ",";
ss << "\"b_p\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_B.h) << ",";
ss << "\"c\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_C.g) << ",";
ss << "\"c_p\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_C.h) << ",";
ss << "\"h\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_H) << ",";
ss << "\"k\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_K);
ss << "},";
ss << "\"inputs\":[";
for (int i = 1; i < public_inputs_length; i++) {
if (i != 1) {
ss << ",";
}
ss << outputInputAsHex<R>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t))));
}
ss << "],";
ss << "\"raw\":\"" << encodeToHexString<2>(serialize(*proof)) << "\"";
ss << "}";
std::string str = ss.str();
return str;
const size_t G1_SIZE = Q * sizeof(mp_limb_t) * 2; // [x, y]
const size_t G2_SIZE = Q * sizeof(mp_limb_t) * 4; // [[x0, x1], [y0, y1]]
const size_t LENGTH = (G1_SIZE * 7) + G2_SIZE;
// [ ------------- LENGTH -------------- ]
// [ a, a_p, b, b_p, c, c_p, h, k ]
buffer_t buffer;
buffer.data = (uint8_t*)malloc(LENGTH);
buffer.length = LENGTH;
uint8_t* ptr = buffer.data;
serialize_g1_affine<Q, G1>(proof->g_A.g, ptr);
serialize_g1_affine<Q, G1>(proof->g_A.h, ptr);
serialize_g2_affine<Q, G2>(proof->g_B.g, ptr);
serialize_g1_affine<Q, G1>(proof->g_B.h, ptr);
serialize_g1_affine<Q, G1>(proof->g_C.g, ptr);
serialize_g1_affine<Q, G1>(proof->g_C.h, ptr);
serialize_g1_affine<Q, G1>(proof->g_H, ptr);
serialize_g1_affine<Q, G1>(proof->g_K, ptr);
return buffer;
}
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
@ -87,23 +97,22 @@ setup_result_t setup(const uint8_t* a, const uint8_t* b, const uint8_t* c, int32
// initialize curve parameters
ppT::init_public_params();
auto cs = createConstraintSystem<r1cs_ppzksnark_constraint_system, R, ppT>(a, b, c, a_len, b_len, c_len, constraints, variables, inputs);
auto cs = create_constraint_system<r1cs_ppzksnark_constraint_system, R, ppT>(a, b, c, a_len, b_len, c_len, constraints, variables, inputs);
assert(cs.num_variables() >= (unsigned)inputs);
assert(cs.num_inputs() == (unsigned)inputs);
assert(cs.num_constraints() == (unsigned)constraints);
r1cs_ppzksnark_keypair<ppT> keypair = r1cs_ppzksnark_generator<ppT>(cs);
auto vk = serializeVerificationKey<Q, ppT, G1, G2>(&keypair.vk);
buffer_t vk_buf = createBuffer(vk);
buffer_t pk_buf = createBuffer(keypair.pk);
buffer_t vk_buf = serialize_verification_key<Q, ppT, G1, G2>(&keypair.vk);
buffer_t pk_buf = create_buffer(keypair.pk);
setup_result_t result(vk_buf, pk_buf);
return result;
}
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
proof_result_t generateProof(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 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)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
@ -112,15 +121,15 @@ proof_result_t generateProof(buffer_t* pk_buf, const uint8_t* public_inputs, int
ppT::init_public_params();
r1cs_ppzksnark_proving_key<ppT> proving_key;
fromBuffer<r1cs_ppzksnark_proving_key<ppT>>(pk_buf, proving_key);
from_buffer<r1cs_ppzksnark_proving_key<ppT>>(pk_buf, proving_key);
// assign variables based on witness values, excludes ~one
r1cs_variable_assignment<libff::Fr<ppT>> full_variable_assignment;
for (int i = 1; i < public_inputs_length; i++) {
full_variable_assignment.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
full_variable_assignment.push_back(libff::Fr<ppT>(to_libff_bigint<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
}
for (int i = 0; i < private_inputs_length; i++) {
full_variable_assignment.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(private_inputs + (i * R * sizeof(mp_limb_t)))));
full_variable_assignment.push_back(libff::Fr<ppT>(to_libff_bigint<R>(private_inputs + (i * R * sizeof(mp_limb_t)))));
}
r1cs_primary_input<libff::Fr<ppT>> primary_input(
@ -132,14 +141,12 @@ proof_result_t generateProof(buffer_t* pk_buf, const uint8_t* public_inputs, int
full_variable_assignment.end());
r1cs_ppzksnark_proof<ppT> proof = r1cs_ppzksnark_prover<ppT>(proving_key, primary_input, auxiliary_input);
std::string json = serializeProof<Q, R, ppT, G1, G2>(&proof, public_inputs, public_inputs_length);
buffer_t proof_buf = createBuffer(json);
buffer_t proof_buf = serialize_proof<Q, ppT, G1, G2>(&proof);
proof_result_t result(proof_buf);
return result;
}
template <mp_size_t R, typename ppT>
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
bool verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length)
{
libff::inhibit_profiling_info = true;
@ -148,15 +155,53 @@ bool verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs,
// initialize curve parameters
ppT::init_public_params();
r1cs_ppzksnark_verification_key<ppT> vk;
r1cs_ppzksnark_proof<ppT> proof;
uint8_t *ptr = vk_buf->data;
const G2 alphaA_g2 = deserialize_g2_affine<Q, typename ppT::Fqe_type, G2>(ptr);
const G1 alphaB_g1 = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
const G2 alphaC_g2 = deserialize_g2_affine<Q, typename ppT::Fqe_type, G2>(ptr);
const G2 gamma_g2 = deserialize_g2_affine<Q, typename ppT::Fqe_type, G2>(ptr);
const G1 gamma_beta_g1 = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
const G2 gamma_beta_g2 = deserialize_g2_affine<Q, typename ppT::Fqe_type, G2>(ptr);
const G2 rC_Z_g2 = deserialize_g2_affine<Q, typename ppT::Fqe_type, G2>(ptr);
G1 ic_first = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
fromBuffer<r1cs_ppzksnark_verification_key<ppT>>(vk_buf, vk);
fromBuffer<r1cs_ppzksnark_proof<ppT>>(proof_buf, proof);
std::vector<G1> ic_rest;
const size_t ic_rest_count = ((vk_buf->data + vk_buf->length) - ptr) / (Q * sizeof(mp_limb_t) * 2);
for (size_t i = 0; i < ic_rest_count; i++)
{
auto ic_query = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
ic_rest.push_back(ic_query);
}
accumulation_vector<G1> eIC(std::move(ic_first), std::move(ic_rest));
const r1cs_ppzksnark_verification_key<ppT> vk(alphaA_g2, alphaB_g1, alphaC_g2, gamma_g2, gamma_beta_g1, gamma_beta_g2, rC_Z_g2, eIC);
ptr = proof_buf->data;
const G1 g_A_g = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
const G1 g_A_h = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
const G2 g_B_g = deserialize_g2_affine<Q, typename ppT::Fqe_type, G2>(ptr);
const G1 g_B_h = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
const G1 g_C_g = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
const G1 g_C_h = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
knowledge_commitment<G1, G1> g_A(g_A_g, g_A_h);
knowledge_commitment<G2, G1> g_B(g_B_g, g_B_h);
knowledge_commitment<G1, G1> g_C(g_C_g, g_C_h);
G1 g_H = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
G1 g_K = deserialize_g1_affine<Q, typename ppT::Fq_type, G1>(ptr);
const r1cs_ppzksnark_proof<ppT> proof(
std::move(g_A),
std::move(g_B),
std::move(g_C),
std::move(g_H),
std::move(g_K)
);
r1cs_primary_input<libff::Fr<ppT>> primary_input;
for (int i = 0; i < public_inputs_length; i++) {
primary_input.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
primary_input.push_back(libff::Fr<ppT>(to_libff_bigint<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
}
return r1cs_ppzksnark_verifier_strong_IC<ppT>(vk, primary_input, proof);
}
@ -177,7 +222,7 @@ proof_result_t pghr13_bn128_generate_proof(buffer_t* pk_buf,
const uint8_t* private_inputs,
int32_t private_inputs_length)
{
return pghr13::generateProof<libff::alt_bn128_q_limbs,
return pghr13::generate_proof<libff::alt_bn128_q_limbs,
libff::alt_bn128_r_limbs,
libff::alt_bn128_pp,
libff::alt_bn128_G1,
@ -190,6 +235,9 @@ proof_result_t pghr13_bn128_generate_proof(buffer_t* pk_buf,
bool pghr13_bn128_verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length)
{
return pghr13::verify<libff::alt_bn128_r_limbs,
libff::alt_bn128_pp>(vk_buf, proof_buf, public_inputs, public_inputs_length);
return pghr13::verify<libff::alt_bn128_q_limbs,
libff::alt_bn128_r_limbs,
libff::alt_bn128_pp,
libff::alt_bn128_G1,
libff::alt_bn128_G2>(vk_buf, proof_buf, public_inputs, public_inputs_length);
}

View file

@ -8,67 +8,92 @@
#include <sstream>
#include <string>
template <int W>
std::string encodeToHexString(const std::string& in)
{
std::ostringstream out;
out << std::setfill('0');
for (unsigned char const& c : in) {
out << std::hex << std::setw(W) << static_cast<unsigned int>(c);
}
return out.str();
}
// conversion byte[N] <-> libsnark bigint.
// conversion byte[N] -> libsnark bigint
template <mp_size_t N>
libff::bigint<N> libsnarkBigintFromBytes(const uint8_t* _x)
libff::bigint<N> to_libff_bigint(const uint8_t* input)
{
libff::bigint<N> x;
for (unsigned i = 0; i < N; i++) {
for (unsigned j = 0; j < 8; j++) {
x.data[N - 1 - i] |= uint64_t(_x[i * 8 + j]) << (8 * (7 - j));
x.data[N - 1 - i] |= uint64_t(input[i * 8 + j]) << (8 * (7 - j));
}
}
return x;
}
// conversion libsnark bigint -> byte[N]
template <mp_size_t N>
std::string hexStringFromLibsnarkBigint(libff::bigint<N> _x)
void from_libff_bigint(libff::bigint<N> x, uint8_t* out)
{
uint8_t x[N * sizeof(mp_limb_t)];
for (unsigned i = 0; i < N; i++) {
for (unsigned j = 0; j < 8; j++) {
x[i * 8 + j] = uint8_t(uint64_t(_x.data[N - 1 - i]) >> (8 * (7 - j)));
out[i * 8 + j] = uint8_t(uint64_t(x.data[N - 1 - i]) >> (8 * (7 - j)));
}
}
std::string tmp((char*)x, N * sizeof(mp_limb_t));
return encodeToHexString<2>(tmp);
}
template <mp_size_t Q>
std::string outputInputAsHex(libff::bigint<Q> _x)
{
return "\"0x" + hexStringFromLibsnarkBigint<Q>(_x) + "\"";
}
template <mp_size_t Q, typename G1>
std::string outputPointG1AffineAsHexJson(G1 _p)
void serialize_g1_affine(G1 point, uint8_t*& buffer)
{
G1 aff = _p;
const size_t ELEMENT_SIZE = Q * sizeof(mp_limb_t);
G1 aff = point;
aff.to_affine_coordinates();
return "[\"0x" + hexStringFromLibsnarkBigint<Q>(aff.X.as_bigint()) + "\",\"0x" + hexStringFromLibsnarkBigint<Q>(aff.Y.as_bigint()) + "\"]";
auto x = aff.X.as_bigint();
auto y = aff.Y.as_bigint();
from_libff_bigint<Q>(x, buffer); buffer += ELEMENT_SIZE;
from_libff_bigint<Q>(y, buffer); buffer += ELEMENT_SIZE;
}
template <mp_size_t Q, typename G2>
std::string outputPointG2AffineAsHexJson(G2 _p)
void serialize_g2_affine(G2 point, uint8_t*& buffer)
{
G2 aff = _p;
const size_t ELEMENT_SIZE = Q * sizeof(mp_limb_t);
G2 aff = point;
aff.to_affine_coordinates();
return "[[\"0x" + hexStringFromLibsnarkBigint<Q>(aff.X.c1.as_bigint()) + "\",\"0x" + hexStringFromLibsnarkBigint<Q>(aff.X.c0.as_bigint()) + "\"], [\"0x" + hexStringFromLibsnarkBigint<Q>(aff.Y.c1.as_bigint()) + "\", \"0x" + hexStringFromLibsnarkBigint<Q>(aff.Y.c0.as_bigint()) + "\"]]";
auto x0 = aff.X.c0.as_bigint();
auto x1 = aff.X.c1.as_bigint();
auto y0 = aff.Y.c0.as_bigint();
auto y1 = aff.Y.c1.as_bigint();
from_libff_bigint<Q>(x0, buffer); buffer += ELEMENT_SIZE;
from_libff_bigint<Q>(x1, buffer); buffer += ELEMENT_SIZE;
from_libff_bigint<Q>(y0, buffer); buffer += ELEMENT_SIZE;
from_libff_bigint<Q>(y1, buffer); buffer += ELEMENT_SIZE;
}
template <mp_size_t Q, typename Fq, typename G1>
G1 deserialize_g1_affine(uint8_t*& buffer)
{
const size_t ELEMENT_SIZE = Q * sizeof(mp_limb_t);
auto x = to_libff_bigint<Q>(buffer); buffer += ELEMENT_SIZE;
auto y = to_libff_bigint<Q>(buffer); buffer += ELEMENT_SIZE;
return G1(Fq(x), Fq(y), Fq::one());
}
template <mp_size_t Q, typename Fq2, typename G2>
G2 deserialize_g2_affine(uint8_t*& buffer)
{
const size_t ELEMENT_SIZE = Q * sizeof(mp_limb_t);
auto x0 = to_libff_bigint<Q>(buffer); buffer += ELEMENT_SIZE;
auto x1 = to_libff_bigint<Q>(buffer); buffer += ELEMENT_SIZE;
auto y0 = to_libff_bigint<Q>(buffer); buffer += ELEMENT_SIZE;
auto y1 = to_libff_bigint<Q>(buffer); buffer += ELEMENT_SIZE;
auto x = Fq2(x0, x1);
auto y = Fq2(y0, y1);
return G2(x, y, Fq2::one());
}
template <template <typename ppT> class ConstraintSystem, mp_size_t R, typename ppT>
ConstraintSystem<ppT> createConstraintSystem(const uint8_t* a,
ConstraintSystem<ppT> create_constraint_system(const uint8_t* a,
const uint8_t* b,
const uint8_t* c,
int32_t a_len,
@ -82,19 +107,19 @@ ConstraintSystem<ppT> createConstraintSystem(const uint8_t* a,
cs.primary_input_size = inputs;
cs.auxiliary_input_size = variables - inputs - 1; // ~one not included
std::cout << "num variables: " << variables << std::endl;
std::cout << "num constraints: " << constraints << std::endl;
std::cout << "num inputs: " << inputs << std::endl;
// std::cout << "num variables: " << variables << std::endl;
// std::cout << "num constraints: " << constraints << std::endl;
// std::cout << "num inputs: " << inputs << std::endl;
struct VariableValueMapping {
struct vvmap_t {
int constraint_id;
int variable_id;
uint8_t variable_value[R * sizeof(mp_limb_t)];
};
const VariableValueMapping* a_vvmap = (VariableValueMapping*)a;
const VariableValueMapping* b_vvmap = (VariableValueMapping*)b;
const VariableValueMapping* c_vvmap = (VariableValueMapping*)c;
const vvmap_t* a_vvmap = (vvmap_t*)a;
const vvmap_t* b_vvmap = (vvmap_t*)b;
const vvmap_t* c_vvmap = (vvmap_t*)c;
int a_id = 0;
int b_id = 0;
@ -103,21 +128,21 @@ ConstraintSystem<ppT> createConstraintSystem(const uint8_t* a,
for (int row = 0; row < constraints; row++) {
linear_combination<libff::Fr<ppT>> lin_comb_a, lin_comb_b, lin_comb_c;
while (a_id < a_len && a_vvmap[a_id].constraint_id == row) {
libff::bigint<R> value = libsnarkBigintFromBytes<R>(a_vvmap[a_id].variable_value);
libff::bigint<R> value = to_libff_bigint<R>(a_vvmap[a_id].variable_value);
if (!value.is_zero()) {
lin_comb_a.add_term(a_vvmap[a_id].variable_id, value);
}
a_id++;
}
while (b_id < b_len && b_vvmap[b_id].constraint_id == row) {
libff::bigint<R> value = libsnarkBigintFromBytes<R>(b_vvmap[b_id].variable_value);
libff::bigint<R> value = to_libff_bigint<R>(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<R> value = libsnarkBigintFromBytes<R>(c_vvmap[c_id].variable_value);
libff::bigint<R> value = to_libff_bigint<R>(c_vvmap[c_id].variable_value);
if (!value.is_zero()) {
lin_comb_c.add_term(c_vvmap[c_id].variable_id, value);
}
@ -129,7 +154,7 @@ ConstraintSystem<ppT> createConstraintSystem(const uint8_t* a,
}
template <typename T>
inline void fromBuffer(buffer_t* buffer, T& t)
inline void from_buffer(buffer_t* buffer, T& t)
{
std::string tmp((char*)buffer->data, buffer->length);
std::stringstream ss(tmp);
@ -137,17 +162,12 @@ inline void fromBuffer(buffer_t* buffer, T& t)
}
template <typename T>
inline std::string serialize(const T& t)
inline buffer_t create_buffer(T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
template <typename T>
inline buffer_t createBuffer(T& t)
{
std::string tmp = serialize(t);
std::string tmp = ss.str();
size_t length = tmp.length();
buffer_t buffer;

View file

@ -64,7 +64,7 @@ impl<T: Field + BellmanFieldExtensions> Backend<T, G16> for Bellman {
.map(parse_fr::<T>)
.collect::<Vec<_>>();
Proof::new(proof_points, inputs, None)
Proof::new(proof_points, inputs)
}
fn verify(
@ -123,9 +123,8 @@ mod serialization {
pub fn to_g2<T: BellmanFieldExtensions>(
g2: G2Affine,
) -> <T::BellmanEngine as Engine>::G2Affine {
// apparently the order is reversed
let x = T::new_fq2(&(g2.0).1, &(g2.0).0);
let y = T::new_fq2(&(g2.1).1, &(g2.1).0);
let x = T::new_fq2(&(g2.0).0, &(g2.0).1);
let y = T::new_fq2(&(g2.1).0, &(g2.1).1);
<T::BellmanEngine as Engine>::G2Affine::from_xy_unchecked(x, y)
}
}

View file

@ -249,12 +249,12 @@ mod parse {
let captures = G2_REGEX.captures(&raw_e).unwrap();
G2Affine(
(
captures.name(&"x1").unwrap().as_str().to_string(),
captures.name(&"x0").unwrap().as_str().to_string(),
captures.name(&"x1").unwrap().as_str().to_string(),
),
(
captures.name(&"y1").unwrap().as_str().to_string(),
captures.name(&"y0").unwrap().as_str().to_string(),
captures.name(&"y1").unwrap().as_str().to_string(),
),
)
}

View file

@ -1,13 +1,13 @@
use ir::{Prog, Witness};
use proof_system::libsnark::ffi::{Buffer, ProofResult, SetupResult};
use proof_system::libsnark::{
prepare_generate_proof, prepare_public_inputs, prepare_setup, Libsnark,
prepare_generate_proof, prepare_public_inputs, prepare_setup, serialization::*, Libsnark,
};
use proof_system::scheme::gm17::GM17;
use proof_system::scheme::gm17::{ProofPoints, VerificationKey, GM17};
use proof_system::scheme::Scheme;
use proof_system::{Backend, Proof, SetupKeypair};
use zokrates_field::Bn128Field;
use zokrates_field::Field;
use proof_system::{Backend, G1Affine, G2Affine, Proof, SetupKeypair};
use std::io::{BufReader, BufWriter, Write};
use zokrates_field::{Bn128Field, Field};
extern "C" {
fn gm17_bn128_setup(
@ -70,7 +70,29 @@ impl Backend<Bn128Field, GM17> for Libsnark {
(vk, pk)
};
let vk = serde_json::from_str(String::from_utf8(vk).unwrap().as_str()).unwrap();
let vk_slice = vk.as_slice();
let mut reader = BufReader::new(vk_slice);
let h = read_g2(&mut reader).unwrap();
let g_alpha = read_g1(&mut reader).unwrap();
let h_beta = read_g2(&mut reader).unwrap();
let g_gamma = read_g1(&mut reader).unwrap();
let h_gamma = read_g2(&mut reader).unwrap();
let mut query = vec![];
while let Ok(q) = read_g1(&mut reader) {
query.push(q);
}
let vk = VerificationKey::<G1Affine, G2Affine> {
h,
g_alpha,
h_beta,
g_gamma,
h_gamma,
query,
};
SetupKeypair::new(vk, pk)
}
@ -80,7 +102,7 @@ impl Backend<Bn128Field, GM17> for Libsnark {
proving_key: Vec<u8>,
) -> Proof<<GM17 as Scheme<Bn128Field>>::ProofPoints> {
let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) =
prepare_generate_proof(program, witness);
prepare_generate_proof(program.clone(), witness.clone());
let proof = unsafe {
let mut pk_buffer = Buffer::from_vec(&proving_key);
@ -105,15 +127,51 @@ impl Backend<Bn128Field, GM17> for Libsnark {
proof
};
serde_json::from_str(String::from_utf8(proof).unwrap().as_str()).unwrap()
let mut reader = BufReader::new(proof.as_slice());
let a = read_g1(&mut reader).unwrap();
let b = read_g2(&mut reader).unwrap();
let c = read_g1(&mut reader).unwrap();
let points = ProofPoints::<G1Affine, G2Affine> { a, b, c };
let public_inputs: Vec<String> = program
.main
.arguments
.clone()
.iter()
.zip(program.private.clone())
.filter(|(_, p)| !*p)
.map(|(v, _)| witness.clone().0.get(v).unwrap().clone())
.chain(witness.clone().return_values())
.map(|v| format!("0x{:064x}", v.to_biguint()))
.collect();
Proof::new(points, public_inputs)
}
fn verify(
vk: <GM17 as Scheme<Bn128Field>>::VerificationKey,
proof: Proof<<GM17 as Scheme<Bn128Field>>::ProofPoints>,
) -> bool {
let vk_raw = hex::decode(vk.raw.unwrap().clone()).unwrap();
let proof_raw = hex::decode(proof.raw.unwrap().clone()).unwrap();
let vk_buffer = vec![];
let mut vk_writer = BufWriter::new(vk_buffer);
write_g2(&mut vk_writer, &vk.h);
write_g1(&mut vk_writer, &vk.g_alpha);
write_g2(&mut vk_writer, &vk.h_beta);
write_g1(&mut vk_writer, &vk.g_gamma);
write_g2(&mut vk_writer, &vk.h_gamma);
vk.query.iter().for_each(|q| write_g1(&mut vk_writer, q));
vk_writer.flush().unwrap();
let proof_buffer = vec![];
let mut proof_writer = BufWriter::new(proof_buffer);
write_g1(&mut proof_writer, &proof.proof.a);
write_g2(&mut proof_writer, &proof.proof.b);
write_g1(&mut proof_writer, &proof.proof.c);
proof_writer.flush().unwrap();
let public_inputs: Vec<_> = proof
.inputs
@ -124,8 +182,8 @@ impl Backend<Bn128Field, GM17> for Libsnark {
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_writer.get_ref());
let mut proof_buffer = Buffer::from_vec(proof_writer.get_ref());
let ans = gm17_bn128_verify(
&mut vk_buffer as *mut _,
@ -141,3 +199,41 @@ impl Backend<Bn128Field, GM17> for Libsnark {
}
}
}
#[cfg(feature = "libsnark")]
#[cfg(test)]
mod tests {
use super::*;
use crate::flat_absy::FlatVariable;
use crate::ir::{Function, Interpreter, Prog, Statement};
use zokrates_field::Bn128Field;
#[test]
fn verify() {
let program: Prog<Bn128Field> = Prog {
main: Function {
id: String::from("main"),
arguments: vec![FlatVariable::new(0)],
returns: vec![FlatVariable::public(0)],
statements: vec![Statement::Constraint(
FlatVariable::new(0).into(),
FlatVariable::public(0).into(),
)],
},
private: vec![true],
};
let keypair = <Libsnark as Backend<Bn128Field, GM17>>::setup(program.clone());
let interpreter = Interpreter::default();
let witness = interpreter
.execute(&program, &vec![Bn128Field::from(42)])
.unwrap();
let proof =
<Libsnark as Backend<Bn128Field, GM17>>::generate_proof(program, witness, keypair.pk);
let ans = <Libsnark as Backend<Bn128Field, GM17>>::verify(keypair.vk, proof);
assert!(ans);
}
}

View file

@ -303,3 +303,57 @@ pub fn r1cs_program<T: Field>(
}
(variables_list, private_inputs_offset, a, b, c)
}
pub mod serialization {
use proof_system::{G1Affine, G2Affine};
use std::io::Read;
use std::io::Write;
#[inline]
fn decode_hex(value: &String) -> Vec<u8> {
hex::decode(value.strip_prefix("0x").unwrap()).unwrap()
}
#[inline]
fn encode_hex<T: AsRef<[u8]>>(data: T) -> String {
format!("0x{}", hex::encode(data))
}
pub fn read_g1<R: Read>(reader: &mut R) -> Result<G1Affine, ()> {
let mut buffer = [0; 64];
reader.read_exact(&mut buffer).map_err(|_| ())?;
Ok(G1Affine(
encode_hex(&buffer[0..32].to_vec()),
encode_hex(&buffer[32..64].to_vec()),
))
}
pub fn read_g2<R: Read>(reader: &mut R) -> Result<G2Affine, ()> {
let mut buffer = [0; 128];
reader.read_exact(&mut buffer).map_err(|_| ())?;
Ok(G2Affine(
(
encode_hex(&buffer[0..32].to_vec()),
encode_hex(&buffer[32..64].to_vec()),
),
(
encode_hex(&buffer[64..96].to_vec()),
encode_hex(&buffer[96..128].to_vec()),
),
))
}
pub fn write_g1<W: Write>(writer: &mut W, g1: &G1Affine) {
writer.write(decode_hex(&g1.0).as_ref()).unwrap();
writer.write(decode_hex(&g1.1).as_ref()).unwrap();
}
pub fn write_g2<W: Write>(writer: &mut W, g2: &G2Affine) {
writer.write(decode_hex(&(g2.0).0).as_ref()).unwrap();
writer.write(decode_hex(&(g2.0).1).as_ref()).unwrap();
writer.write(decode_hex(&(g2.1).0).as_ref()).unwrap();
writer.write(decode_hex(&(g2.1).1).as_ref()).unwrap();
}
}

View file

@ -2,11 +2,13 @@ use proof_system::libsnark::ffi::{Buffer, ProofResult, SetupResult};
use proof_system::libsnark::{
prepare_generate_proof, prepare_public_inputs, prepare_setup, Libsnark,
};
use proof_system::{Backend, Proof, SetupKeypair};
use proof_system::{Backend, G1Affine, G2Affine, Proof, SetupKeypair};
use ir::{Prog, Witness};
use proof_system::scheme::pghr13::PGHR13;
use proof_system::libsnark::serialization::{read_g1, read_g2, write_g1, write_g2};
use proof_system::scheme::pghr13::{ProofPoints, VerificationKey, PGHR13};
use proof_system::scheme::Scheme;
use std::io::{BufReader, BufWriter, Write};
use zokrates_field::Bn128Field;
use zokrates_field::Field;
@ -71,7 +73,33 @@ impl Backend<Bn128Field, PGHR13> for Libsnark {
(vk, pk)
};
let vk = serde_json::from_str(String::from_utf8(vk).unwrap().as_str()).unwrap();
let vk_slice = vk.as_slice();
let mut reader = BufReader::new(vk_slice);
let a = read_g2(&mut reader).unwrap();
let b = read_g1(&mut reader).unwrap();
let c = read_g2(&mut reader).unwrap();
let gamma = read_g2(&mut reader).unwrap();
let gamma_beta_1 = read_g1(&mut reader).unwrap();
let gamma_beta_2 = read_g2(&mut reader).unwrap();
let z = read_g2(&mut reader).unwrap();
let mut ic = vec![];
while let Ok(q) = read_g1(&mut reader) {
ic.push(q);
}
let vk = VerificationKey::<G1Affine, G2Affine> {
a,
b,
c,
gamma,
gamma_beta_1,
gamma_beta_2,
z,
ic,
};
SetupKeypair::new(vk, pk)
}
@ -81,7 +109,7 @@ impl Backend<Bn128Field, PGHR13> for Libsnark {
proving_key: Vec<u8>,
) -> Proof<<PGHR13 as Scheme<Bn128Field>>::ProofPoints> {
let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) =
prepare_generate_proof(program, witness);
prepare_generate_proof(program.clone(), witness.clone());
let proof = unsafe {
let mut pk_buffer = Buffer::from_vec(&proving_key);
@ -106,15 +134,74 @@ impl Backend<Bn128Field, PGHR13> for Libsnark {
proof
};
serde_json::from_str(String::from_utf8(proof).unwrap().as_str()).unwrap()
let mut reader = BufReader::new(proof.as_slice());
let a = read_g1(&mut reader).unwrap();
let a_p = read_g1(&mut reader).unwrap();
let b = read_g2(&mut reader).unwrap();
let b_p = read_g1(&mut reader).unwrap();
let c = read_g1(&mut reader).unwrap();
let c_p = read_g1(&mut reader).unwrap();
let h = read_g1(&mut reader).unwrap();
let k = read_g1(&mut reader).unwrap();
let points = ProofPoints::<G1Affine, G2Affine> {
a,
a_p,
b,
b_p,
c,
c_p,
h,
k,
};
let public_inputs: Vec<String> = program
.main
.arguments
.clone()
.iter()
.zip(program.private.clone())
.filter(|(_, p)| !*p)
.map(|(v, _)| witness.clone().0.get(v).unwrap().clone())
.chain(witness.clone().return_values())
.map(|v| format!("0x{:064x}", v.to_biguint()))
.collect();
Proof::new(points, public_inputs)
}
fn verify(
vk: <PGHR13 as Scheme<Bn128Field>>::VerificationKey,
proof: Proof<<PGHR13 as Scheme<Bn128Field>>::ProofPoints>,
) -> bool {
let vk_raw = hex::decode(vk.raw.unwrap().clone()).unwrap();
let proof_raw = hex::decode(proof.raw.unwrap().clone()).unwrap();
let vk_buffer = vec![];
let mut vk_writer = BufWriter::new(vk_buffer);
write_g2(&mut vk_writer, &vk.a);
write_g1(&mut vk_writer, &vk.b);
write_g2(&mut vk_writer, &vk.c);
write_g2(&mut vk_writer, &vk.gamma);
write_g1(&mut vk_writer, &vk.gamma_beta_1);
write_g2(&mut vk_writer, &vk.gamma_beta_2);
write_g2(&mut vk_writer, &vk.z);
vk.ic
.iter()
.for_each(|ic_query| write_g1(&mut vk_writer, ic_query));
vk_writer.flush().unwrap();
let proof_buffer = vec![];
let mut proof_writer = BufWriter::new(proof_buffer);
write_g1(&mut proof_writer, &proof.proof.a);
write_g1(&mut proof_writer, &proof.proof.a_p);
write_g2(&mut proof_writer, &proof.proof.b);
write_g1(&mut proof_writer, &proof.proof.b_p);
write_g1(&mut proof_writer, &proof.proof.c);
write_g1(&mut proof_writer, &proof.proof.c_p);
write_g1(&mut proof_writer, &proof.proof.h);
write_g1(&mut proof_writer, &proof.proof.k);
proof_writer.flush().unwrap();
let public_inputs: Vec<_> = proof
.inputs
@ -125,8 +212,8 @@ impl Backend<Bn128Field, PGHR13> for Libsnark {
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_writer.get_ref());
let mut proof_buffer = Buffer::from_vec(proof_writer.get_ref());
let ans = pghr13_bn128_verify(
&mut vk_buffer as *mut _,
@ -142,3 +229,41 @@ impl Backend<Bn128Field, PGHR13> for Libsnark {
}
}
}
#[cfg(feature = "libsnark")]
#[cfg(test)]
mod tests {
use super::*;
use crate::flat_absy::FlatVariable;
use crate::ir::{Function, Interpreter, Prog, Statement};
use zokrates_field::Bn128Field;
#[test]
fn verify() {
let program: Prog<Bn128Field> = Prog {
main: Function {
id: String::from("main"),
arguments: vec![FlatVariable::new(0)],
returns: vec![FlatVariable::public(0)],
statements: vec![Statement::Constraint(
FlatVariable::new(0).into(),
FlatVariable::public(0).into(),
)],
},
private: vec![true],
};
let keypair = <Libsnark as Backend<Bn128Field, PGHR13>>::setup(program.clone());
let interpreter = Interpreter::default();
let witness = interpreter
.execute(&program, &vec![Bn128Field::from(42)])
.unwrap();
let proof =
<Libsnark as Backend<Bn128Field, PGHR13>>::generate_proof(program, witness, keypair.pk);
let ans = <Libsnark as Backend<Bn128Field, PGHR13>>::verify(keypair.vk, proof);
assert!(ans);
}
}

View file

@ -29,13 +29,11 @@ impl<V: Serialize + DeserializeOwned> SetupKeypair<V> {
pub struct Proof<T> {
proof: T,
inputs: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
raw: Option<String>,
}
impl<T: Serialize + DeserializeOwned> Proof<T> {
fn new(proof: T, inputs: Vec<String>, raw: Option<String>) -> Self {
Proof { proof, inputs, raw }
fn new(proof: T, inputs: Vec<String>) -> Self {
Proof { proof, inputs }
}
}

View file

@ -28,7 +28,6 @@ pub struct VerificationKey<G1, G2> {
pub g_gamma: G1,
pub h_gamma: G2,
pub query: Vec<G1>,
pub raw: Option<String>,
}
impl<T: Field + NotBw6_761Field> Scheme<T> for GM17 {
@ -202,7 +201,7 @@ contract Verifier {
function verifyTx(
Proof memory proof<%input_argument%>
) public view returns (bool r) {
uint[] memory inputValues = new uint[](input.length);
uint[] memory inputValues = new uint[](<%vk_input_length%>);
<%input_loop%>
if (verify(inputValues, proof) == 0) {
return true;
@ -270,7 +269,7 @@ contract Verifier {
proof.a = Pairing.G1Point(a[0], a[1]);
proof.b = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.c = Pairing.G1Point(c[0], c[1]);
uint[] memory inputValues = new uint[](input.length);
uint[] memory inputValues = new uint[](<%vk_input_length%>);
<%input_loop%>
if (verify(inputValues, proof) == 0) {
return true;

View file

@ -181,7 +181,7 @@ contract Verifier {
function verifyTx(
Proof memory proof<%input_argument%>
) public view returns (bool r) {
uint[] memory inputValues = new uint[](input.length);
uint[] memory inputValues = new uint[](<%vk_input_length%>);
<%input_loop%>
if (verify(inputValues, proof) == 0) {
return true;

View file

@ -30,7 +30,6 @@ pub struct VerificationKey<G1, G2> {
pub gamma_beta_2: G2,
pub z: G2,
pub ic: Vec<G1>,
pub raw: Option<String>,
}
impl<T: Field> Scheme<T> for PGHR13 {
@ -172,8 +171,8 @@ const CONTRACT_TEMPLATE_V2: &str = r#"contract Verifier {
Pairing.G1Point b_p;
Pairing.G1Point c;
Pairing.G1Point c_p;
Pairing.G1Point k;
Pairing.G1Point h;
Pairing.G1Point k;
}
function verifyingKey() pure internal returns (VerifyingKey memory vk) {
vk.a = Pairing.G2Point(<%vk_a%>);
@ -215,7 +214,7 @@ const CONTRACT_TEMPLATE_V2: &str = r#"contract Verifier {
function verifyTx(
Proof memory proof<%input_argument%>
) public view returns (bool r) {
uint[] memory inputValues = new uint[](input.length);
uint[] memory inputValues = new uint[](<%vk_input_length%>);
<%input_loop%>
if (verify(inputValues, proof) == 0) {
return true;
@ -245,8 +244,8 @@ const CONTRACT_TEMPLATE: &str = r#"contract Verifier {
Pairing.G1Point b_p;
Pairing.G1Point c;
Pairing.G1Point c_p;
Pairing.G1Point k;
Pairing.G1Point h;
Pairing.G1Point k;
}
function verifyingKey() pure internal returns (VerifyingKey memory vk) {
vk.a = Pairing.G2Point(<%vk_a%>);
@ -304,7 +303,7 @@ const CONTRACT_TEMPLATE: &str = r#"contract Verifier {
proof.c_p = Pairing.G1Point(c_p[0], c_p[1]);
proof.h = Pairing.G1Point(h[0], h[1]);
proof.k = Pairing.G1Point(k[0], k[1]);
uint[] memory inputValues = new uint[](input.length);
uint[] memory inputValues = new uint[](<%vk_input_length%>);
<%input_loop%>
if (verify(inputValues, proof) == 0) {
return true;

View file

@ -436,10 +436,10 @@ library Pairing {
/// @return the generator of G2
function P2() pure internal returns (G2Point memory) {
return G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930]
[10857046999023057135944570762232829481370756359578518086990519993285655852781,
11559732032986387107991004021392285783925812861821192530917403151452391805634],
[8495653923123431417604973247489272438418190587263600148770280649306958101930,
4082367875863433681332203403145435568316851327593401208105741076214120093531]
);
}
/// @return the negation of p, i.e. p.addition(p.negate()) should be zero.
@ -467,7 +467,7 @@ library Pairing {
}
/// @return r the sum of two points of G2
function addition(G2Point memory p1, G2Point memory p2) internal view returns (G2Point memory r) {
(r.X[1], r.X[0], r.Y[1], r.Y[0]) = BN256G2.ECTwistAdd(p1.X[1],p1.X[0],p1.Y[1],p1.Y[0],p2.X[1],p2.X[0],p2.Y[1],p2.Y[0]);
(r.X[0], r.X[1], r.Y[0], r.Y[1]) = BN256G2.ECTwistAdd(p1.X[0],p1.X[1],p1.Y[0],p1.Y[1],p2.X[0],p2.X[1],p2.Y[0],p2.Y[1]);
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
@ -497,10 +497,10 @@ library Pairing {
{
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
input[i * 6 + 2] = p2[i].X[1];
input[i * 6 + 3] = p2[i].X[0];
input[i * 6 + 4] = p2[i].Y[1];
input[i * 6 + 5] = p2[i].Y[0];
}
uint[1] memory out;
bool success;
@ -584,10 +584,10 @@ library Pairing {
/// @return the generator of G2
function P2() pure internal returns (G2Point memory) {
return G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930]
[10857046999023057135944570762232829481370756359578518086990519993285655852781,
11559732032986387107991004021392285783925812861821192530917403151452391805634],
[8495653923123431417604973247489272438418190587263600148770280649306958101930,
4082367875863433681332203403145435568316851327593401208105741076214120093531]
);
}
/// @return the negation of p, i.e. p.addition(p.negate()) should be zero.
@ -615,7 +615,7 @@ library Pairing {
}
/// @return r the sum of two points of G2
function addition(G2Point memory p1, G2Point memory p2) internal view returns (G2Point memory r) {
(r.X[1], r.X[0], r.Y[1], r.Y[0]) = BN256G2.ECTwistAdd(p1.X[1],p1.X[0],p1.Y[1],p1.Y[0],p2.X[1],p2.X[0],p2.Y[1],p2.Y[0]);
(r.X[0], r.X[1], r.Y[0], r.Y[1]) = BN256G2.ECTwistAdd(p1.X[0],p1.X[1],p1.Y[0],p1.Y[1],p2.X[0],p2.X[1],p2.Y[0],p2.Y[1]);
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
@ -645,10 +645,10 @@ library Pairing {
{
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
input[i * 6 + 2] = p2[i].X[1];
input[i * 6 + 3] = p2[i].X[0];
input[i * 6 + 4] = p2[i].Y[1];
input[i * 6 + 5] = p2[i].Y[0];
}
uint[1] memory out;
bool success;

View file

@ -33,7 +33,6 @@ impl<T: Field + ZexeFieldExtensions + NotBw6_761Field> Backend<T, GM17> for Zexe
.iter()
.map(|g1| parse_g1::<T>(g1))
.collect(),
raw: None,
};
SetupKeypair::new(vk, pk)
@ -64,7 +63,7 @@ impl<T: Field + ZexeFieldExtensions + NotBw6_761Field> Backend<T, GM17> for Zexe
.map(parse_fr::<T>)
.collect::<Vec<_>>();
Proof::new(proof_points, inputs, None)
Proof::new(proof_points, inputs)
}
fn verify(
@ -128,7 +127,6 @@ impl Backend<Bw6_761Field, GM17> for Zexe {
.iter()
.map(|g1| parse_g1::<Bw6_761Field>(g1))
.collect(),
raw: None,
};
SetupKeypair::new(vk, pk)
@ -159,7 +157,7 @@ impl Backend<Bw6_761Field, GM17> for Zexe {
.map(parse_fr::<Bw6_761Field>)
.collect::<Vec<_>>();
Proof::new(proof_points, inputs, None)
Proof::new(proof_points, inputs)
}
fn verify(