Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(bn254): include G2 membership check in ML #1387

Merged
merged 5 commits into from
Jan 15, 2025

Conversation

yelhousni
Copy link
Contributor

@yelhousni yelhousni commented Jan 7, 2025

Description

Including G2 subgroup membership in the pairing computations saves a lot of constraints. For Linea zkEVM, gnark circuit has only to check G2 membership as the arithemtization does the check for G1.

In computeLines the accumulated point is [6x₀+2]Q (x₀ being the curve seed). We can tweak* the subgroup membership to check [6x₀+2]Q + ψ(Q) + ψ³(Q) == ψ²(Q) instead of ψ³([2x₀]Q) - ψ²([x₀]Q) - ψ([x₀]Q) - [x₀]Q == Q. This saves the multiplication by 6x₀+2 and enforces G2 membership check systematically in pairing calls, simplifying probably the Wizard glue.

* since x₀ ≠ 4 mod 13 and x₀ ≠ 92 mod 97 for BN254, V=(6x₀+ 2,1,−1,1) is also a valid short vector.

TL;DR: G2 subgroup membership becomes ~2 point additions instead of ~81 point additions.

Type of change

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

How has this been tested?

All current tests pass.

How has this been benchmarked?

On one hand a product of 2 pairings check increases by 18,857 scs but on the other hand the G2 membership which costs (for 2 points) 407,729 scs is removed.

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 this to the v0.11.N milestone Jan 7, 2025
@yelhousni yelhousni requested a review from ivokub January 7, 2025 22:30
@yelhousni yelhousni self-assigned this Jan 7, 2025
@ivokub
Copy link
Collaborator

ivokub commented Jan 15, 2025

Suggested edit:

diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go
index 4798876a..6d9d170c 100644
--- a/std/algebra/emulated/sw_bn254/pairing.go
+++ b/std/algebra/emulated/sw_bn254/pairing.go
@@ -81,10 +81,10 @@ func NewPairing(api frontend.API) (*Pairing, error) {
 	}, nil
 }
 
-// Pair calculates the reduced pairing for a set of points
-// ∏ᵢ e(Pᵢ, Qᵢ).
+// Pair calculates the reduced pairing for a set of points ∏ᵢ e(Pᵢ, Qᵢ).
 //
-// This function checks that the Qᵢ are in the correct subgroupsi, but does not check Pᵢ. See AssertIsOnG1.
+// This function checks that the Qᵢ are in the correct subgroup, but does not
+// check Pᵢ. See AssertIsOnG1.
 func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) {
 	res, err := pr.MillerLoop(P, Q)
 	if err != nil {
@@ -206,10 +206,13 @@ func (pr Pairing) AssertFinalExponentiationIsOne(a *GTEl) {
 	pr.AssertIsEqual(t0, t2)
 }
 
-// PairingCheck calculates the reduced pairing for a set of points and asserts if the result is One
-// ∏ᵢ e(Pᵢ, Qᵢ) =? 1
+// PairingCheck calculates the reduced pairing for a set of points and asserts
+// if the result is one:
 //
-// This function checks that the Qᵢ are in the correct subgroupsi, but does not check Pᵢ. See AssertIsOnG1.
+//	∏ᵢ e(Pᵢ, Qᵢ) =? 1
+//
+// This function checks that the Qᵢ are in the correct subgroup, but does not
+// check Pᵢ. See AssertIsOnG1.
 func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error {
 	f, err := pr.MillerLoop(P, Q)
 	if err != nil {

@ivokub
Copy link
Collaborator

ivokub commented Jan 15, 2025

Suggested edit:

diff --git a/std/evmprecompiles/08-bnpairing.go b/std/evmprecompiles/08-bnpairing.go
index b5bd7a54..f4ff6b1b 100644
--- a/std/evmprecompiles/08-bnpairing.go
+++ b/std/evmprecompiles/08-bnpairing.go
@@ -76,7 +76,6 @@ func ECPairMillerLoopAndMul(api frontend.API, accumulator *sw_bn254.GTEl, P *sw_
 	if err != nil {
 		return fmt.Errorf("new pairing: %w", err)
 	}
-	pairing.AssertIsOnG2(Q)
 	ml, err := pairing.MillerLoopAndMul(P, Q, accumulator)
 	if err != nil {
 		return fmt.Errorf("miller loop and mul: %w", err)
@@ -94,7 +93,6 @@ func ECPairMillerLoopAndFinalExpCheck(api frontend.API, accumulator *sw_bn254.GT
 	if err != nil {
 		return fmt.Errorf("new pairing: %w", err)
 	}
-	pairing.AssertIsOnG2(Q)
 
 	isSuccess := pairing.IsMillerLoopAndFinalExpOne(P, Q, accumulator)
 	api.AssertIsEqual(expectedIsSuccess, isSuccess)

Copy link
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.

Looks very good. However, in the context of Linea we also need to remove the G2 subgroup checks from the ECPairMillerLoopAndMul and ECPairMillerLoopAndFinalExpCheck methods. These are the ones called from the precompile glue.

I created suggested edits for that and also for some method comments. If you can include them then good to merge from my side.

@yelhousni yelhousni merged commit cfa30d9 into master Jan 15, 2025
5 checks passed
@yelhousni yelhousni deleted the perf/g2-membership-in-pairing branch January 15, 2025 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants