diff --git a/examples/test.py b/examples/test.py deleted file mode 100644 index 6a7f5f8..0000000 --- a/examples/test.py +++ /dev/null @@ -1 +0,0 @@ -import PyZPK.main \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 29459f4..3309a7e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,14 +1,17 @@ set( SRC + "${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/utils/Fp_model.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/common/data_structures/integer_permutation.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/common/data_structures/set_commitment.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/common/routing_algorithms/benes_routing_algorithm.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/common/routing_algorithms/as_waksman_routing_algorithm.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/common/default_types/r1cs_ppzkpcd_pp.cpp" "${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/arithmetic_programs/qap.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/relations/arithmetic_programs/sap.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/reductions/r1cs_to_qap.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/PyZPK/binding.cpp" ) diff --git a/src/PyZPK/binding.cpp b/src/PyZPK/binding.cpp index 73973ed..0ab31ee 100644 --- a/src/PyZPK/binding.cpp +++ b/src/PyZPK/binding.cpp @@ -1,27 +1,33 @@ #include namespace py = pybind11; +void init_utils_Fp_model(py::module &); void init_data_structures_integer_permutation(py::module &); void init_data_structures_set_commitment(py::module &); void init_algorithms_benes(py::module &); void init_algorithms_as_waksman(py::module &); 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_arithmetic_programs_qap(py::module &); void init_relations_arithmetic_programs_sap(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); init_algorithms_benes(m); init_algorithms_as_waksman(m); init_default_types_r1cs_ppzkpcd_pp(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_arithmetic_programs_qap(m); init_relations_arithmetic_programs_sap(m); + init_reductions_r1cs_to_qap(m); } \ No newline at end of file diff --git a/src/PyZPK/reductions/r1cs_to_qap.cpp b/src/PyZPK/reductions/r1cs_to_qap.cpp new file mode 100644 index 0000000..bdf9474 --- /dev/null +++ b/src/PyZPK/reductions/r1cs_to_qap.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +namespace py = pybind11; +using namespace libsnark; +using namespace libff; + +// Implementation of interfaces for a R1CS-to-QAP reduction. +void init_reductions_r1cs_to_qap(py::module &m) +{ + using FieldT = Fp_model<5l, libff::mnt46_modulus_B>; + + // Instance map for the R1CS-to-QAP reduction. + m.def("r1cs_to_qap_instance_map", &r1cs_to_qap_instance_map, py::arg("cs")); + + // Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance. + m.def("r1cs_to_qap_instance_map_with_evaluation", &r1cs_to_qap_instance_map_with_evaluation, + py::arg("cs"), py::arg("t")); + + // Witness map for the R1CS-to-QAP reduction. + // The witness map takes zero knowledge into account when d1,d2,d3 are random. + m.def("r1cs_to_qap_witness_map", &r1cs_to_qap_witness_map, + py::arg("cs"), py::arg("primary_input"), py::arg("auxiliary_input"), + py::arg("d1"), py::arg("d2"), py::arg("d3")); +} \ No newline at end of file diff --git a/src/PyZPK/relations/arithmetic_programs/qap.cpp b/src/PyZPK/relations/arithmetic_programs/qap.cpp index 85678e2..30ea585 100644 --- a/src/PyZPK/relations/arithmetic_programs/qap.cpp +++ b/src/PyZPK/relations/arithmetic_programs/qap.cpp @@ -8,15 +8,16 @@ #include #include #include -#define FieldT libff::Fr using namespace std; namespace py = pybind11; using namespace libsnark; +using namespace libff; // Implementation of interfaces for a QAP ("Quadratic Arithmetic Program"). void init_relations_arithmetic_programs_qap(py::module &m) { + using FieldT = Fp_model<5l, libff::mnt46_modulus_B>; // A QAP instance. py::class_>(m, "qap_instance") .def(py::init> &, diff --git a/src/PyZPK/relations/arithmetic_programs/sap.cpp b/src/PyZPK/relations/arithmetic_programs/sap.cpp index 567ef31..de78dde 100644 --- a/src/PyZPK/relations/arithmetic_programs/sap.cpp +++ b/src/PyZPK/relations/arithmetic_programs/sap.cpp @@ -8,15 +8,16 @@ #include #include #include -#define FieldT libff::Fr using namespace std; namespace py = pybind11; using namespace libsnark; +using namespace libff; // Implementation of interfaces for a SAP ("Square Arithmetic Program"). void init_relations_arithmetic_programs_sap(py::module &m) { + using FieldT = Fp_model<5l, libff::mnt46_modulus_B>; // A SAP instance. py::class_>(m, "sap_instance") .def(py::init> &, diff --git a/src/PyZPK/relations/constraint_satisfaction_problems/r1cs/r1cs.cpp b/src/PyZPK/relations/constraint_satisfaction_problems/r1cs/r1cs.cpp new file mode 100644 index 0000000..ad7f96b --- /dev/null +++ b/src/PyZPK/relations/constraint_satisfaction_problems/r1cs/r1cs.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +namespace py = pybind11; +using namespace libsnark; +using namespace libff; + +// Interfaces for a R1CS constraint, a R1CS variable assignment, and a R1CS constraint system. +void init_relations_constraint_satisfaction_problems_r1cs(py::module &m) +{ + using FieldT = Fp_model<5l, libff::mnt46_modulus_B>; + py::class_>(m, "r1cs_constraint") + .def(py::init<>()) + .def_readwrite("a", &r1cs_constraint::a) + .def_readwrite("b", &r1cs_constraint::b) + .def_readwrite("c", &r1cs_constraint::c) + .def(py::init &, + const linear_combination &, + const linear_combination &>()) + .def(py::init> &, + const std::initializer_list> &, + const std::initializer_list> &>()) + .def( + "__eq__", [](r1cs_constraint const &self, r1cs_constraint const &other) { return self == other; }, py::is_operator()) + .def("__ostr__", [](r1cs_constraint const &self) { + std::ostringstream os; + os << self.a << "\n"; + os << self.b << "\n"; + os << self.c << "\n"; + return os; + }) + .def("__istr__", [](r1cs_constraint &self) { + std::istringstream os; + os >> self.a; + os >> self.b; + os >> self.c; + return os; + }); + + py::class_>(m, "r1cs_constraint_system") + .def(py::init<>()) + .def_readwrite("primary_input_size", &r1cs_constraint_system::primary_input_size) + .def_readwrite("auxiliary_input_size", &r1cs_constraint_system::auxiliary_input_size) + .def_readwrite("constraints", &r1cs_constraint_system::constraints) + .def("num_inputs", &r1cs_constraint_system::num_inputs) + .def("num_variables", &r1cs_constraint_system::num_variables) + .def("num_constraints", &r1cs_constraint_system::num_constraints) + .def("is_valid", &r1cs_constraint_system::is_valid) + .def("add_constraint", (void (r1cs_constraint_system::*)(const r1cs_constraint &)) & r1cs_constraint_system::add_constraint, py::arg("c")) + .def("add_constraint", (void (r1cs_constraint_system::*)(const r1cs_constraint &, const std::string &)) & r1cs_constraint_system::add_constraint, py::arg("c"), py::arg("annotation")) + .def("is_satisfied", &r1cs_constraint_system::is_satisfied, py::arg("primary_input"), py::arg("auxiliary_input")) + .def("swap_AB_if_beneficial", &r1cs_constraint_system::swap_AB_if_beneficial) + .def( + "__eq__", [](r1cs_constraint_system const &self, r1cs_constraint_system const &other) { return self == other; }, py::is_operator()) + .def("report_linear_constraint_statistics", &r1cs_constraint_system::report_linear_constraint_statistics) + .def("__ostr__", [](r1cs_constraint_system const &self) { + std::ostringstream os; + os << self.primary_input_size << "\n"; + os << self.auxiliary_input_size << "\n"; + for (const r1cs_constraint &c : self.constraints) + { + os << c; + } + return os; + }) + .def("__istr__", [](r1cs_constraint_system &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) + { + r1cs_constraint c; + os >> c; + self.constraints.emplace_back(c); + } + return os; + }); +} \ No newline at end of file diff --git a/src/PyZPK/relations/constraint_satisfaction_problems/r1cs/r1cs_examples.cpp b/src/PyZPK/relations/constraint_satisfaction_problems/r1cs/r1cs_examples.cpp index 1360361..994a76a 100644 --- a/src/PyZPK/relations/constraint_satisfaction_problems/r1cs/r1cs_examples.cpp +++ b/src/PyZPK/relations/constraint_satisfaction_problems/r1cs/r1cs_examples.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -8,22 +10,18 @@ #include #include #include -#include #include -#define FieldT libff::Fr using namespace std; namespace py = pybind11; using namespace libsnark; +using namespace libff; // Declaration of interfaces for a R1CS example, as well as functions to sample -// R1CS examples with prescribed parameters (according to some distribution). +// R1CS examples with prescribed parameters (according to some distribution) void init_relations_constraint_satisfaction_problems_r1cs_examples(py::module &m) { - py::class_>(m, "r1cs_constraint_system") - .def(py::init<>()) - .def("is_satisfied", &r1cs_constraint_system::is_satisfied); - + using FieldT = Fp_model<5l, libff::mnt46_modulus_B>; py::class_>(m, "r1cs_example") .def(py::init &, const r1cs_primary_input &, @@ -31,7 +29,7 @@ void init_relations_constraint_satisfaction_problems_r1cs_examples(py::module &m .def_readwrite("constraint_system", &r1cs_example::constraint_system) .def_readwrite("primary_input", &r1cs_example::primary_input) .def_readwrite("auxiliary_input", &r1cs_example::auxiliary_input); - + m.def("generate_r1cs_example_with_field_input", &generate_r1cs_example_with_field_input, py::arg("num_constraints"), py::arg("num_inputs")); m.def("generate_r1cs_example_with_binary_input", &generate_r1cs_example_with_binary_input, py::arg("num_constraints"), py::arg("num_inputs")); -} \ No newline at end of file +} diff --git a/src/PyZPK/utils/Fp_model.cpp b/src/PyZPK/utils/Fp_model.cpp new file mode 100644 index 0000000..7867ab4 --- /dev/null +++ b/src/PyZPK/utils/Fp_model.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +namespace py = pybind11; +using namespace libff; + +// Used as FieldT class type +void init_utils_Fp_model(py::module &m) +{ + // bigint wrapper class around GMP's MPZ long integers. + py::class_>(m, "bigint") + .def(py::init<>()) + .def(py::init()) + .def(py::init()) + .def("test_bit", &bigint<5l>::test_bit) + .def("randomize", &bigint<5l>::randomize); + + py::class_(m, "mnt6_pp"); + + // Implementation of arithmetic in the finite field F[p], for prime p of fixed length. + py::class_>(m, "Fp_model") + .def(py::init<>()) + .def(py::init &>()) + .def(py::init()) + .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("inverse", &Fp_model<5l, libff::mnt46_modulus_B>::inverse); + +} \ No newline at end of file diff --git a/test/test_relations.py b/test/test_relations.py new file mode 100644 index 0000000..289fe61 --- /dev/null +++ b/test/test_relations.py @@ -0,0 +1,43 @@ +import pytest +import pyzpk +import math + +# Test for QAP +@pytest.mark.parametrize("qap_degree, 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_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) + assert example.constraint_system.is_satisfied( + example.primary_input, example.auxiliary_input) + +# Test for SAP +@pytest.mark.parametrize("sap_degree, num_inputs, binary_input", + [ + # basic_domain_size_special + ((1 << pyzpk.mnt6_Fr_s) - 1, 10, True), + # # step_domain_size_special + ((1 << 10) + (1 << 8) - 1, 10, True), + # # extended_domain_size_special + (1 << (pyzpk.mnt6_Fr_s+1) - 1, 10, True) + ]) +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) + assert example.constraint_system.is_satisfied( + example.primary_input, example.auxiliary_input) diff --git a/test/test_binding.py b/test/test_routing_algorithms.py similarity index 98% rename from test/test_binding.py rename to test/test_routing_algorithms.py index 20aa064..4b4754e 100644 --- a/test/test_binding.py +++ b/test/test_routing_algorithms.py @@ -59,4 +59,4 @@ def test_data_structures(): # set a number above max_element for idx 5 vec.set(5,10) # Check is_valid permute - assert vec.is_valid() == False + assert vec.is_valid() == False \ No newline at end of file