gnark is a fast zk-SNARK library that offers a high-level API to design circuits. The library is open source and developed under the Apache 2.0 license
After creating a new instance of Rangechecker by using rangecheck.New(api), calling Check function using this instance passes even when the input bits is 1 less than the actual bit-length of v when bits is odd.
Expected Behavior
Check should fail
Actual Behavior
Check passes, implying v has bit-length bits
Steps to Reproduce
import (
"testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/std/rangecheck"
"github.com/consensys/gnark/test"
)
type TestRangeCheckCircuit struct {
I1 frontend.Variable
N int
}
func (circuit *TestRangeCheckCircuit) Define(api frontend.API) error {
rangeChecker := rangecheck.New(api)
rangeChecker.Check(circuit.I1, circuit.N)
return nil
}
func TestRangeCheck_Odd(t *testing.T) {
assert := test.NewAssert(t)
type testData struct {
i1 uint64
n int
}
tests := []testData{}
for i := 128; i < 256; i++ { //[128, 256) all have bit-length 8
tests = append(tests, testData{i1: uint64(i), n: 7})
}
for _, t_i := range tests {
circuit := TestRangeCheckCircuit{
N: t_i.n,
}
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
if err != nil {
t.Fatal("Error in compiling circuit: ", err)
}
var witness TestRangeCheckCircuit
witness.I1 = t_i.i1
w, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField())
if err != nil {
t.Fatal("Error in witness: ", err, "\n test: ", t_i)
}
err = r1cs.IsSolved(w)
if err != nil {
t.Fatal("Circuit not solved: ", err, "\n test: ", t_i)
}
assert.CheckCircuit(&circuit, test.WithValidAssignment(&witness), test.WithCurves(ecc.BN254))
}
}
func TestRangeCheck_Even(t *testing.T) {
assert := test.NewAssert(t)
type testData struct {
i1 uint64
n int
}
tests := []testData{}
for i := 64; i < 128; i++ { //[64, 128) all have bit-length 7
tests = append(tests, testData{i1: uint64(i), n: 6})
}
for _, t_i := range tests {
circuit := TestRangeCheckCircuit{
N: t_i.n,
}
r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
if err != nil {
t.Fatal("Error in compiling circuit: ", err)
}
var witness TestRangeCheckCircuit
witness.I1 = t_i.i1
w, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField())
if err != nil {
t.Fatal("Error in witness: ", err, "\n test: ", t_i)
}
err = r1cs.IsSolved(w)
if err != nil {
t.Fatal("Circuit not solved: ", err, "\n test: ", t_i)
}
assert.CheckCircuit(&circuit, test.WithValidAssignment(&witness), test.WithCurves(ecc.BN254))
}
}
TestRangeCheck_Odd output: okTestRangeCheck_Even output: Circuit not solved: constraint #0 is not satisfied: 1 ⋅ 0 != 64 test: {64 6}
Your Environment
gnark version used: v0.9.1
gnark-crypto version used: v0.12.2-0.20231013160410-1f65e75b6dfb
Description
After creating a new instance of
Rangechecker
by usingrangecheck.New(api)
, callingCheck
function using this instance passes even when the inputbits
is 1 less than the actual bit-length ofv
whenbits
is odd.Expected Behavior
Check
should failActual Behavior
Check
passes, implyingv
has bit-lengthbits
Steps to Reproduce
TestRangeCheck_Odd
output:ok
TestRangeCheck_Even
output:Circuit not solved: constraint #0 is not satisfied: 1 ⋅ 0 != 64 test: {64 6}
Your Environment