Skip to content

Commit

Permalink
Add Bindings for SSP, USCS and Test for SSP (#49)
Browse files Browse the repository at this point in the history
* Fix bug while generating random_element

* Add Binding for Square Arithmetic Program

* Add Binding for USCS

* Add USCS examples

* Add test for SSP
  • Loading branch information
gargarchit authored Jun 16, 2020
1 parent d2c873b commit 533a6fb
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 11 deletions.
3 changes: 3 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ set(
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/common/default_types/tinyram_ppzksnark_pp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/relations/constraint_satisfaction_problems/r1cs/r1cs.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/relations/constraint_satisfaction_problems/r1cs/r1cs_examples.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/relations/constraint_satisfaction_problems/uscs/uscs.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/relations/constraint_satisfaction_problems/uscs/uscs_examples.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/relations/arithmetic_programs/qap.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/relations/arithmetic_programs/sap.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/relations/arithmetic_programs/ssp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/reductions/r1cs_to_qap.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/binding.cpp"
)
Expand Down
8 changes: 7 additions & 1 deletion src/PyZPK/binding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ void init_default_types_r1cs_ppzkpcd_pp(py::module &);
void init_default_types_tinyram_ppzksnark_pp(py::module &);
void init_relations_constraint_satisfaction_problems_r1cs(py::module &);
void init_relations_constraint_satisfaction_problems_r1cs_examples(py::module &);
void init_relations_constraint_satisfaction_problems_uscs(py::module &);
void init_relations_constraint_satisfaction_problems_uscs_examples(py::module &);
void init_relations_arithmetic_programs_qap(py::module &);
void init_relations_arithmetic_programs_sap(py::module &);
void init_relations_arithmetic_programs_ssp(py::module &);
void init_reductions_r1cs_to_qap(py::module &);

PYBIND11_MODULE(pyzpk, m)
{
m.doc() = "Python wrapper for open source Zero Proof Knowledge Library";

init_utils_Fp_model(m);
init_data_structures_integer_permutation(m);
init_data_structures_set_commitment(m);
Expand All @@ -27,7 +30,10 @@ PYBIND11_MODULE(pyzpk, m)
init_default_types_tinyram_ppzksnark_pp(m);
init_relations_constraint_satisfaction_problems_r1cs(m);
init_relations_constraint_satisfaction_problems_r1cs_examples(m);
init_relations_constraint_satisfaction_problems_uscs(m);
init_relations_constraint_satisfaction_problems_uscs_examples(m);
init_relations_arithmetic_programs_qap(m);
init_relations_arithmetic_programs_sap(m);
init_relations_arithmetic_programs_ssp(m);
init_reductions_r1cs_to_qap(m);
}
2 changes: 0 additions & 2 deletions src/PyZPK/relations/arithmetic_programs/sap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,4 @@ void init_relations_arithmetic_programs_sap(py::module &m)
.def("num_variables", &sap_witness<FieldT>::num_variables)
.def("degree", &sap_witness<FieldT>::degree)
.def("num_inputs", &sap_witness<FieldT>::num_inputs);

m.attr("mnt6_Fr_s") = 17;
}
80 changes: 80 additions & 0 deletions src/PyZPK/relations/arithmetic_programs/ssp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include <pybind11/pybind11.h>
#include <pybind11/operators.h>
#include <pybind11/stl.h>
#include <libff/algebra/curves/mnt/mnt6/mnt6_pp.hpp>
#include <libff/algebra/fields/field_utils.hpp>
#include <libff/algebra/scalar_multiplication/multiexp.hpp>
#include <libff/common/profiling.hpp>
#include <libff/common/utils.hpp>
#include <libfqfft/evaluation_domain/evaluation_domain.hpp>
#include <map>
#include <memory>
#include <libsnark/relations/arithmetic_programs/ssp/ssp.hpp>

using namespace std;
namespace py = pybind11;
using namespace libsnark;
using namespace libff;

// Implementation of interfaces for a SSP ("Square Span Program").
void init_relations_arithmetic_programs_ssp(py::module &m)
{
using FieldT = Fp_model<5l, libff::mnt46_modulus_B>;
// A SSP instance.
py::class_<ssp_instance<FieldT>>(m, "ssp_instance")
.def(py::init<const std::shared_ptr<libfqfft::evaluation_domain<FieldT>> &,
const size_t,
const size_t,
const size_t,
const std::vector<std::map<size_t, FieldT>> &>())
.def(py::init<const std::shared_ptr<libfqfft::evaluation_domain<FieldT>> &,
const size_t,
const size_t,
const size_t,
std::vector<std::map<size_t, FieldT>> &>())
.def("num_variables", &ssp_instance<FieldT>::num_variables)
.def("degree", &ssp_instance<FieldT>::degree)
.def("num_inputs", &ssp_instance<FieldT>::num_inputs)
.def("is_satisfied", &ssp_instance<FieldT>::is_satisfied, py::arg("witness"));

// A SSP instance evaluation is a SSP instance that is evaluated at a field element t.
py::class_<ssp_instance_evaluation<FieldT>>(m, "ssp_instance_evaluation")
.def(py::init<const std::shared_ptr<libfqfft::evaluation_domain<FieldT>> &,
const size_t,
const size_t,
const size_t,
const FieldT &,
const std::vector<FieldT> &,
const std::vector<FieldT> &,
const FieldT &>())
.def(py::init<const std::shared_ptr<libfqfft::evaluation_domain<FieldT>> &,
const size_t,
const size_t,
const size_t,
const FieldT &,
std::vector<FieldT> &&,
std::vector<FieldT> &&,
const FieldT &>())
.def("num_variables", &ssp_instance_evaluation<FieldT>::num_variables)
.def("degree", &ssp_instance_evaluation<FieldT>::degree)
.def("num_inputs", &ssp_instance_evaluation<FieldT>::num_inputs)
.def("is_satisfied", &ssp_instance_evaluation<FieldT>::is_satisfied, py::arg("witness"));

//A SSP witness.
py::class_<ssp_witness<FieldT>>(m, "ssp_witness")
.def(py::init<const size_t,
const size_t,
const size_t,
const FieldT &,
const std::vector<FieldT> &,
const std::vector<FieldT> &>())
.def(py::init<const size_t,
const size_t,
const size_t,
const FieldT &,
const std::vector<FieldT> &,
std::vector<FieldT> &>())
.def("num_variables", &ssp_witness<FieldT>::num_variables)
.def("degree", &ssp_witness<FieldT>::degree)
.def("num_inputs", &ssp_witness<FieldT>::num_inputs);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <libff/algebra/scalar_multiplication/multiexp.hpp>
#include <libff/common/profiling.hpp>
#include <libff/common/utils.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp>

using namespace std;
Expand Down
77 changes: 77 additions & 0 deletions src/PyZPK/relations/constraint_satisfaction_problems/uscs/uscs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <pybind11/cast.h>
#include <pybind11/complex.h>
#include <pybind11/functional.h>
#include <pybind11/chrono.h>
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <libff/algebra/fields/bigint.hpp>
#include <libff/algebra/curves/mnt/mnt6/mnt6_pp.hpp>
#include <libff/algebra/fields/field_utils.hpp>
#include <libff/algebra/scalar_multiplication/multiexp.hpp>
#include <libff/common/profiling.hpp>
#include <libff/common/utils.hpp>
#include <libsnark/relations/variable.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/uscs/uscs.hpp>

using namespace std;
namespace py = pybind11;
using namespace libsnark;
using namespace libff;

// Interfaces for a USCS constraint, a USCS variable assignment, and a USCS constraint system.
// USCS stands for "Unitary-Square Constraint System".
void init_relations_constraint_satisfaction_problems_uscs(py::module &m)
{
using FieldT = Fp_model<5l, libff::mnt46_modulus_B>;
py::class_<uscs_constraint_system<FieldT>>(m, "uscs_constraint_system")
.def(py::init<>())
.def_readwrite("primary_input_size", &uscs_constraint_system<FieldT>::primary_input_size)
.def_readwrite("auxiliary_input_size", &uscs_constraint_system<FieldT>::auxiliary_input_size)
.def_readwrite("constraints", &uscs_constraint_system<FieldT>::constraints)
.def("num_inputs", &uscs_constraint_system<FieldT>::num_inputs)
.def("num_variables", &uscs_constraint_system<FieldT>::num_variables)
.def("num_constraints", &uscs_constraint_system<FieldT>::num_constraints)
// .def("is_valid", &uscs_constraint_system<FieldT>::is_valid)
// valid_vector was not declared in this scope of libsnark
.def("add_constraint", (void (uscs_constraint_system<FieldT>::*)(const uscs_constraint<FieldT> &)) & uscs_constraint_system<FieldT>::add_constraint, py::arg("constraint"))
.def("add_constraint", (void (uscs_constraint_system<FieldT>::*)(const uscs_constraint<FieldT> &, const std::string &)) & uscs_constraint_system<FieldT>::add_constraint, py::arg("constraint"), py::arg("annotation"))
.def("is_satisfied", &uscs_constraint_system<FieldT>::is_satisfied, py::arg("primary_input"), py::arg("auxiliary_input"))
.def(
"__eq__", [](uscs_constraint_system<FieldT> const &self, uscs_constraint_system<FieldT> const &other) { return self == other; }, py::is_operator())
.def("report_linear_constraint_statistics", &uscs_constraint_system<FieldT>::report_linear_constraint_statistics)
.def("__ostr__", [](uscs_constraint_system<FieldT> const &self) {
std::ostringstream os;
os << self.primary_input_size << "\n";
os << self.auxiliary_input_size << "\n";
os << self.num_constraints() << "\n";
for (const uscs_constraint<FieldT> &c : self.constraints)
{
os << c;
}
return os;
})
.def("__istr__", [](uscs_constraint_system<FieldT> &self) {
std::istringstream os;
os >> self.primary_input_size;
os >> self.auxiliary_input_size;
self.constraints.clear();
size_t s;
os >> s;
char b;
os.read(&b, 1);
self.constraints.reserve(s);
for (size_t i = 0; i < s; ++i)
{
uscs_constraint<FieldT> c;
os >> c;
self.constraints.emplace_back(c);
}
return os;
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <pybind11/cast.h>
#include <pybind11/complex.h>
#include <vector>
#include <cassert>
#include <libff/algebra/curves/mnt/mnt6/mnt6_pp.hpp>
#include <libff/algebra/fields/field_utils.hpp>
#include <libff/algebra/scalar_multiplication/multiexp.hpp>
#include <libff/common/profiling.hpp>
#include <libff/common/utils.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/uscs/uscs.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp>

using namespace std;
namespace py = pybind11;
using namespace libsnark;
using namespace libff;

// Declaration of interfaces for a USCS example, as well as functions to sample
// USCS examples with prescribed parameters
void init_relations_constraint_satisfaction_problems_uscs_examples(py::module &m)
{
using FieldT = Fp_model<5l, libff::mnt46_modulus_B>;
py::class_<uscs_example<FieldT>>(m, "uscs_example")
.def(py::init<const uscs_constraint_system<FieldT> &,
const uscs_primary_input<FieldT> &,
const uscs_auxiliary_input<FieldT> &>())
.def_readwrite("constraint_system", &uscs_example<FieldT>::constraint_system)
.def_readwrite("primary_input", &uscs_example<FieldT>::primary_input)
.def_readwrite("auxiliary_input", &uscs_example<FieldT>::auxiliary_input);

m.def("generate_uscs_example_with_field_input", &generate_uscs_example_with_field_input<FieldT>, py::arg("num_constraints"), py::arg("num_inputs"));
m.def("generate_uscs_example_with_binary_input", &generate_uscs_example_with_binary_input<FieldT>, py::arg("num_constraints"), py::arg("num_inputs"));
}
22 changes: 18 additions & 4 deletions src/PyZPK/utils/Fp_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <pybind11/stl_bind.h>
#include <pybind11/cast.h>
#include <pybind11/complex.h>
#include <pybind11/operators.h>
#include <vector>
#include <cassert>
#include <cmath>
Expand Down Expand Up @@ -38,19 +39,32 @@ void init_utils_Fp_model(py::module &m)
py::class_<bigint<5l>>(m, "bigint")
.def(py::init<>())
.def(py::init<const unsigned long>())
.def(py::init<const char*>())
.def(py::init<const char *>())
.def("test_bit", &bigint<5l>::test_bit)
.def("randomize", &bigint<5l>::randomize);

py::class_<mnt6_pp>(m, "mnt6_pp");

// Implementation of arithmetic in the finite field F[p], for prime p of fixed length.
py::class_<Fp_model<5l, libff::mnt46_modulus_B>>(m, "Fp_model")
.def(py::init<>())
.def(py::init<const bigint<5l> &>())
.def(py::init<const long, const bool>())
.def_readwrite("mont_repr", &Fp_model<5l, libff::mnt46_modulus_B>::mont_repr)
.def("random_element", &Fp_model<5l, libff::mnt46_modulus_B>::random_element) // Todo
// .def_static("random_element", &Fp_model<5l, libff::mnt46_modulus_B>::random_element) // Todo
.def_static("random_element", []() {
Fp_model<5l, mnt46_modulus_B> r;
while (mpn_cmp(r.mont_repr.data, mnt46_modulus_B.data, 5l))
{
size_t bitno = GMP_NUMB_BITS * 5 - 1;
while (mnt46_modulus_B.test_bit(bitno) == false)
{
const size_t part = bitno / GMP_NUMB_BITS;
const size_t bit = bitno - (GMP_NUMB_BITS * part);
r.mont_repr.data[part] &= ~(1ul << bit);
bitno--;
}
}
return r;
})
.def("inverse", &Fp_model<5l, libff::mnt46_modulus_B>::inverse);

}
42 changes: 38 additions & 4 deletions test/test_relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,16 @@ def test_qap(qap_degree, num_inputs, binary_input):
assert num_inputs + 1 <= qap_degree
num_constraints = qap_degree - num_inputs - 1
# For Binary input
example = pyzpk.generate_r1cs_example_with_binary_input(
num_constraints, num_inputs)
if binary_input:
example = pyzpk.generate_r1cs_example_with_binary_input(
num_constraints, num_inputs)

assert example.constraint_system.is_satisfied(
example.primary_input, example.auxiliary_input)
t = pyzpk.Fp_model.random_element()
d1 = pyzpk.Fp_model.random_element()
d2 = pyzpk.Fp_model.random_element()
d3 = pyzpk.Fp_model.random_element()

# Test for SAP
@pytest.mark.parametrize("sap_degree, num_inputs, binary_input",
Expand All @@ -37,7 +43,35 @@ def test_sap(sap_degree, num_inputs, binary_input):
num_constraints = int((sap_degree - 1) / 2) - num_inputs
assert num_constraints >= 1
# For Binary input
example = pyzpk.generate_r1cs_example_with_binary_input(
num_constraints, num_inputs)
if binary_input:
example = pyzpk.generate_r1cs_example_with_binary_input(
num_constraints, num_inputs)
assert example.constraint_system.is_satisfied(
example.primary_input, example.auxiliary_input)
t = pyzpk.Fp_model.random_element()
d1 = pyzpk.Fp_model.random_element()
d2 = pyzpk.Fp_model.random_element()
d3 = pyzpk.Fp_model.random_element()

# Test for SSP
@pytest.mark.parametrize("num_constraints, num_inputs, binary_input",
[
# basic_domain_size
(1 << pyzpk.mnt6_Fr_s, 10, True),
# step_domain_size
((1 << 10) + (1 << 8), 10, True),
# extended_domain_size
(1 << (pyzpk.mnt6_Fr_s+1), 10, True),
# extended_domain_size_special
((1 << (pyzpk.mnt6_Fr_s+1))-1, 10, True)
])
def test_ssp(num_constraints, num_inputs, binary_input):
# For Binary input
if binary_input:
example = pyzpk.generate_uscs_example_with_binary_input(
num_constraints, num_inputs)

assert example.constraint_system.is_satisfied(
example.primary_input, example.auxiliary_input)
t = pyzpk.Fp_model.random_element()
d1 = pyzpk.Fp_model.random_element()

0 comments on commit 533a6fb

Please sign in to comment.