From 7b5c8a47df35e40e4384d9e210cffaa83c8583bf Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 4 Nov 2024 16:32:01 +0000 Subject: [PATCH 01/14] perf: use nonnative eval for fp6 mul --- std/algebra/emulated/fields_bw6761/e6.go | 35 +++++++++++++++++-- std/algebra/emulated/fields_bw6761/e6_test.go | 35 +++++++++++++++++-- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/std/algebra/emulated/fields_bw6761/e6.go b/std/algebra/emulated/fields_bw6761/e6.go index 433b92cc5a..ded395bd57 100644 --- a/std/algebra/emulated/fields_bw6761/e6.go +++ b/std/algebra/emulated/fields_bw6761/e6.go @@ -190,9 +190,7 @@ func (e Ext6) mulFpByNonResidue(fp *curveF, x *baseEl) *baseEl { } func (e Ext6) Mul(x, y *E6) *E6 { - x = e.Reduce(x) - y = e.Reduce(y) - return e.mulToomCook6(x, y) + return e.mulDirect(x, y) } func (e Ext6) mulMontgomery6(x, y *E6) *E6 { @@ -426,6 +424,37 @@ func (e Ext6) mulMontgomery6(x, y *E6) *E6 { } } +func (e Ext6) mulDirect(x, y *E6) *E6 { + nonResidue := e.fp.NewElement(-4) + // c0 = a0b0 + β(a1b5 + a2b4 + a3b3 + a4b2 + a5b1) + c0 := e.fp.Eval([][]*baseEl{{&x.A0, &y.A0}, {nonResidue, &x.A1, &y.A5}, {nonResidue, &x.A2, &y.A4}, {nonResidue, &x.A3, &y.A3}, {nonResidue, &x.A4, &y.A2}, {nonResidue, &x.A5, &y.A1}}, + []int{1, 1, 1, 1, 1, 1}) + // c1 = a0b1 + a1b0 + β(a2b5 + a3b4 + a4b3 + a5b2) + c1 := e.fp.Eval([][]*baseEl{{&x.A0, &y.A1}, {&x.A1, &y.A0}, {nonResidue, &x.A2, &y.A5}, {nonResidue, &x.A3, &y.A4}, {nonResidue, &x.A4, &y.A3}, {nonResidue, &x.A5, &y.A2}}, + []int{1, 1, 1, 1, 1, 1}) + // c2 = a0b2 + a1b1 + a2b0 + β(a3b5 + a4b4 + a5b3) + c2 := e.fp.Eval([][]*baseEl{{&x.A0, &y.A2}, {&x.A1, &y.A1}, {&x.A2, &y.A0}, {nonResidue, &x.A3, &y.A5}, {nonResidue, &x.A4, &y.A4}, {nonResidue, &x.A5, &y.A3}}, + []int{1, 1, 1, 1, 1, 1}) + // c3 = a0b3 + a1b2 + a2b1 + a3b0 + β(a4b5 + a5b4) + c3 := e.fp.Eval([][]*baseEl{{&x.A0, &y.A3}, {&x.A1, &y.A2}, {&x.A2, &y.A1}, {&x.A3, &y.A0}, {nonResidue, &x.A4, &y.A5}, {nonResidue, &x.A5, &y.A4}}, + []int{1, 1, 1, 1, 1, 1}) + // c4 = a0b4 + a1b3 + a2b2 + a3b1 + a4b0 + βa5b5 + c4 := e.fp.Eval([][]*baseEl{{&x.A0, &y.A4}, {&x.A1, &y.A3}, {&x.A2, &y.A2}, {&x.A3, &y.A1}, {&x.A4, &y.A0}, {nonResidue, &x.A5, &y.A5}}, + []int{1, 1, 1, 1, 1, 1}) + // c5 = a0b5 + a1b4 + a2b3 + a3b2 + a4b1 + a5b0, + c5 := e.fp.Eval([][]*baseEl{{&x.A0, &y.A5}, {&x.A1, &y.A4}, {&x.A2, &y.A3}, {&x.A3, &y.A2}, {&x.A4, &y.A1}, {&x.A5, &y.A0}}, + []int{1, 1, 1, 1, 1, 1}) + + return &E6{ + A0: *c0, + A1: *c1, + A2: *c2, + A3: *c3, + A4: *c4, + A5: *c5, + } +} + func (e Ext6) mulToomCook6(x, y *E6) *E6 { // Toom-Cook 6-way multiplication: // diff --git a/std/algebra/emulated/fields_bw6761/e6_test.go b/std/algebra/emulated/fields_bw6761/e6_test.go index b5745e77c6..b98f2878b2 100644 --- a/std/algebra/emulated/fields_bw6761/e6_test.go +++ b/std/algebra/emulated/fields_bw6761/e6_test.go @@ -107,8 +107,10 @@ func (circuit *e6MulVariants) Define(api frontend.API) error { e := NewExt6(api) expected1 := *e.mulMontgomery6(&circuit.A, &circuit.B) expected2 := *e.mulToomCook6(&circuit.A, &circuit.B) + expected3 := *e.mulDirect(&circuit.A, &circuit.B) e.AssertIsEqual(&expected1, &circuit.C) e.AssertIsEqual(&expected2, &circuit.C) + e.AssertIsEqual(&expected3, &circuit.C) return nil } @@ -130,15 +132,42 @@ func TestMulVariantsFp6(t *testing.T) { assert.NoError(err) } +type e6DirectMul struct { + A, B, C E6 +} + +func (circuit *e6DirectMul) Define(api frontend.API) error { + e := NewExt6(api) + expected := e.mulDirect(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDirectMulFp6(t *testing.T) { + assert := test.NewAssert(t) + // witness values + var a, b, c bw6761.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + witness := e6DirectMul{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + err := test.IsSolved(&e6DirectMul{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + type e6Mul struct { A, B, C E6 } func (circuit *e6Mul) Define(api frontend.API) error { - var expected E6 e := NewExt6(api) - expected = *e.Mul(&circuit.A, &circuit.B) - e.AssertIsEqual(&expected, &circuit.C) + expected := e.Mul(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) return nil } From 0b976b3d8308455e3882440f1c0be36c40946d65 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 4 Nov 2024 23:15:23 +0000 Subject: [PATCH 02/14] perf: add square with eval --- std/algebra/emulated/fields_bw6761/e6.go | 35 +++++++++++++ std/algebra/emulated/fields_bw6761/e6_test.go | 49 ++++++++++--------- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/std/algebra/emulated/fields_bw6761/e6.go b/std/algebra/emulated/fields_bw6761/e6.go index ded395bd57..ef7c149a8b 100644 --- a/std/algebra/emulated/fields_bw6761/e6.go +++ b/std/algebra/emulated/fields_bw6761/e6.go @@ -733,6 +733,41 @@ func (e Ext6) mulToomCook6(x, y *E6) *E6 { } func (e Ext6) Square(x *E6) *E6 { + return e.squareDirect(x) +} + +func (e Ext6) squareDirect(x *E6) *E6 { + nonResidue := e.fp.NewElement(-4) + // c0 = a0b0 + β(a1b5 + a2b4 + a3b3 + a4b2 + a5b1) + c0 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A0}, {nonResidue, &x.A1, &x.A5}, {nonResidue, &x.A2, &x.A4}, {nonResidue, &x.A3, &x.A3}, {nonResidue, &x.A4, &x.A2}, {nonResidue, &x.A5, &x.A1}}, + []int{1, 1, 1, 1, 1, 1}) + // c1 = a0b1 + a1b0 + β(a2b5 + a3b4 + a4b3 + a5b2) + c1 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A1}, {&x.A1, &x.A0}, {nonResidue, &x.A2, &x.A5}, {nonResidue, &x.A3, &x.A4}, {nonResidue, &x.A4, &x.A3}, {nonResidue, &x.A5, &x.A2}}, + []int{1, 1, 1, 1, 1, 1}) + // c2 = a0b2 + a1b1 + a2b0 + β(a3b5 + a4b4 + a5b3) + c2 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A2}, {&x.A1, &x.A1}, {&x.A2, &x.A0}, {nonResidue, &x.A3, &x.A5}, {nonResidue, &x.A4, &x.A4}, {nonResidue, &x.A5, &x.A3}}, + []int{1, 1, 1, 1, 1, 1}) + // c3 = a0b3 + a1b2 + a2b1 + a3b0 + β(a4b5 + a5b4) + c3 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A3}, {&x.A1, &x.A2}, {&x.A2, &x.A1}, {&x.A3, &x.A0}, {nonResidue, &x.A4, &x.A5}, {nonResidue, &x.A5, &x.A4}}, + []int{1, 1, 1, 1, 1, 1}) + // c4 = a0b4 + a1b3 + a2b2 + a3b1 + a4b0 + βa5b5 + c4 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A4}, {&x.A1, &x.A3}, {&x.A2, &x.A2}, {&x.A3, &x.A1}, {&x.A4, &x.A0}, {nonResidue, &x.A5, &x.A5}}, + []int{1, 1, 1, 1, 1, 1}) + // c5 = a0b5 + a1b4 + a2b3 + a3b2 + a4b1 + a5b0, + c5 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A5}, {&x.A1, &x.A4}, {&x.A2, &x.A3}, {&x.A3, &x.A2}, {&x.A4, &x.A1}, {&x.A5, &x.A0}}, + []int{1, 1, 1, 1, 1, 1}) + + return &E6{ + A0: *c0, + A1: *c1, + A2: *c2, + A3: *c3, + A4: *c4, + A5: *c5, + } +} + +func (e Ext6) squareEmulatedTower(x *E6) *E6 { // We don't use Montgomery-6 or Toom-Cook-6 for the squaring but instead we // simulate a quadratic over cubic extension tower because Karatsuba over // Chung-Hasan SQR2 is better constraint wise. diff --git a/std/algebra/emulated/fields_bw6761/e6_test.go b/std/algebra/emulated/fields_bw6761/e6_test.go index b98f2878b2..a0c7476047 100644 --- a/std/algebra/emulated/fields_bw6761/e6_test.go +++ b/std/algebra/emulated/fields_bw6761/e6_test.go @@ -105,12 +105,12 @@ type e6MulVariants struct { func (circuit *e6MulVariants) Define(api frontend.API) error { e := NewExt6(api) - expected1 := *e.mulMontgomery6(&circuit.A, &circuit.B) - expected2 := *e.mulToomCook6(&circuit.A, &circuit.B) - expected3 := *e.mulDirect(&circuit.A, &circuit.B) - e.AssertIsEqual(&expected1, &circuit.C) - e.AssertIsEqual(&expected2, &circuit.C) - e.AssertIsEqual(&expected3, &circuit.C) + expected1 := e.mulMontgomery6(&circuit.A, &circuit.B) + expected2 := e.mulToomCook6(&circuit.A, &circuit.B) + expected3 := e.mulDirect(&circuit.A, &circuit.B) + e.AssertIsEqual(expected1, &circuit.C) + e.AssertIsEqual(expected2, &circuit.C) + e.AssertIsEqual(expected3, &circuit.C) return nil } @@ -132,18 +132,18 @@ func TestMulVariantsFp6(t *testing.T) { assert.NoError(err) } -type e6DirectMul struct { +type e6Mul struct { A, B, C E6 } -func (circuit *e6DirectMul) Define(api frontend.API) error { +func (circuit *e6Mul) Define(api frontend.API) error { e := NewExt6(api) - expected := e.mulDirect(&circuit.A, &circuit.B) + expected := e.Mul(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil } -func TestDirectMulFp6(t *testing.T) { +func TestMulFp6(t *testing.T) { assert := test.NewAssert(t) // witness values var a, b, c bw6761.E6 @@ -151,41 +151,42 @@ func TestDirectMulFp6(t *testing.T) { _, _ = b.SetRandom() c.Mul(&a, &b) - witness := e6DirectMul{ + witness := e6Mul{ A: FromE6(&a), B: FromE6(&b), C: FromE6(&c), } - err := test.IsSolved(&e6DirectMul{}, &witness, ecc.BN254.ScalarField()) + + err := test.IsSolved(&e6Mul{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e6Mul struct { - A, B, C E6 +type e6SquareVariants struct { + A, C E6 } -func (circuit *e6Mul) Define(api frontend.API) error { +func (circuit *e6SquareVariants) Define(api frontend.API) error { e := NewExt6(api) - expected := e.Mul(&circuit.A, &circuit.B) - e.AssertIsEqual(expected, &circuit.C) + expected1 := e.squareDirect(&circuit.A) + expected2 := e.squareEmulatedTower(&circuit.A) + e.AssertIsEqual(expected1, &circuit.C) + e.AssertIsEqual(expected2, &circuit.C) return nil } -func TestMulFp6(t *testing.T) { +func TestSquareVariantsFp6(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, b, c bw6761.E6 + var a, c bw6761.E6 _, _ = a.SetRandom() - _, _ = b.SetRandom() - c.Mul(&a, &b) + c.Square(&a) - witness := e6Mul{ + witness := e6SquareVariants{ A: FromE6(&a), - B: FromE6(&b), C: FromE6(&c), } - err := test.IsSolved(&e6Mul{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&e6SquareVariants{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } From 7789aed7597dcceb5b33b979c4aae789ae4904cd Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 4 Nov 2024 23:28:05 +0000 Subject: [PATCH 03/14] perf: add mul 023 using eval --- .../emulated/fields_bw6761/e6_pairing.go | 32 +++++++++++++++ std/algebra/emulated/fields_bw6761/e6_test.go | 39 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/std/algebra/emulated/fields_bw6761/e6_pairing.go b/std/algebra/emulated/fields_bw6761/e6_pairing.go index e2715f3cca..0768857273 100644 --- a/std/algebra/emulated/fields_bw6761/e6_pairing.go +++ b/std/algebra/emulated/fields_bw6761/e6_pairing.go @@ -132,6 +132,38 @@ func (e Ext6) ExpC2(z *E6) *E6 { // // E6{A0: c0, A1: 0, A2: c1, A3: 1, A4: 0, A5: 0} func (e *Ext6) MulBy023(z *E6, c0, c1 *baseEl) *E6 { + return e.mulBy023Direct(z, c0, c1) +} + +// MulBy023 multiplies z by an E6 sparse element 023 using schoolbook multiplication +func (e Ext6) mulBy023Direct(z *E6, c0, c1 *baseEl) *E6 { + nonResidue := e.fp.NewElement(-4) + + // z0 = a0c0 + β(a3 + a4c1) + z0 := e.fp.Eval([][]*baseEl{{&z.A0, c0}, {nonResidue, &z.A3}, {nonResidue, &z.A4, c1}}, []int{1, 1, 1}) + // z1 = a1c0 + β(a4 + a5c1) + z1 := e.fp.Eval([][]*baseEl{{&z.A1, c0}, {nonResidue, &z.A4}, {nonResidue, &z.A5, c1}}, []int{1, 1, 1}) + // z2 = a0c1 + a2c0 + β(a5) + z2 := e.fp.Eval([][]*baseEl{{&z.A0, c1}, {&z.A2, c0}, {nonResidue, &z.A5}}, []int{1, 1, 1}) + // c3 = a0 + a1c1 + a3c0 + z3 := e.fp.Eval([][]*baseEl{{&z.A0}, {&z.A1, c1}, {&z.A3, c0}}, []int{1, 1, 1}) + // c4 = a1 + a2c1 + a4c0 + z4 := e.fp.Eval([][]*baseEl{{&z.A1}, {&z.A2, c1}, {&z.A4, c0}}, []int{1, 1, 1}) + // c5 = a2 + a3c1 + a5c0, + z5 := e.fp.Eval([][]*baseEl{{&z.A2}, {&z.A3, c1}, {&z.A5, c0}}, []int{1, 1, 1}) + + return &E6{ + A0: *z0, + A1: *z1, + A2: *z2, + A3: *z3, + A4: *z4, + A5: *z5, + } +} + +// mulBy023 multiplies z by an E6 sparse element 023 +func (e Ext6) mulBy023(z *E6, c0, c1 *baseEl) *E6 { z = e.Reduce(z) a := e.fp.Mul(&z.A0, c0) diff --git a/std/algebra/emulated/fields_bw6761/e6_test.go b/std/algebra/emulated/fields_bw6761/e6_test.go index a0c7476047..98f43024cc 100644 --- a/std/algebra/emulated/fields_bw6761/e6_test.go +++ b/std/algebra/emulated/fields_bw6761/e6_test.go @@ -342,6 +342,45 @@ func TestExptFp6(t *testing.T) { assert.NoError(err) } +type e6MulBy023Variants struct { + A E6 `gnark:",public"` + W E6 + B, C baseEl +} + +func (circuit *e6MulBy023Variants) Define(api frontend.API) error { + e := NewExt6(api) + expected1 := e.mulBy023(&circuit.A, &circuit.B, &circuit.C) + expected2 := e.mulBy023Direct(&circuit.A, &circuit.B, &circuit.C) + e.AssertIsEqual(expected1, &circuit.W) + e.AssertIsEqual(expected2, &circuit.W) + return nil +} + +func TestFp6MulBy023Variants(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, w bw6761.E6 + _, _ = a.SetRandom() + var one, b, c fp.Element + one.SetOne() + _, _ = b.SetRandom() + _, _ = c.SetRandom() + w.Set(&a) + w.MulBy014(&b, &c, &one) + + witness := e6MulBy023Variants{ + A: FromE6(&a), + B: emulated.ValueOf[emulated.BW6761Fp](&b), + C: emulated.ValueOf[emulated.BW6761Fp](&c), + W: FromE6(&w), + } + + err := test.IsSolved(&e6MulBy023Variants{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + type e6MulBy023 struct { A E6 `gnark:",public"` W E6 From cb6988b4fbe63e6bab72eca2cb2302c7f6b47303 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 4 Nov 2024 23:34:19 +0000 Subject: [PATCH 04/14] perf: add mul023By023 using eval --- .../emulated/fields_bw6761/e6_pairing.go | 28 ++++++++++++++++ std/algebra/emulated/fields_bw6761/e6_test.go | 32 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/std/algebra/emulated/fields_bw6761/e6_pairing.go b/std/algebra/emulated/fields_bw6761/e6_pairing.go index 0768857273..791279f9d5 100644 --- a/std/algebra/emulated/fields_bw6761/e6_pairing.go +++ b/std/algebra/emulated/fields_bw6761/e6_pairing.go @@ -238,6 +238,34 @@ func (e Ext6) mulBy023(z *E6, c0, c1 *baseEl) *E6 { // // E6{A0: c0, A1: 0, A2: c1, A3: 1, A4: 0, A5: 0} func (e Ext6) Mul023By023(d0, d1, c0, c1 *baseEl) [5]*baseEl { + return e.mul023by023Direct(d0, d1, c0, c1) +} + +// mul023by023Direct multiplies two E6 sparse element using schoolbook multiplication +func (e Ext6) mul023by023Direct(d0, d1, c0, c1 *baseEl) [5]*baseEl { + nonResidue := e.fp.NewElement(-4) + // c0 = d0c0 + β + z0 := e.fp.Eval([][]*baseEl{{d0, c0}, {nonResidue}}, []int{1, 1}) + // c2 = d0c1 + d1c0 + z2 := e.fp.Eval([][]*baseEl{{d0, c1}, {d1, c0}}, []int{1, 1}) + // c3 = d0 + c0 + z3 := e.fp.Add(d0, c0) + // c4 = d1c1 + z4 := e.fp.Mul(d1, c1) + // c5 = d1 + c1, + z5 := e.fp.Add(d1, c1) + + return [5]*baseEl{z0, z2, z3, z4, z5} +} + +// Mul023By023 multiplies two E6 sparse element of the form: +// +// E6{A0: c0, A1: 0, A2: c1, A3: 1, A4: 0, A5: 0} +// +// and +// +// E6{A0: c0, A1: 0, A2: c1, A3: 1, A4: 0, A5: 0} +func (e Ext6) mul023By023(d0, d1, c0, c1 *baseEl) [5]*baseEl { x0 := e.fp.Mul(c0, d0) x1 := e.fp.Mul(c1, d1) x04 := e.fp.Add(c0, d0) diff --git a/std/algebra/emulated/fields_bw6761/e6_test.go b/std/algebra/emulated/fields_bw6761/e6_test.go index 98f43024cc..59bad93e81 100644 --- a/std/algebra/emulated/fields_bw6761/e6_test.go +++ b/std/algebra/emulated/fields_bw6761/e6_test.go @@ -417,3 +417,35 @@ func TestFp6MulBy023(t *testing.T) { err := test.IsSolved(&e6MulBy023{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type e6Mul023By023Variants struct { + A E6 `gnark:",public"` + B E6 `gnark:",public"` +} + +func (circuit *e6Mul023By023Variants) Define(api frontend.API) error { + e := NewExt6(api) + expected1 := e.mul023By023(&circuit.A.A0, &circuit.A.A2, &circuit.B.A0, &circuit.B.A2) + expected2 := e.mul023by023Direct(&circuit.A.A0, &circuit.A.A2, &circuit.B.A0, &circuit.B.A2) + for i := range expected1 { + e.fp.AssertIsEqual(expected1[i], expected2[i]) + } + return nil +} + +func TestFp6Mul023By023Variants(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b bw6761.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + + witness := e6Mul023By023Variants{ + A: FromE6(&a), + B: FromE6(&b), + } + + err := test.IsSolved(&e6Mul023By023Variants{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From 743889766a20c04e9c6a73daa8cde5233cf753e2 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 4 Nov 2024 23:41:01 +0000 Subject: [PATCH 05/14] perf: mulby02345 using eval --- .../emulated/fields_bw6761/e6_pairing.go | 40 +++++++++++++++++++ std/algebra/emulated/fields_bw6761/e6_test.go | 30 ++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/std/algebra/emulated/fields_bw6761/e6_pairing.go b/std/algebra/emulated/fields_bw6761/e6_pairing.go index 791279f9d5..e02ff5ed3f 100644 --- a/std/algebra/emulated/fields_bw6761/e6_pairing.go +++ b/std/algebra/emulated/fields_bw6761/e6_pairing.go @@ -287,6 +287,46 @@ func (e Ext6) mul023By023(d0, d1, c0, c1 *baseEl) [5]*baseEl { // E6{A0: y0, A1: 0, A2: y1, A3: y2, A4: y3, A5: y4}, // } func (e *Ext6) MulBy02345(z *E6, x [5]*baseEl) *E6 { + return e.mulBy02345Direct(z, x) +} + +// mulBy02345Direct multiplies z by an E6 sparse element using schoolbook multiplication +func (e Ext6) mulBy02345Direct(z *E6, x [5]*baseEl) *E6 { + nonResidue := e.fp.NewElement(-4) + + // c0 = a0y0 + β(a1y4 + a2y3 + a3y2 + a4y1) + c0 := e.fp.Eval([][]*baseEl{{&z.A0, x[0]}, {nonResidue, &z.A1, x[4]}, {nonResidue, &z.A2, x[3]}, {nonResidue, &z.A3, x[2]}, {nonResidue, &z.A4, x[1]}}, + []int{1, 1, 1, 1, 1}) + // c1 = a1y0 + β(a2y4 + a3y3 + a4y2 + a5y1) + c1 := e.fp.Eval([][]*baseEl{{&z.A1, x[0]}, {nonResidue, &z.A2, x[4]}, {nonResidue, &z.A3, x[3]}, {nonResidue, &z.A4, x[2]}, {nonResidue, &z.A5, x[1]}}, + []int{1, 1, 1, 1, 1}) + // c2 = a0y1 + a2y0 + β(a3y4 + a4y3 + a5y2) + c2 := e.fp.Eval([][]*baseEl{{&z.A0, x[1]}, {&z.A2, x[0]}, {nonResidue, &z.A3, x[4]}, {nonResidue, &z.A4, x[3]}, {nonResidue, &z.A5, x[2]}}, + []int{1, 1, 1, 1, 1}) + // c3 = a0y2 + a1y1 + a3y0 + β(a4y4 + a5y3) + c3 := e.fp.Eval([][]*baseEl{{&z.A0, x[2]}, {&z.A1, x[1]}, {&z.A3, x[0]}, {nonResidue, &z.A4, x[4]}, {nonResidue, &z.A5, x[3]}}, + []int{1, 1, 1, 1, 1}) + // c4 = a0y3 + a1y2 + a2y1 + a4y0 + βa5y4 + c4 := e.fp.Eval([][]*baseEl{{&z.A0, x[3]}, {&z.A1, x[2]}, {&z.A2, x[1]}, {&z.A4, x[0]}, {nonResidue, &z.A5, x[4]}}, + []int{1, 1, 1, 1, 1}) + // c5 = a0y4 + a1y3 + a2y2 + a3y1 + a5y0, + c5 := e.fp.Eval([][]*baseEl{{&z.A0, x[4]}, {&z.A1, x[3]}, {&z.A2, x[2]}, {&z.A3, x[1]}, {&z.A5, x[0]}}, + []int{1, 1, 1, 1, 1}) + + return &E6{ + A0: *c0, + A1: *c1, + A2: *c2, + A3: *c3, + A4: *c4, + A5: *c5, + } +} + +// mulBy02345 multiplies z by an E6 sparse element of the form +// +// E6{A0: y0, A1: 0, A2: y1, A3: y2, A4: y3, A5: y4}, +func (e *Ext6) mulBy02345(z *E6, x [5]*baseEl) *E6 { a0 := e.fp.Add(&z.A0, &z.A1) a1 := e.fp.Add(&z.A2, &z.A3) a2 := e.fp.Add(&z.A4, &z.A5) diff --git a/std/algebra/emulated/fields_bw6761/e6_test.go b/std/algebra/emulated/fields_bw6761/e6_test.go index 59bad93e81..c54a0b0cd0 100644 --- a/std/algebra/emulated/fields_bw6761/e6_test.go +++ b/std/algebra/emulated/fields_bw6761/e6_test.go @@ -449,3 +449,33 @@ func TestFp6Mul023By023Variants(t *testing.T) { err := test.IsSolved(&e6Mul023By023Variants{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type e6MulBy02345Variants struct { + A E6 `gnark:",public"` + B E6 `gnark:",public"` +} + +func (circuit *e6MulBy02345Variants) Define(api frontend.API) error { + e := NewExt6(api) + expected1 := e.mulBy02345(&circuit.A, [5]*baseEl{&circuit.B.A0, &circuit.B.A2, &circuit.B.A3, &circuit.B.A4, &circuit.B.A5}) + expected2 := e.mulBy02345Direct(&circuit.A, [5]*baseEl{&circuit.B.A0, &circuit.B.A2, &circuit.B.A3, &circuit.B.A4, &circuit.B.A5}) + e.AssertIsEqual(expected1, expected2) + return nil +} + +func TestFp6MulBy02345Variants(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b bw6761.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + + witness := e6MulBy02345Variants{ + A: FromE6(&a), + B: FromE6(&b), + } + + err := test.IsSolved(&e6MulBy02345Variants{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From 384dcf47136f0f2af646beab73c7cb5d5252f6dd Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 4 Nov 2024 23:41:36 +0000 Subject: [PATCH 06/14] chore: fix docs --- std/algebra/emulated/fields_bw6761/e6.go | 1 + std/algebra/emulated/fields_bw6761/e6_pairing.go | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/std/algebra/emulated/fields_bw6761/e6.go b/std/algebra/emulated/fields_bw6761/e6.go index ef7c149a8b..47919d0d22 100644 --- a/std/algebra/emulated/fields_bw6761/e6.go +++ b/std/algebra/emulated/fields_bw6761/e6.go @@ -736,6 +736,7 @@ func (e Ext6) Square(x *E6) *E6 { return e.squareDirect(x) } +// squareDirect computes the square of an element in E6 using schoolbook multiplication. func (e Ext6) squareDirect(x *E6) *E6 { nonResidue := e.fp.NewElement(-4) // c0 = a0b0 + β(a1b5 + a2b4 + a3b3 + a4b2 + a5b1) diff --git a/std/algebra/emulated/fields_bw6761/e6_pairing.go b/std/algebra/emulated/fields_bw6761/e6_pairing.go index e02ff5ed3f..47a1fec18d 100644 --- a/std/algebra/emulated/fields_bw6761/e6_pairing.go +++ b/std/algebra/emulated/fields_bw6761/e6_pairing.go @@ -135,7 +135,7 @@ func (e *Ext6) MulBy023(z *E6, c0, c1 *baseEl) *E6 { return e.mulBy023Direct(z, c0, c1) } -// MulBy023 multiplies z by an E6 sparse element 023 using schoolbook multiplication +// mulBy023Direct multiplies z by an E6 sparse element 023 using schoolbook multiplication func (e Ext6) mulBy023Direct(z *E6, c0, c1 *baseEl) *E6 { nonResidue := e.fp.NewElement(-4) @@ -230,7 +230,7 @@ func (e Ext6) mulBy023(z *E6, c0, c1 *baseEl) *E6 { } -// Mul023By023 multiplies two E6 sparse element of the form: +// Mul023By023 multiplies two E6 sparse element of the form: // // E6{A0: c0, A1: 0, A2: c1, A3: 1, A4: 0, A5: 0} // @@ -258,7 +258,7 @@ func (e Ext6) mul023by023Direct(d0, d1, c0, c1 *baseEl) [5]*baseEl { return [5]*baseEl{z0, z2, z3, z4, z5} } -// Mul023By023 multiplies two E6 sparse element of the form: +// mul023By023 multiplies two E6 sparse element of the form: // // E6{A0: c0, A1: 0, A2: c1, A3: 1, A4: 0, A5: 0} // @@ -284,8 +284,7 @@ func (e Ext6) mul023By023(d0, d1, c0, c1 *baseEl) [5]*baseEl { // MulBy02345 multiplies z by an E6 sparse element of the form // -// E6{A0: y0, A1: 0, A2: y1, A3: y2, A4: y3, A5: y4}, -// } +// E6{A0: y0, A1: 0, A2: y1, A3: y2, A4: y3, A5: y4} func (e *Ext6) MulBy02345(z *E6, x [5]*baseEl) *E6 { return e.mulBy02345Direct(z, x) } From c6c4df9332eca4937325c0123ec5648ee1ac6a0a Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 5 Nov 2024 00:05:25 +0000 Subject: [PATCH 07/14] perf: cyclotomic square using eval --- std/algebra/emulated/fields_bw6761/e6.go | 65 +++++++++++++++++++ std/algebra/emulated/fields_bw6761/e6_test.go | 39 +++++++++++ 2 files changed, 104 insertions(+) diff --git a/std/algebra/emulated/fields_bw6761/e6.go b/std/algebra/emulated/fields_bw6761/e6.go index 47919d0d22..475d934759 100644 --- a/std/algebra/emulated/fields_bw6761/e6.go +++ b/std/algebra/emulated/fields_bw6761/e6.go @@ -857,6 +857,45 @@ func (e Ext6) squareEmulatedTower(x *E6) *E6 { // https://eprint.iacr.org/2010/542.pdf // Sec. 5.6 with minor modifications to fit our tower func (e Ext6) CyclotomicSquareKarabina12345(x *E6) *E6 { + return e.cyclotomicSquareKarabina12345Eval(x) +} + +// cyclotomicSquareKarabina12345Eval computes +// [Ext6.cyclotomicSquareKarabina12345] but with the non-native Eval method. +func (e Ext6) cyclotomicSquareKarabina12345Eval(x *E6) *E6 { + c := e.fp.NewElement(-4) + mone := e.fp.NewElement(-1) + g1 := x.A2 + g2 := x.A4 + g3 := x.A1 + g4 := x.A3 + g5 := x.A5 + // h1 = 3*c*g2^2 + 3*g3^2 - 2*g1 + h1 := e.fp.Eval([][]*baseEl{{c, &g2, &g2}, {&g3, &g3}, {mone, &g1}}, []int{3, 3, 2}) + // h2 = 3*c*g5^2 + 3*g1^2 - 2*g2 + h2 := e.fp.Eval([][]*baseEl{{c, &g5, &g5}, {&g1, &g1}, {mone, &g2}}, []int{3, 3, 2}) + // h3 = 6*c*g1*g5 + 2*g3 + h3 := e.fp.Eval([][]*baseEl{{c, &g1, &g5}, {&g3}}, []int{6, 2}) + // h4 = 3*c*g2*g5 + 3*g1*g3 - g4 + h4 := e.fp.Eval([][]*baseEl{{c, &g2, &g5}, {&g1, &g3}, {mone, &g4}}, []int{3, 3, 1}) + // h5 = 6*g2*g3 + 2*g5 + h5 := e.fp.Eval([][]*baseEl{{&g2, &g3}, {&g5}}, []int{6, 2}) + + return &E6{ + A0: x.A0, + A1: *h3, + A2: *h1, + A3: *h4, + A4: *h2, + A5: *h5, + } + +} + +// Karabina's compressed cyclotomic square SQR12345 +// https://eprint.iacr.org/2010/542.pdf +// Sec. 5.6 with minor modifications to fit our tower +func (e Ext6) cyclotomicSquareKarabina12345(x *E6) *E6 { x = e.Reduce(x) // h4 = -g4 + 3((g3+g5)(g1+c*g2)-g1g5-c*g3g2) @@ -917,6 +956,32 @@ func (e Ext6) CyclotomicSquareKarabina12345(x *E6) *E6 { // DecompressKarabina12345 decompresses Karabina's cyclotomic square result SQR12345 func (e Ext6) DecompressKarabina12345(x *E6) *E6 { + return e.decompressKarabina12345Eval(x) +} + +// decompressKarabina12345Eval computes [Ext6.DecompressKarabina12345] but with the non-native Eval method. +func (e Ext6) decompressKarabina12345Eval(x *E6) *E6 { + mone := e.fp.NewElement(-1) + c := e.fp.NewElement(-4) + g1 := x.A2 + g2 := x.A4 + g3 := x.A1 + g4 := x.A3 + g5 := x.A5 + // h0 = -3*c*g1*g2 + 2*c*g4^2 + c*g3*g5 + 1 + h0 := e.fp.Eval([][]*baseEl{{mone, c, &g1, &g2}, {c, &g4, &g4}, {c, &g3, &g5}, {e.fp.One()}}, []int{3, 2, 1, 1}) + return &E6{ + A0: *h0, + A1: g3, + A2: g1, + A3: g4, + A4: g2, + A5: g5, + } +} + +// DecompressKarabina12345 decompresses Karabina's cyclotomic square result SQR12345 +func (e Ext6) decompressKarabina12345(x *E6) *E6 { x = e.Reduce(x) // h0 = (2g4^2 + g3g5 - 3g2g1)*c + 1 diff --git a/std/algebra/emulated/fields_bw6761/e6_test.go b/std/algebra/emulated/fields_bw6761/e6_test.go index c54a0b0cd0..c011eb8b56 100644 --- a/std/algebra/emulated/fields_bw6761/e6_test.go +++ b/std/algebra/emulated/fields_bw6761/e6_test.go @@ -479,3 +479,42 @@ func TestFp6MulBy02345Variants(t *testing.T) { err := test.IsSolved(&e6MulBy02345Variants{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type e6CycolotomicSquareKarabina12345Variants struct { + A E6 `gnark:",public"` + C E6 `gnark:",public"` +} + +func (circuit *e6CycolotomicSquareKarabina12345Variants) Define(api frontend.API) error { + e := NewExt6(api) + expected1 := e.cyclotomicSquareKarabina12345(&circuit.A) + expected2 := e.cyclotomicSquareKarabina12345Eval(&circuit.A) + e.AssertIsEqual(expected1, expected2) + dec1 := e.decompressKarabina12345(expected1) + dec2 := e.decompressKarabina12345Eval(expected2) + e.AssertIsEqual(dec1, dec2) + e.fp.AssertIsEqual(&dec1.A1, &circuit.C.A1) + e.fp.AssertIsEqual(&dec1.A2, &circuit.C.A2) + // e.fp.AssertIsEqual(&dec1.A3, &circuit.C.A3) + e.fp.AssertIsEqual(&dec1.A4, &circuit.C.A4) + e.fp.AssertIsEqual(&dec1.A5, &circuit.C.A5) + + return nil +} + +func TestFp6CyclotomicSquareKarabina12345Variants(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bw6761.E6 + _, _ = a.SetRandom() + c.CyclotomicSquare(&a) + + witness := e6CycolotomicSquareKarabina12345Variants{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6CycolotomicSquareKarabina12345Variants{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From df0f0201d4c150ad9ecafb2d94475b4afa1db502 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 5 Nov 2024 12:10:30 +0000 Subject: [PATCH 08/14] chore: update stats --- internal/stats/latest_stats.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/stats/latest_stats.csv b/internal/stats/latest_stats.csv index eb7b4efb74..b3e5b2bb93 100644 --- a/internal/stats/latest_stats.csv +++ b/internal/stats/latest_stats.csv @@ -195,14 +195,14 @@ pairing_bn254,bls24_315,plonk,0,0 pairing_bn254,bls24_317,plonk,0,0 pairing_bn254,bw6_761,plonk,0,0 pairing_bn254,bw6_633,plonk,0,0 -pairing_bw6761,bn254,groth16,3014749,4979960 +pairing_bw6761,bn254,groth16,1843705,3084217 pairing_bw6761,bls12_377,groth16,0,0 pairing_bw6761,bls12_381,groth16,0,0 pairing_bw6761,bls24_315,groth16,0,0 pairing_bw6761,bls24_317,groth16,0,0 pairing_bw6761,bw6_761,groth16,0,0 pairing_bw6761,bw6_633,groth16,0,0 -pairing_bw6761,bn254,plonk,11486969,10777222 +pairing_bw6761,bn254,plonk,6947630,6315782 pairing_bw6761,bls12_377,plonk,0,0 pairing_bw6761,bls12_381,plonk,0,0 pairing_bw6761,bls24_315,plonk,0,0 From 6f184be5073ce16cffffc54993331a2896b47320 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 26 Nov 2024 13:17:25 -0500 Subject: [PATCH 09/14] perf: use Granger-Scott for 1 and 2 squares instead of Karabina --- std/algebra/emulated/fields_bw6761/e6.go | 45 +++++++++++++++++++ .../emulated/fields_bw6761/e6_pairing.go | 34 +++++++------- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/std/algebra/emulated/fields_bw6761/e6.go b/std/algebra/emulated/fields_bw6761/e6.go index 475d934759..2528891e00 100644 --- a/std/algebra/emulated/fields_bw6761/e6.go +++ b/std/algebra/emulated/fields_bw6761/e6.go @@ -853,6 +853,51 @@ func (e Ext6) squareEmulatedTower(x *E6) *E6 { } } +// Granger-Scott's cyclotomic square +// https://eprint.iacr.org/2009/565.pdf, 3.2 +func (e Ext6) CyclotomicSquareGS(x *E6) *E6 { + return e.cyclotomicSquareGSEval(x) +} + +// cyclotomicSquareGSEval computes [Ext6.CyclotomicSquareGS] but with the non-native Eval method. +func (e Ext6) cyclotomicSquareGSEval(x *E6) *E6 { + // x=(x0,x2,x4,x1,x3,x5) in E6 + // cyclosquare(x) = 3*x4²*u + 3*x0² - 2*x0, + // 6*x1*x5*u + 2*x3, + // 3*x2²*u + 3*x3² - 2*x1, + // 6*x0*x4 + 2*x4, + // 3*x5²*u + 3*x1² - 2*x2, + // 6*x2*x3 + 2*x5, + u := e.fp.NewElement(-4) + mone := e.fp.NewElement(-1) + g0 := x.A0 + g1 := x.A2 + g2 := x.A4 + g3 := x.A1 + g4 := x.A3 + g5 := x.A5 + // h0 = 3*x4²*u + 3*x0² - 2*x0 + h0 := e.fp.Eval([][]*baseEl{{u, &g4, &g4}, {&g0, &g0}, {mone, &g0}}, []int{3, 3, 2}) + // h1 = 3*x2²*u + 3*x3² - 2*x1 + h1 := e.fp.Eval([][]*baseEl{{u, &g2, &g2}, {&g3, &g3}, {mone, &g1}}, []int{3, 3, 2}) + // h2 = 3*x5²*u + 3*x1² - 2*x2 + h2 := e.fp.Eval([][]*baseEl{{u, &g5, &g5}, {&g1, &g1}, {mone, &g2}}, []int{3, 3, 2}) + // h3 = 6*x1*x5*u + 2*x3 + h3 := e.fp.Eval([][]*baseEl{{u, &g1, &g5}, {&g3}}, []int{6, 2}) + // h4 = 6*x0*x4 + 2*x4 + h4 := e.fp.Eval([][]*baseEl{{&g0, &g4}, {&g4}}, []int{6, 2}) + // h5 = 6*x2*x3 + 2*x5 + h5 := e.fp.Eval([][]*baseEl{{&g2, &g3}, {&g5}}, []int{6, 2}) + return &E6{ + A0: *h0, + A1: *h3, + A2: *h1, + A3: *h4, + A4: *h2, + A5: *h5, + } +} + // Karabina's compressed cyclotomic square SQR12345 // https://eprint.iacr.org/2010/542.pdf // Sec. 5.6 with minor modifications to fit our tower diff --git a/std/algebra/emulated/fields_bw6761/e6_pairing.go b/std/algebra/emulated/fields_bw6761/e6_pairing.go index 47a1fec18d..a4a40e840f 100644 --- a/std/algebra/emulated/fields_bw6761/e6_pairing.go +++ b/std/algebra/emulated/fields_bw6761/e6_pairing.go @@ -26,7 +26,7 @@ func (e Ext6) ExpX0Minus1(z *E6) *E6 { result = e.Mul(result, z33) result = e.nSquareKarabina12345(result, 4) result = e.Mul(result, z) - result = e.nSquareKarabina12345(result, 1) + result = e.CyclotomicSquareGS(result) result = e.Mul(result, z) result = e.nSquareKarabina12345(result, 46) @@ -39,11 +39,11 @@ func (e Ext6) ExpX0Minus1Square(z *E6) *E6 { z = e.Reduce(z) result := e.Copy(z) result = e.nSquareKarabina12345(result, 3) - t0 := e.nSquareKarabina12345(result, 1) + t0 := e.CyclotomicSquareGS(result) t2 := e.Mul(z, t0) result = e.Mul(result, t2) t0 = e.Mul(z, result) - t1 := e.nSquareKarabina12345(t0, 1) + t1 := e.CyclotomicSquareGS(t0) t1 = e.Mul(t2, t1) t3 := e.nSquareKarabina12345(t1, 7) t2 = e.Mul(t2, t3) @@ -65,7 +65,7 @@ func (e Ext6) ExpX0Minus1Square(z *E6) *E6 { func (e Ext6) ExpX0Plus1(z *E6) *E6 { z = e.Reduce(z) result := e.Copy(z) - t := e.nSquareKarabina12345(result, 1) + t := e.CyclotomicSquareGS(result) result = e.nSquareKarabina12345(t, 4) result = e.Mul(result, z) z33 := e.Copy(result) @@ -73,7 +73,7 @@ func (e Ext6) ExpX0Plus1(z *E6) *E6 { result = e.Mul(result, z33) result = e.nSquareKarabina12345(result, 4) result = e.Mul(result, z) - result = e.nSquareKarabina12345(result, 1) + result = e.CyclotomicSquareGS(result) result = e.Mul(result, z) result = e.nSquareKarabina12345(result, 46) result = e.Mul(result, t) @@ -86,9 +86,10 @@ func (e Ext6) ExpX0Plus1(z *E6) *E6 { func (e Ext6) ExptMinus1Div3(z *E6) *E6 { z = e.Reduce(z) result := e.Copy(z) - result = e.nSquareKarabina12345(result, 2) + result = e.CyclotomicSquareGS(result) + result = e.CyclotomicSquareGS(result) result = e.Mul(result, z) - result = e.nSquareKarabina12345(result, 1) + result = e.CyclotomicSquareGS(result) result = e.Mul(result, z) t0 := e.nSquareKarabina12345(result, 7) result = e.Mul(result, t0) @@ -105,9 +106,10 @@ func (e Ext6) ExptMinus1Div3(z *E6) *E6 { func (e Ext6) ExpC1(z *E6) *E6 { z = e.Reduce(z) result := e.Copy(z) - result = e.nSquareKarabina12345(result, 2) + result = e.CyclotomicSquareGS(result) + result = e.CyclotomicSquareGS(result) result = e.Mul(result, z) - result = e.nSquareKarabina12345(result, 1) + result = e.CyclotomicSquareGS(result) result = e.Mul(result, z) return result @@ -118,11 +120,11 @@ func (e Ext6) ExpC1(z *E6) *E6 { // C2 = (ht**2+3*hy**2)/4 = 103 func (e Ext6) ExpC2(z *E6) *E6 { z = e.Reduce(z) - result := e.nSquareKarabina12345(z, 1) + result := e.CyclotomicSquareGS(z) result = e.Mul(result, z) t0 := e.nSquareKarabina12345(result, 4) result = e.Mul(result, t0) - result = e.nSquareKarabina12345(result, 1) + result = e.CyclotomicSquareGS(result) result = e.Mul(result, z) return result @@ -463,7 +465,7 @@ func (e Ext6) AssertFinalExponentiationIsOne(x *E6) { func (e Ext6) ExpByU2(z *E6) *E6 { z = e.Reduce(z) result := e.Copy(z) - t := e.nSquareKarabina12345(result, 1) + t := e.CyclotomicSquareGS(result) result = e.nSquareKarabina12345(t, 4) result = e.Mul(result, z) z33 := e.Copy(result) @@ -471,7 +473,7 @@ func (e Ext6) ExpByU2(z *E6) *E6 { result = e.Mul(result, z33) result = e.nSquareKarabina12345(result, 4) result = e.Mul(result, z) - result = e.nSquareKarabina12345(result, 1) + result = e.CyclotomicSquareGS(result) result = e.Mul(result, z) result = e.nSquareKarabina12345(result, 46) result = e.Mul(result, t) @@ -482,9 +484,9 @@ func (e Ext6) ExpByU2(z *E6) *E6 { // ExpByU1 set z to z^(x₀^3-x₀^2+1) in E12 and return z // x₀^3-x₀^2+1 = 880904806456922042166256752416502360965158762994674434049 func (e Ext6) ExpByU1(x *E6) *E6 { - t5 := e.nSquareKarabina12345(x, 1) + t5 := e.CyclotomicSquareGS(x) z := e.Mul(x, t5) - t0 := e.nSquareKarabina12345(z, 1) + t0 := e.CyclotomicSquareGS(z) t6 := e.Mul(x, t0) t8 := e.Mul(x, t6) t7 := e.Mul(t5, t8) @@ -493,7 +495,7 @@ func (e Ext6) ExpByU1(x *E6) *E6 { t2 := e.Mul(x, t3) t1 := e.Mul(t6, t2) t0 = e.Mul(t8, t1) - t4 := e.nSquareKarabina12345(t0, 1) + t4 := e.CyclotomicSquareGS(t0) t4 = e.Mul(z, t4) t8 = e.Mul(t8, t4) t2 = e.Mul(t2, t8) From 3ee80baa32690afb3141b7a4d1cf122650c93057 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 26 Nov 2024 13:20:59 -0500 Subject: [PATCH 10/14] chore: update stats --- internal/stats/latest_stats.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/stats/latest_stats.csv b/internal/stats/latest_stats.csv index b3e5b2bb93..3975f5dfc3 100644 --- a/internal/stats/latest_stats.csv +++ b/internal/stats/latest_stats.csv @@ -195,14 +195,14 @@ pairing_bn254,bls24_315,plonk,0,0 pairing_bn254,bls24_317,plonk,0,0 pairing_bn254,bw6_761,plonk,0,0 pairing_bn254,bw6_633,plonk,0,0 -pairing_bw6761,bn254,groth16,1843705,3084217 +pairing_bw6761,bn254,groth16,1840353,3079059 pairing_bw6761,bls12_377,groth16,0,0 pairing_bw6761,bls12_381,groth16,0,0 pairing_bw6761,bls24_315,groth16,0,0 pairing_bw6761,bls24_317,groth16,0,0 pairing_bw6761,bw6_761,groth16,0,0 pairing_bw6761,bw6_633,groth16,0,0 -pairing_bw6761,bn254,plonk,6947630,6315782 +pairing_bw6761,bn254,plonk,6936530,6306286 pairing_bw6761,bls12_377,plonk,0,0 pairing_bw6761,bls12_381,plonk,0,0 pairing_bw6761,bls24_315,plonk,0,0 From 51ebab861fb7c470151e03e60edaf4cc0632ecec Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 26 Nov 2024 15:36:08 -0500 Subject: [PATCH 11/14] perf: optimize squareDirect --- std/algebra/emulated/fields_bw6761/e6.go | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/std/algebra/emulated/fields_bw6761/e6.go b/std/algebra/emulated/fields_bw6761/e6.go index 2528891e00..972209cfab 100644 --- a/std/algebra/emulated/fields_bw6761/e6.go +++ b/std/algebra/emulated/fields_bw6761/e6.go @@ -739,24 +739,24 @@ func (e Ext6) Square(x *E6) *E6 { // squareDirect computes the square of an element in E6 using schoolbook multiplication. func (e Ext6) squareDirect(x *E6) *E6 { nonResidue := e.fp.NewElement(-4) - // c0 = a0b0 + β(a1b5 + a2b4 + a3b3 + a4b2 + a5b1) - c0 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A0}, {nonResidue, &x.A1, &x.A5}, {nonResidue, &x.A2, &x.A4}, {nonResidue, &x.A3, &x.A3}, {nonResidue, &x.A4, &x.A2}, {nonResidue, &x.A5, &x.A1}}, - []int{1, 1, 1, 1, 1, 1}) - // c1 = a0b1 + a1b0 + β(a2b5 + a3b4 + a4b3 + a5b2) - c1 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A1}, {&x.A1, &x.A0}, {nonResidue, &x.A2, &x.A5}, {nonResidue, &x.A3, &x.A4}, {nonResidue, &x.A4, &x.A3}, {nonResidue, &x.A5, &x.A2}}, - []int{1, 1, 1, 1, 1, 1}) - // c2 = a0b2 + a1b1 + a2b0 + β(a3b5 + a4b4 + a5b3) - c2 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A2}, {&x.A1, &x.A1}, {&x.A2, &x.A0}, {nonResidue, &x.A3, &x.A5}, {nonResidue, &x.A4, &x.A4}, {nonResidue, &x.A5, &x.A3}}, - []int{1, 1, 1, 1, 1, 1}) - // c3 = a0b3 + a1b2 + a2b1 + a3b0 + β(a4b5 + a5b4) - c3 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A3}, {&x.A1, &x.A2}, {&x.A2, &x.A1}, {&x.A3, &x.A0}, {nonResidue, &x.A4, &x.A5}, {nonResidue, &x.A5, &x.A4}}, - []int{1, 1, 1, 1, 1, 1}) - // c4 = a0b4 + a1b3 + a2b2 + a3b1 + a4b0 + βa5b5 - c4 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A4}, {&x.A1, &x.A3}, {&x.A2, &x.A2}, {&x.A3, &x.A1}, {&x.A4, &x.A0}, {nonResidue, &x.A5, &x.A5}}, - []int{1, 1, 1, 1, 1, 1}) - // c5 = a0b5 + a1b4 + a2b3 + a3b2 + a4b1 + a5b0, - c5 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A5}, {&x.A1, &x.A4}, {&x.A2, &x.A3}, {&x.A3, &x.A2}, {&x.A4, &x.A1}, {&x.A5, &x.A0}}, - []int{1, 1, 1, 1, 1, 1}) + // c0 = a0a0 + β(2*a1a5 + 2*a2a4 + a3a3) + c0 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A0}, {nonResidue, &x.A1, &x.A5}, {nonResidue, &x.A2, &x.A4}, {nonResidue, &x.A3, &x.A3}}, + []int{1, 2, 2, 1}) + // c1 = 2*a0a1 + β(2*a2a5 + 2*a3a4) + c1 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A1}, {nonResidue, &x.A2, &x.A5}, {nonResidue, &x.A3, &x.A4}}, + []int{2, 2, 2}) + // c2 = 2*a0a2 + a1a1 + β(2*a3a5 + a4a4) + c2 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A2}, {&x.A1, &x.A1}, {nonResidue, &x.A3, &x.A5}, {nonResidue, &x.A4, &x.A4}}, + []int{2, 1, 2, 1}) + // c3 = 2*a0a3 + 2*a1a2 + β(2*a4a5) + c3 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A3}, {&x.A1, &x.A2}, {nonResidue, &x.A5, &x.A4}}, + []int{2, 2, 2}) + // c4 = 2*a0a4 + 2*a1a3 + a2a2 + βa5a5 + c4 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A4}, {&x.A1, &x.A3}, {&x.A2, &x.A2}, {nonResidue, &x.A5, &x.A5}}, + []int{2, 2, 1, 1}) + // c5 = 2*a0a5 + 2*a1a4 + 2*a2a3, + c5 := e.fp.Eval([][]*baseEl{{&x.A0, &x.A5}, {&x.A1, &x.A4}, {&x.A2, &x.A3}}, + []int{2, 2, 2}) return &E6{ A0: *c0, From f7404478d2188d2fd71d4d37d674af958811f1e7 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 26 Nov 2024 15:40:16 -0500 Subject: [PATCH 12/14] chore: update stats --- internal/stats/latest_stats.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/stats/latest_stats.csv b/internal/stats/latest_stats.csv index 3975f5dfc3..d11e37f99c 100644 --- a/internal/stats/latest_stats.csv +++ b/internal/stats/latest_stats.csv @@ -195,14 +195,14 @@ pairing_bn254,bls24_315,plonk,0,0 pairing_bn254,bls24_317,plonk,0,0 pairing_bn254,bw6_761,plonk,0,0 pairing_bn254,bw6_633,plonk,0,0 -pairing_bw6761,bn254,groth16,1840353,3079059 +pairing_bw6761,bn254,groth16,1835104,3072870 pairing_bw6761,bls12_377,groth16,0,0 pairing_bw6761,bls12_381,groth16,0,0 pairing_bw6761,bls24_315,groth16,0,0 pairing_bw6761,bls24_317,groth16,0,0 pairing_bw6761,bw6_761,groth16,0,0 pairing_bw6761,bw6_633,groth16,0,0 -pairing_bw6761,bn254,plonk,6936530,6306286 +pairing_bw6761,bn254,plonk,6929024,6298968 pairing_bw6761,bls12_377,plonk,0,0 pairing_bw6761,bls12_381,plonk,0,0 pairing_bw6761,bls24_315,plonk,0,0 From cf051d833ff2b53e7ed23d5ee99468bfd84f6427 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 26 Nov 2024 18:53:00 -0500 Subject: [PATCH 13/14] perf: optimize Karabina decompression Eval --- internal/stats/latest_stats.csv | 4 ++-- std/algebra/emulated/fields_bw6761/e6.go | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/internal/stats/latest_stats.csv b/internal/stats/latest_stats.csv index d11e37f99c..ae631c172c 100644 --- a/internal/stats/latest_stats.csv +++ b/internal/stats/latest_stats.csv @@ -195,14 +195,14 @@ pairing_bn254,bls24_315,plonk,0,0 pairing_bn254,bls24_317,plonk,0,0 pairing_bn254,bw6_761,plonk,0,0 pairing_bn254,bw6_633,plonk,0,0 -pairing_bw6761,bn254,groth16,1835104,3072870 +pairing_bw6761,bn254,groth16,1832163,3067889 pairing_bw6761,bls12_377,groth16,0,0 pairing_bw6761,bls12_381,groth16,0,0 pairing_bw6761,bls24_315,groth16,0,0 pairing_bw6761,bls24_317,groth16,0,0 pairing_bw6761,bw6_761,groth16,0,0 pairing_bw6761,bw6_633,groth16,0,0 -pairing_bw6761,bn254,plonk,6929024,6298968 +pairing_bw6761,bn254,plonk,6917962,6288314 pairing_bw6761,bls12_377,plonk,0,0 pairing_bw6761,bls12_381,plonk,0,0 pairing_bw6761,bls24_315,plonk,0,0 diff --git a/std/algebra/emulated/fields_bw6761/e6.go b/std/algebra/emulated/fields_bw6761/e6.go index 972209cfab..f43cdd28e3 100644 --- a/std/algebra/emulated/fields_bw6761/e6.go +++ b/std/algebra/emulated/fields_bw6761/e6.go @@ -1006,7 +1006,6 @@ func (e Ext6) DecompressKarabina12345(x *E6) *E6 { // decompressKarabina12345Eval computes [Ext6.DecompressKarabina12345] but with the non-native Eval method. func (e Ext6) decompressKarabina12345Eval(x *E6) *E6 { - mone := e.fp.NewElement(-1) c := e.fp.NewElement(-4) g1 := x.A2 g2 := x.A4 @@ -1014,7 +1013,7 @@ func (e Ext6) decompressKarabina12345Eval(x *E6) *E6 { g4 := x.A3 g5 := x.A5 // h0 = -3*c*g1*g2 + 2*c*g4^2 + c*g3*g5 + 1 - h0 := e.fp.Eval([][]*baseEl{{mone, c, &g1, &g2}, {c, &g4, &g4}, {c, &g3, &g5}, {e.fp.One()}}, []int{3, 2, 1, 1}) + h0 := e.fp.Eval([][]*baseEl{{&g1, &g2}, {c, &g4, &g4}, {c, &g3, &g5}, {e.fp.One()}}, []int{12, 2, 1, 1}) return &E6{ A0: *h0, A1: g3, From 43b80d2332fc64241c855c228701ea5763eb5ee4 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 26 Nov 2024 19:27:57 -0500 Subject: [PATCH 14/14] perf: optimize Mul023By023 Eval --- internal/stats/latest_stats.csv | 4 ++-- std/algebra/emulated/fields_bw6761/e6_pairing.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/stats/latest_stats.csv b/internal/stats/latest_stats.csv index ae631c172c..4013dce11f 100644 --- a/internal/stats/latest_stats.csv +++ b/internal/stats/latest_stats.csv @@ -195,14 +195,14 @@ pairing_bn254,bls24_315,plonk,0,0 pairing_bn254,bls24_317,plonk,0,0 pairing_bn254,bw6_761,plonk,0,0 pairing_bn254,bw6_633,plonk,0,0 -pairing_bw6761,bn254,groth16,1832163,3067889 +pairing_bw6761,bn254,groth16,1831910,3067456 pairing_bw6761,bls12_377,groth16,0,0 pairing_bw6761,bls12_381,groth16,0,0 pairing_bw6761,bls24_315,groth16,0,0 pairing_bw6761,bls24_317,groth16,0,0 pairing_bw6761,bw6_761,groth16,0,0 pairing_bw6761,bw6_633,groth16,0,0 -pairing_bw6761,bn254,plonk,6917962,6288314 +pairing_bw6761,bn254,plonk,6917026,6287414 pairing_bw6761,bls12_377,plonk,0,0 pairing_bw6761,bls12_381,plonk,0,0 pairing_bw6761,bls24_315,plonk,0,0 diff --git a/std/algebra/emulated/fields_bw6761/e6_pairing.go b/std/algebra/emulated/fields_bw6761/e6_pairing.go index a4a40e840f..5750f7e63f 100644 --- a/std/algebra/emulated/fields_bw6761/e6_pairing.go +++ b/std/algebra/emulated/fields_bw6761/e6_pairing.go @@ -253,7 +253,7 @@ func (e Ext6) mul023by023Direct(d0, d1, c0, c1 *baseEl) [5]*baseEl { // c3 = d0 + c0 z3 := e.fp.Add(d0, c0) // c4 = d1c1 - z4 := e.fp.Mul(d1, c1) + z4 := e.fp.Eval([][]*baseEl{{d1, c1}}, []int{1}) // c5 = d1 + c1, z5 := e.fp.Add(d1, c1)