Skip to content

Commit

Permalink
Merge pull request #506 from Consensys/perf/affine-pairing
Browse files Browse the repository at this point in the history
perf(bn254): optimize affine pairing with doubleAndAdd
  • Loading branch information
yelhousni committed Jul 3, 2024
2 parents f7d26b6 + 4ac930a commit 5d8b5fa
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 16 deletions.
62 changes: 55 additions & 7 deletions ecc/bn254/pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,13 +439,15 @@ func PrecomputeLines(Q G2Affine) (PrecomputedLines [2][len(LoopCounter)]LineEval

n := len(LoopCounter)
for i := n - 2; i >= 0; i-- {
accQ.doubleStep(&PrecomputedLines[0][i])
if LoopCounter[i] == 1 {
accQ.addStep(&PrecomputedLines[1][i], &Q)
} else if LoopCounter[i] == -1 {
accQ.addStep(&PrecomputedLines[1][i], &negQ)
} else {
continue
switch LoopCounter[i] {
case 0:
accQ.doubleStep(&PrecomputedLines[0][i])
case 1:
accQ.doubleAndAddStep(&PrecomputedLines[0][i], &PrecomputedLines[1][i], &Q)
case -1:
accQ.doubleAndAddStep(&PrecomputedLines[0][i], &PrecomputedLines[1][i], &negQ)
default:
return [2][len(LoopCounter)]LineEvaluationAff{}
}
}

Expand Down Expand Up @@ -673,3 +675,49 @@ func (p *G2Affine) addStep(evaluations *LineEvaluationAff, a *G2Affine) {
p.X.Set(&xr)
p.Y.Set(&yr)
}

func (p *G2Affine) doubleAndAddStep(evaluations1, evaluations2 *LineEvaluationAff, a *G2Affine) {
var n, d, l1, x3, l2, x4, y4 fptower.E2

// compute λ1 = (y2-y1)/(x2-x1)
n.Sub(&p.Y, &a.Y)
d.Sub(&p.X, &a.X)
l1.Div(&n, &d)

// compute x3 =λ1²-x1-x2
x3.Square(&l1)
x3.Sub(&x3, &p.X)
x3.Sub(&x3, &a.X)

// omit y3 computation

// compute line1
evaluations1.R0.Set(&l1)
evaluations1.R1.Mul(&l1, &p.X)
evaluations1.R1.Sub(&evaluations1.R1, &p.Y)

// compute λ2 = -λ1-2y1/(x3-x1)
n.Double(&p.Y)
d.Sub(&x3, &p.X)
l2.Div(&n, &d)
l2.Add(&l2, &l1)
l2.Neg(&l2)

// compute x4 = λ2²-x1-x3
x4.Square(&l2)
x4.Sub(&x4, &p.X)
x4.Sub(&x4, &x3)

// compute y4 = λ2(x1 - x4)-y1
y4.Sub(&p.X, &x4)
y4.Mul(&l2, &y4)
y4.Sub(&y4, &p.Y)

// compute line2
evaluations2.R0.Set(&l2)
evaluations2.R1.Mul(&l2, &p.X)
evaluations2.R1.Sub(&evaluations2.R1, &p.Y)

p.X.Set(&x4)
p.Y.Set(&y4)
}
80 changes: 71 additions & 9 deletions ecc/bw6-761/pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,31 +411,32 @@ func PrecomputeLines(Q G2Affine) (PrecomputedLines [2][len(LoopCounter) - 1]Line
// precomputations
var accQ, imQ, imQneg, negQ G2Affine
imQ.Y.Neg(&Q.Y)
imQ.X.Mul(&Q.X, &thirdRootOneG1)
negQ.X.Set(&Q.X)
negQ.Y.Set(&imQ.Y)
imQ.X.Mul(&Q.X, &thirdRootOneG1)
accQ.Set(&imQ)
imQneg.Neg(&imQ)
imQneg.X.Set(&imQ.X)
imQneg.Y.Set(&Q.Y)

for i := len(LoopCounter) - 2; i >= 0; i-- {
accQ.doubleStep(&PrecomputedLines[0][i])
for i := len(LoopCounter) - 2; i > 0; i-- {

switch LoopCounter1[i]*3 + LoopCounter[i] {
// cases -4, -2, 2, 4 do not occur, given the static LoopCounters
case -3:
accQ.addStep(&PrecomputedLines[1][i], &imQneg)
accQ.doubleAndAddStep(&PrecomputedLines[0][i], &PrecomputedLines[1][i], &imQneg)
case -1:
accQ.addStep(&PrecomputedLines[1][i], &negQ)
accQ.doubleAndAddStep(&PrecomputedLines[0][i], &PrecomputedLines[1][i], &negQ)
case 0:
continue
accQ.doubleStep(&PrecomputedLines[0][i])
case 1:
accQ.addStep(&PrecomputedLines[1][i], &Q)
accQ.doubleAndAddStep(&PrecomputedLines[0][i], &PrecomputedLines[1][i], &Q)
case 3:
accQ.addStep(&PrecomputedLines[1][i], &imQ)
accQ.doubleAndAddStep(&PrecomputedLines[0][i], &PrecomputedLines[1][i], &imQ)
default:
return [2][len(LoopCounter) - 1]LineEvaluationAff{}
}
}
accQ.tangentCompute(&PrecomputedLines[0][0])

return PrecomputedLines
}
Expand Down Expand Up @@ -578,3 +579,64 @@ func (p *G2Affine) addStep(evaluations *LineEvaluationAff, a *G2Affine) {
p.X.Set(&xr)
p.Y.Set(&yr)
}

func (p *G2Affine) doubleAndAddStep(evaluations1, evaluations2 *LineEvaluationAff, a *G2Affine) {
var n, d, l1, x3, l2, x4, y4 fp.Element

// compute λ1 = (y2-y1)/(x2-x1)
n.Sub(&p.Y, &a.Y)
d.Sub(&p.X, &a.X)
l1.Div(&n, &d)

// compute x3 =λ1²-x1-x2
x3.Square(&l1)
x3.Sub(&x3, &p.X)
x3.Sub(&x3, &a.X)

// omit y3 computation

// compute line1
evaluations1.R0.Set(&l1)
evaluations1.R1.Mul(&l1, &p.X)
evaluations1.R1.Sub(&evaluations1.R1, &p.Y)

// compute λ2 = -λ1-2y1/(x3-x1)
n.Double(&p.Y)
d.Sub(&x3, &p.X)
l2.Div(&n, &d)
l2.Add(&l2, &l1)
l2.Neg(&l2)

// compute x4 = λ2²-x1-x3
x4.Square(&l2)
x4.Sub(&x4, &p.X)
x4.Sub(&x4, &x3)

// compute y4 = λ2(x1 - x4)-y1
y4.Sub(&p.X, &x4)
y4.Mul(&l2, &y4)
y4.Sub(&y4, &p.Y)

// compute line2
evaluations2.R0.Set(&l2)
evaluations2.R1.Mul(&l2, &p.X)
evaluations2.R1.Sub(&evaluations2.R1, &p.Y)

p.X.Set(&x4)
p.Y.Set(&y4)
}

func (p *G2Affine) tangentCompute(evaluations *LineEvaluationAff) {

var n, d, λ fp.Element
// λ = 3x²/2y
n.Square(&p.X)
λ.Double(&n).
Add(&λ, &n)
d.Double(&p.Y)
λ.Div(&λ, &d)

evaluations.R0.Set(&λ)
evaluations.R1.Mul(&λ, &p.X).
Sub(&evaluations.R1, &p.Y)
}

0 comments on commit 5d8b5fa

Please sign in to comment.