From 52ac37a7b1ac8c4cd090923db4615fb31cb00c3d Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Mon, 10 Jun 2024 14:11:58 -0500 Subject: [PATCH 1/2] fix: fixes #1157 ensures calls to AttachDebugInfo are surrounded with compile time check on debug.Debug --- debug_test.go | 3 ++ frontend/cs/r1cs/api.go | 13 ++++--- frontend/cs/r1cs/api_assertions.go | 13 +++---- frontend/cs/scs/api_assertions.go | 60 +++++++++++++++++++++--------- 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/debug_test.go b/debug_test.go index e171942779..0b1548e66f 100644 --- a/debug_test.go +++ b/debug_test.go @@ -78,6 +78,9 @@ func (circuit *divBy0Trace) Define(api frontend.API) error { } func TestTraceDivBy0(t *testing.T) { + if !debug.Debug { + t.Skip("skipping test in non debug mode") + } assert := require.New(t) var circuit, witness divBy0Trace diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 958741632d..a23665fbb8 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -294,12 +294,14 @@ func (builder *builder) Div(i1, i2 frontend.Variable) frontend.Variable { if !v2Constant { res := builder.newInternalVariable() - debug := builder.newDebugInfo("div", v1, "/", v2, " == ", res) v2Inv := builder.newInternalVariable() // note that here we ensure that v2 can't be 0, but it costs us one extra constraint c1 := builder.cs.AddR1C(builder.newR1C(v2, v2Inv, builder.cstOne()), builder.genericGate) c2 := builder.cs.AddR1C(builder.newR1C(v1, v2Inv, res), builder.genericGate) - builder.cs.AttachDebugInfo(debug, []int{c1, c2}) + if debug.Debug { + debug := builder.newDebugInfo("div", v1, "/", v2, " == ", res) + builder.cs.AttachDebugInfo(debug, []int{c1, c2}) + } return res } @@ -542,8 +544,6 @@ func (builder *builder) IsZero(i1 frontend.Variable) frontend.Variable { return builder.cstZero() } - debug := builder.newDebugInfo("isZero", a) - // x = 1/a // in a hint (x == 0 if a == 0) // m = -a*x + 1 // constrain m to be 1 if a == 0 // a * m = 0 // constrain m to be 0 if a != 0 @@ -563,7 +563,10 @@ func (builder *builder) IsZero(i1 frontend.Variable) frontend.Variable { // a * m = 0 // constrain m to be 0 if a != 0 c2 := builder.cs.AddR1C(builder.newR1C(a, m, builder.cstZero()), builder.genericGate) - builder.cs.AttachDebugInfo(debug, []int{c1, c2}) + if debug.Debug { + debug := builder.newDebugInfo("isZero", a) + builder.cs.AttachDebugInfo(debug, []int{c1, c2}) + } builder.MarkBoolean(m) diff --git a/frontend/cs/r1cs/api_assertions.go b/frontend/cs/r1cs/api_assertions.go index 530a5fe412..0fdc72be3c 100644 --- a/frontend/cs/r1cs/api_assertions.go +++ b/frontend/cs/r1cs/api_assertions.go @@ -132,8 +132,6 @@ func (builder *builder) mustBeLessOrEqVar(a, bound frontend.Variable) { _, aConst := builder.constantValue(a) - debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) - nbBits := builder.cs.FieldBitLen() aBits := bits.ToBinary(builder, a, bits.WithNbDigits(nbBits), bits.WithUnconstrainedOutputs(), bits.OmitModulusCheck()) @@ -179,7 +177,10 @@ func (builder *builder) mustBeLessOrEqVar(a, bound frontend.Variable) { } } - builder.cs.AttachDebugInfo(debug, added) + if debug.Debug { + debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) + builder.cs.AttachDebugInfo(debug, added) + } } @@ -204,9 +205,6 @@ func (builder *builder) MustBeLessOrEqCst(aBits []frontend.Variable, bound *big. panic("AssertIsLessOrEqual: bound is too large, constraint will never be satisfied") } - // debug info - debug := builder.newDebugInfo("mustBeLessOrEq", aForDebug, " <= ", builder.toVariable(bound)) - // t trailing bits in the bound t := 0 for i := 0; i < nbBits; i++ { @@ -243,7 +241,8 @@ func (builder *builder) MustBeLessOrEqCst(aBits []frontend.Variable, bound *big. } } - if len(added) != 0 { + if debug.Debug && len(added) != 0 { + debug := builder.newDebugInfo("mustBeLessOrEq", aForDebug, " <= ", builder.toVariable(bound)) builder.cs.AttachDebugInfo(debug, added) } } diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 3fe9ef1d9a..1b59b3d34d 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -183,7 +183,7 @@ func (builder *builder) AssertIsLessOrEqual(v frontend.Variable, bound frontend. func (builder *builder) mustBeLessOrEqVar(a frontend.Variable, bound expr.Term) { - debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) + debugInfo := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) nbBits := builder.cs.FieldBitLen() @@ -216,17 +216,34 @@ func (builder *builder) mustBeLessOrEqVar(a frontend.Variable, bound expr.Term) if ai, ok := builder.constantValue(aBits[i]); ok { // a is constant; ensure l == 0 l.Coeff = builder.cs.Mul(l.Coeff, ai) - builder.addPlonkConstraint(sparseR1C{ - xa: l.VID, - qL: l.Coeff, - }, debug) + if debug.Debug { + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + qL: l.Coeff, + }, debugInfo) + } else { + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + qL: l.Coeff, + }) + } + } else { // l * a[i] == 0 - builder.addPlonkConstraint(sparseR1C{ - xa: l.VID, - xb: aBits[i].(expr.Term).VID, - qM: l.Coeff, - }, debug) + if debug.Debug { + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + xb: aBits[i].(expr.Term).VID, + qM: l.Coeff, + }, debugInfo) + } else { + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + xb: aBits[i].(expr.Term).VID, + qM: l.Coeff, + }) + } + } } @@ -254,8 +271,8 @@ func (builder *builder) MustBeLessOrEqCst(aBits []frontend.Variable, bound *big. panic("AssertIsLessOrEqual: bound is too large, constraint will never be satisfied") } - // debug info - debug := builder.newDebugInfo("mustBeLessOrEq", aForDebug, " <= ", bound) + // debugInfo info + debugInfo := builder.newDebugInfo("mustBeLessOrEq", aForDebug, " <= ", bound) // t trailing bits in the bound t := 0 @@ -285,11 +302,20 @@ func (builder *builder) MustBeLessOrEqCst(aBits []frontend.Variable, bound *big. l := builder.Sub(1, p[i+1], aBits[i]).(expr.Term) //l = builder.Sub(l, ).(term) - builder.addPlonkConstraint(sparseR1C{ - xa: l.VID, - xb: aBits[i].(expr.Term).VID, - qM: builder.tOne, - }, debug) + if debug.Debug { + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + xb: aBits[i].(expr.Term).VID, + qM: builder.tOne, + }, debugInfo) + } else { + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + xb: aBits[i].(expr.Term).VID, + qM: builder.tOne, + }) + } + } else { builder.AssertIsBoolean(aBits[i]) } From 7974b3d6fcafee8cab59737079f82ff248904330 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 11 Jun 2024 09:28:28 -0500 Subject: [PATCH 2/2] fix: apply PR suggested diff --- frontend/cs/scs/api_assertions.go | 66 +++++++++++-------------------- 1 file changed, 23 insertions(+), 43 deletions(-) diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 1b59b3d34d..56ba022157 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -20,6 +20,7 @@ import ( "fmt" "math/big" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" @@ -182,8 +183,10 @@ func (builder *builder) AssertIsLessOrEqual(v frontend.Variable, bound frontend. } func (builder *builder) mustBeLessOrEqVar(a frontend.Variable, bound expr.Term) { - - debugInfo := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) + var debugInfo []constraint.DebugInfo + if debug.Debug { + debugInfo = []constraint.DebugInfo{builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound)} + } nbBits := builder.cs.FieldBitLen() @@ -216,34 +219,17 @@ func (builder *builder) mustBeLessOrEqVar(a frontend.Variable, bound expr.Term) if ai, ok := builder.constantValue(aBits[i]); ok { // a is constant; ensure l == 0 l.Coeff = builder.cs.Mul(l.Coeff, ai) - if debug.Debug { - builder.addPlonkConstraint(sparseR1C{ - xa: l.VID, - qL: l.Coeff, - }, debugInfo) - } else { - builder.addPlonkConstraint(sparseR1C{ - xa: l.VID, - qL: l.Coeff, - }) - } - + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + qL: l.Coeff, + }, debugInfo...) } else { // l * a[i] == 0 - if debug.Debug { - builder.addPlonkConstraint(sparseR1C{ - xa: l.VID, - xb: aBits[i].(expr.Term).VID, - qM: l.Coeff, - }, debugInfo) - } else { - builder.addPlonkConstraint(sparseR1C{ - xa: l.VID, - xb: aBits[i].(expr.Term).VID, - qM: l.Coeff, - }) - } - + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + xb: aBits[i].(expr.Term).VID, + qM: l.Coeff, + }, debugInfo...) } } @@ -272,7 +258,10 @@ func (builder *builder) MustBeLessOrEqCst(aBits []frontend.Variable, bound *big. } // debugInfo info - debugInfo := builder.newDebugInfo("mustBeLessOrEq", aForDebug, " <= ", bound) + var debugInfo []constraint.DebugInfo + if debug.Debug { + debugInfo = []constraint.DebugInfo{builder.newDebugInfo("mustBeLessOrEq", aForDebug, " <= ", bound)} + } // t trailing bits in the bound t := 0 @@ -302,20 +291,11 @@ func (builder *builder) MustBeLessOrEqCst(aBits []frontend.Variable, bound *big. l := builder.Sub(1, p[i+1], aBits[i]).(expr.Term) //l = builder.Sub(l, ).(term) - if debug.Debug { - builder.addPlonkConstraint(sparseR1C{ - xa: l.VID, - xb: aBits[i].(expr.Term).VID, - qM: builder.tOne, - }, debugInfo) - } else { - builder.addPlonkConstraint(sparseR1C{ - xa: l.VID, - xb: aBits[i].(expr.Term).VID, - qM: builder.tOne, - }) - } - + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + xb: aBits[i].(expr.Term).VID, + qM: builder.tOne, + }, debugInfo...) } else { builder.AssertIsBoolean(aBits[i]) }