Skip to content

Commit

Permalink
Add Bindings for bacs ppzksnark (OpenMined#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
gargarchit committed Aug 14, 2020
1 parent 618f552 commit 92ec4b6
Show file tree
Hide file tree
Showing 5 changed files with 353 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ set(
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/zk_proof_systems/ppzksnark/r1cs_se_ppzksnark/run_r1cs_se_ppzksnark.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/run_r1cs_gg_ppzksnark.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/zk_proof_systems/ppzksnark/bacs_ppzksnark/run_bacs_ppzksnark.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/binding.cpp"
)

Expand Down
4 changes: 4 additions & 0 deletions src/PyZPK/binding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ void init_zk_proof_systems_ppzksnark_r1cs_se_ppzksnark_r1cs_se_ppzksnark(py::mod
void init_zk_proof_systems_ppzksnark_r1cs_se_ppzksnark_run_r1cs_se_ppzksnark(py::module &);
void init_zk_proof_systems_ppzksnark_r1cs_gg_ppzksnark_r1cs_gg_ppzksnark(py::module &);
void init_zk_proof_systems_ppzksnark_r1cs_gg_ppzksnark_run_r1cs_gg_ppzksnark(py::module &);
void init_zk_proof_systems_ppzksnark_bacs_ppzksnark_bacs_ppzksnark(py::module &);
void init_zk_proof_systems_ppzksnark_bacs_ppzksnark_run_bacs_ppzksnark(py::module &);

PYBIND11_MODULE(pyzpk, m)
{
Expand Down Expand Up @@ -186,4 +188,6 @@ PYBIND11_MODULE(pyzpk, m)
init_zk_proof_systems_ppzksnark_r1cs_se_ppzksnark_run_r1cs_se_ppzksnark(m);
init_zk_proof_systems_ppzksnark_r1cs_gg_ppzksnark_r1cs_gg_ppzksnark(m);
init_zk_proof_systems_ppzksnark_r1cs_gg_ppzksnark_run_r1cs_gg_ppzksnark(m);
init_zk_proof_systems_ppzksnark_bacs_ppzksnark_bacs_ppzksnark(m);
init_zk_proof_systems_ppzksnark_bacs_ppzksnark_run_bacs_ppzksnark(m);
}
276 changes: 276 additions & 0 deletions src/PyZPK/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <libsnark/common/default_types/bacs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.hpp>
namespace py = pybind11;
using namespace libsnark;
using namespace libff;

// Interfaces for a ppzkSNARK for BACS.

// This includes:
// - class for proving key
// - class for verification key
// - class for processed verification key
// - class for key pair (proving key & verification key)
// - class for proof
// - generator algorithm
// - prover algorithm
// - verifier algorithm (with strong or weak input consistency)
// - online verifier algorithm (with strong or weak input consistency)
// The implementation is a straightforward combination of:
// (1) a BACS-to-R1CS reduction, and
// (2) a ppzkSNARK for R1CS.

void declare_bacs_ppzksnark_proving_key(py::module &m)
{
// A proving key for the BACS ppzkSNARK.
using ppT = default_bacs_ppzksnark_pp;

py::class_<bacs_ppzksnark_proving_key<ppT>>(m, "bacs_ppzksnark_proving_key")
.def(py::init<>())
.def(py::init<const bacs_ppzksnark_proving_key<ppT> &>())
.def(py::init<const bacs_ppzksnark_circuit<ppT> &,
const r1cs_ppzksnark_proving_key<ppT> &>())
.def("G1_size", &bacs_ppzksnark_proving_key<ppT>::G1_size)
.def("G2_size", &bacs_ppzksnark_proving_key<ppT>::G2_size)
.def("G1_sparse_size", &bacs_ppzksnark_proving_key<ppT>::G1_sparse_size)
.def("G2_sparse_size", &bacs_ppzksnark_proving_key<ppT>::G2_sparse_size)
.def("size_in_bits", &bacs_ppzksnark_proving_key<ppT>::size_in_bits)
.def("print_size", &bacs_ppzksnark_proving_key<ppT>::print_size)
.def(
"__eq__", [](bacs_ppzksnark_proving_key<ppT> const &self, bacs_ppzksnark_proving_key<ppT> const &other) { return self == other; }, py::is_operator())
.def("__ostr__", [](bacs_ppzksnark_proving_key<ppT> const &pk) {
std::ostringstream os;
os << pk.circuit << OUTPUT_NEWLINE;
os << pk.r1cs_pk << OUTPUT_NEWLINE;
return os;
})
.def("__istr__", [](bacs_ppzksnark_proving_key<ppT> &pk) {
std::istringstream in;
in >> pk.circuit;
libff::consume_OUTPUT_NEWLINE(in);
in >> pk.r1cs_pk;
libff::consume_OUTPUT_NEWLINE(in);
return in;
});
}

void declare_bacs_ppzksnark_verification_key(py::module &m)
{
// A verification key for the BACS ppzkSNARK.
using ppT = default_bacs_ppzksnark_pp;

py::class_<r1cs_ppzksnark_verification_key<ppT>>(m, "bacs_ppzksnark_verification_key")
.def(py::init<>())
.def(py::init<const libff::G2<ppT> &,
const libff::G1<ppT> &,
const libff::G2<ppT> &,
const libff::G2<ppT> &,
const libff::G1<ppT> &,
const libff::G2<ppT> &,
const libff::G2<ppT> &,
const accumulation_vector<libff::G1<ppT>> &>())
.def_readwrite("alphaA_g2", &r1cs_ppzksnark_verification_key<ppT>::alphaA_g2)
.def_readwrite("alphaB_g1", &r1cs_ppzksnark_verification_key<ppT>::alphaB_g1)
.def_readwrite("alphaC_g2", &r1cs_ppzksnark_verification_key<ppT>::alphaC_g2)
.def_readwrite("gamma_g2", &r1cs_ppzksnark_verification_key<ppT>::gamma_g2)
.def_readwrite("gamma_beta_g1", &r1cs_ppzksnark_verification_key<ppT>::gamma_beta_g1)
.def_readwrite("gamma_beta_g2", &r1cs_ppzksnark_verification_key<ppT>::gamma_beta_g2)
.def_readwrite("rC_Z_g2", &r1cs_ppzksnark_verification_key<ppT>::rC_Z_g2)
.def("G1_size", &r1cs_ppzksnark_verification_key<ppT>::G1_size)
.def("G2_size", &r1cs_ppzksnark_verification_key<ppT>::G2_size)
.def("size_in_bits", &r1cs_ppzksnark_verification_key<ppT>::size_in_bits)
.def("print_size", &r1cs_ppzksnark_verification_key<ppT>::print_size)
.def_static("dummy_verification_key", &r1cs_ppzksnark_verification_key<ppT>::dummy_verification_key)
.def(
"__eq__", [](r1cs_ppzksnark_verification_key<ppT> const &self, r1cs_ppzksnark_verification_key<ppT> const &other) { return self == other; }, py::is_operator())
.def("__ostr__", [](r1cs_ppzksnark_verification_key<ppT> const &self) {
std::ostringstream os;
os << self.alphaA_g2 << OUTPUT_NEWLINE;
os << self.alphaB_g1 << OUTPUT_NEWLINE;
os << self.alphaC_g2 << OUTPUT_NEWLINE;
os << self.gamma_g2 << OUTPUT_NEWLINE;
os << self.gamma_beta_g1 << OUTPUT_NEWLINE;
os << self.gamma_beta_g2 << OUTPUT_NEWLINE;
os << self.rC_Z_g2 << OUTPUT_NEWLINE;
os << self.encoded_IC_query << OUTPUT_NEWLINE;
return os;
})
.def("__istr__", [](r1cs_ppzksnark_verification_key<ppT> &self) {
std::istringstream in;
in >> self.alphaA_g2;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.alphaB_g1;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.alphaC_g2;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.gamma_g2;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.gamma_beta_g1;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.gamma_beta_g2;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.rC_Z_g2;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.encoded_IC_query;
libff::consume_OUTPUT_NEWLINE(in);
return in;
});
}

void declare_bacs_ppzksnark_processed_verification_key(py::module &m)
{
// A verification key for the BACS ppzkSNARK.
using ppT = default_bacs_ppzksnark_pp;

py::class_<r1cs_ppzksnark_processed_verification_key<ppT>>(m, "bacs_ppzksnark_processed_verification_key")
.def(py::init<>())
.def_readwrite("pp_G2_one_precomp", &r1cs_ppzksnark_processed_verification_key<ppT>::pp_G2_one_precomp)
.def_readwrite("vk_alphaA_g2_precomp", &r1cs_ppzksnark_processed_verification_key<ppT>::vk_alphaA_g2_precomp)
.def_readwrite("vk_alphaB_g1_precomp", &r1cs_ppzksnark_processed_verification_key<ppT>::vk_alphaB_g1_precomp)
.def_readwrite("vk_alphaC_g2_precomp", &r1cs_ppzksnark_processed_verification_key<ppT>::vk_alphaC_g2_precomp)
.def_readwrite("vk_rC_Z_g2_precomp", &r1cs_ppzksnark_processed_verification_key<ppT>::vk_rC_Z_g2_precomp)
.def_readwrite("vk_gamma_g2_precomp", &r1cs_ppzksnark_processed_verification_key<ppT>::vk_gamma_g2_precomp)
.def_readwrite("vk_gamma_beta_g1_precomp", &r1cs_ppzksnark_processed_verification_key<ppT>::vk_gamma_beta_g1_precomp)
.def_readwrite("vk_gamma_beta_g2_precomp", &r1cs_ppzksnark_processed_verification_key<ppT>::vk_gamma_beta_g2_precomp)
.def_readwrite("encoded_IC_query", &r1cs_ppzksnark_processed_verification_key<ppT>::encoded_IC_query)
.def(
"__eq__", [](r1cs_ppzksnark_processed_verification_key<ppT> const &self, r1cs_ppzksnark_processed_verification_key<ppT> const &other) { return self == other; }, py::is_operator())
.def("__ostr__", [](r1cs_ppzksnark_processed_verification_key<ppT> const &self) {
std::ostringstream os;
os << self.pp_G2_one_precomp << OUTPUT_NEWLINE;
os << self.vk_alphaA_g2_precomp << OUTPUT_NEWLINE;
os << self.vk_alphaB_g1_precomp << OUTPUT_NEWLINE;
os << self.vk_alphaC_g2_precomp << OUTPUT_NEWLINE;
os << self.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE;
os << self.vk_gamma_g2_precomp << OUTPUT_NEWLINE;
os << self.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE;
os << self.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE;
os << self.encoded_IC_query << OUTPUT_NEWLINE;
return os;
})
.def("__istr__", [](r1cs_ppzksnark_processed_verification_key<ppT> &self) {
std::istringstream in;
in >> self.pp_G2_one_precomp;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.vk_alphaA_g2_precomp;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.vk_alphaB_g1_precomp;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.vk_alphaC_g2_precomp;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.vk_rC_Z_g2_precomp;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.vk_gamma_g2_precomp;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.vk_gamma_beta_g1_precomp;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.vk_gamma_beta_g2_precomp;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.encoded_IC_query;
libff::consume_OUTPUT_NEWLINE(in);
return in;
});
}

void declare_bacs_ppzksnark_keypair(py::module &m)
{
// A key pair for the BACS ppzkSNARK, which consists of a proving key and a verification key.
using ppT = default_bacs_ppzksnark_pp;

py::class_<bacs_ppzksnark_keypair<ppT>>(m, "bacs_ppzksnark_keypair")
.def(py::init<>())
.def(py::init<const bacs_ppzksnark_proving_key<ppT> &,
const bacs_ppzksnark_verification_key<ppT> &>());
}

void declare_bacs_ppzksnark_proof(py::module &m)
{
// A verification key for the BACS ppzkSNARK.
using ppT = default_bacs_ppzksnark_pp;

py::class_<r1cs_ppzksnark_proof<ppT>>(m, "bacs_ppzksnark_proof")
.def(py::init<>())
.def_readwrite("g_A", &r1cs_ppzksnark_proof<ppT>::g_A)
.def_readwrite("g_B", &r1cs_ppzksnark_proof<ppT>::g_B)
.def_readwrite("g_C", &r1cs_ppzksnark_proof<ppT>::g_C)
.def_readwrite("g_H", &r1cs_ppzksnark_proof<ppT>::g_H)
.def_readwrite("g_K", &r1cs_ppzksnark_proof<ppT>::g_K)
.def("G1_size", &r1cs_ppzksnark_proof<ppT>::G1_size)
.def("G2_size", &r1cs_ppzksnark_proof<ppT>::G2_size)
.def("size_in_bits", &r1cs_ppzksnark_proof<ppT>::size_in_bits)
.def("print_size", &r1cs_ppzksnark_proof<ppT>::print_size)
.def("is_well_formed", &r1cs_ppzksnark_proof<ppT>::is_well_formed)
.def(
"__eq__", [](r1cs_ppzksnark_proof<ppT> const &self, r1cs_ppzksnark_proof<ppT> const &other) { return self == other; }, py::is_operator())
.def("__ostr__", [](r1cs_ppzksnark_proof<ppT> const &self) {
std::ostringstream os;
os << self.g_A << OUTPUT_NEWLINE;
os << self.g_B << OUTPUT_NEWLINE;
os << self.g_C << OUTPUT_NEWLINE;
os << self.g_H << OUTPUT_NEWLINE;
os << self.g_K << OUTPUT_NEWLINE;
return os;
})
.def("__istr__", [](r1cs_ppzksnark_proof<ppT> &self) {
std::istringstream in;
in >> self.g_A;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.g_B;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.g_C;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.g_H;
libff::consume_OUTPUT_NEWLINE(in);
in >> self.g_K;
libff::consume_OUTPUT_NEWLINE(in);
return in;
});
}

void declare_BACS_Main_Algorithms(py::module &m)
{
using ppT = default_bacs_ppzksnark_pp;

// A generator algorithm for the R1CS GG-ppzkSNARK.
// Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS.
m.def("bacs_ppzksnark_generator", &bacs_ppzksnark_generator<ppT>);

// A prover algorithm for the BACS ppzkSNARK.
m.def("bacs_ppzksnark_prover", &bacs_ppzksnark_prover<ppT>);

// A verifier algorithm for the BACS ppzkSNARK that:
//(1) accepts a non-processed verification key, and
//(2) has weak input consistency.
m.def("bacs_ppzksnark_verifier_weak_IC", &bacs_ppzksnark_verifier_weak_IC<ppT>);

// A verifier algorithm for the BACS ppzkSNARK that:
//(1) accepts a non-processed verification key, and
//(2) has strong input consistency.
m.def("bacs_ppzksnark_verifier_strong_IC", &bacs_ppzksnark_verifier_strong_IC<ppT>);

// Convert a (non-processed) verification key into a processed verification key.
m.def("bacs_ppzksnark_verifier_process_vk", &bacs_ppzksnark_verifier_process_vk<ppT>);

// A verifier algorithm for the BACS ppzkSNARK that:
//(1) accepts a processed verification key, and
//(2) has weak input consistency.
m.def("bacs_ppzksnark_online_verifier_weak_IC", &bacs_ppzksnark_online_verifier_weak_IC<ppT>);

// A verifier algorithm for the BACS ppzkSNARK that:
//(1) accepts a processed verification key, and
//(2) has strong input consistency.
m.def("bacs_ppzksnark_online_verifier_strong_IC", &bacs_ppzksnark_online_verifier_strong_IC<ppT>);
}

void init_zk_proof_systems_ppzksnark_bacs_ppzksnark_bacs_ppzksnark(py::module &m)
{
declare_bacs_ppzksnark_proving_key(m);
declare_bacs_ppzksnark_verification_key(m);
declare_bacs_ppzksnark_processed_verification_key(m);
declare_bacs_ppzksnark_keypair(m);
declare_bacs_ppzksnark_proof(m);
declare_BACS_Main_Algorithms(m);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <libsnark/common/default_types/bacs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp>
namespace py = pybind11;
using namespace libsnark;
using namespace libff;

// Declaration of functionality that runs the BACS ppzkSNARK for
// a given BACS example.
void init_zk_proof_systems_ppzksnark_bacs_ppzksnark_run_bacs_ppzksnark(py::module &m)
{
// Runs the ppzkSNARK (generator, prover, and verifier) for a given
// BACS example (specified by a circuit, primary input, and auxiliary input).

using ppT = default_bacs_ppzksnark_pp;
m.def("run_bacs_ppzksnark", &run_bacs_ppzksnark<ppT>);
}
53 changes: 52 additions & 1 deletion test/test_zk_proof_systems.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,55 @@ def test_se_and_gg_ppzksnark():
input_size = 100
test_serialization = True
example = pyzpk.generate_r1cs_example_with_binary_input(num_constraints, input_size)
assert(example)
assert(example)

def test_bacs_ppzksnark():
primary_input_size = 10
auxiliary_input_size = 10
num_gates = 20
num_outputs = 5
test_serialization = True
example = pyzpk.bacs_example()
primary_input_list = list()
auxiliary_input_list = list()
for i in range(0, primary_input_size):
primary_input_list.append(pyzpk.Fp_model4bn.random_element())
for i in range(0, auxiliary_input_size):
auxiliary_input_list.append(pyzpk.Fp_model4bn.random_element())

example.circuit.primary_input_size = primary_input_size
example.circuit.auxiliary_input_size = auxiliary_input_size

all_vals = list()
all_vals.extend(primary_input_list)
all_vals.extend(auxiliary_input_list)
all_vals.extend(all_vals)
for i in range(0, num_gates):
num_variables = primary_input_size + auxiliary_input_size + i
gate = pyzpk.bacs_gate()
gate.lhs = pyzpk.random_linear_combination(num_variables)
gate.rhs = pyzpk.random_linear_combination(num_variables)
gate.output = pyzpk.variable(num_variables+1)
if(i >= num_gates - num_outputs):
gate.is_circuit_output = True
var_idx = random.randint(
0, (primary_input_size + auxiliary_input_size))
var_val = pyzpk.Fp_model.one(
) if var_idx == 0 else all_vals[var_idx-1]
if random.randint(0, (primary_input_size + auxiliary_input_size)) % 2 == 0:
lhs_val = gate.lhs.evaluate(all_vals)
coeff = -(lhs_val * var_val.inverse())
gate.lhs = gate.lhs + coeff * pyzpk.variable(var_idx)
else:
rhs_val = gate.rhs.evaluate(all_vals)
coeff = -(rhs_val * var_val.inverse())
gate.rhs = gate.rhs + coeff * pyzpk.variable(var_idx)
assert(gate.evaluate(all_vals).is_zero())
else:
gate.is_circuit_output = False
example.circuit.add_gate(gate)
evl_val = gate.evaluate(all_vals)
all_vals.append(evl_val)

assert example.circuit.is_satisfied(
primary_input_list, auxiliary_input_list)

0 comments on commit 92ec4b6

Please sign in to comment.