From 263b4b3e84b3041557cbc1d6e4e60ff77e1a51e7 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 23 Mar 2023 17:42:15 +0000 Subject: [PATCH 01/28] feat: add IsOnCurve to sw_emulated --- std/algebra/emulated/sw_emulated/point.go | 15 ++++++++ .../emulated/sw_emulated/point_test.go | 34 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 414b011de2..c650afd4d3 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -38,6 +38,7 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam }, gm: emuGm, a: emulated.ValueOf[Base](params.A), + b: emulated.ValueOf[Base](params.B), addA: params.A.Cmp(big.NewInt(0)) != 0, }, nil } @@ -60,6 +61,7 @@ type Curve[Base, Scalars emulated.FieldParams] struct { gm []AffinePoint[Base] a emulated.Element[Base] + b emulated.Element[Base] addA bool } @@ -120,6 +122,19 @@ func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { } } +func (c *Curve[B, S]) AssertIsOnCurve(p *AffinePoint[B]) { + // y^2 = x^3+ax+b + left := c.baseApi.Mul(&p.Y, &p.Y) + right := c.baseApi.Mul(&p.X, &p.X) + right = c.baseApi.Mul(right, &p.X) + right = c.baseApi.Add(right, &c.b) + if c.addA { + ax := c.baseApi.Mul(&c.a, &p.X) + right = c.baseApi.Add(right, ax) + } + c.baseApi.AssertIsEqual(left, right) +} + // Double doubles p and return it. It doesn't modify p. // It uses affine coordinates. func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 6703970c1a..11539b046d 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -345,3 +345,37 @@ func TestScalarMul2(t *testing.T) { _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) assert.NoError(err) } + +type IsOnCurveTest[T, S emulated.FieldParams] struct { + Q AffinePoint[T] +} + +func (c *IsOnCurveTest[T, S]) Define(api frontend.API) error { + cr, err := New[T, S](api, GetCurveParams[T]()) + if err != nil { + return err + } + cr.AssertIsOnCurve(&c.Q) + return nil +} + +func TestIsOnCurve(t *testing.T) { + assert := test.NewAssert(t) + _, g := secp256k1.Generators() + var r fr_secp.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var Q secp256k1.G1Affine + Q.ScalarMultiplication(&g, s) + + circuit := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} + witness := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ + Q: AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](Q.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](Q.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} From fc31d311cfb92b3191d69bdc790c78ad197c04cc Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 10:03:25 +0000 Subject: [PATCH 02/28] feat: add IsOnCurve to sw_bn254/g2 --- std/algebra/emulated/sw_bn254/g2.go | 18 +++++++++++++++ std/algebra/emulated/sw_bn254/g2_test.go | 28 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 std/algebra/emulated/sw_bn254/g2_test.go diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 9fd94325c5..3a11c7872f 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -2,6 +2,7 @@ package sw_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" "github.com/consensys/gnark/std/math/emulated" ) @@ -22,3 +23,20 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { }, } } + +func (p *G2Affine) AssertIsOnCurve(api frontend.API) { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := fields_bn254.NewExt2(ba) + + // Y^2 = X^3 + b + // where b = 3/(9+u) + b := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), + A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), + } + left := e.Square(&p.Y) + right := e.Square(&p.X) + right = e.Mul(right, &p.X) + right = e.Add(right, &b) + e.AssertIsEqual(left, right) +} diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go new file mode 100644 index 0000000000..8a04a91381 --- /dev/null +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -0,0 +1,28 @@ +package sw_bn254 + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type IsOnCurveCircuit struct { + Q G2Affine +} + +func (c *IsOnCurveCircuit) Define(api frontend.API) error { + c.Q.AssertIsOnCurve(api) + return nil +} + +func TestIsOnCurve(t *testing.T) { + assert := test.NewAssert(t) + _, q := randomG1G2Affines(assert) + witness := IsOnCurveCircuit{ + Q: NewG2Affine(q), + } + err := test.IsSolved(&IsOnCurveCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From 45394fcb21b8eab46576188d7e6baf1ec24f85a0 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 12:19:49 +0000 Subject: [PATCH 03/28] feat(pairing): check points are on curve and twist --- std/algebra/emulated/sw_bn254/g2.go | 18 ------------ std/algebra/emulated/sw_bn254/g2_test.go | 28 ------------------ std/algebra/emulated/sw_bn254/pairing.go | 29 +++++++++++++++++++ std/algebra/emulated/sw_bn254/pairing_test.go | 14 +++++++++ 4 files changed, 43 insertions(+), 46 deletions(-) delete mode 100644 std/algebra/emulated/sw_bn254/g2_test.go diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 3a11c7872f..9fd94325c5 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -2,7 +2,6 @@ package sw_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" "github.com/consensys/gnark/std/math/emulated" ) @@ -23,20 +22,3 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { }, } } - -func (p *G2Affine) AssertIsOnCurve(api frontend.API) { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := fields_bn254.NewExt2(ba) - - // Y^2 = X^3 + b - // where b = 3/(9+u) - b := fields_bn254.E2{ - A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), - A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), - } - left := e.Square(&p.Y) - right := e.Square(&p.X) - right = e.Mul(right, &p.X) - right = e.Add(right, &b) - e.AssertIsEqual(left, right) -} diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go deleted file mode 100644 index 8a04a91381..0000000000 --- a/std/algebra/emulated/sw_bn254/g2_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package sw_bn254 - -import ( - "testing" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/test" -) - -type IsOnCurveCircuit struct { - Q G2Affine -} - -func (c *IsOnCurveCircuit) Define(api frontend.API) error { - c.Q.AssertIsOnCurve(api) - return nil -} - -func TestIsOnCurve(t *testing.T) { - assert := test.NewAssert(t) - _, q := randomG1G2Affines(assert) - witness := IsOnCurveCircuit{ - Q: NewG2Affine(q), - } - err := test.IsSolved(&IsOnCurveCircuit{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index dfc8b3ac84..c80ad6eb49 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -142,6 +142,29 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext12.AssertIsEqual(x, y) } +func (pr Pairing) AssertIsOnCurve(P *G1Affine) { + // Curve: Y^2 = X^3 + b, where b = 3 + three := emulated.ValueOf[emulated.BN254Fp](3) + left := pr.curveF.Mul(&P.Y, &P.Y) + right := pr.curveF.Mul(&P.X, &P.X) + right = pr.curveF.Mul(right, &P.X) + right = pr.curveF.Add(right, &three) + pr.curveF.AssertIsEqual(left, right) +} + +func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { + // Twist: Y^2 = X^3 + b', where b' = 3/(9+u) + b := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), + A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), + } + left := pr.Ext2.Square(&Q.Y) + right := pr.Ext2.Square(&Q.X) + right = pr.Ext2.Mul(right, &Q.X) + right = pr.Ext2.Add(right, &b) + pr.Ext2.AssertIsEqual(left, right) +} + // loopCounter = 6x₀+2 = 29793968203157093288 // // in 2-NAF @@ -171,6 +194,12 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { return nil, errors.New("invalid inputs sizes") } + // check points are on curve + for k := 0; k < n; k++ { + pr.AssertIsOnCurve(P[k]) + pr.AssertIsOnTwist(Q[k]) + } + res := pr.Ext12.One() var prodLines [5]fields_bn254.E2 diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 7009a2a21f..4cb7ed26fc 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -7,7 +7,10 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -123,3 +126,14 @@ func TestMultiPairTestSolve(t *testing.T) { err = test.IsSolved(&MultiPairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +// bench +var ccsBench constraint.ConstraintSystem + +func BenchmarkPairing(b *testing.B) { + var c PairCircuit + p := profile.Start() + ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) + p.Stop() + fmt.Println(p.NbConstraints()) +} From 52f24650e36d937dedeaec017478ba2828d55d78 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 7 Apr 2023 16:13:04 +0200 Subject: [PATCH 04/28] test: test bls12-381 in sw_emulated + comments --- std/algebra/emulated/sw_bls12381/pairing.go | 23 ++++++++ std/algebra/emulated/sw_bn254/pairing.go | 10 +--- std/algebra/emulated/sw_emulated/params.go | 19 +++++++ .../emulated/sw_emulated/params_compute.go | 27 ++++++++++ std/algebra/emulated/sw_emulated/point.go | 33 +++++++----- .../emulated/sw_emulated/point_test.go | 54 +++++++++++++++++++ std/math/emulated/params.go | 11 ++++ 7 files changed, 156 insertions(+), 21 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 788f6203b1..032453d788 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -227,6 +227,29 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext12.AssertIsEqual(x, y) } +func (pr Pairing) AssertIsOnCurve(P *G1Affine) { + // Curve: Y² == X³ + aX + b, where a=0 and b=4 + four := emulated.ValueOf[emulated.BLS12381Fp](4) + left := pr.curveF.Mul(&P.Y, &P.Y) + right := pr.curveF.Mul(&P.X, &P.X) + right = pr.curveF.Mul(right, &P.X) + right = pr.curveF.Add(right, &four) + pr.curveF.AssertIsEqual(left, right) +} + +func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { + // Twist: Y² == X³ + aX + b, where a=0 and b=4(1+u) + b := fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp]("4"), + A1: emulated.ValueOf[emulated.BLS12381Fp]("4"), + } + left := pr.Ext2.Square(&Q.Y) + right := pr.Ext2.Square(&Q.X) + right = pr.Ext2.Mul(right, &Q.X) + right = pr.Ext2.Add(right, &b) + pr.Ext2.AssertIsEqual(left, right) +} + // loopCounter = seed in binary // // seed=-15132376222941642752 diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 15d7f2f88e..22798fa029 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -233,7 +233,7 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { } func (pr Pairing) AssertIsOnCurve(P *G1Affine) { - // Curve: Y^2 = X^3 + b, where b = 3 + // Curve: Y² == X³ + aX + b, where a=0 and b=3 three := emulated.ValueOf[emulated.BN254Fp](3) left := pr.curveF.Mul(&P.Y, &P.Y) right := pr.curveF.Mul(&P.X, &P.X) @@ -243,7 +243,7 @@ func (pr Pairing) AssertIsOnCurve(P *G1Affine) { } func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { - // Twist: Y^2 = X^3 + b', where b' = 3/(9+u) + // Twist: Y² == X³ + aX + b, where a=0 and b=3/(9+u) b := fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), @@ -284,12 +284,6 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { return nil, errors.New("invalid inputs sizes") } - // check points are on curve - for k := 0; k < n; k++ { - pr.AssertIsOnCurve(P[k]) - pr.AssertIsOnTwist(Q[k]) - } - res := pr.Ext12.One() var prodLines [5]fields_bn254.E2 diff --git a/std/algebra/emulated/sw_emulated/params.go b/std/algebra/emulated/sw_emulated/params.go index b9f00ec707..bb513b6e41 100644 --- a/std/algebra/emulated/sw_emulated/params.go +++ b/std/algebra/emulated/sw_emulated/params.go @@ -3,6 +3,7 @@ package sw_emulated import ( "math/big" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/secp256k1" "github.com/consensys/gnark/std/math/emulated" @@ -50,6 +51,20 @@ func GetBN254Params() CurveParams { } } +// GetBLS12381Params returns the curve parameters for the curve BLS12-381. +// When initialising new curve, use the base field [emulated.BLS12381Fp] and scalar +// field [emulated.BLS12381Fr]. +func GetBLS12381Params() CurveParams { + _, _, g1aff, _ := bls12381.Generators() + return CurveParams{ + A: big.NewInt(0), + B: big.NewInt(4), + Gx: g1aff.X.BigInt(new(big.Int)), + Gy: g1aff.Y.BigInt(new(big.Int)), + Gm: computeBLS12381Table(), + } +} + // GetCurveParams returns suitable curve parameters given the parametric type Base as base field. func GetCurveParams[Base emulated.FieldParams]() CurveParams { var t Base @@ -58,6 +73,8 @@ func GetCurveParams[Base emulated.FieldParams]() CurveParams { return secp256k1Params case "30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47": return bn254Params + case "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab": + return bls12381Params default: panic("no stored parameters") } @@ -66,9 +83,11 @@ func GetCurveParams[Base emulated.FieldParams]() CurveParams { var ( secp256k1Params CurveParams bn254Params CurveParams + bls12381Params CurveParams ) func init() { secp256k1Params = GetSecp256k1Params() bn254Params = GetBN254Params() + bls12381Params = GetBLS12381Params() } diff --git a/std/algebra/emulated/sw_emulated/params_compute.go b/std/algebra/emulated/sw_emulated/params_compute.go index fbdabea300..58d3e26df8 100644 --- a/std/algebra/emulated/sw_emulated/params_compute.go +++ b/std/algebra/emulated/sw_emulated/params_compute.go @@ -3,6 +3,7 @@ package sw_emulated import ( "math/big" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/secp256k1" ) @@ -58,3 +59,29 @@ func computeBN254Table() [][2]*big.Int { } return table } + +func computeBLS12381Table() [][2]*big.Int { + Gjac, _, _, _ := bls12381.Generators() + table := make([][2]*big.Int, 256) + tmp := new(bls12381.G1Jac).Set(&Gjac) + aff := new(bls12381.G1Affine) + jac := new(bls12381.G1Jac) + for i := 1; i < 256; i++ { + tmp = tmp.Double(tmp) + switch i { + case 1, 2: + jac.Set(tmp).AddAssign(&Gjac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + case 3: + jac.Set(tmp).SubAssign(&Gjac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + fallthrough + default: + aff.FromJacobian(tmp) + table[i] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + } + } + return table +} diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index c650afd4d3..511e528825 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -98,6 +98,8 @@ func (c *Curve[B, S]) AssertIsEqual(p, q *AffinePoint[B]) { } // Add adds p and q and returns it. It doesn't modify p nor q. +// This function doesn't check that the p and q are on the curve. See AssertIsOnCurve. +// // It uses incomplete formulas in affine coordinates. // The points p and q should be different and nonzero (neutral element). func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { @@ -122,11 +124,11 @@ func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { } } +// AssertIsOnCurve asserts if p belongs to the curve. It doesn't modify p. func (c *Curve[B, S]) AssertIsOnCurve(p *AffinePoint[B]) { - // y^2 = x^3+ax+b + // Y² == X³ + aX + b left := c.baseApi.Mul(&p.Y, &p.Y) - right := c.baseApi.Mul(&p.X, &p.X) - right = c.baseApi.Mul(right, &p.X) + right := c.baseApi.Mul(&p.X, c.baseApi.Mul(&p.X, &p.X)) right = c.baseApi.Add(right, &c.b) if c.addA { ax := c.baseApi.Mul(&c.a, &p.X) @@ -136,6 +138,8 @@ func (c *Curve[B, S]) AssertIsOnCurve(p *AffinePoint[B]) { } // Double doubles p and return it. It doesn't modify p. +// This function doesn't check that the p is on the curve. See AssertIsOnCurve. +// // It uses affine coordinates. func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { @@ -164,13 +168,14 @@ func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { } } -// Triple triples p and return it. It follows [ELM03] (Section 3.1). -// Saves the computation of the y coordinate of 2p as it is used only in the computation of λ2, -// which can be computed as +// Triple triples p and return it. It doesn't modify p. +// This function doesn't check that the p is on the curve. See AssertIsOnCurve. // -// λ2 = -λ1-2*p.y/(x2-p.x) +// It follows [ELM03] (Section 3.1). This saves the computation of the y +// coordinate of 2p as it is used only in the computation of λ2, which can be +// computed as // -// instead. It doesn't modify p. +// λ2 = -λ1-2*p.y/(x2-p.x) // // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { @@ -211,13 +216,14 @@ func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { } } -// DoubleAndAdd computes 2p+q as (p+q)+p. It follows [ELM03] (Section 3.1) -// Saves the computation of the y coordinate of p+q as it is used only in the computation of λ2, -// which can be computed as +// DoubleAndAdd computes 2p+q as (p+q)+p. It doesn't modify p nor q. +// This function doesn't check that the p and q are on the curve. See AssertIsOnCurve. // -// λ2 = -λ1-2*p.y/(x2-p.x) +// It follows [ELM03] (Section 3.1). This saves the computation of the y +// coordinate of p+q as it is used only in the computation of λ2, which can be +// computed as // -// instead. It doesn't modify p nor q. +// λ2 = -λ1-2*p.y/(x2-p.x) // // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf func (c *Curve[B, S]) DoubleAndAdd(p, q *AffinePoint[B]) *AffinePoint[B] { @@ -284,6 +290,7 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo } // ScalarMul computes s * p and returns it. It doesn't modify p nor s. +// This function doesn't check that the p is on the curve. See AssertIsOnCurve. // // It computes the standard little-endian variable-base double-and-add algorithm // [HMV04] (Algorithm 3.26). diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 11539b046d..a7557cc6ce 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -5,6 +5,8 @@ import ( "testing" "github.com/consensys/gnark-crypto/ecc" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + fr_bls381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bn254" fr_bn "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/secp256k1" @@ -275,6 +277,30 @@ func TestScalarMulBase2(t *testing.T) { assert.NoError(err) } +func TestScalarMulBase3(t *testing.T) { + assert := test.NewAssert(t) + _, _, g, _ := bls12381.Generators() + var r fr_bn.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var S bls12381.G1Affine + S.ScalarMultiplication(&g, s) + + circuit := ScalarMulBaseTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{} + witness := ScalarMulBaseTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ + S: emulated.ValueOf[emulated.BLS12381Fr](s), + Q: AffinePoint[emulated.BLS12381Fp]{ + X: emulated.ValueOf[emulated.BLS12381Fp](S.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](S.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) + _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) + assert.NoError(err) +} + type ScalarMulTest[T, S emulated.FieldParams] struct { P, Q AffinePoint[T] S emulated.Element[S] @@ -346,6 +372,34 @@ func TestScalarMul2(t *testing.T) { assert.NoError(err) } +func TestScalarMul3(t *testing.T) { + assert := test.NewAssert(t) + var r fr_bls381.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var res bls12381.G1Affine + _, _, gen, _ := bls12381.Generators() + res.ScalarMultiplication(&gen, s) + + circuit := ScalarMulTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{} + witness := ScalarMulTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ + S: emulated.ValueOf[emulated.BLS12381Fr](s), + P: AffinePoint[emulated.BLS12381Fp]{ + X: emulated.ValueOf[emulated.BLS12381Fp](gen.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](gen.Y), + }, + Q: AffinePoint[emulated.BLS12381Fp]{ + X: emulated.ValueOf[emulated.BLS12381Fp](res.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](res.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) + _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) + assert.NoError(err) +} + type IsOnCurveTest[T, S emulated.FieldParams] struct { Q AffinePoint[T] } diff --git a/std/math/emulated/params.go b/std/math/emulated/params.go index eda8ebddc5..b40b2f2493 100644 --- a/std/math/emulated/params.go +++ b/std/math/emulated/params.go @@ -97,3 +97,14 @@ func (fp BLS12381Fp) NbLimbs() uint { return 6 } func (fp BLS12381Fp) BitsPerLimb() uint { return 64 } func (fp BLS12381Fp) IsPrime() bool { return true } func (fp BLS12381Fp) Modulus() *big.Int { return ecc.BLS12_381.BaseField() } + +// BLS12381Fr provide type parametrization for emulated field on 4 limb of width +// 64bits for modulus +// 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001. +// This is the scalar field of the BLS12-381 curve. +type BLS12381Fr struct{} + +func (fp BLS12381Fr) NbLimbs() uint { return 4 } +func (fp BLS12381Fr) BitsPerLimb() uint { return 64 } +func (fp BLS12381Fr) IsPrime() bool { return true } +func (fp BLS12381Fr) Modulus() *big.Int { return ecc.BLS12_381.ScalarField() } From b9484d1bf36af264b801b83d18eee0d7f04d65ac Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 7 Apr 2023 16:15:29 +0200 Subject: [PATCH 05/28] test: add bn254 and bl12381 test of AssertIsOnCurve --- .../emulated/sw_emulated/point_test.go | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index a7557cc6ce..14c18c5c2f 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -433,3 +433,45 @@ func TestIsOnCurve(t *testing.T) { err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) assert.NoError(err) } + +func TestIsOnCurve2(t *testing.T) { + assert := test.NewAssert(t) + _, _, g, _ := bn254.Generators() + var r fr_secp.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var Q bn254.G1Affine + Q.ScalarMultiplication(&g, s) + + circuit := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{} + witness := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{ + Q: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](Q.X), + Y: emulated.ValueOf[emulated.BN254Fp](Q.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} + +func TestIsOnCurve3(t *testing.T) { + assert := test.NewAssert(t) + _, _, g, _ := bls12381.Generators() + var r fr_secp.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var Q bls12381.G1Affine + Q.ScalarMultiplication(&g, s) + + circuit := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{} + witness := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ + Q: AffinePoint[emulated.BLS12381Fp]{ + X: emulated.ValueOf[emulated.BLS12381Fp](Q.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](Q.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} From 3bea95b9bbe44eb1dc08be44dd5dbd56d5c215bc Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 7 Apr 2023 18:04:58 +0200 Subject: [PATCH 06/28] feat(sw_bn254): add AssertIsOnG2 --- std/algebra/emulated/sw_bn254/hints.go | 43 +++++++++++++++++++ std/algebra/emulated/sw_bn254/pairing.go | 28 ++++++++++++ std/algebra/emulated/sw_bn254/pairing_test.go | 32 ++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 std/algebra/emulated/sw_bn254/hints.go diff --git a/std/algebra/emulated/sw_bn254/hints.go b/std/algebra/emulated/sw_bn254/hints.go new file mode 100644 index 0000000000..b1674afdb9 --- /dev/null +++ b/std/algebra/emulated/sw_bn254/hints.go @@ -0,0 +1,43 @@ +package sw_bn254 + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/std/math/emulated" +) + +func init() { + solver.RegisterHint(subgroupG2Hint) +} + +func subgroupG2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.G2Affine + + a.X.A0.SetBigInt(inputs[0]) + a.X.A1.SetBigInt(inputs[1]) + a.Y.A0.SetBigInt(inputs[2]) + a.Y.A1.SetBigInt(inputs[3]) + + // c = ψ³([2x₀]a) - ψ²([x₀]a) - ψ([x₀]a) - [x₀]a + x0, _ := new(big.Int).SetString("4965661367192848881", 10) + var aJac, t1, t2, t3 bn254.G2Jac + aJac.FromAffine(&a) + aJac.ScalarMultiplication(&aJac, x0) + t1.Psi(&aJac) + t2.Psi(&t1) + t3.Psi(&t2).Double(&t3).Neg(&t3) + aJac.AddAssign(&t1).AddAssign(&t2).AddAssign(&t3).Neg(&aJac) + c.FromJacobian(&aJac) + + c.X.A0.BigInt(outputs[0]) + c.X.A1.BigInt(outputs[1]) + c.Y.A0.BigInt(outputs[2]) + c.Y.A1.BigInt(outputs[3]) + + return nil + }) +} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 22798fa029..f710639dde 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -255,6 +255,34 @@ func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { pr.Ext2.AssertIsEqual(left, right) } +func (pr Pairing) AssertIsOnG1(P *G1Affine) { + // BN254 has a prime order, so we only + // 1- Check P is on the curve + pr.AssertIsOnCurve(P) +} + +func (pr Pairing) AssertIsOnG2(Q *G2Affine) { + // 1- Check Q is on the curve + pr.AssertIsOnTwist(Q) + + // 2- Check Q has the right subgroup order + res, err := pr.curveF.NewHint(subgroupG2Hint, 4, &Q.X.A0, &Q.X.A1, &Q.Y.A0, &Q.Y.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + // _Q = ψ³([2x₀]Q) - ψ²([x₀]Q) - ψ([x₀]Q) - [x₀]Q + _Q := G2Affine{ + X: fields_bn254.E2{A0: *res[0], A1: *res[1]}, + Y: fields_bn254.E2{A0: *res[2], A1: *res[3]}, + } + + // [r]Q == 0 <==> Q = _Q + pr.Ext2.AssertIsEqual(&Q.X, &_Q.X) + pr.Ext2.AssertIsEqual(&Q.Y, &_Q.Y) +} + // loopCounter = 6x₀+2 = 29793968203157093288 // // in 2-NAF diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 1d76ca0d45..e31adee388 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -66,6 +66,8 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) @@ -101,6 +103,10 @@ func (c *MultiPairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + pairing.AssertIsOnG1(&c.In1G1) + pairing.AssertIsOnG1(&c.In2G1) + pairing.AssertIsOnG2(&c.In1G2) + pairing.AssertIsOnG2(&c.In2G2) res, err := pairing.Pair([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) if err != nil { return fmt.Errorf("pair: %w", err) @@ -196,3 +202,29 @@ func TestFinalExponentiationSafeCircuit(t *testing.T) { }, ecc.BN254.ScalarField()) assert.NoError(err) } + +type GroupMembershipCircuit struct { + InG1 G1Affine + InG2 G2Affine +} + +func (c *GroupMembershipCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) + return nil +} + +func TestGroupMembershipSolve(t *testing.T) { + assert := test.NewAssert(t) + p, q := randomG1G2Affines(assert) + witness := GroupMembershipCircuit{ + InG1: NewG1Affine(p), + InG2: NewG2Affine(q), + } + err := test.IsSolved(&GroupMembershipCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From d62695e0a0f8c8e27cfe92f6c16f45665be91921 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 7 Apr 2023 18:44:30 +0200 Subject: [PATCH 07/28] feat(sw_bls12381): add AssertIsOnG1 and AssertIsOnG2 --- std/algebra/emulated/sw_bls12381/hints.go | 68 +++++++++++++++++++ std/algebra/emulated/sw_bls12381/pairing.go | 59 ++++++++++++++++ .../emulated/sw_bls12381/pairing_test.go | 32 +++++++++ std/algebra/emulated/sw_bn254/pairing.go | 14 ++-- 4 files changed, 166 insertions(+), 7 deletions(-) create mode 100644 std/algebra/emulated/sw_bls12381/hints.go diff --git a/std/algebra/emulated/sw_bls12381/hints.go b/std/algebra/emulated/sw_bls12381/hints.go new file mode 100644 index 0000000000..b9f34dcc1a --- /dev/null +++ b/std/algebra/emulated/sw_bls12381/hints.go @@ -0,0 +1,68 @@ +package sw_bls12381 + +import ( + "math/big" + + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/std/math/emulated" +) + +func init() { + solver.RegisterHint(GetHints()...) +} + +// GetHints returns all hint functions used in the package. +func GetHints() []solver.Hint { + return []solver.Hint{ + subgroupG1Hint, + subgroupG2Hint, + } +} + +func subgroupG1Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.G1Affine + + a.X.SetBigInt(inputs[0]) + a.Y.SetBigInt(inputs[1]) + + // c = -[x²]ϕ(p) + x0, _ := new(big.Int).SetString("15132376222941642752", 10) // negative + var jac bls12381.G1Jac + jac.FromAffine(&a) + jac.Phi(&jac).ScalarMultiplication(&jac, x0). + ScalarMultiplication(&jac, x0). + Neg(&jac) + c.FromJacobian(&jac) + + c.X.BigInt(outputs[0]) + c.Y.BigInt(outputs[1]) + + return nil + }) +} + +func subgroupG2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.G2Affine + + a.X.A0.SetBigInt(inputs[0]) + a.X.A1.SetBigInt(inputs[1]) + a.Y.A0.SetBigInt(inputs[2]) + a.Y.A1.SetBigInt(inputs[3]) + + // c = [x₀]a + x0, _ := new(big.Int).SetString("15132376222941642752", 10) // negative + c.ScalarMultiplication(&a, x0).Neg(&c) + + c.X.A0.BigInt(outputs[0]) + c.X.A1.BigInt(outputs[1]) + c.Y.A0.BigInt(outputs[2]) + c.Y.A1.BigInt(outputs[3]) + + return nil + }) +} diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 032453d788..0f15634c44 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -250,6 +250,65 @@ func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { pr.Ext2.AssertIsEqual(left, right) } +func (pr Pairing) AssertIsOnG1(P *G1Affine) { + // 1- Check P is on the curve + pr.AssertIsOnCurve(P) + + // 2- Check P has the right subgroup order + res, err := pr.curveF.NewHint(subgroupG1Hint, 2, &P.X, &P.Y) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + // _P = -[x²]ϕ(p) + _P := G1Affine{ + X: *res[0], + Y: *res[1], + } + + // [r]Q == 0 <==> P = _P + pr.curveF.AssertIsEqual(&P.X, &_P.X) + pr.curveF.AssertIsEqual(&P.Y, &_P.Y) +} + +func (pr Pairing) AssertIsOnG2(Q *G2Affine) { + // 1- Check Q is on the curve + pr.AssertIsOnTwist(Q) + + // 2- Check Q has the right subgroup order + res, err := pr.curveF.NewHint(subgroupG2Hint, 4, &Q.X.A0, &Q.X.A1, &Q.Y.A0, &Q.Y.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + // _Q = [x₀]Q + _Q := G2Affine{ + X: fields_bls12381.E2{A0: *res[0], A1: *res[1]}, + Y: fields_bls12381.E2{A0: *res[2], A1: *res[3]}, + } + + // [r]Q == 0 <==> ψ(Q) = _Q + var psiQ G2Affine + u1 := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") + v := fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp]("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530"), + A1: emulated.ValueOf[emulated.BLS12381Fp]("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"), + } + + // ψ(Q) + psiQ.X = *pr.Ext2.Conjugate(&Q.X) + tmp := *pr.curveF.Mul(&psiQ.X.A1, &u1) + psiQ.X.A1 = *pr.curveF.Mul(&psiQ.X.A0, &u1) + psiQ.X.A0 = *pr.curveF.Neg(&tmp) + psiQ.Y = *pr.Ext2.Conjugate(&Q.Y) + psiQ.Y = *pr.Ext2.Mul(&psiQ.Y, &v) + + pr.Ext2.AssertIsEqual(&psiQ.X, &_Q.X) + pr.Ext2.AssertIsEqual(&psiQ.Y, &_Q.Y) +} + // loopCounter = seed in binary // // seed=-15132376222941642752 diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index ec1bf2baec..5a104df470 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -66,6 +66,8 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) @@ -101,6 +103,10 @@ func (c *MultiPairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + pairing.AssertIsOnG1(&c.In1G1) + pairing.AssertIsOnG1(&c.In2G1) + pairing.AssertIsOnG2(&c.In1G2) + pairing.AssertIsOnG2(&c.In2G2) res, err := pairing.Pair([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) if err != nil { return fmt.Errorf("pair: %w", err) @@ -196,3 +202,29 @@ func TestFinalExponentiationSafeCircuit(t *testing.T) { }, ecc.BN254.ScalarField()) assert.NoError(err) } + +type GroupMembershipCircuit struct { + InG1 G1Affine + InG2 G2Affine +} + +func (c *GroupMembershipCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) + return nil +} + +func TestGroupMembershipSolve(t *testing.T) { + assert := test.NewAssert(t) + p, q := randomG1G2Affines(assert) + witness := GroupMembershipCircuit{ + InG1: NewG1Affine(p), + InG2: NewG2Affine(q), + } + err := test.IsSolved(&GroupMembershipCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index f710639dde..b1563011ed 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -487,15 +487,15 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { Q1, Q2 := new(G2Affine), new(G2Affine) for k := 0; k < n; k++ { //Q1 = π(Q) - Q1.X = *pr.Ext12.Ext2.Conjugate(&Q[k].X) - Q1.X = *pr.Ext12.Ext2.MulByNonResidue1Power2(&Q1.X) - Q1.Y = *pr.Ext12.Ext2.Conjugate(&Q[k].Y) - Q1.Y = *pr.Ext12.Ext2.MulByNonResidue1Power3(&Q1.Y) + Q1.X = *pr.Ext2.Conjugate(&Q[k].X) + Q1.X = *pr.Ext2.MulByNonResidue1Power2(&Q1.X) + Q1.Y = *pr.Ext2.Conjugate(&Q[k].Y) + Q1.Y = *pr.Ext2.MulByNonResidue1Power3(&Q1.Y) // Q2 = -π²(Q) - Q2.X = *pr.Ext12.Ext2.MulByNonResidue2Power2(&Q[k].X) - Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&Q[k].Y) - Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) + Q2.X = *pr.Ext2.MulByNonResidue2Power2(&Q[k].X) + Q2.Y = *pr.Ext2.MulByNonResidue2Power3(&Q[k].Y) + Q2.Y = *pr.Ext2.Neg(&Q2.Y) // Qacc[k] ← Qacc[k]+π(Q) and // l1 the line passing Qacc[k] and π(Q) From ba144ccb6c7fd887900667365e2d26c12693bb58 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 11 Apr 2023 15:34:58 +0000 Subject: [PATCH 08/28] chore: point to gnark-crypto@develop --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 5a9e32610b..e27a842665 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de + github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index aa7606bed0..b840dcf2ae 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de h1:W5lRxU8Rk8CDLHMTeyNst0VESbcU5RZ3U1TS9MNGgCQ= github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59 h1:KYAxBDzdiFQWO+lptSBb+7/UUHKjObS87Bx7pBGX1DU= +github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 0e0958ccc78c3b199f514ea17ed3d4e42a5e51cf Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 11 Apr 2023 18:54:54 +0000 Subject: [PATCH 09/28] feat: use AssertIsOnG2 for ECPAIR precompile + comments --- std/evmprecompiles/06-bnadd.go | 1 + std/evmprecompiles/07-bnmul.go | 1 + std/evmprecompiles/08-bnpairing.go | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/std/evmprecompiles/06-bnadd.go b/std/evmprecompiles/06-bnadd.go index d9eb8b32dd..43760da543 100644 --- a/std/evmprecompiles/06-bnadd.go +++ b/std/evmprecompiles/06-bnadd.go @@ -14,6 +14,7 @@ func ECAdd(api frontend.API, P, Q *sw_emulated.AffinePoint[emulated.BN254Fp]) *s if err != nil { panic(err) } + // Check that P and Q are on the curve (done in the zkEVM ⚠️ ) res := curve.Add(P, Q) return res } diff --git a/std/evmprecompiles/07-bnmul.go b/std/evmprecompiles/07-bnmul.go index 1b6d2d6fa8..eb1c02ccda 100644 --- a/std/evmprecompiles/07-bnmul.go +++ b/std/evmprecompiles/07-bnmul.go @@ -14,6 +14,7 @@ func ECMul(api frontend.API, P *sw_emulated.AffinePoint[emulated.BN254Fp], u *em if err != nil { panic(err) } + // Check that P is on the curve (done in the zkEVM ⚠️ ) res := curve.ScalarMul(P, u) return res } diff --git a/std/evmprecompiles/08-bnpairing.go b/std/evmprecompiles/08-bnpairing.go index cab5c3ad2b..01dbbab99c 100644 --- a/std/evmprecompiles/08-bnpairing.go +++ b/std/evmprecompiles/08-bnpairing.go @@ -13,6 +13,13 @@ func ECPair(api frontend.API, P []*sw_bn254.G1Affine, Q []*sw_bn254.G2Affine) { if err != nil { panic(err) } + // 1- Check that Pᵢ are on G1 (done in the zkEVM ⚠️ ) + // 2- Check that Qᵢ are on G2 + for i := 0; i < len(Q); i++ { + pair.AssertIsOnG2(Q[i]) + } + + // 3- Check that ∏ᵢ e(Pᵢ, Qᵢ) == 1 if err := pair.PairingCheck(P, Q); err != nil { panic(err) } From 760d53473e8cad885416d8d45f31bda9e74124c7 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 13 Apr 2023 10:57:46 +0000 Subject: [PATCH 10/28] fix: add (0,0) case to curve membership --- std/algebra/emulated/sw_bls12381/pairing.go | 20 ++++++-- std/algebra/emulated/sw_bn254/pairing.go | 24 ++++++--- std/algebra/emulated/sw_emulated/point.go | 9 +++- .../emulated/sw_emulated/point_test.go | 51 +++++++++++++++---- 4 files changed, 83 insertions(+), 21 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 0f15634c44..285f7cae23 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -229,24 +229,36 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { func (pr Pairing) AssertIsOnCurve(P *G1Affine) { // Curve: Y² == X³ + aX + b, where a=0 and b=4 - four := emulated.ValueOf[emulated.BLS12381Fp](4) + // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) + + // if P=(0,0) we assign b=0 otherwise 3, and continue + selector := pr.api.And(pr.curveF.IsZero(&P.X), pr.curveF.IsZero(&P.Y)) + bCurve := emulated.ValueOf[emulated.BLS12381Fp](4) + b := pr.curveF.Select(selector, pr.curveF.Zero(), &bCurve) + left := pr.curveF.Mul(&P.Y, &P.Y) right := pr.curveF.Mul(&P.X, &P.X) right = pr.curveF.Mul(right, &P.X) - right = pr.curveF.Add(right, &four) + right = pr.curveF.Add(right, b) pr.curveF.AssertIsEqual(left, right) } func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { // Twist: Y² == X³ + aX + b, where a=0 and b=4(1+u) - b := fields_bls12381.E2{ + // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) + + // if Q=(0,0) we assign b=0 otherwise 3/(9+u), and continue + selector := pr.api.And(pr.Ext2.IsZero(&Q.X), pr.Ext2.IsZero(&Q.Y)) + bTwist := fields_bls12381.E2{ A0: emulated.ValueOf[emulated.BLS12381Fp]("4"), A1: emulated.ValueOf[emulated.BLS12381Fp]("4"), } + b := pr.Ext2.Select(selector, pr.Ext2.Zero(), &bTwist) + left := pr.Ext2.Square(&Q.Y) right := pr.Ext2.Square(&Q.X) right = pr.Ext2.Mul(right, &Q.X) - right = pr.Ext2.Add(right, &b) + right = pr.Ext2.Add(right, b) pr.Ext2.AssertIsEqual(left, right) } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index b1563011ed..09cb1d3637 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -202,7 +202,7 @@ func (pr Pairing) finalExponentiation(e *GTEl, unsafe bool) *GTEl { // Pair calculates the reduced pairing for a set of points // ∏ᵢ e(Pᵢ, Qᵢ). // -// This function doesn't check that the inputs are in the correct subgroups. +// This function doesn't check that the inputs are in the correct subgroups. See AssertIsOnG1 and AssertIsOnG2. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, err := pr.MillerLoop(P, Q) if err != nil { @@ -215,7 +215,7 @@ func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // PairingCheck calculates the reduced pairing for a set of points and asserts if the result is One // ∏ᵢ e(Pᵢ, Qᵢ) =? 1 // -// This function doesn't check that the inputs are in the correct subgroups. +// This function doesn't check that the inputs are in the correct subgroups. See AssertIsOnG1 and AssertIsOnG2. func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error { f, err := pr.Pair(P, Q) if err != nil { @@ -234,24 +234,36 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { func (pr Pairing) AssertIsOnCurve(P *G1Affine) { // Curve: Y² == X³ + aX + b, where a=0 and b=3 - three := emulated.ValueOf[emulated.BN254Fp](3) + // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) + + // if P=(0,0) we assign b=0 otherwise 3, and continue + selector := pr.api.And(pr.curveF.IsZero(&P.X), pr.curveF.IsZero(&P.Y)) + bCurve := emulated.ValueOf[emulated.BN254Fp](3) + b := pr.curveF.Select(selector, pr.curveF.Zero(), &bCurve) + left := pr.curveF.Mul(&P.Y, &P.Y) right := pr.curveF.Mul(&P.X, &P.X) right = pr.curveF.Mul(right, &P.X) - right = pr.curveF.Add(right, &three) + right = pr.curveF.Add(right, b) pr.curveF.AssertIsEqual(left, right) } func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { // Twist: Y² == X³ + aX + b, where a=0 and b=3/(9+u) - b := fields_bn254.E2{ + // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) + + // if Q=(0,0) we assign b=0 otherwise 3/(9+u), and continue + selector := pr.api.And(pr.Ext2.IsZero(&Q.X), pr.Ext2.IsZero(&Q.Y)) + bTwist := fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), } + b := pr.Ext2.Select(selector, pr.Ext2.Zero(), &bTwist) + left := pr.Ext2.Square(&Q.Y) right := pr.Ext2.Square(&Q.X) right = pr.Ext2.Mul(right, &Q.X) - right = pr.Ext2.Add(right, &b) + right = pr.Ext2.Add(right, b) pr.Ext2.AssertIsEqual(left, right) } diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 511e528825..fe87a384ad 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -126,10 +126,15 @@ func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { // AssertIsOnCurve asserts if p belongs to the curve. It doesn't modify p. func (c *Curve[B, S]) AssertIsOnCurve(p *AffinePoint[B]) { - // Y² == X³ + aX + b + // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) + + // if p=(0,0) we assign b=0 and continue + selector := c.api.And(c.baseApi.IsZero(&p.X), c.baseApi.IsZero(&p.Y)) + b := c.baseApi.Select(selector, c.baseApi.Zero(), &c.b) + left := c.baseApi.Mul(&p.Y, &p.Y) right := c.baseApi.Mul(&p.X, c.baseApi.Mul(&p.X, &p.X)) - right = c.baseApi.Add(right, &c.b) + right = c.baseApi.Add(right, b) if c.addA { ax := c.baseApi.Mul(&c.a, &p.X) right = c.baseApi.Add(right, ax) diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 14c18c5c2f..d78085c9ea 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -420,17 +420,28 @@ func TestIsOnCurve(t *testing.T) { _, _ = r.SetRandom() s := new(big.Int) r.BigInt(s) - var Q secp256k1.G1Affine + var Q, infinity secp256k1.G1Affine Q.ScalarMultiplication(&g, s) + // Q=[s]G is on curve circuit := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} - witness := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ + witness1 := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ Q: AffinePoint[emulated.Secp256k1Fp]{ X: emulated.ValueOf[emulated.Secp256k1Fp](Q.X), Y: emulated.ValueOf[emulated.Secp256k1Fp](Q.Y), }, } - err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + err := test.IsSolved(&circuit, &witness1, testCurve.ScalarField()) + assert.NoError(err) + + // (0,0) is on curve + witness2 := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ + Q: AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](infinity.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](infinity.Y), + }, + } + err = test.IsSolved(&circuit, &witness2, testCurve.ScalarField()) assert.NoError(err) } @@ -441,17 +452,28 @@ func TestIsOnCurve2(t *testing.T) { _, _ = r.SetRandom() s := new(big.Int) r.BigInt(s) - var Q bn254.G1Affine + var Q, infinity bn254.G1Affine Q.ScalarMultiplication(&g, s) + // Q=[s]G is on curve circuit := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{} - witness := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{ + witness1 := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{ Q: AffinePoint[emulated.BN254Fp]{ X: emulated.ValueOf[emulated.BN254Fp](Q.X), Y: emulated.ValueOf[emulated.BN254Fp](Q.Y), }, } - err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + err := test.IsSolved(&circuit, &witness1, testCurve.ScalarField()) + assert.NoError(err) + + // (0,0) is on curve + witness2 := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{ + Q: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + } + err = test.IsSolved(&circuit, &witness2, testCurve.ScalarField()) assert.NoError(err) } @@ -462,16 +484,27 @@ func TestIsOnCurve3(t *testing.T) { _, _ = r.SetRandom() s := new(big.Int) r.BigInt(s) - var Q bls12381.G1Affine + var Q, infinity bls12381.G1Affine Q.ScalarMultiplication(&g, s) + // Q=[s]G is on curve circuit := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{} - witness := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ + witness1 := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ Q: AffinePoint[emulated.BLS12381Fp]{ X: emulated.ValueOf[emulated.BLS12381Fp](Q.X), Y: emulated.ValueOf[emulated.BLS12381Fp](Q.Y), }, } - err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + err := test.IsSolved(&circuit, &witness1, testCurve.ScalarField()) + assert.NoError(err) + + // (0,0) is on curve + witness2 := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ + Q: AffinePoint[emulated.BLS12381Fp]{ + X: emulated.ValueOf[emulated.BLS12381Fp](infinity.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](infinity.Y), + }, + } + err = test.IsSolved(&circuit, &witness2, testCurve.ScalarField()) assert.NoError(err) } From b6cc50544f4d1368c1b5c65108ca3ce2021c0750 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 16:57:33 +0200 Subject: [PATCH 11/28] feat(sw_bn254): G2 membership without hints --- std/algebra/emulated/sw_bn254/g2.go | 119 +++++++++++++++++++++++ std/algebra/emulated/sw_bn254/g2_test.go | 89 +++++++++++++++++ std/algebra/emulated/sw_bn254/hints.go | 43 -------- std/algebra/emulated/sw_bn254/pairing.go | 27 +++-- 4 files changed, 225 insertions(+), 53 deletions(-) create mode 100644 std/algebra/emulated/sw_bn254/g2_test.go delete mode 100644 std/algebra/emulated/sw_bn254/hints.go diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 9fd94325c5..8c5ab4f7e6 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -1,15 +1,28 @@ package sw_bn254 import ( + "math/big" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" "github.com/consensys/gnark/std/math/emulated" ) +type G2 struct { + *fields_bn254.Ext2 +} + type G2Affine struct { X, Y fields_bn254.E2 } +func NewG2(api frontend.API) G2 { + return G2{ + Ext2: fields_bn254.NewExt2(api), + } +} + func NewG2Affine(v bn254.G2Affine) G2Affine { return G2Affine{ X: fields_bn254.E2{ @@ -22,3 +35,109 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { }, } } + +func (g2 *G2) psi(q *G2Affine) *G2Affine { + u := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), + A1: emulated.ValueOf[emulated.BN254Fp]("10307601595873709700152284273816112264069230130616436755625194854815875713954"), + } + v := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("2821565182194536844548159561693502659359617185244120367078079554186484126554"), + A1: emulated.ValueOf[emulated.BN254Fp]("3505843767911556378687030309984248845540243509899259641013678093033130930403"), + } + + var psiq G2Affine + psiq.X = *g2.Ext2.Conjugate(&q.X) + psiq.X = *g2.Ext2.Mul(&psiq.X, &u) + psiq.Y = *g2.Ext2.Conjugate(&q.Y) + psiq.Y = *g2.Ext2.Mul(&psiq.Y, &v) + + return &psiq +} + +func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { + // TODO: use 2-NAF or addchain (or maybe a ternary expansion) + var seed = [63]int8{1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1} + + // i = 62 + res := q + + for i := 61; i >= 0; i-- { + res = g2.double(res) + if seed[i] == 1 { + // TODO: use doubleAndAdd + res = g2.add(res, q) + } + } + + return res +} + +func (g2 G2) add(p, q *G2Affine) *G2Affine { + // compute λ = (q.y-p.y)/(q.x-p.x) + qypy := g2.Ext2.Sub(&q.Y, &p.Y) + qxpx := g2.Ext2.Sub(&q.X, &p.X) + // TODO: use Div + qxpx = g2.Ext2.Inverse(qxpx) + λ := g2.Ext2.Mul(qypy, qxpx) + + // xr = λ²-p.x-q.x + λλ := g2.Ext2.Mul(λ, λ) + qxpx = g2.Ext2.Add(&p.X, &q.X) + xr := g2.Ext2.Sub(λλ, qxpx) + + // p.y = λ(p.x-r.x) - p.y + pxrx := g2.Ext2.Sub(&p.X, xr) + λpxrx := g2.Ext2.Mul(λ, pxrx) + yr := g2.Ext2.Sub(λpxrx, &p.Y) + + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 G2) neg(p *G2Affine) *G2Affine { + xr := &p.X + yr := g2.Ext2.Neg(&p.Y) + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 G2) sub(p, q *G2Affine) *G2Affine { + qNeg := g2.neg(q) + return g2.add(p, qNeg) +} + +func (g2 *G2) double(p *G2Affine) *G2Affine { + // compute λ = (3p.x²)/2*p.y + xx3a := g2.Mul(&p.X, &p.X) + xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) + y2 := g2.Double(&p.Y) + // TODO: use Div + y2 = g2.Inverse(y2) + λ := g2.Mul(xx3a, y2) + + // xr = λ²-2p.x + x2 := g2.Double(&p.X) + λλ := g2.Mul(λ, λ) + xr := g2.Sub(λλ, x2) + + // yr = λ(p-xr) - p.y + pxrx := g2.Sub(&p.X, xr) + λpxrx := g2.Mul(λ, pxrx) + yr := g2.Sub(λpxrx, &p.Y) + + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +// AssertIsEqual asserts that p and q are the same point. +func (g2 *G2) AssertIsEqual(p, q *G2Affine) { + g2.Ext2.AssertIsEqual(&p.X, &q.X) + g2.Ext2.AssertIsEqual(&p.Y, &q.Y) +} diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go new file mode 100644 index 0000000000..8a22c04063 --- /dev/null +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -0,0 +1,89 @@ +package sw_bn254 + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type addG2Circuit struct { + In1, In2 G2Affine + Res G2Affine +} + +func (c *addG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.add(&c.In1, &c.In2) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestAddG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + _, in2 := randomG1G2Affines(assert) + var res bn254.G2Affine + res.Add(&in1, &in2) + witness := addG2Circuit{ + In1: NewG2Affine(in1), + In2: NewG2Affine(in2), + Res: NewG2Affine(res), + } + err := test.IsSolved(&addG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type doubleG2Circuit struct { + In1 G2Affine + Res G2Affine +} + +func (c *doubleG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.double(&c.In1) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestDoubleG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + var res bn254.G2Affine + res.Double(&in1) + witness := doubleG2Circuit{ + In1: NewG2Affine(in1), + Res: NewG2Affine(res), + } + err := test.IsSolved(&doubleG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type scalarMulG2BySeedCircuit struct { + In1 G2Affine + Res G2Affine +} + +func (c *scalarMulG2BySeedCircuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.scalarMulBySeed(&c.In1) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestScalarMulG2BySeedTestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + var res bn254.G2Affine + x0, _ := new(big.Int).SetString("4965661367192848881", 10) + res.ScalarMultiplication(&in1, x0) + witness := scalarMulG2BySeedCircuit{ + In1: NewG2Affine(in1), + Res: NewG2Affine(res), + } + err := test.IsSolved(&scalarMulG2BySeedCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/sw_bn254/hints.go b/std/algebra/emulated/sw_bn254/hints.go deleted file mode 100644 index b1674afdb9..0000000000 --- a/std/algebra/emulated/sw_bn254/hints.go +++ /dev/null @@ -1,43 +0,0 @@ -package sw_bn254 - -import ( - "math/big" - - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/math/emulated" -) - -func init() { - solver.RegisterHint(subgroupG2Hint) -} - -func subgroupG2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bn254.G2Affine - - a.X.A0.SetBigInt(inputs[0]) - a.X.A1.SetBigInt(inputs[1]) - a.Y.A0.SetBigInt(inputs[2]) - a.Y.A1.SetBigInt(inputs[3]) - - // c = ψ³([2x₀]a) - ψ²([x₀]a) - ψ([x₀]a) - [x₀]a - x0, _ := new(big.Int).SetString("4965661367192848881", 10) - var aJac, t1, t2, t3 bn254.G2Jac - aJac.FromAffine(&a) - aJac.ScalarMultiplication(&aJac, x0) - t1.Psi(&aJac) - t2.Psi(&t1) - t3.Psi(&t2).Double(&t3).Neg(&t3) - aJac.AddAssign(&t1).AddAssign(&t2).AddAssign(&t3).Neg(&aJac) - c.FromJacobian(&aJac) - - c.X.A0.BigInt(outputs[0]) - c.X.A1.BigInt(outputs[1]) - c.Y.A0.BigInt(outputs[2]) - c.Y.A1.BigInt(outputs[3]) - - return nil - }) -} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 09cb1d3637..eb5da2957f 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -15,6 +15,7 @@ type Pairing struct { api frontend.API *fields_bn254.Ext12 curveF *emulated.Field[emulated.BN254Fp] + g2 G2 } type GTEl = fields_bn254.E12 @@ -61,6 +62,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { api: api, Ext12: fields_bn254.NewExt12(api), curveF: ba, + g2: NewG2(api), }, nil } @@ -278,19 +280,24 @@ func (pr Pairing) AssertIsOnG2(Q *G2Affine) { pr.AssertIsOnTwist(Q) // 2- Check Q has the right subgroup order - res, err := pr.curveF.NewHint(subgroupG2Hint, 4, &Q.X.A0, &Q.X.A1, &Q.Y.A0, &Q.Y.A1) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } + + // [x₀]Q + xQ := *pr.g2.scalarMulBySeed(Q) + // ψ([x₀]Q) + psixQ := *pr.g2.psi(&xQ) + // ψ²([x₀]Q) + // TODO: use phi instead (psi^2 = -phi) + psi2xQ := *pr.g2.psi(&psixQ) + // ψ³([2x₀]Q) + psi3xxQ := *pr.g2.double(&psi2xQ) + psi3xxQ = *pr.g2.psi(&psi3xxQ) // _Q = ψ³([2x₀]Q) - ψ²([x₀]Q) - ψ([x₀]Q) - [x₀]Q - _Q := G2Affine{ - X: fields_bn254.E2{A0: *res[0], A1: *res[1]}, - Y: fields_bn254.E2{A0: *res[2], A1: *res[3]}, - } + _Q := *pr.g2.sub(&psi3xxQ, &psi2xQ) + _Q = *pr.g2.sub(&_Q, &psixQ) + _Q = *pr.g2.sub(&_Q, &xQ) - // [r]Q == 0 <==> Q = _Q + // [r]Q == 0 <==> _Q == Q pr.Ext2.AssertIsEqual(&Q.X, &_Q.X) pr.Ext2.AssertIsEqual(&Q.Y, &_Q.Y) } From 1da8f15d35bb56aba58eda948c6cb286d6ae8a6d Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 18:51:19 +0200 Subject: [PATCH 12/28] feat(sw_bn254): endomorphism optims for G2 membership --- std/algebra/emulated/sw_bn254/g2.go | 18 ++++++++++++------ std/algebra/emulated/sw_bn254/g2_test.go | 24 ++++++++++++++++++++++++ std/algebra/emulated/sw_bn254/pairing.go | 7 +++---- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 8c5ab4f7e6..be15c491d7 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -36,6 +36,16 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { } } +func (g2 *G2) phi(q *G2Affine) *G2Affine { + w := emulated.ValueOf[emulated.BN254Fp]("21888242871839275220042445260109153167277707414472061641714758635765020556616") + + var phiq G2Affine + phiq.X = *g2.Ext2.MulByElement(&q.X, &w) + phiq.Y = q.Y + + return &phiq +} + func (g2 *G2) psi(q *G2Affine) *G2Affine { u := fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), @@ -77,9 +87,7 @@ func (g2 G2) add(p, q *G2Affine) *G2Affine { // compute λ = (q.y-p.y)/(q.x-p.x) qypy := g2.Ext2.Sub(&q.Y, &p.Y) qxpx := g2.Ext2.Sub(&q.X, &p.X) - // TODO: use Div - qxpx = g2.Ext2.Inverse(qxpx) - λ := g2.Ext2.Mul(qypy, qxpx) + λ := g2.Ext2.DivUnchecked(qypy, qxpx) // xr = λ²-p.x-q.x λλ := g2.Ext2.Mul(λ, λ) @@ -116,9 +124,7 @@ func (g2 *G2) double(p *G2Affine) *G2Affine { xx3a := g2.Mul(&p.X, &p.X) xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) y2 := g2.Double(&p.Y) - // TODO: use Div - y2 = g2.Inverse(y2) - λ := g2.Mul(xx3a, y2) + λ := g2.DivUnchecked(xx3a, y2) // xr = λ²-2p.x x2 := g2.Double(&p.X) diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go index 8a22c04063..d7ccd9b848 100644 --- a/std/algebra/emulated/sw_bn254/g2_test.go +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -87,3 +87,27 @@ func TestScalarMulG2BySeedTestSolve(t *testing.T) { err := test.IsSolved(&scalarMulG2BySeedCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type endomorphismG2Circuit struct { + In1 G2Affine +} + +func (c *endomorphismG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res1 := g2.phi(&c.In1) + res1 = g2.neg(res1) + res2 := g2.psi(&c.In1) + res2 = g2.psi(res2) + g2.AssertIsEqual(res1, res2) + return nil +} + +func TestEndomorphismG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + witness := endomorphismG2Circuit{ + In1: NewG2Affine(in1), + } + err := test.IsSolved(&endomorphismG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index eb5da2957f..939d4832aa 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -285,15 +285,14 @@ func (pr Pairing) AssertIsOnG2(Q *G2Affine) { xQ := *pr.g2.scalarMulBySeed(Q) // ψ([x₀]Q) psixQ := *pr.g2.psi(&xQ) - // ψ²([x₀]Q) - // TODO: use phi instead (psi^2 = -phi) - psi2xQ := *pr.g2.psi(&psixQ) + // ψ²([x₀]Q) = -ϕ([x₀]Q) + psi2xQ := *pr.g2.phi(&xQ) // ψ³([2x₀]Q) psi3xxQ := *pr.g2.double(&psi2xQ) psi3xxQ = *pr.g2.psi(&psi3xxQ) // _Q = ψ³([2x₀]Q) - ψ²([x₀]Q) - ψ([x₀]Q) - [x₀]Q - _Q := *pr.g2.sub(&psi3xxQ, &psi2xQ) + _Q := *pr.g2.sub(&psi2xQ, &psi3xxQ) _Q = *pr.g2.sub(&_Q, &psixQ) _Q = *pr.g2.sub(&_Q, &xQ) From 3979f8d2a2f17aae29bd87469614b344d2678b92 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 19:01:25 +0200 Subject: [PATCH 13/28] perf(sw_bn254): optim of fixed scalar Mul on G2 --- std/algebra/emulated/sw_bn254/g2.go | 50 +++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index be15c491d7..3278a91a51 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -73,10 +73,10 @@ func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { res := q for i := 61; i >= 0; i-- { - res = g2.double(res) - if seed[i] == 1 { - // TODO: use doubleAndAdd - res = g2.add(res, q) + if seed[i] == 0 { + res = g2.double(res) + } else { + res = g2.doubleAndAdd(res, q) } } @@ -90,7 +90,7 @@ func (g2 G2) add(p, q *G2Affine) *G2Affine { λ := g2.Ext2.DivUnchecked(qypy, qxpx) // xr = λ²-p.x-q.x - λλ := g2.Ext2.Mul(λ, λ) + λλ := g2.Ext2.Square(λ) qxpx = g2.Ext2.Add(&p.X, &q.X) xr := g2.Ext2.Sub(λλ, qxpx) @@ -121,14 +121,14 @@ func (g2 G2) sub(p, q *G2Affine) *G2Affine { func (g2 *G2) double(p *G2Affine) *G2Affine { // compute λ = (3p.x²)/2*p.y - xx3a := g2.Mul(&p.X, &p.X) + xx3a := g2.Square(&p.X) xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) y2 := g2.Double(&p.Y) λ := g2.DivUnchecked(xx3a, y2) // xr = λ²-2p.x x2 := g2.Double(&p.X) - λλ := g2.Mul(λ, λ) + λλ := g2.Square(λ) xr := g2.Sub(λλ, x2) // yr = λ(p-xr) - p.y @@ -142,6 +142,42 @@ func (g2 *G2) double(p *G2Affine) *G2Affine { } } +func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { + + // compute λ1 = (q.y-p.y)/(q.x-p.x) + yqyp := g2.Ext2.Sub(&q.Y, &p.Y) + xqxp := g2.Ext2.Sub(&q.X, &p.X) + λ1 := g2.Ext2.DivUnchecked(yqyp, xqxp) + + // compute x2 = λ1²-p.x-q.x + λ1λ1 := g2.Ext2.Square(λ1) + xqxp = g2.Ext2.Add(&p.X, &q.X) + x2 := g2.Ext2.Sub(λ1λ1, xqxp) + + // ommit y2 computation + // compute λ2 = -λ1-2*p.y/(x2-p.x) + ypyp := g2.Ext2.Add(&p.Y, &p.Y) + x2xp := g2.Ext2.Sub(x2, &p.X) + λ2 := g2.Ext2.DivUnchecked(ypyp, x2xp) + λ2 = g2.Ext2.Add(λ1, λ2) + λ2 = g2.Ext2.Neg(λ2) + + // compute x3 =λ2²-p.x-x3 + λ2λ2 := g2.Ext2.Square(λ2) + x3 := g2.Ext2.Sub(λ2λ2, &p.X) + x3 = g2.Ext2.Sub(x3, x2) + + // compute y3 = λ2*(p.x - x3)-p.y + y3 := g2.Ext2.Sub(&p.X, x3) + y3 = g2.Ext2.Mul(λ2, y3) + y3 = g2.Ext2.Sub(y3, &p.Y) + + return &G2Affine{ + X: *x3, + Y: *y3, + } +} + // AssertIsEqual asserts that p and q are the same point. func (g2 *G2) AssertIsEqual(p, q *G2Affine) { g2.Ext2.AssertIsEqual(&p.X, &q.X) From 73f927c994bc51dcee74a507c6c7777feb0b42b4 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 19:14:46 +0200 Subject: [PATCH 14/28] perf(sw_bn254): use 2-NAF for fixed scalar Mul on G2 --- std/algebra/emulated/sw_bn254/g2.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 3278a91a51..95bbfd8e63 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -66,17 +66,21 @@ func (g2 *G2) psi(q *G2Affine) *G2Affine { } func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { - // TODO: use 2-NAF or addchain (or maybe a ternary expansion) - var seed = [63]int8{1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1} + + qNeg := g2.neg(q) + seed := [66]int8{1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0, -1, 0, -1, 0, 1, 0, 1, 0, 0, -1, 0, 1, 0, 1, 0, -1, 0, 0, 1, 0, 1, 0, 0, 0, 1} // i = 62 res := q for i := 61; i >= 0; i-- { - if seed[i] == 0 { + switch seed[i] { + case 0: res = g2.double(res) - } else { + case 1: res = g2.doubleAndAdd(res, q) + case -1: + res = g2.doubleAndAdd(res, qNeg) } } From ead049caef13abac48dabe20a48a23d5568d67e7 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 19:27:54 +0200 Subject: [PATCH 15/28] fix(sw_bn254): fix size of 2-naf table of the seed --- std/algebra/emulated/sw_bn254/g2.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 95bbfd8e63..41429b6f03 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -68,7 +68,7 @@ func (g2 *G2) psi(q *G2Affine) *G2Affine { func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { qNeg := g2.neg(q) - seed := [66]int8{1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0, -1, 0, -1, 0, 1, 0, 1, 0, 0, -1, 0, 1, 0, 1, 0, -1, 0, 0, 1, 0, 1, 0, 0, 0, 1} + seed := [63]int8{1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0, -1, 0, -1, 0, 1, 0, 1, 0, 0, -1, 0, 1, 0, 1, 0, -1, 0, 0, 1, 0, 1, 0, 0, 0, 1} // i = 62 res := q From b5caf13020e018f0e5c75d5dd28e5dd4b62a240f Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 19:52:08 +0200 Subject: [PATCH 16/28] perf(sw_bn254): use addchain/doubleAndAdd for fixed scalar mul --- std/algebra/emulated/sw_bn254/g2.go | 59 +++++++++++++++++++---------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 41429b6f03..bd6505cbb5 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -66,25 +66,38 @@ func (g2 *G2) psi(q *G2Affine) *G2Affine { } func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { - - qNeg := g2.neg(q) - seed := [63]int8{1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0, -1, 0, -1, 0, 1, 0, 1, 0, 0, -1, 0, 1, 0, 1, 0, -1, 0, 0, 1, 0, 1, 0, 0, 0, 1} - - // i = 62 - res := q - - for i := 61; i >= 0; i-- { - switch seed[i] { - case 0: - res = g2.double(res) - case 1: - res = g2.doubleAndAdd(res, q) - case -1: - res = g2.doubleAndAdd(res, qNeg) - } - } - - return res + z := g2.double(q) + t0 := g2.add(q, z) + t2 := g2.add(q, t0) + t1 := g2.add(z, t2) + z = g2.doubleAndAdd(t1, t0) + t0 = g2.add(t0, z) + t2 = g2.add(t2, t0) + t1 = g2.add(t1, t2) + t0 = g2.add(t0, t1) + t1 = g2.add(t1, t0) + t0 = g2.add(t0, t1) + t2 = g2.add(t2, t0) + t1 = g2.doubleAndAdd(t2, t1) + t2 = g2.add(t2, t1) + z = g2.add(z, t2) + t2 = g2.add(t2, z) + z = g2.doubleAndAdd(t2, z) + t0 = g2.add(t0, z) + t1 = g2.add(t1, t0) + t3 := g2.double(t1) + t3 = g2.doubleAndAdd(t3, t1) + t2 = g2.add(t2, t3) + t1 = g2.add(t1, t2) + t2 = g2.add(t2, t1) + t2 = g2.doubleN(t2, 16) + t1 = g2.doubleAndAdd(t2, t1) + t1 = g2.doubleN(t1, 13) + t0 = g2.doubleAndAdd(t1, t0) + t0 = g2.doubleN(t0, 15) + z = g2.doubleAndAdd(t0, z) + + return z } func (g2 G2) add(p, q *G2Affine) *G2Affine { @@ -146,6 +159,14 @@ func (g2 *G2) double(p *G2Affine) *G2Affine { } } +func (g2 *G2) doubleN(p *G2Affine, n int) *G2Affine { + pn := p + for s := 0; s < n; s++ { + pn = g2.double(pn) + } + return pn +} + func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { // compute λ1 = (q.y-p.y)/(q.x-p.x) From e955bb54d8af13ba7554d7f8d56520ceb7927650 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 20:18:19 +0200 Subject: [PATCH 17/28] fix: use jacobain double for test --- std/algebra/emulated/sw_bn254/g2_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go index d7ccd9b848..8aa5ae6cef 100644 --- a/std/algebra/emulated/sw_bn254/g2_test.go +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -53,7 +53,10 @@ func TestDoubleG2TestSolve(t *testing.T) { assert := test.NewAssert(t) _, in1 := randomG1G2Affines(assert) var res bn254.G2Affine - res.Double(&in1) + var in1Jac, resJac bn254.G2Jac + in1Jac.FromAffine(&in1) + resJac.Double(&in1Jac) + res.FromJacobian(&resJac) witness := doubleG2Circuit{ In1: NewG2Affine(in1), Res: NewG2Affine(res), From 0d17cd7109efc8d5be4165a2d9f58b91fed7a61c Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 01:36:10 +0200 Subject: [PATCH 18/28] refactor: init emulated constants once --- std/algebra/emulated/sw_bn254/g2.go | 31 ++++++++++++++++------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index bd6505cbb5..5b9336d16f 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -11,6 +11,8 @@ import ( type G2 struct { *fields_bn254.Ext2 + w *emulated.Element[emulated.BN254Fp] + u, v *fields_bn254.E2 } type G2Affine struct { @@ -18,8 +20,20 @@ type G2Affine struct { } func NewG2(api frontend.API) G2 { + w := emulated.ValueOf[emulated.BN254Fp]("21888242871839275220042445260109153167277707414472061641714758635765020556616") + u := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), + A1: emulated.ValueOf[emulated.BN254Fp]("10307601595873709700152284273816112264069230130616436755625194854815875713954"), + } + v := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("2821565182194536844548159561693502659359617185244120367078079554186484126554"), + A1: emulated.ValueOf[emulated.BN254Fp]("3505843767911556378687030309984248845540243509899259641013678093033130930403"), + } return G2{ Ext2: fields_bn254.NewExt2(api), + w: &w, + u: &u, + v: &v, } } @@ -37,30 +51,19 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { } func (g2 *G2) phi(q *G2Affine) *G2Affine { - w := emulated.ValueOf[emulated.BN254Fp]("21888242871839275220042445260109153167277707414472061641714758635765020556616") - var phiq G2Affine - phiq.X = *g2.Ext2.MulByElement(&q.X, &w) + phiq.X = *g2.Ext2.MulByElement(&q.X, g2.w) phiq.Y = q.Y return &phiq } func (g2 *G2) psi(q *G2Affine) *G2Affine { - u := fields_bn254.E2{ - A0: emulated.ValueOf[emulated.BN254Fp]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), - A1: emulated.ValueOf[emulated.BN254Fp]("10307601595873709700152284273816112264069230130616436755625194854815875713954"), - } - v := fields_bn254.E2{ - A0: emulated.ValueOf[emulated.BN254Fp]("2821565182194536844548159561693502659359617185244120367078079554186484126554"), - A1: emulated.ValueOf[emulated.BN254Fp]("3505843767911556378687030309984248845540243509899259641013678093033130930403"), - } - var psiq G2Affine psiq.X = *g2.Ext2.Conjugate(&q.X) - psiq.X = *g2.Ext2.Mul(&psiq.X, &u) + psiq.X = *g2.Ext2.Mul(&psiq.X, g2.u) psiq.Y = *g2.Ext2.Conjugate(&q.Y) - psiq.Y = *g2.Ext2.Mul(&psiq.Y, &v) + psiq.Y = *g2.Ext2.Mul(&psiq.Y, g2.v) return &psiq } From d6a723205229239547e130b650d0623b14de88a1 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 01:51:30 +0200 Subject: [PATCH 19/28] refactor: g2 gadget as pointer --- std/algebra/emulated/sw_bn254/g2.go | 4 ++-- std/algebra/emulated/sw_bn254/pairing.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 5b9336d16f..5daa790c7b 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -19,7 +19,7 @@ type G2Affine struct { X, Y fields_bn254.E2 } -func NewG2(api frontend.API) G2 { +func NewG2(api frontend.API) *G2 { w := emulated.ValueOf[emulated.BN254Fp]("21888242871839275220042445260109153167277707414472061641714758635765020556616") u := fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), @@ -29,7 +29,7 @@ func NewG2(api frontend.API) G2 { A0: emulated.ValueOf[emulated.BN254Fp]("2821565182194536844548159561693502659359617185244120367078079554186484126554"), A1: emulated.ValueOf[emulated.BN254Fp]("3505843767911556378687030309984248845540243509899259641013678093033130930403"), } - return G2{ + return &G2{ Ext2: fields_bn254.NewExt2(api), w: &w, u: &u, diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 939d4832aa..5934392ddb 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -15,7 +15,7 @@ type Pairing struct { api frontend.API *fields_bn254.Ext12 curveF *emulated.Field[emulated.BN254Fp] - g2 G2 + g2 *G2 } type GTEl = fields_bn254.E12 From 8c87b181c71aa77a4403905ef46690a89d810934 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 01:52:13 +0200 Subject: [PATCH 20/28] docs: subgroup check in doc-example --- std/algebra/emulated/sw_bls12381/doc_test.go | 4 ++++ std/algebra/emulated/sw_bn254/doc_test.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/std/algebra/emulated/sw_bls12381/doc_test.go b/std/algebra/emulated/sw_bls12381/doc_test.go index ae87b72997..a1ce0f5ca5 100644 --- a/std/algebra/emulated/sw_bls12381/doc_test.go +++ b/std/algebra/emulated/sw_bls12381/doc_test.go @@ -23,6 +23,10 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + // Pair method does not check that the points are in the proper groups. + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) + // Compute the pairing res, err := pairing.Pair([]*sw_bls12381.G1Affine{&c.InG1}, []*sw_bls12381.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) diff --git a/std/algebra/emulated/sw_bn254/doc_test.go b/std/algebra/emulated/sw_bn254/doc_test.go index db095a0210..7d8ef6a6cd 100644 --- a/std/algebra/emulated/sw_bn254/doc_test.go +++ b/std/algebra/emulated/sw_bn254/doc_test.go @@ -23,6 +23,10 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + // Pair method does not check that the points are in the proper groups. + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) + // Compute the pairing res, err := pairing.Pair([]*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) From c89e53653cd6d3711f4d85bd6ea0e4db5819c7a9 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 01:56:41 +0200 Subject: [PATCH 21/28] refactor: init point at return --- std/algebra/emulated/sw_bn254/g2.go | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 5daa790c7b..71026f66f0 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -51,21 +51,24 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { } func (g2 *G2) phi(q *G2Affine) *G2Affine { - var phiq G2Affine - phiq.X = *g2.Ext2.MulByElement(&q.X, g2.w) - phiq.Y = q.Y + x := g2.Ext2.MulByElement(&q.X, g2.w) - return &phiq + return &G2Affine{ + X: *x, + Y: q.Y, + } } func (g2 *G2) psi(q *G2Affine) *G2Affine { - var psiq G2Affine - psiq.X = *g2.Ext2.Conjugate(&q.X) - psiq.X = *g2.Ext2.Mul(&psiq.X, g2.u) - psiq.Y = *g2.Ext2.Conjugate(&q.Y) - psiq.Y = *g2.Ext2.Mul(&psiq.Y, g2.v) + x := g2.Ext2.Conjugate(&q.X) + x = g2.Ext2.Mul(x, g2.u) + y := g2.Ext2.Conjugate(&q.Y) + y = g2.Ext2.Mul(y, g2.v) - return &psiq + return &G2Affine{ + X: *x, + Y: *y, + } } func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { From ee8e8836dcfd2a297d051b52bdbca6b8f42ef140 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 02:08:04 +0200 Subject: [PATCH 22/28] refactor: use assertIsOnCurve from sw_emulated --- std/algebra/emulated/sw_bls12381/pairing.go | 21 ++++++++------------- std/algebra/emulated/sw_bn254/pairing.go | 21 ++++++++------------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 285f7cae23..3344d5edf4 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -8,6 +8,7 @@ import ( bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bls12381" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) @@ -15,6 +16,7 @@ type Pairing struct { api frontend.API *fields_bls12381.Ext12 curveF *emulated.Field[emulated.BLS12381Fp] + curve *sw_emulated.Curve[emulated.BLS12381Fp, emulated.BLS12381Fr] } type GTEl = fields_bls12381.E12 @@ -57,10 +59,15 @@ func NewPairing(api frontend.API) (*Pairing, error) { if err != nil { return nil, fmt.Errorf("new base api: %w", err) } + curve, err := sw_emulated.New[emulated.BLS12381Fp, emulated.BLS12381Fr](api, sw_emulated.GetBLS12381Params()) + if err != nil { + return nil, fmt.Errorf("new curve: %w", err) + } return &Pairing{ api: api, Ext12: fields_bls12381.NewExt12(api), curveF: ba, + curve: curve, }, nil } @@ -228,19 +235,7 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { } func (pr Pairing) AssertIsOnCurve(P *G1Affine) { - // Curve: Y² == X³ + aX + b, where a=0 and b=4 - // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) - - // if P=(0,0) we assign b=0 otherwise 3, and continue - selector := pr.api.And(pr.curveF.IsZero(&P.X), pr.curveF.IsZero(&P.Y)) - bCurve := emulated.ValueOf[emulated.BLS12381Fp](4) - b := pr.curveF.Select(selector, pr.curveF.Zero(), &bCurve) - - left := pr.curveF.Mul(&P.Y, &P.Y) - right := pr.curveF.Mul(&P.X, &P.X) - right = pr.curveF.Mul(right, &P.X) - right = pr.curveF.Add(right, b) - pr.curveF.AssertIsEqual(left, right) + pr.curve.AssertIsOnCurve(P) } func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 5934392ddb..686b85ad12 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -8,6 +8,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) @@ -15,6 +16,7 @@ type Pairing struct { api frontend.API *fields_bn254.Ext12 curveF *emulated.Field[emulated.BN254Fp] + curve *sw_emulated.Curve[emulated.BN254Fp, emulated.BN254Fr] g2 *G2 } @@ -58,10 +60,15 @@ func NewPairing(api frontend.API) (*Pairing, error) { if err != nil { return nil, fmt.Errorf("new base api: %w", err) } + curve, err := sw_emulated.New[emulated.BN254Fp, emulated.BN254Fr](api, sw_emulated.GetBN254Params()) + if err != nil { + return nil, fmt.Errorf("new curve: %w", err) + } return &Pairing{ api: api, Ext12: fields_bn254.NewExt12(api), curveF: ba, + curve: curve, g2: NewG2(api), }, nil } @@ -235,19 +242,7 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { } func (pr Pairing) AssertIsOnCurve(P *G1Affine) { - // Curve: Y² == X³ + aX + b, where a=0 and b=3 - // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) - - // if P=(0,0) we assign b=0 otherwise 3, and continue - selector := pr.api.And(pr.curveF.IsZero(&P.X), pr.curveF.IsZero(&P.Y)) - bCurve := emulated.ValueOf[emulated.BN254Fp](3) - b := pr.curveF.Select(selector, pr.curveF.Zero(), &bCurve) - - left := pr.curveF.Mul(&P.Y, &P.Y) - right := pr.curveF.Mul(&P.X, &P.X) - right = pr.curveF.Mul(right, &P.X) - right = pr.curveF.Add(right, b) - pr.curveF.AssertIsEqual(left, right) + pr.curve.AssertIsOnCurve(P) } func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { From 36ee060ff50731d14b88e0117ec6affc2c410036 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 02:12:26 +0200 Subject: [PATCH 23/28] refactor: init b of twist once --- std/algebra/emulated/sw_bn254/pairing.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 686b85ad12..0602451f82 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -18,6 +18,7 @@ type Pairing struct { curveF *emulated.Field[emulated.BN254Fp] curve *sw_emulated.Curve[emulated.BN254Fp, emulated.BN254Fr] g2 *G2 + bTwist *fields_bn254.E2 } type GTEl = fields_bn254.E12 @@ -64,12 +65,17 @@ func NewPairing(api frontend.API) (*Pairing, error) { if err != nil { return nil, fmt.Errorf("new curve: %w", err) } + bTwist := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), + A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), + } return &Pairing{ api: api, Ext12: fields_bn254.NewExt12(api), curveF: ba, curve: curve, g2: NewG2(api), + bTwist: &bTwist, }, nil } @@ -251,11 +257,7 @@ func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { // if Q=(0,0) we assign b=0 otherwise 3/(9+u), and continue selector := pr.api.And(pr.Ext2.IsZero(&Q.X), pr.Ext2.IsZero(&Q.Y)) - bTwist := fields_bn254.E2{ - A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), - A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), - } - b := pr.Ext2.Select(selector, pr.Ext2.Zero(), &bTwist) + b := pr.Ext2.Select(selector, pr.Ext2.Zero(), pr.bTwist) left := pr.Ext2.Square(&Q.Y) right := pr.Ext2.Square(&Q.X) From 93604b78ac50f50113016a337e59f60f0a9d25f1 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 02:13:08 +0200 Subject: [PATCH 24/28] refactor: in method work with pointers instead of values --- std/algebra/emulated/sw_bn254/pairing.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 0602451f82..852c731bae 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -279,19 +279,19 @@ func (pr Pairing) AssertIsOnG2(Q *G2Affine) { // 2- Check Q has the right subgroup order // [x₀]Q - xQ := *pr.g2.scalarMulBySeed(Q) + xQ := pr.g2.scalarMulBySeed(Q) // ψ([x₀]Q) - psixQ := *pr.g2.psi(&xQ) + psixQ := pr.g2.psi(xQ) // ψ²([x₀]Q) = -ϕ([x₀]Q) - psi2xQ := *pr.g2.phi(&xQ) + psi2xQ := pr.g2.phi(xQ) // ψ³([2x₀]Q) - psi3xxQ := *pr.g2.double(&psi2xQ) - psi3xxQ = *pr.g2.psi(&psi3xxQ) + psi3xxQ := pr.g2.double(psi2xQ) + psi3xxQ = pr.g2.psi(psi3xxQ) // _Q = ψ³([2x₀]Q) - ψ²([x₀]Q) - ψ([x₀]Q) - [x₀]Q - _Q := *pr.g2.sub(&psi2xQ, &psi3xxQ) - _Q = *pr.g2.sub(&_Q, &psixQ) - _Q = *pr.g2.sub(&_Q, &xQ) + _Q := pr.g2.sub(psi2xQ, psi3xxQ) + _Q = pr.g2.sub(_Q, psixQ) + _Q = pr.g2.sub(_Q, xQ) // [r]Q == 0 <==> _Q == Q pr.Ext2.AssertIsEqual(&Q.X, &_Q.X) From af9d1d4efdf88285683628bdf0d2ceb435a4a8b6 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 18 Apr 2023 15:01:30 +0200 Subject: [PATCH 25/28] feat(sw_bls12381): G1 and G2 membership without hints --- std/algebra/emulated/sw_bls12381/g1.go | 29 +++ std/algebra/emulated/sw_bls12381/g2.go | 195 ++++++++++++++++++++ std/algebra/emulated/sw_bls12381/g2_test.go | 120 ++++++++++++ std/algebra/emulated/sw_bls12381/hints.go | 68 ------- std/algebra/emulated/sw_bls12381/pairing.go | 81 ++++---- std/algebra/emulated/sw_bn254/g2_test.go | 28 +++ std/algebra/emulated/sw_bn254/pairing.go | 3 +- 7 files changed, 405 insertions(+), 119 deletions(-) create mode 100644 std/algebra/emulated/sw_bls12381/g2_test.go delete mode 100644 std/algebra/emulated/sw_bls12381/hints.go diff --git a/std/algebra/emulated/sw_bls12381/g1.go b/std/algebra/emulated/sw_bls12381/g1.go index fd95f4722b..f7908b5ded 100644 --- a/std/algebra/emulated/sw_bls12381/g1.go +++ b/std/algebra/emulated/sw_bls12381/g1.go @@ -1,7 +1,10 @@ package sw_bls12381 import ( + "fmt" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) @@ -14,3 +17,29 @@ func NewG1Affine(v bls12381.G1Affine) G1Affine { Y: emulated.ValueOf[emulated.BLS12381Fp](v.Y), } } + +type G1 struct { + curveF *emulated.Field[emulated.BLS12381Fp] + w *emulated.Element[emulated.BLS12381Fp] +} + +func NewG1(api frontend.API) (*G1, error) { + ba, err := emulated.NewField[emulated.BLS12381Fp](api) + if err != nil { + return nil, fmt.Errorf("new base api: %w", err) + } + w := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436") + return &G1{ + curveF: ba, + w: &w, + }, nil +} + +func (g1 *G1) phi(q *G1Affine) *G1Affine { + x := g1.curveF.Mul(&q.X, g1.w) + + return &G1Affine{ + X: *x, + Y: q.Y, + } +} diff --git a/std/algebra/emulated/sw_bls12381/g2.go b/std/algebra/emulated/sw_bls12381/g2.go index f96ea4c354..45077a6cba 100644 --- a/std/algebra/emulated/sw_bls12381/g2.go +++ b/std/algebra/emulated/sw_bls12381/g2.go @@ -1,15 +1,39 @@ package sw_bls12381 import ( + "math/big" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bls12381" "github.com/consensys/gnark/std/math/emulated" ) +type G2 struct { + *fields_bls12381.Ext2 + u1, w *emulated.Element[emulated.BLS12381Fp] + v *fields_bls12381.E2 +} + type G2Affine struct { X, Y fields_bls12381.E2 } +func NewG2(api frontend.API) *G2 { + w := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436") + u1 := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") + v := fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp]("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530"), + A1: emulated.ValueOf[emulated.BLS12381Fp]("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"), + } + return &G2{ + Ext2: fields_bls12381.NewExt2(api), + w: &w, + u1: &u1, + v: &v, + } +} + func NewG2Affine(v bls12381.G2Affine) G2Affine { return G2Affine{ X: fields_bls12381.E2{ @@ -22,3 +46,174 @@ func NewG2Affine(v bls12381.G2Affine) G2Affine { }, } } + +func (g2 *G2) psi(q *G2Affine) *G2Affine { + x := g2.Ext2.MulByElement(&q.X, g2.u1) + y := g2.Ext2.Conjugate(&q.Y) + y = g2.Ext2.Mul(y, g2.v) + + return &G2Affine{ + X: fields_bls12381.E2{A0: x.A1, A1: x.A0}, + Y: *y, + } +} + +func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { + + z := g2.triple(q) + z = g2.double(z) + z = g2.doubleAndAdd(z, q) + z = g2.doubleN(z, 2) + z = g2.doubleAndAdd(z, q) + z = g2.doubleN(z, 8) + z = g2.doubleAndAdd(z, q) + z = g2.doubleN(z, 31) + z = g2.doubleAndAdd(z, q) + z = g2.doubleN(z, 16) + + return g2.neg(z) +} + +func (g2 G2) add(p, q *G2Affine) *G2Affine { + // compute λ = (q.y-p.y)/(q.x-p.x) + qypy := g2.Ext2.Sub(&q.Y, &p.Y) + qxpx := g2.Ext2.Sub(&q.X, &p.X) + λ := g2.Ext2.DivUnchecked(qypy, qxpx) + + // xr = λ²-p.x-q.x + λλ := g2.Ext2.Square(λ) + qxpx = g2.Ext2.Add(&p.X, &q.X) + xr := g2.Ext2.Sub(λλ, qxpx) + + // p.y = λ(p.x-r.x) - p.y + pxrx := g2.Ext2.Sub(&p.X, xr) + λpxrx := g2.Ext2.Mul(λ, pxrx) + yr := g2.Ext2.Sub(λpxrx, &p.Y) + + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 G2) neg(p *G2Affine) *G2Affine { + xr := &p.X + yr := g2.Ext2.Neg(&p.Y) + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 G2) sub(p, q *G2Affine) *G2Affine { + qNeg := g2.neg(q) + return g2.add(p, qNeg) +} + +func (g2 *G2) double(p *G2Affine) *G2Affine { + // compute λ = (3p.x²)/2*p.y + xx3a := g2.Square(&p.X) + xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) + y2 := g2.Double(&p.Y) + λ := g2.DivUnchecked(xx3a, y2) + + // xr = λ²-2p.x + x2 := g2.Double(&p.X) + λλ := g2.Square(λ) + xr := g2.Sub(λλ, x2) + + // yr = λ(p-xr) - p.y + pxrx := g2.Sub(&p.X, xr) + λpxrx := g2.Mul(λ, pxrx) + yr := g2.Sub(λpxrx, &p.Y) + + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 *G2) doubleN(p *G2Affine, n int) *G2Affine { + pn := p + for s := 0; s < n; s++ { + pn = g2.double(pn) + } + return pn +} + +func (g2 G2) triple(p *G2Affine) *G2Affine { + + // compute λ1 = (3p.x²)/2p.y + xx := g2.Square(&p.X) + xx = g2.MulByConstElement(xx, big.NewInt(3)) + y2 := g2.Double(&p.Y) + λ1 := g2.DivUnchecked(xx, y2) + + // xr = λ1²-2p.x + x2 := g2.MulByConstElement(&p.X, big.NewInt(2)) + λ1λ1 := g2.Square(λ1) + x2 = g2.Sub(λ1λ1, x2) + + // ommit y2 computation, and + // compute λ2 = 2p.y/(x2 − p.x) − λ1. + x1x2 := g2.Sub(&p.X, x2) + λ2 := g2.DivUnchecked(y2, x1x2) + λ2 = g2.Sub(λ2, λ1) + + // xr = λ²-p.x-x2 + λ2λ2 := g2.Square(λ2) + qxrx := g2.Add(x2, &p.X) + xr := g2.Sub(λ2λ2, qxrx) + + // yr = λ(p.x-xr) - p.y + pxrx := g2.Sub(&p.X, xr) + λ2pxrx := g2.Mul(λ2, pxrx) + yr := g2.Sub(λ2pxrx, &p.Y) + + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { + + // compute λ1 = (q.y-p.y)/(q.x-p.x) + yqyp := g2.Ext2.Sub(&q.Y, &p.Y) + xqxp := g2.Ext2.Sub(&q.X, &p.X) + λ1 := g2.Ext2.DivUnchecked(yqyp, xqxp) + + // compute x2 = λ1²-p.x-q.x + λ1λ1 := g2.Ext2.Square(λ1) + xqxp = g2.Ext2.Add(&p.X, &q.X) + x2 := g2.Ext2.Sub(λ1λ1, xqxp) + + // ommit y2 computation + // compute λ2 = -λ1-2*p.y/(x2-p.x) + ypyp := g2.Ext2.Add(&p.Y, &p.Y) + x2xp := g2.Ext2.Sub(x2, &p.X) + λ2 := g2.Ext2.DivUnchecked(ypyp, x2xp) + λ2 = g2.Ext2.Add(λ1, λ2) + λ2 = g2.Ext2.Neg(λ2) + + // compute x3 =λ2²-p.x-x3 + λ2λ2 := g2.Ext2.Square(λ2) + x3 := g2.Ext2.Sub(λ2λ2, &p.X) + x3 = g2.Ext2.Sub(x3, x2) + + // compute y3 = λ2*(p.x - x3)-p.y + y3 := g2.Ext2.Sub(&p.X, x3) + y3 = g2.Ext2.Mul(λ2, y3) + y3 = g2.Ext2.Sub(y3, &p.Y) + + return &G2Affine{ + X: *x3, + Y: *y3, + } +} + +// AssertIsEqual asserts that p and q are the same point. +func (g2 *G2) AssertIsEqual(p, q *G2Affine) { + g2.Ext2.AssertIsEqual(&p.X, &q.X) + g2.Ext2.AssertIsEqual(&p.Y, &q.Y) +} diff --git a/std/algebra/emulated/sw_bls12381/g2_test.go b/std/algebra/emulated/sw_bls12381/g2_test.go new file mode 100644 index 0000000000..76937d9623 --- /dev/null +++ b/std/algebra/emulated/sw_bls12381/g2_test.go @@ -0,0 +1,120 @@ +package sw_bls12381 + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type addG2Circuit struct { + In1, In2 G2Affine + Res G2Affine +} + +func (c *addG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.add(&c.In1, &c.In2) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestAddG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + _, in2 := randomG1G2Affines(assert) + var res bls12381.G2Affine + res.Add(&in1, &in2) + witness := addG2Circuit{ + In1: NewG2Affine(in1), + In2: NewG2Affine(in2), + Res: NewG2Affine(res), + } + err := test.IsSolved(&addG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type doubleG2Circuit struct { + In1 G2Affine + Res G2Affine +} + +func (c *doubleG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.double(&c.In1) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestDoubleG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + var res bls12381.G2Affine + var in1Jac, resJac bls12381.G2Jac + in1Jac.FromAffine(&in1) + resJac.Double(&in1Jac) + res.FromJacobian(&resJac) + witness := doubleG2Circuit{ + In1: NewG2Affine(in1), + Res: NewG2Affine(res), + } + err := test.IsSolved(&doubleG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type doubleAndAddG2Circuit struct { + In1, In2 G2Affine + Res G2Affine +} + +func (c *doubleAndAddG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.doubleAndAdd(&c.In1, &c.In2) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestDoubleAndAddG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + _, in2 := randomG1G2Affines(assert) + var res bls12381.G2Affine + res.Double(&in1). + Add(&res, &in2) + witness := doubleAndAddG2Circuit{ + In1: NewG2Affine(in1), + In2: NewG2Affine(in2), + Res: NewG2Affine(res), + } + err := test.IsSolved(&doubleAndAddG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type scalarMulG2BySeedCircuit struct { + In1 G2Affine + Res G2Affine +} + +func (c *scalarMulG2BySeedCircuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.scalarMulBySeed(&c.In1) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestScalarMulG2BySeedTestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + var res bls12381.G2Affine + x0, _ := new(big.Int).SetString("15132376222941642752", 10) + res.ScalarMultiplication(&in1, x0).Neg(&res) + witness := scalarMulG2BySeedCircuit{ + In1: NewG2Affine(in1), + Res: NewG2Affine(res), + } + err := test.IsSolved(&scalarMulG2BySeedCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/sw_bls12381/hints.go b/std/algebra/emulated/sw_bls12381/hints.go deleted file mode 100644 index b9f34dcc1a..0000000000 --- a/std/algebra/emulated/sw_bls12381/hints.go +++ /dev/null @@ -1,68 +0,0 @@ -package sw_bls12381 - -import ( - "math/big" - - bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/math/emulated" -) - -func init() { - solver.RegisterHint(GetHints()...) -} - -// GetHints returns all hint functions used in the package. -func GetHints() []solver.Hint { - return []solver.Hint{ - subgroupG1Hint, - subgroupG2Hint, - } -} - -func subgroupG1Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bls12381.G1Affine - - a.X.SetBigInt(inputs[0]) - a.Y.SetBigInt(inputs[1]) - - // c = -[x²]ϕ(p) - x0, _ := new(big.Int).SetString("15132376222941642752", 10) // negative - var jac bls12381.G1Jac - jac.FromAffine(&a) - jac.Phi(&jac).ScalarMultiplication(&jac, x0). - ScalarMultiplication(&jac, x0). - Neg(&jac) - c.FromJacobian(&jac) - - c.X.BigInt(outputs[0]) - c.Y.BigInt(outputs[1]) - - return nil - }) -} - -func subgroupG2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bls12381.G2Affine - - a.X.A0.SetBigInt(inputs[0]) - a.X.A1.SetBigInt(inputs[1]) - a.Y.A0.SetBigInt(inputs[2]) - a.Y.A1.SetBigInt(inputs[3]) - - // c = [x₀]a - x0, _ := new(big.Int).SetString("15132376222941642752", 10) // negative - c.ScalarMultiplication(&a, x0).Neg(&c) - - c.X.A0.BigInt(outputs[0]) - c.X.A1.BigInt(outputs[1]) - c.Y.A0.BigInt(outputs[2]) - c.Y.A1.BigInt(outputs[3]) - - return nil - }) -} diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 3344d5edf4..58038989c0 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -16,7 +16,10 @@ type Pairing struct { api frontend.API *fields_bls12381.Ext12 curveF *emulated.Field[emulated.BLS12381Fp] + g2 *G2 + g1 *G1 curve *sw_emulated.Curve[emulated.BLS12381Fp, emulated.BLS12381Fr] + bTwist *fields_bls12381.E2 } type GTEl = fields_bls12381.E12 @@ -63,11 +66,22 @@ func NewPairing(api frontend.API) (*Pairing, error) { if err != nil { return nil, fmt.Errorf("new curve: %w", err) } + bTwist := fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp]("4"), + A1: emulated.ValueOf[emulated.BLS12381Fp]("4"), + } + g1, err := NewG1(api) + if err != nil { + return nil, fmt.Errorf("new G1 struct: %w", err) + } return &Pairing{ api: api, Ext12: fields_bls12381.NewExt12(api), curveF: ba, curve: curve, + g1: g1, + g2: NewG2(api), + bTwist: &bTwist, }, nil } @@ -244,11 +258,8 @@ func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { // if Q=(0,0) we assign b=0 otherwise 3/(9+u), and continue selector := pr.api.And(pr.Ext2.IsZero(&Q.X), pr.Ext2.IsZero(&Q.Y)) - bTwist := fields_bls12381.E2{ - A0: emulated.ValueOf[emulated.BLS12381Fp]("4"), - A1: emulated.ValueOf[emulated.BLS12381Fp]("4"), - } - b := pr.Ext2.Select(selector, pr.Ext2.Zero(), &bTwist) + + b := pr.Ext2.Select(selector, pr.Ext2.Zero(), pr.bTwist) left := pr.Ext2.Square(&Q.Y) right := pr.Ext2.Square(&Q.X) @@ -262,21 +273,16 @@ func (pr Pairing) AssertIsOnG1(P *G1Affine) { pr.AssertIsOnCurve(P) // 2- Check P has the right subgroup order - res, err := pr.curveF.NewHint(subgroupG1Hint, 2, &P.X, &P.Y) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } - - // _P = -[x²]ϕ(p) - _P := G1Affine{ - X: *res[0], - Y: *res[1], - } - - // [r]Q == 0 <==> P = _P - pr.curveF.AssertIsEqual(&P.X, &_P.X) - pr.curveF.AssertIsEqual(&P.Y, &_P.Y) + // TODO: add phi and scalarMulBySeedSquare to g1.go + // [x²]ϕ(P) + phiP := pr.g1.phi(P) + seedSquare := emulated.ValueOf[emulated.BLS12381Fr]("228988810152649578064853576960394133504") + // TODO: use addchain to construct a fixed-scalar ScalarMul + _P := pr.curve.ScalarMul(phiP, &seedSquare) + _P = pr.curve.Neg(_P) + + // [r]Q == 0 <==> P = -[x²]ϕ(P) + pr.curve.AssertIsEqual(_P, P) } func (pr Pairing) AssertIsOnG2(Q *G2Affine) { @@ -284,36 +290,13 @@ func (pr Pairing) AssertIsOnG2(Q *G2Affine) { pr.AssertIsOnTwist(Q) // 2- Check Q has the right subgroup order - res, err := pr.curveF.NewHint(subgroupG2Hint, 4, &Q.X.A0, &Q.X.A1, &Q.Y.A0, &Q.Y.A1) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } - - // _Q = [x₀]Q - _Q := G2Affine{ - X: fields_bls12381.E2{A0: *res[0], A1: *res[1]}, - Y: fields_bls12381.E2{A0: *res[2], A1: *res[3]}, - } - - // [r]Q == 0 <==> ψ(Q) = _Q - var psiQ G2Affine - u1 := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") - v := fields_bls12381.E2{ - A0: emulated.ValueOf[emulated.BLS12381Fp]("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530"), - A1: emulated.ValueOf[emulated.BLS12381Fp]("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"), - } - + // [x₀]Q + xQ := pr.g2.scalarMulBySeed(Q) // ψ(Q) - psiQ.X = *pr.Ext2.Conjugate(&Q.X) - tmp := *pr.curveF.Mul(&psiQ.X.A1, &u1) - psiQ.X.A1 = *pr.curveF.Mul(&psiQ.X.A0, &u1) - psiQ.X.A0 = *pr.curveF.Neg(&tmp) - psiQ.Y = *pr.Ext2.Conjugate(&Q.Y) - psiQ.Y = *pr.Ext2.Mul(&psiQ.Y, &v) - - pr.Ext2.AssertIsEqual(&psiQ.X, &_Q.X) - pr.Ext2.AssertIsEqual(&psiQ.Y, &_Q.Y) + psiQ := pr.g2.psi(Q) + + // [r]Q == 0 <==> ψ(Q) == [x₀]Q + pr.g2.AssertIsEqual(xQ, psiQ) } // loopCounter = seed in binary diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go index 8aa5ae6cef..1b189abc5b 100644 --- a/std/algebra/emulated/sw_bn254/g2_test.go +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -65,6 +65,34 @@ func TestDoubleG2TestSolve(t *testing.T) { assert.NoError(err) } +type doubleAndAddG2Circuit struct { + In1, In2 G2Affine + Res G2Affine +} + +func (c *doubleAndAddG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.doubleAndAdd(&c.In1, &c.In2) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestDoubleAndAddG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + _, in2 := randomG1G2Affines(assert) + var res bn254.G2Affine + res.Double(&in1). + Add(&res, &in2) + witness := doubleAndAddG2Circuit{ + In1: NewG2Affine(in1), + In2: NewG2Affine(in2), + Res: NewG2Affine(res), + } + err := test.IsSolved(&doubleAndAddG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + type scalarMulG2BySeedCircuit struct { In1 G2Affine Res G2Affine diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 852c731bae..5ed4e08f81 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -294,8 +294,7 @@ func (pr Pairing) AssertIsOnG2(Q *G2Affine) { _Q = pr.g2.sub(_Q, xQ) // [r]Q == 0 <==> _Q == Q - pr.Ext2.AssertIsEqual(&Q.X, &_Q.X) - pr.Ext2.AssertIsEqual(&Q.Y, &_Q.Y) + pr.g2.AssertIsEqual(Q, _Q) } // loopCounter = 6x₀+2 = 29793968203157093288 From 20aba9cb40f685022b3562ce6b681e79fee0ba9b Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 18 Apr 2023 15:03:42 +0200 Subject: [PATCH 26/28] chore: go get gnark-crypto@develop --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index e27a842665..6339d3788b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59 + github.com/consensys/gnark-crypto v0.10.1-0.20230418130058-330c1cb071dc github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index b840dcf2ae..65a38fcad0 100644 --- a/go.sum +++ b/go.sum @@ -4,10 +4,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de h1:W5lRxU8Rk8CDLHMTeyNst0VESbcU5RZ3U1TS9MNGgCQ= -github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= -github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59 h1:KYAxBDzdiFQWO+lptSBb+7/UUHKjObS87Bx7pBGX1DU= -github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.10.1-0.20230418130058-330c1cb071dc h1:n5DKBt6tIB2+jm0mjgU56Zur9DiQE7FcWsDgK1+PijI= +github.com/consensys/gnark-crypto v0.10.1-0.20230418130058-330c1cb071dc/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 462d04f1df5552f528cdbac6ca900c1bd2788a87 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 25 Apr 2023 15:23:53 +0200 Subject: [PATCH 27/28] docs: typo --- std/evmprecompiles/06-bnadd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/evmprecompiles/06-bnadd.go b/std/evmprecompiles/06-bnadd.go index ed40938a2f..ff6c397fc9 100644 --- a/std/evmprecompiles/06-bnadd.go +++ b/std/evmprecompiles/06-bnadd.go @@ -15,7 +15,7 @@ func ECAdd(api frontend.API, P, Q *sw_emulated.AffinePoint[emulated.BN254Fp]) *s panic(err) } // Check that P and Q are on the curve (done in the zkEVM ⚠️ ) - // We use AddUnified because P can be equal to Q, -Q and eithier or both can be (0,0) + // We use AddUnified because P can be equal to Q, -Q and either or both can be (0,0) res := curve.AddUnified(P, Q) return res } From 07416c77e302a141a9796fe411df6afa27554e18 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 25 Apr 2023 19:47:37 +0200 Subject: [PATCH 28/28] test: use assertless sampling --- std/algebra/emulated/sw_bn254/g2_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go index 1b189abc5b..3e61f05cc4 100644 --- a/std/algebra/emulated/sw_bn254/g2_test.go +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -24,8 +24,8 @@ func (c *addG2Circuit) Define(api frontend.API) error { func TestAddG2TestSolve(t *testing.T) { assert := test.NewAssert(t) - _, in1 := randomG1G2Affines(assert) - _, in2 := randomG1G2Affines(assert) + _, in1 := randomG1G2Affines() + _, in2 := randomG1G2Affines() var res bn254.G2Affine res.Add(&in1, &in2) witness := addG2Circuit{ @@ -51,7 +51,7 @@ func (c *doubleG2Circuit) Define(api frontend.API) error { func TestDoubleG2TestSolve(t *testing.T) { assert := test.NewAssert(t) - _, in1 := randomG1G2Affines(assert) + _, in1 := randomG1G2Affines() var res bn254.G2Affine var in1Jac, resJac bn254.G2Jac in1Jac.FromAffine(&in1) @@ -79,8 +79,8 @@ func (c *doubleAndAddG2Circuit) Define(api frontend.API) error { func TestDoubleAndAddG2TestSolve(t *testing.T) { assert := test.NewAssert(t) - _, in1 := randomG1G2Affines(assert) - _, in2 := randomG1G2Affines(assert) + _, in1 := randomG1G2Affines() + _, in2 := randomG1G2Affines() var res bn254.G2Affine res.Double(&in1). Add(&res, &in2) @@ -107,7 +107,7 @@ func (c *scalarMulG2BySeedCircuit) Define(api frontend.API) error { func TestScalarMulG2BySeedTestSolve(t *testing.T) { assert := test.NewAssert(t) - _, in1 := randomG1G2Affines(assert) + _, in1 := randomG1G2Affines() var res bn254.G2Affine x0, _ := new(big.Int).SetString("4965661367192848881", 10) res.ScalarMultiplication(&in1, x0) @@ -135,7 +135,7 @@ func (c *endomorphismG2Circuit) Define(api frontend.API) error { func TestEndomorphismG2TestSolve(t *testing.T) { assert := test.NewAssert(t) - _, in1 := randomG1G2Affines(assert) + _, in1 := randomG1G2Affines() witness := endomorphismG2Circuit{ In1: NewG2Affine(in1), }