Bug in r1cs is_valid() check
johannes-reinhart opened this issue · comments
bool r1cs_constraint_system::is_valid() returns false for correct setups.
Minimal Example:
#include <libff/common/default_types/ec_pp.hpp>
#include <libsnark/gadgetlib1/protoboard.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp>
typedef libff::default_ec_pp ExampleEllipticCurve;
typedef libff::Fr<ExampleEllipticCurve> ExampleFieldType;
int main() {
libsnark::protoboard<ExampleFieldType> pb;
libsnark::pb_variable<ExampleFieldType> a;
libsnark::pb_variable<ExampleFieldType> b;
libsnark::pb_variable<ExampleFieldType> c;
a.allocate(pb, "a");
b.allocate(pb, "b");
c.allocate(pb, "c");
pb.add_r1cs_constraint(libsnark::r1cs_constraint<ExampleFieldType>(a, b, c), "a*b=c");
libsnark::r1cs_constraint_system<ExampleFieldType> cs = pb.get_constraint_system();
assert(cs.is_valid());
}
Expected behaviour: cs.is_valid() returns true
Observed behaviour: cs.is_valid() returns false
I think the issue is in libsnark/relations/variable.tcc, in
bool linear_combination<FieldT>::is_valid(const size_t num_variables) const
...
if ((--terms.end())->index >= num_variables)
which checks the largest index used. It should probably be
if ((--terms.end())->index > num_variables)
to account for the additional row representing ONE in the constraint system.
Additionally in libsnark/gadgetlib2/gadget.cpp
R1P_InnerProduct_Gadget::R1P_InnerProduct_Gadget(ProtoboardPtr pb,
const VariableArray& A,
const VariableArray& B,
const Variable& result) : Gadget(pb), InnerProduct_GadgetBase(pb), R1P_Gadget(pb), partialSums_(A.size(), "partialSums"), A_(A), B_(B), result_(result)
Should initialize partialSums with size A.size() - 1, as the last element is never used within the constraints. This was probably the reason, that the assert(cs.is_valid) in libsnark/gadgetlib2/examples/simple_example.cpp never triggered.
Do you agree?