libsnark
libsnark copied to clipboard
gadgetlib2 to r1cs_constraint_system conversion issue
Hi
I am playing with gadgetlib2 and have a weird issue: after converting it to an r1cs constraint system, the is_valid() function returns false.
The demo is using the Comparison_Gadget to compare two numbers (5 <=5`):
#include <iostream>
#include <gadgetlib2/gadget.hpp>
#include <gadgetlib2/integration.hpp>
using namespace libsnark;
int main() {
typedef Fr<default_ec_pp> FieldT;
gadgetlib2::initPublicParamsFromDefaultPp();
auto pb = gadgetlib2::Protoboard::create(gadgetlib2::R1P);
size_t size = 100;
const gadgetlib2::PackedWord lhs;
const gadgetlib2::PackedWord rhs;
const gadgetlib2::FlagVariable less;
const gadgetlib2::FlagVariable lessOrEqual;
auto g = gadgetlib2::Comparison_Gadget::create(pb, 3, lhs, rhs, less, lessOrEqual);
g->generateConstraints();
pb->val(lhs) = 5;
pb->val(rhs) = 5;
g->generateWitness();
assert(pb->isSatisfied());
assert(pb->val(less) == 0);
assert(pb->val(lessOrEqual) == 1);
// translate constraint system to libsnark format.
r1cs_constraint_system<FieldT> cs = get_constraint_system_from_gadgetlib2(*pb);
// translate full variable assignment to libsnark format
const r1cs_variable_assignment<FieldT> full_assignment = get_variable_assignment_from_gadgetlib2(*pb);
// extract primary and auxiliary input
const r1cs_primary_input<FieldT> primary_input(full_assignment.begin(), full_assignment.begin() + cs.num_inputs());
const r1cs_auxiliary_input<FieldT> auxiliary_input(full_assignment.begin() + cs.num_inputs(), full_assignment.end());
assert(cs.is_satisfied(primary_input, auxiliary_input));
assert(cs.is_valid()); // FAILS
}
(The Makefile I used to compile the above is here: https://github.com/benma/libsnark/blob/6be0121cbeedefc2bffd4b89e7ef268a7da90efe/link_example/Makefile)
g++ main.cpp -o main -std=c++11 -L./lib -lsnark -lsupercop -lgmp -lgmpxx -I./include -I./include/libsnark -DCURVE_BN128
LD_LIBRARY_PATH=./lib ./main
main: main.cpp:35: int main(): Assertion `cs.is_valid()' failed.
Aborted (core dumped)
Even though the protoboard behaves correctly (see the three asserts after g->generateWitness();), the derived r1cs system is invalid. Interestingly, cs.is_satisfied also behaves as expected.
I am not sure whether I did something wrong in the setup / conversion, or if there is a bug in get_constraint_system_from_gadgetlib2 or in the implementation of is_valid().
The same happens if I try to convert the first example of the gadgetlib2 tutorial (https://github.com/scipr-lab/libsnark/blob/e2c8bf06c7cbec7b5e2c6134d6dabd4573382bfd/src/gadgetlib2/examples/tutorial.cpp#L46-L82).
It doesn't happen this example: https://github.com/scipr-lab/libsnark/blob/e2c8bf06c7cbec7b5e2c6134d6dabd4573382bfd/src/gadgetlib2/examples/simple_example.cpp#L50
I'd appreciate any hints.
Similarly, if you add assert(pb.get_constraint_system().is_valid()); here:
https://github.com/scipr-lab/libsnark/blob/e2c8bf06c7cbec7b5e2c6134d6dabd4573382bfd/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp#L39
The test will fail.
I encountered this bug during my testing too, iirc I debugged as far as determining that there is an off-by-one error when checking the number of variables (although I don't know where).
This isn't an issue for most of the built-in examples, as they will often assign too many variables. A somewhat sketchy workaround is to just assign a dummy variable, and don't use it. (Or just don't call is_valid)