Skip to content

Commit

Permalink
Merge pull request #366 from ConsenSys/refactor/pairings
Browse files Browse the repository at this point in the history
Refactor: pairings
  • Loading branch information
yelhousni authored Mar 29, 2023
2 parents 19b2b0c + 0805f8b commit a57dcc3
Show file tree
Hide file tree
Showing 24 changed files with 1,704 additions and 382 deletions.
50 changes: 50 additions & 0 deletions ecc/bls12-377/internal/fptower/e12_pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,53 @@ func (z *E12) MulBy034(c0, c3, c4 *E2) *E12 {

return z
}

// Mul034By034 multiplication of sparse element (c0,0,0,c3,c4,0) by sparse element (d0,0,0,d3,d4,0)
func Mul034By034(d0, d3, d4, c0, c3, c4 *E2) [5]E2 {
var z00, tmp, x0, x3, x4, x04, x03, x34 E2
x0.Mul(c0, d0)
x3.Mul(c3, d3)
x4.Mul(c4, d4)
tmp.Add(c0, c4)
x04.Add(d0, d4).
Mul(&x04, &tmp).
Sub(&x04, &x0).
Sub(&x04, &x4)
tmp.Add(c0, c3)
x03.Add(d0, d3).
Mul(&x03, &tmp).
Sub(&x03, &x0).
Sub(&x03, &x3)
tmp.Add(c3, c4)
x34.Add(d3, d4).
Mul(&x34, &tmp).
Sub(&x34, &x3).
Sub(&x34, &x4)

z00.MulByNonResidue(&x4).
Add(&z00, &x0)

return [5]E2{z00, x3, x34, x03, x04}
}

// MulBy01234 multiplies z by an E12 sparse element of the form (x0, x1, x2, x3, x4, 0)
func (z *E12) MulBy01234(x *[5]E2) *E12 {
var c1, a, b, c, z0, z1 E6
c0 := &E6{B0: x[0], B1: x[1], B2: x[2]}
c1.B0 = x[3]
c1.B1 = x[4]
a.Add(&z.C0, &z.C1)
b.Add(c0, &c1)
a.Mul(&a, &b)
b.Mul(&z.C0, c0)
c.Set(&z.C1).MulBy01(&x[3], &x[4])
z1.Sub(&a, &b)
z1.Sub(&z1, &c)
z0.MulByNonResidue(&c)
z0.Add(&z0, &b)

z.C0 = z0
z.C1 = z1

return z
}
28 changes: 28 additions & 0 deletions ecc/bls12-377/internal/fptower/e6.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

142 changes: 113 additions & 29 deletions ecc/bls12-377/pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func FinalExponentiation(z *GT, _z ...*GT) GT {
}

// MillerLoop computes the multi-Miller loop
// ∏ᵢ MillerLoop(Pᵢ, Qᵢ)
// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) = ∏ᵢ { fᵢ_{x,Qᵢ}(Pᵢ) }
func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) {
// check input size match
n := len(P)
Expand Down Expand Up @@ -134,49 +134,113 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) {

var result GT
result.SetOne()
var l1, l2 lineEvaluation
var prodLines [5]E2

// Compute ∏ᵢ { fᵢ_{x₀,Q}(P) }
if n >= 1 {
// i = 62, separately to avoid an E12 Square
// (Square(res) = 1² = 1)
// loopCounter[62] = 0
// k = 0, separately to avoid MulBy034 (res × ℓ)
// (assign line to res)

// qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0]
qProj[0].doubleStep(&l1)
// line evaluation at P[0] (assign)
result.C0.B0.MulByElement(&l1.r0, &p[0].Y)
result.C1.B0.MulByElement(&l1.r1, &p[0].X)
result.C1.B1.Set(&l1.r2)
}

var l lineEvaluation
if n >= 2 {
// k = 1, separately to avoid MulBy034 (res × ℓ)
// (res is also a line at this point, so we use Mul034By034 ℓ × ℓ)

// qProj[1] ← 2qProj[1] and l1 the tangent ℓ passing 2qProj[1]
qProj[1].doubleStep(&l1)
// line evaluation at P[1]
l1.r0.MulByElement(&l1.r0, &p[1].Y)
l1.r1.MulByElement(&l1.r1, &p[1].X)
// ℓ × res
prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &result.C0.B0, &result.C1.B0, &result.C1.B1)
result.C0.B0 = prodLines[0]
result.C0.B1 = prodLines[1]
result.C0.B2 = prodLines[2]
result.C1.B0 = prodLines[3]
result.C1.B1 = prodLines[4]
}

// i == len(loopCounter) - 2
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)
// k >= 2
for k := 2; k < n; k++ {
// qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k]
qProj[k].doubleStep(&l1)
// line evaluation at P[k]
l1.r0.MulByElement(&l1.r0, &p[k].Y)
l1.r1.MulByElement(&l1.r1, &p[k].X)
// ℓ × res
result.MulBy034(&l1.r0, &l1.r1, &l1.r2)
}

for i := len(loopCounter) - 3; i >= 0; i-- {
// i <= 61
for i := len(loopCounter) - 3; i >= 1; i-- {
// mutualize the square among n Miller loops
// (∏ᵢfᵢ)²
result.Square(&result)

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[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k]
qProj[k].doubleStep(&l1)
// line evaluation at P[k]
l1.r0.MulByElement(&l1.r0, &p[k].Y)
l1.r1.MulByElement(&l1.r1, &p[k].X)

if loopCounter[i] == 0 {
// ℓ × res
result.MulBy034(&l1.r0, &l1.r1, &l1.r2)
} else {
// qProj[k] ← qProj[k]+Q[k] and
// l2 the line ℓ passing qProj[k] and Q[k]
qProj[k].addMixedStep(&l2, &q[k])
// line evaluation at P[k]
l2.r0.MulByElement(&l2.r0, &p[k].Y)
l2.r1.MulByElement(&l2.r1, &p[k].X)
// ℓ × ℓ
prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2)
// (ℓ × ℓ) × res
result.MulBy01234(&prodLines)
}
}

if loopCounter[i] == 0 {
continue
}
}

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)
}
// i = 0, separately to avoid a point addition
// loopCounter[0] = 1
result.Square(&result)
for k := 0; k < n; k++ {
// qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k]
qProj[k].doubleStep(&l1)
// line evaluation at P[k]
l1.r0.MulByElement(&l1.r0, &p[k].Y)
l1.r1.MulByElement(&l1.r1, &p[k].X)

// l2 the line passing qProj[k] and Q
qProj[k].lineCompute(&l2, &q[k])
// line evaluation at P[k]
l2.r0.MulByElement(&l2.r0, &p[k].Y)
l2.r1.MulByElement(&l2.r1, &p[k].X)
// ℓ × ℓ
prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2)
// (ℓ × ℓ) × res
result.MulBy01234(&prodLines)
}

return result, nil
}

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

// get some Element from our pool
var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2
Expand Down Expand Up @@ -215,9 +279,9 @@ func (p *g2Proj) DoubleStep(evaluations *lineEvaluation) {
evaluations.r2.Set(&I)
}

// AddMixedStep point addition in Mixed Homogenous projective and Affine coordinates
// 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(evaluations *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 @@ -251,3 +315,23 @@ func (p *g2Proj) AddMixedStep(evaluations *lineEvaluation, a *G2Affine) {
evaluations.r1.Neg(&O)
evaluations.r2.Set(&J)
}

// lineCompute computes the line through p in Homogenous projective coordinates
// and a in affine coordinates. It does not compute the resulting point p+a.
func (p *g2Proj) lineCompute(evaluations *lineEvaluation, a *G2Affine) {

// get some Element from our pool
var Y2Z1, X2Z1, O, L, t2, J fptower.E2
Y2Z1.Mul(&a.Y, &p.z)
O.Sub(&p.y, &Y2Z1)
X2Z1.Mul(&a.X, &p.z)
L.Sub(&p.x, &X2Z1)
t2.Mul(&L, &a.Y)
J.Mul(&a.X, &O).
Sub(&J, &t2)

// Line evaluation
evaluations.r0.Set(&L)
evaluations.r1.Neg(&O)
evaluations.r2.Set(&J)
}
35 changes: 26 additions & 9 deletions ecc/bls12-378/internal/fptower/e12_pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ func (z *E12) MulBy014(c0, c1, c4 *E2) *E12 {
}

// Mul014By014 multiplication of sparse element (c0,c1,0,0,c4,0) by sparse element (d0,d1,0,0,d4,0)
func (z *E12) Mul014By014(d0, d1, d4, c0, c1, c4 *E2) *E12 {
var tmp, x0, x1, x4, x04, x01, x14 E2
func Mul014By014(d0, d1, d4, c0, c1, c4 *E2) [5]E2 {
var z00, tmp, x0, x1, x4, x04, x01, x14 E2
x0.Mul(c0, d0)
x1.Mul(c1, d1)
x4.Mul(c4, d4)
Expand All @@ -116,13 +116,30 @@ func (z *E12) Mul014By014(d0, d1, d4, c0, c1, c4 *E2) *E12 {
Sub(&x14, &x1).
Sub(&x14, &x4)

z.C0.B0.MulByNonResidue(&x4).
Add(&z.C0.B0, &x0)
z.C0.B1.Set(&x01)
z.C0.B2.Set(&x1)
z.C1.B0.SetZero()
z.C1.B1.Set(&x04)
z.C1.B2.Set(&x14)
z00.MulByNonResidue(&x4).
Add(&z00, &x0)

return [5]E2{z00, x01, x1, x04, x14}
}

// MulBy01245 multiplies z by an E12 sparse element of the form (x0, x1, x2, 0, x4, x5)
func (z *E12) MulBy01245(x *[5]E2) *E12 {
var c1, a, b, c, z0, z1 E6
c0 := &E6{B0: x[0], B1: x[1], B2: x[2]}
c1.B1 = x[3]
c1.B2 = x[4]
a.Add(&z.C0, &z.C1)
b.Add(c0, &c1)
a.Mul(&a, &b)
b.Mul(&z.C0, c0)
c.Set(&z.C1).MulBy12(&x[3], &x[4])
z1.Sub(&a, &b)
z1.Sub(&z1, &c)
z0.MulByNonResidue(&c)
z0.Add(&z0, &b)

z.C0 = z0
z.C1 = z1

return z
}
28 changes: 28 additions & 0 deletions ecc/bls12-378/internal/fptower/e6.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a57dcc3

Please sign in to comment.