Skip to content

Perf: Pairing on BN254 using direct Fp12 extension and non-native Eval()#1339

Merged
yelhousni merged 30 commits intomasterfrom
perf/bn254-eval
Dec 14, 2024
Merged

Perf: Pairing on BN254 using direct Fp12 extension and non-native Eval()#1339
yelhousni merged 30 commits intomasterfrom
perf/bn254-eval

Conversation

@yelhousni
Copy link
Copy Markdown
Contributor

@yelhousni yelhousni commented Dec 9, 2024

Description

Similar to #1312 but for BN254.
This PR refactor methods in fields_bn254 and sw_bn254 using a direct Fp12 extension and non-native Eval() introduced in #1299.

TODO:

  • Granger-Scott's cyclotomic squarings.
  • Karabina's cyclotomic squarings.
  • Torus-based arithmetic over direct Fp6 extension.

Type of change

  • New feature (non-breaking change which adds functionality)

How has this been tested?

  • New tests corresponding to new methods.
  • PairingCheck and FinalExpCheck tests against gnark-crypto.

How has this been benchmarked?

Some circuits proved in a in a BN254-PLONK:

circuit old (scs) new (scs) diff (scs)
e(a,b) 3,534,755 2,030,447 1,504,308
e(a,b) * e(c,d) == 1 3,879,428 2,239,682 1,639,746
ECPAIR-2 precompile* 4,407,402 2,425,399 1,982,003
ECPAIR-4 precompile* 7,815,376 4,181,633 3,633,743

*ECPAIR precompiles include G2 subgroup membership.

Checklist:

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • I did not modify files generated from templates
  • golangci-lint does not output errors locally
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@yelhousni yelhousni added type: perf dep: linea Issues affecting Linea downstream labels Dec 9, 2024
@yelhousni yelhousni requested a review from ivokub December 9, 2024 21:35
@yelhousni yelhousni self-assigned this Dec 9, 2024
@ivokub
Copy link
Copy Markdown
Collaborator

ivokub commented Dec 10, 2024

Suggested edit:

diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go
index fdfedafe..d2e95540 100644
--- a/std/algebra/emulated/sw_bn254/pairing.go
+++ b/std/algebra/emulated/sw_bn254/pairing.go
@@ -24,7 +24,6 @@ type Pairing struct {
 	curve  *sw_emulated.Curve[BaseField, ScalarField]
 	g2     *G2
 	bTwist *fields_bn254.E2
-	g2gen  *G2Affine
 }
 
 func NewGTEl(a bn254.GT) GTEl {
@@ -82,15 +81,6 @@ func NewPairing(api frontend.API) (*Pairing, error) {
 	}, nil
 }
 
-func (pr Pairing) generators() *G2Affine {
-	if pr.g2gen == nil {
-		_, _, _, g2gen := bn254.Generators()
-		cg2gen := NewG2AffineFixed(g2gen)
-		pr.g2gen = &cg2gen
-	}
-	return pr.g2gen
-}
-
 // Pair calculates the reduced pairing for a set of points
 // ∏ᵢ e(Pᵢ, Qᵢ).
 //

Copy link
Copy Markdown
Collaborator

@ivokub ivokub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the suggested edits for removing deadcode.

Looks good to me, I didn't go through the formulas, but as the tests are functioning, then I think everything is valid. See only comments about removed examples and tests.

One thing I would do is to create isomorphism maps between the tower and direct extension as explicit methods and use them, as imo it makes it a bit clearer to see what extension is used where.

And I think it would be better to wait for #1340 to be merged to ensure that there are no failing tests for edge cases (which I understood you bypassed?)

@yelhousni
Copy link
Copy Markdown
Contributor Author

yelhousni commented Dec 11, 2024

See the suggested edits for removing deadcode.

Looks good to me, I didn't go through the formulas, but as the tests are functioning, then I think everything is valid. See only comments about removed examples and tests.

One thing I would do is to create isomorphism maps between the tower and direct extension as explicit methods and use them, as imo it makes it a bit clearer to see what extension is used where.

And I think it would be better to wait for #1340 to be merged to ensure that there are no failing tests for edge cases (which I understood you bypassed?)

That makes sense. I pushed a few comments that address your review points. We can wait for #1340.
I'm still thinking whether to implement Karabina and Torus-based direct-Fp6 as it would be only useful for computing the exact value of the pairing, but we only use PairingCheck in our protocols. However torus stuff might come in handy in the future for Ethereum SSLE (ethresearch post).

@ivokub
Copy link
Copy Markdown
Collaborator

ivokub commented Dec 11, 2024

That makes sense. I pushed a few comments that address your review points. We can wait for #1340. I'm still thinking whether to implement Karabina and Torus-based direct-Fp6 as it would be only useful for computing the exact value of the pairing, but we only use PairingCheck in our protocols. However torus stuff might come in handy in the future for Ethereum SSLE (ethresearch post).

Yup, I agree that with different extensions computing pairing makes less sense and we'd mostly be interested in pairing check (or multi-pairing check). I guess we can keep it currently as is, but have documentation update that it may not be efficient.

@yelhousni
Copy link
Copy Markdown
Contributor Author

@ivokub PR is ready now!

@ivokub
Copy link
Copy Markdown
Collaborator

ivokub commented Dec 13, 2024

Suggested edit:

diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go
index 10b27de3..7fce40b4 100644
--- a/std/algebra/emulated/sw_emulated/point.go
+++ b/std/algebra/emulated/sw_emulated/point.go
@@ -214,13 +214,15 @@ func (c *Curve[B, S]) AssertIsOnCurve(p *AffinePoint[B]) {
 	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.Eval([][]*emulated.Element[B]{{&p.X, &p.X, &p.X}, {b}}, []int{1, 1})
-	if c.addA {
-		ax := c.baseApi.Mul(&c.a, &p.X)
-		right = c.baseApi.Add(right, ax)
+	mone := c.baseApi.NewElement(-1)
+
+	var check *emulated.Element[B]
+	if !c.addA {
+		check = c.baseApi.Eval([][]*emulated.Element[B]{{&p.X, &p.X, &p.X}, {b}, {mone, &p.Y, &p.Y}}, []int{1, 1, 1})
+	} else {
+		check = c.baseApi.Eval([][]*emulated.Element[B]{{&p.X, &p.X, &p.X}, {&c.a, &p.X}, {b}, {mone, &p.Y, &p.Y}}, []int{1, 1, 1, 1})
 	}
-	c.baseApi.AssertIsEqual(left, right)
+	c.baseApi.AssertIsEqual(check, c.baseApi.Zero())
 }
 
 // AddUnified adds p and q and returns it. It doesn't modify p nor q.

Copy link
Copy Markdown
Collaborator

@ivokub ivokub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Now looks very nice. I also found one optimization for AssertIsOnCurve where we can bring the left hand side to the right and then do only a single eval.

@yelhousni yelhousni merged commit e5315fb into master Dec 14, 2024
@yelhousni yelhousni deleted the perf/bn254-eval branch December 14, 2024 16:03
lucasmenendez pushed a commit to lucasmenendez/gnark that referenced this pull request Jan 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dep: linea Issues affecting Linea downstream type: perf

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants