Skip to content

Commit

Permalink
perf/fix: assume variable as zero constant when subtracting from itse…
Browse files Browse the repository at this point in the history
…lf (#1089)

* test: add test case for no-op subtraction

* fix: mark value as constant when coefficient zero

* test: add expected constant equality assertion

* perf: direct equality check for constants

* fix: return constant zero if coeff zero

* fix: test assert to zero
  • Loading branch information
ivokub authored Mar 22, 2024
1 parent 9bb4153 commit 6fed1e2
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 1 deletion.
9 changes: 9 additions & 0 deletions frontend/cs/r1cs/api_assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ import (

// AssertIsEqual adds an assertion in the constraint builder (i1 == i2)
func (builder *builder) AssertIsEqual(i1, i2 frontend.Variable) {
c1, i1Constant := builder.constantValue(i1)
c2, i2Constant := builder.constantValue(i2)

if i1Constant && i2Constant {
if c1 != c2 {
panic("non-equal constant values")
}
return
}
// encoded 1 * i1 == i2
r := builder.getLinearExpression(builder.toVariable(i1))
o := builder.getLinearExpression(builder.toVariable(i2))
Expand Down
3 changes: 3 additions & 0 deletions frontend/cs/r1cs/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,9 @@ func (builder *builder) constantValue(v frontend.Variable) (constraint.Element,
// and are always reduced to one element. may not always be true?
return constraint.Element{}, false
}
if _v[0].Coeff.IsZero() {
return constraint.Element{}, true
}
if !(_v[0].WireID() == 0) { // public ONE WIRE
return constraint.Element{}, false
}
Expand Down
20 changes: 20 additions & 0 deletions frontend/cs/r1cs/r1cs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,23 @@ func TestPreCompileHook(t *testing.T) {
t.Error("callback not called")
}
}

type subSameNoConstraintCircuit struct {
A frontend.Variable
}

func (c *subSameNoConstraintCircuit) Define(api frontend.API) error {
r := api.Sub(c.A, c.A)
api.AssertIsEqual(r, 0)
return nil
}

func TestSubSameNoConstraint(t *testing.T) {
ccs, err := frontend.Compile(ecc.BN254.ScalarField(), NewBuilder, &subSameNoConstraintCircuit{})
if err != nil {
t.Fatal(err)
}
if ccs.GetNbConstraints() != 0 {
t.Fatal("expected 0 constraints")
}
}
19 changes: 19 additions & 0 deletions frontend/cs/scs/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,22 @@ func TestMulAccFastTrack(t *testing.T) {
assert.NoError(err)
_ = solution
}

type subSameNoConstraintCircuit struct {
A frontend.Variable
}

func (c *subSameNoConstraintCircuit) Define(api frontend.API) error {
r := api.Sub(c.A, c.A)
api.AssertIsEqual(r, 0)
return nil
}

func TestSubSameNoConstraint(t *testing.T) {
assert := test.NewAssert(t)
ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &subSameNoConstraintCircuit{})
assert.NoError(err)
if ccs.GetNbConstraints() != 0 {
t.Fatal("expected 0 constraints")
}
}
5 changes: 4 additions & 1 deletion frontend/cs/scs/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,10 @@ func (builder *builder) ConstantValue(v frontend.Variable) (*big.Int, bool) {
}

func (builder *builder) constantValue(v frontend.Variable) (constraint.Element, bool) {
if _, ok := v.(expr.Term); ok {
if vv, ok := v.(expr.Term); ok {
if vv.Coeff.IsZero() {
return constraint.Element{}, true
}
return constraint.Element{}, false
}
return builder.cs.FromInterface(v), true
Expand Down

0 comments on commit 6fed1e2

Please sign in to comment.