scipr-lab / libsnark

C++ library for zkSNARKs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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?