Skip to content

Commit

Permalink
Merge pull request #714 from Consensys/perf/emulated-pairing
Browse files Browse the repository at this point in the history
Perf: emulated pairing BN254
  • Loading branch information
yelhousni committed Jul 4, 2023
2 parents b267eb4 + 8bdadb1 commit bb5a773
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 25 deletions.
25 changes: 21 additions & 4 deletions std/algebra/emulated/sw_bn254/pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) {
res = pr.MulBy01234(res, &prodLines)
}

l1s := make([]*lineEvaluation, n)
for i := 62; i >= 0; i-- {
// mutualize the square among n Miller loops
// (∏ᵢfᵢ)²
Expand All @@ -438,16 +439,32 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) {
switch loopCounter[i] {

case 0:
// precompute lines
for k := 0; k < n; k++ {
// Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k]
Qacc[k], l1 = pr.doubleStep(Qacc[k])
Qacc[k], l1s[k] = pr.doubleStep(Qacc[k])

// line evaluation at P[k]
l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k])
l1.R1 = *pr.MulByElement(&l1.R1, yInv[k])
l1s[k].R0 = *pr.MulByElement(&l1s[k].R0, xOverY[k])
l1s[k].R1 = *pr.MulByElement(&l1s[k].R1, yInv[k])

}

// if number of lines is odd, mul last line by res
// works for n=1 as well
if n%2 != 0 {
// ℓ × res
res = pr.MulBy034(res, &l1.R0, &l1.R1)
res = pr.MulBy034(res, &l1s[n-1].R0, &l1s[n-1].R1)

}

// mul lines 2-by-2
for k := 1; k < n; k += 2 {
// ℓ × ℓ
prodLines = *pr.Mul034By034(&l1s[k].R0, &l1s[k].R1, &l1s[k-1].R0, &l1s[k-1].R1)
// (ℓ × ℓ) × res
res = pr.MulBy01234(res, &prodLines)

}

case 1:
Expand Down
50 changes: 29 additions & 21 deletions std/algebra/emulated/sw_bn254/pairing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,25 @@ func TestPairTestSolve(t *testing.T) {
}

type MultiPairCircuit struct {
In1G1 G1Affine
In2G1 G1Affine
In1G2 G2Affine
In2G2 G2Affine
Res GTEl
InG1 G1Affine
InG2 G2Affine
Res GTEl
n int
}

func (c *MultiPairCircuit) Define(api frontend.API) error {
pairing, err := NewPairing(api)
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})
pairing.AssertIsOnG1(&c.InG1)
pairing.AssertIsOnG2(&c.InG2)
P, Q := []*G1Affine{}, []*G2Affine{}
for i := 0; i < c.n; i++ {
P = append(P, &c.InG1)
Q = append(Q, &c.InG2)
}
res, err := pairing.Pair(P, Q)
if err != nil {
return fmt.Errorf("pair: %w", err)
}
Expand All @@ -126,18 +128,24 @@ func (c *MultiPairCircuit) Define(api frontend.API) error {
func TestMultiPairTestSolve(t *testing.T) {
assert := test.NewAssert(t)
p1, q1 := randomG1G2Affines()
p2, q2 := randomG1G2Affines()
res, err := bn254.Pair([]bn254.G1Affine{p1, p1, p2, p2}, []bn254.G2Affine{q1, q2, q1, q2})
assert.NoError(err)
witness := MultiPairCircuit{
In1G1: NewG1Affine(p1),
In1G2: NewG2Affine(q1),
In2G1: NewG1Affine(p2),
In2G2: NewG2Affine(q2),
Res: NewGTEl(res),
p := make([]bn254.G1Affine, 10)
q := make([]bn254.G2Affine, 10)
for i := 0; i < 10; i++ {
p[i] = p1
q[i] = q1
}

for i := 2; i < 10; i++ {
res, err := bn254.Pair(p[:i], q[:i])
assert.NoError(err)
witness := MultiPairCircuit{
InG1: NewG1Affine(p1),
InG2: NewG2Affine(q1),
Res: NewGTEl(res),
}
err = test.IsSolved(&MultiPairCircuit{n: i}, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}
err = test.IsSolved(&MultiPairCircuit{}, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}

type PairingCheckCircuit struct {
Expand Down

0 comments on commit bb5a773

Please sign in to comment.