From 14816d5d35c958db8301cbb8fd391b0ba54c8e0e Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 30 Jan 2024 13:57:29 +0100 Subject: [PATCH 1/2] fix: use subtraction with reduce in AssertIsEqual To show that two field elements are equal, we instead show that the difference of the field elements is a multiple of emulated modulus. However, for computing the difference we used non-reducing version of subtraction to avoid infinite cycles. With the new mulmod implementation the reducing versions do not call AssertIsEqual anymore so the infinite cycles are averted. For some edge cases the difference may overflow scalar field and solving may fail. --- std/math/emulated/field_assert.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/math/emulated/field_assert.go b/std/math/emulated/field_assert.go index ce6d5dbf9c..692db8ef2e 100644 --- a/std/math/emulated/field_assert.go +++ b/std/math/emulated/field_assert.go @@ -128,7 +128,7 @@ func (f *Field[T]) AssertIsEqual(a, b *Element[T]) { return } - diff := f.subNoReduce(b, a) + diff := f.Sub(b, a) // we compute k such that diff / p == k // so essentially, we say "I know an element k such that k*p == diff" From 78a756435ce116707825f8c8384f78176e218e7a Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 30 Jan 2024 17:58:34 +0100 Subject: [PATCH 2/2] test: add regression test --- std/math/emulated/regression_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/std/math/emulated/regression_test.go b/std/math/emulated/regression_test.go index daff5822b0..440cbc00aa 100644 --- a/std/math/emulated/regression_test.go +++ b/std/math/emulated/regression_test.go @@ -94,3 +94,27 @@ func TestIssue867Division(t *testing.T) { } test.IsSolved(&testIssue867Circuit{A: ac, B: bc}, &testIssue867Circuit{A: a, B: b}, ecc.BLS12_381.ScalarField()) } + +type testIssue1021Circuit struct { + A Element[BN254Fp] +} + +func (c *testIssue1021Circuit) Define(api frontend.API) error { + f, err := NewField[BN254Fp](api) + if err != nil { + return err + } + b := f.NewElement(c.A) + p := f.Modulus() + for i := 0; i < 188; i++ { + b = f.Add(b, p) + } + f.AssertIsEqual(b, &c.A) + return nil +} + +func TestIssue1021(t *testing.T) { + assert := test.NewAssert(t) + err := test.IsSolved(&testIssue1021Circuit{}, &testIssue1021Circuit{A: ValueOf[BN254Fp](10)}, ecc.BN254.ScalarField()) + assert.NoError(err) +}