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

Pairing: remove preCompute and go routines in MillerLoop #27

Merged
merged 5 commits into from
Jan 11, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ These benchmarks ran on a AWS z1d.3xlarge instance, with hyperthreading disabled
|G2::ScalarMul| 88423| 141000|
|G2::Add |598| 871|
|G2::Double |371| 386|
|Pairing |478244 |606000|
|Pairing |478244 |489258|


----
Expand All @@ -80,7 +80,7 @@ These benchmarks ran on a AWS z1d.3xlarge instance, with hyperthreading disabled
|G2::ScalarMul| 159068| 273000|
|G2::Add |1162| 1240|
|G2::Double |727| 799|
|Pairing |676513 |949000|
|Pairing |676513 |707984|

*note that some routines don't have assembly implementation in `goff` yet.

Expand Down
140 changes: 60 additions & 80 deletions bls381/pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package bls381

import (
"errors"
"sync"

"github.com/consensys/gurvy/bls381/internal/fptower"
)
Expand Down Expand Up @@ -97,106 +96,86 @@ func FinalExponentiation(z *GT, _z ...*GT) GT {
return result
}

var lineEvalPool = sync.Pool{
New: func() interface{} {
return new([68]lineEvaluation)
},
}

// MillerLoop Miller loop
func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) {
nP := len(P)
if nP == 0 || nP != len(Q) {
// check input size match
n := len(P)
if n == 0 || n != len(Q) {
return GT{}, errors.New("invalid inputs sizes")
}

var (
ch = make([]chan struct{}, 0, nP)
evaluations = make([]*[68]lineEvaluation, 0, nP)
)
// filter infinity points
p := make([]G1Affine, 0, n)
q := make([]G2Affine, 0, n)

var countInf = 0
for k := 0; k < nP; k++ {
for k := 0; k < n; k++ {
if P[k].IsInfinity() || Q[k].IsInfinity() {
countInf++
continue
}
p = append(p, P[k])
q = append(q, Q[k])
}

ch = append(ch, make(chan struct{}, 10))
evaluations = append(evaluations, lineEvalPool.Get().(*[68]lineEvaluation))
n = len(p)

go preCompute(evaluations[k-countInf], &Q[k], ch[k-countInf])
// projective points for Q
qProj := make([]g2Proj, n)
for k := 0; k < n; k++ {
qProj[k].FromAffine(&q[k])
}

nP = nP - countInf

var result GT
result.SetOne()

j := 0
for i := len(loopCounter) - 2; i >= 0; i-- {
var l lineEvaluation

// i == 62
for k := 0; k < n; k++ {
qProj[k].DoubleStep(&l)
// line eval
l.r1.MulByElement(&l.r1, &p[k].X)
l.r2.MulByElement(&l.r2, &p[k].Y)
result.MulBy014(&l.r0, &l.r1, &l.r2)

qProj[k].AddMixedStep(&l, &q[k])
// line eval
l.r1.MulByElement(&l.r1, &p[k].X)
l.r2.MulByElement(&l.r2, &p[k].Y)
result.MulBy014(&l.r0, &l.r1, &l.r2)
}

for i := 61; i >= 0; i-- {
result.Square(&result)
for k := 0; k < nP; k++ {
<-ch[k]
lineEval(&result, &evaluations[k][j], &P[k])

for k := 0; k < n; k++ {
qProj[k].DoubleStep(&l)
// line eval
l.r1.MulByElement(&l.r1, &p[k].X)
l.r2.MulByElement(&l.r2, &p[k].Y)
result.MulBy014(&l.r0, &l.r1, &l.r2)
}
j++

if loopCounter[i] == 1 {
for k := 0; k < nP; k++ {
<-ch[k]
lineEval(&result, &evaluations[k][j], &P[k])
}
j++

if loopCounter[i] == 0 {
continue
}

for k := 0; k < n; k++ {
qProj[k].AddMixedStep(&l, &q[k])
// line eval
l.r1.MulByElement(&l.r1, &p[k].X)
l.r2.MulByElement(&l.r2, &p[k].Y)
result.MulBy014(&l.r0, &l.r1, &l.r2)
}
}

result.Conjugate(&result)

// release objects into the pool
for i := 0; i < len(evaluations); i++ {
lineEvalPool.Put(evaluations[i])
}

return result, nil
}

func lineEval(z *GT, l *lineEvaluation, P *G1Affine) *GT {

l.r2.MulByElement(&l.r2, &P.Y)
l.r1.MulByElement(&l.r1, &P.X)

z.MulBy014(&l.r0, &l.r1, &l.r2)
return z
}

// precomputes the line evaluations used during the Miller loop.
func preCompute(evaluations *[68]lineEvaluation, Q *G2Affine, ch chan struct{}) {

var Qproj g2Proj
Qproj.FromAffine(Q)

j := 0

for i := len(loopCounter) - 2; i >= 0; i-- {

Qproj.DoubleStep(&evaluations[j])
ch <- struct{}{}

if loopCounter[i] != 0 {
j++
Qproj.AddMixedStep(&evaluations[j], Q)
ch <- struct{}{}
}
j++
}
close(ch)
}

// DoubleStep doubles a point in Homogenous projective coordinates, and evaluates the line in Miller loop
// https://eprint.iacr.org/2013/722.pdf (Section 4.3)
func (p *g2Proj) DoubleStep(evaluations *lineEvaluation) {
func (p *g2Proj) DoubleStep(l *lineEvaluation) {

// get some Element from our pool
var t0, t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2
Expand Down Expand Up @@ -229,15 +208,16 @@ func (p *g2Proj) DoubleStep(evaluations *lineEvaluation) {
p.z.Mul(&B, &H)

// Line evaluation
evaluations.r0.Set(&I)
evaluations.r1.Double(&J).
Add(&evaluations.r1, &J)
evaluations.r2.Neg(&H)
l.r0.Set(&I)
l.r1.Double(&J).
Add(&l.r1, &J)
l.r2.Neg(&H)

}

// AddMixedStep point addition in Mixed Homogenous projective and Affine coordinates
// https://eprint.iacr.org/2013/722.pdf (Section 4.3)
func (p *g2Proj) AddMixedStep(evaluations *lineEvaluation, a *G2Affine) {
func (p *g2Proj) AddMixedStep(l *lineEvaluation, a *G2Affine) {

// get some Element from our pool
var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2
Expand Down Expand Up @@ -267,7 +247,7 @@ func (p *g2Proj) AddMixedStep(evaluations *lineEvaluation, a *G2Affine) {
Sub(&J, &t2)

// Line evaluation
evaluations.r0.Set(&J)
evaluations.r1.Neg(&O)
evaluations.r2.Set(&L)
l.r0.Set(&J)
l.r1.Neg(&O)
l.r2.Set(&L)
}
Loading