-
Notifications
You must be signed in to change notification settings - Fork 380
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: optimize DoublePairingCheck
i.e. e(a,b)e(c,d) == 1
#1230
base: master
Are you sure you want to change the base?
Conversation
Suggested edit: diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go
index b59d18c8..27391122 100644
--- a/std/algebra/emulated/sw_bls12381/pairing.go
+++ b/std/algebra/emulated/sw_bls12381/pairing.go
@@ -266,9 +266,11 @@ func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error {
}
// DoublePairingCheck calculates the reduced pairing for a 2 pairs of points and asserts if the result is One
-// e(P0, Q0) * e(P1, Q1) =? 1
//
-// This function doesn't check that the inputs are in the correct subgroups. See AssertIsOnG1 and AssertIsOnG2.
+// e(P0, Q0) * e(P1, Q1) =? 1
+//
+// This function doesn't check that the inputs are in the correct subgroups. See
+// [Pairing.AssertIsOnG1] and [Pairing.AssertIsOnG2].
func (pr Pairing) DoublePairingCheck(P [2]*G1Affine, Q [2]*G2Affine) error {
// hint the non-residue witness
hint, err := pr.curveF.NewHint(doublePairingCheckHint, 18, &P[0].X, &P[0].Y, &P[1].X, &P[1].Y, &Q[0].P.X.A0, &Q[0].P.X.A1, &Q[0].P.Y.A0, &Q[0].P.Y.A1, &Q[1].P.X.A0, &Q[1].P.X.A1, &Q[1].P.Y.A0, &Q[1].P.Y.A1)
diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go
index d0b1c672..bdc9f6b2 100644
--- a/std/algebra/emulated/sw_bn254/pairing.go
+++ b/std/algebra/emulated/sw_bn254/pairing.go
@@ -266,9 +266,11 @@ func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error {
}
// DoublePairingCheck calculates the reduced pairing for a 2 pairs of points and asserts if the result is One
-// e(P0, Q0) * e(P1, Q1) =? 1
//
-// This function doesn't check that the inputs are in the correct subgroups. See AssertIsOnG1 and AssertIsOnG2.
+// e(P0, Q0) * e(P1, Q1) =? 1
+//
+// This function doesn't check that the inputs are in the correct subgroups. See
+// [Pairing.AssertIsOnG1] and [Pairing.AssertIsOnG2].
func (pr Pairing) DoublePairingCheck(P [2]*G1Affine, Q [2]*G2Affine) error {
// hint the non-residue witness
hint, err := pr.curveF.NewHint(doublePairingCheckHint, 18, &P[0].X, &P[0].Y, &P[1].X, &P[1].Y, &Q[0].P.X.A0, &Q[0].P.X.A1, &Q[0].P.Y.A0, &Q[0].P.Y.A1, &Q[1].P.X.A0, &Q[1].P.X.A1, &Q[1].P.Y.A0, &Q[1].P.Y.A1)
diff --git a/std/algebra/emulated/sw_bw6761/pairing.go b/std/algebra/emulated/sw_bw6761/pairing.go
index 2c481e75..7a7dc331 100644
--- a/std/algebra/emulated/sw_bw6761/pairing.go
+++ b/std/algebra/emulated/sw_bw6761/pairing.go
@@ -164,7 +164,8 @@ func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error {
// DoublePairingCheck calculates the reduced pairing for a 2 pairs of points and asserts if the result is One
// e(P0, Q0) * e(P1, Q1) =? 1
//
-// This function doesn't check that the inputs are in the correct subgroups. See AssertIsOnG1 and AssertIsOnG2.
+// This function doesn't check that the inputs are in the correct subgroups. See
+// [Pairing.AssertIsOnG1] and [Pairing.AssertIsOnG2].
func (pr Pairing) DoublePairingCheck(P [2]*G1Affine, Q [2]*G2Affine) error {
return pr.PairingCheck(P[:], Q[:])
}
diff --git a/std/algebra/native/sw_bls12377/pairing.go b/std/algebra/native/sw_bls12377/pairing.go
index 75e2af03..3dcd4c16 100644
--- a/std/algebra/native/sw_bls12377/pairing.go
+++ b/std/algebra/native/sw_bls12377/pairing.go
@@ -274,9 +274,10 @@ func PairingCheck(api frontend.API, P []G1Affine, Q []G2Affine) error {
}
// DoublePairingCheck calculates the reduced pairing for 2 pairs of points and asserts if the result is One
-// e(P0, Q0) * e(P1, Q1) =? 1
//
-// This function doesn't check that the inputs are in the correct subgroups
+// e(P0, Q0) * e(P1, Q1) =? 1
+//
+// This function doesn't check that the inputs are in the correct subgroups.
func DoublePairingCheck(api frontend.API, P [2]G1Affine, Q [2]G2Affine) error {
// hint the non-residue witness
hint, err := api.NewHint(doublePairingCheckHint, 18, P[0].X, P[0].Y, P[1].X, P[1].Y, Q[0].P.X.A0, Q[0].P.X.A1, Q[0].P.Y.A0, Q[0].P.Y.A1, Q[1].P.X.A0, Q[1].P.X.A1, Q[1].P.Y.A0, Q[1].P.Y.A1)
diff --git a/std/algebra/native/sw_bls12377/pairing2.go b/std/algebra/native/sw_bls12377/pairing2.go
index b765d731..769c220f 100644
--- a/std/algebra/native/sw_bls12377/pairing2.go
+++ b/std/algebra/native/sw_bls12377/pairing2.go
@@ -330,9 +330,12 @@ func (p *Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error {
return nil
}
-// DoublePairingCheck computes the multi-pairing of the 2 input pairs and asserts that
-// the result is an identity element in the target group. It returns an error if
-// there is a mismatch between the lengths of the inputs.
+// DoublePairingCheck calculates the reduced pairing for a 2 pairs of points and asserts if the result is One
+//
+// e(P0, Q0) * e(P1, Q1) =? 1
+//
+// This function doesn't check that the inputs are in the correct subgroups. See
+// [Pairing.AssertIsOnG1] and [Pairing.AssertIsOnG2].
func (p *Pairing) DoublePairingCheck(P [2]*G1Affine, Q [2]*G2Affine) error {
var inP [2]G1Affine
inP[0] = *P[0]
diff --git a/std/algebra/native/sw_bls24315/pairing2.go b/std/algebra/native/sw_bls24315/pairing2.go
index b86d06ee..9d7f97de 100644
--- a/std/algebra/native/sw_bls24315/pairing2.go
+++ b/std/algebra/native/sw_bls24315/pairing2.go
@@ -313,9 +313,12 @@ func (p *Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error {
return nil
}
-// DoublePairingCheck computes the multi-pairing of the 2 input pairs and asserts that
-// the result is an identity element in the target group. It returns an error if
-// there is a mismatch between the lengths of the inputs.
+// DoublePairingCheck calculates the reduced pairing for a 2 pairs of points and asserts if the result is One
+//
+// e(P0, Q0) * e(P1, Q1) =? 1
+//
+// This function doesn't check that the inputs are in the correct subgroups. See
+// [Pairing.AssertIsOnG1] and [Pairing.AssertIsOnG2].
func (p *Pairing) DoublePairingCheck(P [2]*G1Affine, Q [2]*G2Affine) error {
return p.PairingCheck(P[:], Q[:])
}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in general it looks good. I only suggested some edits to the method documentation and maybe changing one of the hint functions to be a bit more descriptive (it took me a few minutes to understand what was happening in the loops).
I'm testing locally against gnark-crypto commit ffaaea73e1b67358e625343c0d32fc785792b3f6 and it looks like tests pass. That corresponding gnark-crypto PR is also good to merge on my side.
x.Exp(residueWitness, &exp2) | ||
|
||
// 3^t is ord(x^3 / residueWitness) | ||
x3.Square(&x).Mul(&x3, &x).Mul(&x3, &residueWitnessInv) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can assume that x
cannot be zero at this point? It is related to the output of the Miller loop, but I think we can assume it is never zero for any inputs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes x
is some nonzero power of the Miller loop which cannot be 0
} | ||
|
||
for t != 0 { | ||
x.Mul(&x, tmp.Exp(root27thOf1, &exp2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imo this part is a bit difficult to understand. We essentially take this loop only if x^3 * residueWitnessInv != 1
, maybe we could have the check implict?
Maybe something like:
for i := 0; i < someBound; i++ {
if i > 0 {
x.Mul(&x, tmp.Exp(root27thof1, &exp2))
}
x3.Square(&x).Mul(&x3, &x).Mul(&x3, &residueWitnessInv)
if x3.IsOne() {
continue
}
for !x3.IsOne() {
tmp.Square(&x3)
x3.Mul(&tmp, &x3)
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that would work too I guess
DoublePairingChekc
i.e. e(a,b)e(c,d) == 1DoublePairingCheck
i.e. e(a,b)e(c,d) == 1
Description
This PR needs Consensys/gnark-crypto#524 to be merged first.
We define the
DoublePairingCheck
method which asserts thate(a,b)e(c,d) == 1
. We merge the squares in final exp equivalence check forwitnessResidue^λ
with the Miller loop computation. This PR optimizes KZG and Pedersen commitments.Type of change
How has this been tested?
Added tests for the new method in addition to existing tests for
PairingCheck
.How has this been benchmarked?
The PR saves for a double-pairing check:
Checklist:
golangci-lint
does not output errors locally