Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
108 changes: 44 additions & 64 deletions bls377/pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,91 +113,71 @@ var lineEvalPool = sync.Pool{

// 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([]*[69]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
}
ch = append(ch, make(chan struct{}, 10))
evaluations = append(evaluations, lineEvalPool.Get().(*[69]lineEvaluation))

go preCompute(evaluations[k-countInf], &Q[k], ch[k-countInf])
p = append(p, P[k])
q = append(q, Q[k])
}

nP = nP - countInf
n = len(p)

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

var result GT
result.SetOne()

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

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

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

// release objects into the pool
for i := 0; i < len(evaluations); i++ {
lineEvalPool.Put(evaluations[i])
// i == 62
for k := 0; k < n; k++ {
qProj[k].DoubleStep(&l)
// line eval
l.r0.MulByElement(&l.r0, &p[k].Y)
l.r1.MulByElement(&l.r1, &p[k].X)
result.MulBy034(&l.r0, &l.r1, &l.r2)
}

return result, nil
}

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

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

z.MulBy034(&l.r0, &l.r1, &l.r2)

return z
}

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

var Qproj g2Proj
Qproj.FromAffine(Q)

j := 0
for i := 61; i >= 0; i-- {
result.Square(&result)

for i := len(loopCounter) - 2; i >= 0; i-- {
for k := 0; k < n; k++ {
qProj[k].DoubleStep(&l)
// line eval
l.r0.MulByElement(&l.r0, &p[k].Y)
l.r1.MulByElement(&l.r1, &p[k].X)
result.MulBy034(&l.r0, &l.r1, &l.r2)
}

Qproj.DoubleStep(&evaluations[j])
ch <- struct{}{}
if loopCounter[i] == 0 {
continue
}

if loopCounter[i] != 0 {
j++
Qproj.AddMixedStep(&evaluations[j], Q)
ch <- struct{}{}
for k := 0; k < n; k++ {
qProj[k].AddMixedStep(&l, &q[k])
// line eval
l.r0.MulByElement(&l.r0, &p[k].Y)
l.r1.MulByElement(&l.r1, &p[k].X)
result.MulBy034(&l.r0, &l.r1, &l.r2)
}
j++
}
close(ch)

return result, nil
}

// DoubleStep doubles a point in Homogenous projective coordinates, and evaluates the line in Miller loop
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