From e18af6611432653f68465cc4892be2d6ef245d02 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 23 Mar 2023 10:05:40 +0000 Subject: [PATCH 01/18] refactor(pairings): make DoubleStep and AddMixedStep private --- ecc/bls12-377/pairing.go | 14 +++++++------- ecc/bls12-378/pairing.go | 14 +++++++------- ecc/bls12-381/pairing.go | 16 ++++++++-------- ecc/bls24-315/pairing.go | 16 ++++++++-------- ecc/bls24-317/pairing.go | 16 ++++++++-------- ecc/bn254/pairing.go | 20 ++++++++++---------- ecc/bw6-633/pairing.go | 32 ++++++++++++++++---------------- ecc/bw6-756/pairing.go | 32 ++++++++++++++++---------------- ecc/bw6-761/pairing.go | 33 ++++++++++++++++----------------- 9 files changed, 96 insertions(+), 97 deletions(-) diff --git a/ecc/bls12-377/pairing.go b/ecc/bls12-377/pairing.go index b1ed68e1a..409a476e7 100644 --- a/ecc/bls12-377/pairing.go +++ b/ecc/bls12-377/pairing.go @@ -139,7 +139,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // i == len(loopCounter) - 2 for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l) + qProj[k].doubleStep(&l) // line eval l.r0.MulByElement(&l.r0, &p[k].Y) l.r1.MulByElement(&l.r1, &p[k].X) @@ -151,7 +151,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Square(&result) for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l) + qProj[k].doubleStep(&l) // line eval l.r0.MulByElement(&l.r0, &p[k].Y) l.r1.MulByElement(&l.r1, &p[k].X) @@ -163,7 +163,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } for k := 0; k < n; k++ { - qProj[k].AddMixedStep(&l, &q[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) @@ -174,9 +174,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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 @@ -215,9 +215,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 diff --git a/ecc/bls12-378/pairing.go b/ecc/bls12-378/pairing.go index c88db7548..e36e5b076 100644 --- a/ecc/bls12-378/pairing.go +++ b/ecc/bls12-378/pairing.go @@ -138,7 +138,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // i == len(loopCounter) - 2 for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l1) + qProj[k].doubleStep(&l1) // line eval l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) @@ -150,7 +150,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Square(&result) for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l1) + qProj[k].doubleStep(&l1) // line eval l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) @@ -158,7 +158,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { if loopCounter[i] == 0 { result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } else { - qProj[k].AddMixedStep(&l2, &q[k]) + qProj[k].addMixedStep(&l2, &q[k]) // line eval l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) @@ -173,9 +173,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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(l *lineEvaluation) { +func (p *g2Proj) doubleStep(l *lineEvaluation) { // get some Element from our pool var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 @@ -215,9 +215,9 @@ func (p *g2Proj) DoubleStep(l *lineEvaluation) { } -// 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(l *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 diff --git a/ecc/bls12-381/pairing.go b/ecc/bls12-381/pairing.go index 9a78d328d..1549132a2 100644 --- a/ecc/bls12-381/pairing.go +++ b/ecc/bls12-381/pairing.go @@ -138,12 +138,12 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // i == len(loopCounter) - 2 for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l1) + qProj[k].doubleStep(&l1) // line eval l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) - qProj[k].AddMixedStep(&l2, &q[k]) + qProj[k].addMixedStep(&l2, &q[k]) // line eval l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) @@ -158,7 +158,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Square(&result) for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l1) + qProj[k].doubleStep(&l1) // line eval l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) @@ -166,7 +166,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { if loopCounter[i] == 0 { result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } else { - qProj[k].AddMixedStep(&l2, &q[k]) + qProj[k].addMixedStep(&l2, &q[k]) // line eval l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) @@ -184,9 +184,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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(l *lineEvaluation) { +func (p *g2Proj) doubleStep(l *lineEvaluation) { // get some Element from our pool var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 @@ -226,9 +226,9 @@ func (p *g2Proj) DoubleStep(l *lineEvaluation) { } -// 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(l *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 diff --git a/ecc/bls24-315/pairing.go b/ecc/bls24-315/pairing.go index 5e1bf1fe3..bb1f15390 100644 --- a/ecc/bls24-315/pairing.go +++ b/ecc/bls24-315/pairing.go @@ -149,7 +149,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // len(loopCounter) - 2 for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l) + qProj[k].doubleStep(&l) // line evaluation l.r0.MulByElement(&l.r0, &p[k].Y) l.r1.MulByElement(&l.r1, &p[k].X) @@ -161,21 +161,21 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Square(&result) for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l) + qProj[k].doubleStep(&l) // line evaluation l.r0.MulByElement(&l.r0, &p[k].Y) l.r1.MulByElement(&l.r1, &p[k].X) result.MulBy034(&l.r0, &l.r1, &l.r2) if loopCounter[i] == 1 { - qProj[k].AddMixedStep(&l, &q[k]) + qProj[k].addMixedStep(&l, &q[k]) // line evaluation l.r0.MulByElement(&l.r0, &p[k].Y) l.r1.MulByElement(&l.r1, &p[k].X) result.MulBy034(&l.r0, &l.r1, &l.r2) } else if loopCounter[i] == -1 { - qProj[k].AddMixedStep(&l, &qNeg[k]) + qProj[k].addMixedStep(&l, &qNeg[k]) // line evaluation l.r0.MulByElement(&l.r0, &p[k].Y) l.r1.MulByElement(&l.r1, &p[k].X) @@ -189,9 +189,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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.E4 @@ -230,9 +230,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.E4 diff --git a/ecc/bls24-317/pairing.go b/ecc/bls24-317/pairing.go index 19f39706b..8ce66d6ac 100644 --- a/ecc/bls24-317/pairing.go +++ b/ecc/bls24-317/pairing.go @@ -153,7 +153,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // i == len(loopCounter) - 2 for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l) + qProj[k].doubleStep(&l) // line evaluation l.r1.MulByElement(&l.r1, &p[k].X) l.r2.MulByElement(&l.r2, &p[k].Y) @@ -165,21 +165,21 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Square(&result) for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l) + qProj[k].doubleStep(&l) // line evaluation l.r1.MulByElement(&l.r1, &p[k].X) l.r2.MulByElement(&l.r2, &p[k].Y) result.MulBy014(&l.r0, &l.r1, &l.r2) if loopCounter[i] == 1 { - qProj[k].AddMixedStep(&l, &q[k]) + qProj[k].addMixedStep(&l, &q[k]) // line evaluation l.r1.MulByElement(&l.r1, &p[k].X) l.r2.MulByElement(&l.r2, &p[k].Y) result.MulBy014(&l.r0, &l.r1, &l.r2) } else if loopCounter[i] == -1 { - qProj[k].AddMixedStep(&l, &qNeg[k]) + qProj[k].addMixedStep(&l, &qNeg[k]) // line evaluation l.r1.MulByElement(&l.r1, &p[k].X) l.r2.MulByElement(&l.r2, &p[k].Y) @@ -191,9 +191,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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.E4 @@ -232,9 +232,9 @@ func (p *g2Proj) DoubleStep(evaluations *lineEvaluation) { evaluations.r2.Neg(&H) } -// 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.E4 diff --git a/ecc/bn254/pairing.go b/ecc/bn254/pairing.go index 53160c9be..b297b84fa 100644 --- a/ecc/bn254/pairing.go +++ b/ecc/bn254/pairing.go @@ -151,7 +151,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // i == len(loopCounter) - 2 for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l) + qProj[k].doubleStep(&l) // line evaluation l.r0.MulByElement(&l.r0, &p[k].Y) l.r1.MulByElement(&l.r1, &p[k].X) @@ -163,13 +163,13 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Square(&result) for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l) + qProj[k].doubleStep(&l) // line evaluation l.r0.MulByElement(&l.r0, &p[k].Y) l.r1.MulByElement(&l.r1, &p[k].X) if loopCounter[i] == 1 { - qProj[k].AddMixedStep(&l0, &q[k]) + qProj[k].addMixedStep(&l0, &q[k]) // line evaluation l0.r0.MulByElement(&l0.r0, &p[k].Y) l0.r1.MulByElement(&l0.r1, &p[k].X) @@ -177,7 +177,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Mul(&result, &tmp) } else if loopCounter[i] == -1 { - qProj[k].AddMixedStep(&l0, &qNeg[k]) + qProj[k].addMixedStep(&l0, &qNeg[k]) // line evaluation l0.r0.MulByElement(&l0.r0, &p[k].Y) l0.r1.MulByElement(&l0.r1, &p[k].X) @@ -199,11 +199,11 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { Q2.X.MulByNonResidue2Power2(&q[k].X) Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - qProj[k].AddMixedStep(&l0, &Q1) + qProj[k].addMixedStep(&l0, &Q1) l0.r0.MulByElement(&l0.r0, &p[k].Y) l0.r1.MulByElement(&l0.r1, &p[k].X) - qProj[k].AddMixedStep(&l, &Q2) + qProj[k].addMixedStep(&l, &Q2) l.r0.MulByElement(&l.r0, &p[k].Y) l.r1.MulByElement(&l.r1, &p[k].X) tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) @@ -213,9 +213,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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 @@ -254,9 +254,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 diff --git a/ecc/bw6-633/pairing.go b/ecc/bw6-633/pairing.go index 337b104b5..d193ae1dd 100644 --- a/ecc/bw6-633/pairing.go +++ b/ecc/bw6-633/pairing.go @@ -214,13 +214,13 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // l_{p0,p1}(q) pProj01[k].Set(&pProj0[k]) - pProj01[k].AddMixedStep(&l01[k], &p1[k]) + pProj01[k].addMixedStep(&l01[k], &p1[k]) l01[k].r1.Mul(&l01[k].r1, &q[k].X) l01[k].r0.Mul(&l01[k].r0, &q[k].Y) // l_{-p0,p1}(q) pProj10[k].Neg(&pProj0[k]) - pProj10[k].AddMixedStep(&l10[k], &p1[k]) + pProj10[k].addMixedStep(&l10[k], &p1[k]) l10[k].r1.Mul(&l10[k].r1, &q[k].X) l10[k].r0.Mul(&l10[k].r0, &q[k].Y) } @@ -236,7 +236,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // i = len(loopCounter)-2 for k := 0; k < n; k++ { - pProj0[k].DoubleStep(&l0) + pProj0[k].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) result.MulBy034(&l0.r0, &l0.r1, &l0.r2) @@ -249,14 +249,14 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { j = loopCounter0[i]*3 + loopCounter1[i] for k := 0; k < n; k++ { - pProj0[k].DoubleStep(&l0) + pProj0[k].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) switch j { case -4: tmp.Neg(&p01[k]) - pProj0[k].AddMixedStep(&l, &tmp) + pProj0[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) @@ -264,13 +264,13 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { Mul(&result, &ss) case -3: tmp.Neg(&p1[k]) - pProj0[k].AddMixedStep(&l, &tmp) + pProj0[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) result.Mul(&result, &ss) case -2: - pProj0[k].AddMixedStep(&l, &p10[k]) + pProj0[k].addMixedStep(&l, &p10[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l10[k].r0, &l10[k].r1, &l10[k].r2) @@ -278,7 +278,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { Mul(&result, &ss) case -1: tmp.Neg(&p0[k]) - pProj0[k].AddMixedStep(&l, &tmp) + pProj0[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) @@ -286,27 +286,27 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { case 0: result.MulBy034(&l0.r0, &l0.r1, &l0.r2) case 1: - pProj0[k].AddMixedStep(&l, &p0[k]) + pProj0[k].addMixedStep(&l, &p0[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) result.Mul(&result, &ss) case 2: tmp.Neg(&p10[k]) - pProj0[k].AddMixedStep(&l, &tmp) + pProj0[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l10[k].r0, &l10[k].r1, &l10[k].r2) result.MulBy034(&l0.r0, &l0.r1, &l0.r2). Mul(&result, &ss) case 3: - pProj0[k].AddMixedStep(&l, &p1[k]) + pProj0[k].addMixedStep(&l, &p1[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) result.Mul(&result, &ss) case 4: - pProj0[k].AddMixedStep(&l, &p01[k]) + pProj0[k].addMixedStep(&l, &p01[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) @@ -321,9 +321,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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 *g1Proj) DoubleStep(evaluations *lineEvaluation) { +func (p *g1Proj) doubleStep(evaluations *lineEvaluation) { // get some Element from our pool var t1, A, B, C, D, E, EE, F, G, H, I, J, K fp.Element @@ -366,9 +366,9 @@ func (p *g1Proj) 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 *g1Proj) AddMixedStep(evaluations *lineEvaluation, a *G1Affine) { +func (p *g1Proj) addMixedStep(evaluations *lineEvaluation, a *G1Affine) { // get some Element from our pool var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fp.Element diff --git a/ecc/bw6-756/pairing.go b/ecc/bw6-756/pairing.go index e4b1f3ad9..e2dc002a6 100644 --- a/ecc/bw6-756/pairing.go +++ b/ecc/bw6-756/pairing.go @@ -191,13 +191,13 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // l_{p0,p1}(q) pProj01[k].Set(&pProj1[k]) - pProj01[k].AddMixedStep(&l01[k], &p0[k]) + pProj01[k].addMixedStep(&l01[k], &p0[k]) l01[k].r1.Mul(&l01[k].r1, &q[k].X) l01[k].r0.Mul(&l01[k].r0, &q[k].Y) // l_{p0,-p1}(q) pProj10[k].Neg(&pProj1[k]) - pProj10[k].AddMixedStep(&l10[k], &p0[k]) + pProj10[k].addMixedStep(&l10[k], &p0[k]) l10[k].r1.Mul(&l10[k].r1, &q[k].X) l10[k].r0.Mul(&l10[k].r0, &q[k].Y) } @@ -213,7 +213,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // i = len(loopCounter) - 2 for k := 0; k < n; k++ { - pProj1[k].DoubleStep(&l0) + pProj1[k].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) result.MulBy034(&l0.r0, &l0.r1, &l0.r2) @@ -227,14 +227,14 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { j = loopCounter1[i]*3 + loopCounter0[i] for k := 0; k < n; k++ { - pProj1[k].DoubleStep(&l0) + pProj1[k].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) switch j { case -4: tmp.Neg(&p01[k]) - pProj1[k].AddMixedStep(&l, &tmp) + pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) @@ -242,13 +242,13 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { Mul(&result, &ss) case -3: tmp.Neg(&p1[k]) - pProj1[k].AddMixedStep(&l, &tmp) + pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) result.Mul(&result, &ss) case -2: - pProj1[k].AddMixedStep(&l, &p10[k]) + pProj1[k].addMixedStep(&l, &p10[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) @@ -256,7 +256,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { Mul(&result, &ss) case -1: tmp.Neg(&p0[k]) - pProj1[k].AddMixedStep(&l, &tmp) + pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) @@ -264,27 +264,27 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { case 0: result.MulBy034(&l0.r0, &l0.r1, &l0.r2) case 1: - pProj1[k].AddMixedStep(&l, &p0[k]) + pProj1[k].addMixedStep(&l, &p0[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) result.Mul(&result, &ss) case 2: tmp.Neg(&p10[k]) - pProj1[k].AddMixedStep(&l, &tmp) + pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) result.MulBy034(&l0.r0, &l0.r1, &l0.r2). Mul(&result, &ss) case 3: - pProj1[k].AddMixedStep(&l, &p1[k]) + pProj1[k].addMixedStep(&l, &p1[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) result.Mul(&result, &ss) case 4: - pProj1[k].AddMixedStep(&l, &p01[k]) + pProj1[k].addMixedStep(&l, &p01[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) @@ -299,9 +299,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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 *g1Proj) DoubleStep(evaluations *lineEvaluation) { +func (p *g1Proj) doubleStep(evaluations *lineEvaluation) { // get some Element from our pool var t1, A, B, C, D, E, EE, F, G, H, I, J, K fp.Element @@ -341,9 +341,9 @@ func (p *g1Proj) 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 *g1Proj) AddMixedStep(evaluations *lineEvaluation, a *G1Affine) { +func (p *g1Proj) addMixedStep(evaluations *lineEvaluation, a *G1Affine) { // get some Element from our pool var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fp.Element diff --git a/ecc/bw6-761/pairing.go b/ecc/bw6-761/pairing.go index 4e5dcfa8d..f2b151b92 100644 --- a/ecc/bw6-761/pairing.go +++ b/ecc/bw6-761/pairing.go @@ -1,4 +1,3 @@ -// Copyright 2020 ConsenSys AG // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -190,13 +189,13 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // l_{p0,p1}(q) pProj01[k].Set(&pProj1[k]) - pProj01[k].AddMixedStep(&l01[k], &p0[k]) + pProj01[k].addMixedStep(&l01[k], &p0[k]) l01[k].r1.Mul(&l01[k].r1, &q[k].X) l01[k].r0.Mul(&l01[k].r0, &q[k].Y) // l_{p0,-p1}(q) pProj10[k].Neg(&pProj1[k]) - pProj10[k].AddMixedStep(&l10[k], &p0[k]) + pProj10[k].addMixedStep(&l10[k], &p0[k]) l10[k].r1.Mul(&l10[k].r1, &q[k].X) l10[k].r0.Mul(&l10[k].r0, &q[k].Y) } @@ -212,7 +211,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // i = len(loopCounter) - 2 for k := 0; k < n; k++ { - pProj1[k].DoubleStep(&l0) + pProj1[k].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) result.MulBy034(&l0.r0, &l0.r1, &l0.r2) @@ -226,14 +225,14 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { j = loopCounter1[i]*3 + loopCounter0[i] for k := 0; k < n; k++ { - pProj1[k].DoubleStep(&l0) + pProj1[k].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) switch j { case -4: tmp.Neg(&p01[k]) - pProj1[k].AddMixedStep(&l, &tmp) + pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) @@ -241,13 +240,13 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { Mul(&result, &ss) case -3: tmp.Neg(&p1[k]) - pProj1[k].AddMixedStep(&l, &tmp) + pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) result.Mul(&result, &ss) case -2: - pProj1[k].AddMixedStep(&l, &p10[k]) + pProj1[k].addMixedStep(&l, &p10[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) @@ -255,7 +254,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { Mul(&result, &ss) case -1: tmp.Neg(&p0[k]) - pProj1[k].AddMixedStep(&l, &tmp) + pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) @@ -263,27 +262,27 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { case 0: result.MulBy034(&l0.r0, &l0.r1, &l0.r2) case 1: - pProj1[k].AddMixedStep(&l, &p0[k]) + pProj1[k].addMixedStep(&l, &p0[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) result.Mul(&result, &ss) case 2: tmp.Neg(&p10[k]) - pProj1[k].AddMixedStep(&l, &tmp) + pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) result.MulBy034(&l0.r0, &l0.r1, &l0.r2). Mul(&result, &ss) case 3: - pProj1[k].AddMixedStep(&l, &p1[k]) + pProj1[k].addMixedStep(&l, &p1[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) result.Mul(&result, &ss) case 4: - pProj1[k].AddMixedStep(&l, &p01[k]) + pProj1[k].addMixedStep(&l, &p01[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) @@ -298,9 +297,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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 *g1Proj) DoubleStep(evaluations *lineEvaluation) { +func (p *g1Proj) doubleStep(evaluations *lineEvaluation) { // get some Element from our pool var t1, A, B, C, D, E, EE, F, G, H, I, J, K fp.Element @@ -342,9 +341,9 @@ func (p *g1Proj) 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 *g1Proj) AddMixedStep(evaluations *lineEvaluation, a *G1Affine) { +func (p *g1Proj) addMixedStep(evaluations *lineEvaluation, a *G1Affine) { // get some Element from our pool var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fp.Element From acf0902f3576874da873e911f6e44ad69c5bfe48 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 13:08:09 +0000 Subject: [PATCH 02/18] perf(pairings): isolate last iteration to avoid a double/add --- ecc/bls12-377/pairing.go | 38 +++++++++++++++++++++++++++++++++++++- ecc/bls12-378/pairing.go | 40 +++++++++++++++++++++++++++++++++++++++- ecc/bls12-381/pairing.go | 37 ++++++++++++++++++++++++++++++++++++- ecc/bls24-315/pairing.go | 38 +++++++++++++++++++++++++++++++++++++- ecc/bls24-317/pairing.go | 37 ++++++++++++++++++++++++++++++++++++- ecc/bn254/pairing.go | 22 +++++++++++++++++++++- ecc/bw6-633/pairing.go | 36 +++++++++++++++++++++++++++++++++++- ecc/bw6-756/pairing.go | 37 ++++++++++++++++++++++++++++++++++++- ecc/bw6-761/pairing.go | 36 +++++++++++++++++++++++++++++++++++- 9 files changed, 312 insertions(+), 9 deletions(-) diff --git a/ecc/bls12-377/pairing.go b/ecc/bls12-377/pairing.go index 409a476e7..87c2d502f 100644 --- a/ecc/bls12-377/pairing.go +++ b/ecc/bls12-377/pairing.go @@ -146,7 +146,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.MulBy034(&l.r0, &l.r1, &l.r2) } - for i := len(loopCounter) - 3; i >= 0; i-- { + for i := len(loopCounter) - 3; i >= 1; i-- { // (∏ᵢfᵢ)² result.Square(&result) @@ -171,6 +171,22 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } + // i = 0 + 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].lineCompute(&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) + } + return result, nil } @@ -251,3 +267,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) +} diff --git a/ecc/bls12-378/pairing.go b/ecc/bls12-378/pairing.go index e36e5b076..98790088a 100644 --- a/ecc/bls12-378/pairing.go +++ b/ecc/bls12-378/pairing.go @@ -145,7 +145,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } - for i := len(loopCounter) - 3; i >= 0; i-- { + for i := len(loopCounter) - 3; i >= 1; i-- { // (∏ᵢfᵢ)² result.Square(&result) @@ -170,6 +170,24 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } + // i = 0 + result.Square(&result) + for k := 0; k < n; k++ { + qProj[k].doubleStep(&l1) + // line eval + l1.r1.MulByElement(&l1.r1, &p[k].X) + l1.r2.MulByElement(&l1.r2, &p[k].Y) + + qProj[k].lineCompute(&l2, &q[k]) + // line eval + l2.r1.MulByElement(&l2.r1, &p[k].X) + l2.r2.MulByElement(&l2.r2, &p[k].Y) + // ℓ × ℓ + lines.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + // (ℓ × ℓ) × result + result.Mul(&result, &lines) + } + return result, nil } @@ -251,3 +269,23 @@ func (p *g2Proj) addMixedStep(l *lineEvaluation, a *G2Affine) { l.r1.Neg(&O) l.r2.Set(&L) } + +// 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(&J) + evaluations.r1.Neg(&O) + evaluations.r2.Set(&L) +} diff --git a/ecc/bls12-381/pairing.go b/ecc/bls12-381/pairing.go index 1549132a2..55aa072da 100644 --- a/ecc/bls12-381/pairing.go +++ b/ecc/bls12-381/pairing.go @@ -153,7 +153,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Mul(&result, &lines) } - for i := len(loopCounter) - 3; i >= 0; i-- { + for i := len(loopCounter) - 3; i >= 1; i-- { // (∏ᵢfᵢ)² result.Square(&result) @@ -178,6 +178,16 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } + // i = 0 + result.Square(&result) + for k := 0; k < n; k++ { + qProj[k].tangentLine(&l1) + // line eval + l1.r1.MulByElement(&l1.r1, &p[k].X) + l1.r2.MulByElement(&l1.r2, &p[k].Y) + result.MulBy014(&l1.r0, &l1.r1, &l1.r2) + } + // negative x₀ result.Conjugate(&result) @@ -262,3 +272,28 @@ func (p *g2Proj) addMixedStep(l *lineEvaluation, a *G2Affine) { l.r1.Neg(&O) l.r2.Set(&L) } + +// tangentCompute computes the tangent through [2]p in Homogenous projective coordinates. +// It does not compute the resulting point [2]p. +func (p *g2Proj) tangentLine(l *lineEvaluation) { + + // get some Element from our pool + var t1, B, C, D, E, H, I, J fptower.E2 + B.Square(&p.y) + C.Square(&p.z) + D.Double(&C). + Add(&D, &C) + E.MulBybTwistCurveCoeff(&D) + H.Add(&p.y, &p.z). + Square(&H) + t1.Add(&B, &C) + H.Sub(&H, &t1) + I.Sub(&E, &B) + J.Square(&p.x) + + // Line evaluation + l.r0.Set(&I) + l.r1.Double(&J). + Add(&l.r1, &J) + l.r2.Neg(&H) +} diff --git a/ecc/bls24-315/pairing.go b/ecc/bls24-315/pairing.go index bb1f15390..147a02195 100644 --- a/ecc/bls24-315/pairing.go +++ b/ecc/bls24-315/pairing.go @@ -156,7 +156,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.MulBy034(&l.r0, &l.r1, &l.r2) } - for i := len(loopCounter) - 3; i >= 0; i-- { + for i := len(loopCounter) - 3; i >= 1; i-- { // (∏ᵢfᵢ)² result.Square(&result) @@ -184,6 +184,22 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } + // i = 0 + result.Square(&result) + for k := 0; k < n; k++ { + qProj[k].doubleStep(&l) + // line evaluation + 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].lineCompute(&l, &qNeg[k]) + // line evaluation + l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1.MulByElement(&l.r1, &p[k].X) + result.MulBy034(&l.r0, &l.r1, &l.r2) + } + result.Conjugate(&result) return result, nil @@ -266,3 +282,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.E4 + 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) +} diff --git a/ecc/bls24-317/pairing.go b/ecc/bls24-317/pairing.go index 8ce66d6ac..ab3a7a4e9 100644 --- a/ecc/bls24-317/pairing.go +++ b/ecc/bls24-317/pairing.go @@ -160,7 +160,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.MulBy014(&l.r0, &l.r1, &l.r2) } - for i := len(loopCounter) - 3; i >= 0; i-- { + for i := len(loopCounter) - 3; i >= 1; i-- { // (∏ᵢfᵢ)² result.Square(&result) @@ -188,6 +188,16 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } + // i = 0 + result.Square(&result) + for k := 0; k < n; k++ { + qProj[k].tangentLine(&l) + // line evaluation + l.r1.MulByElement(&l.r1, &p[k].X) + l.r2.MulByElement(&l.r2, &p[k].Y) + result.MulBy014(&l.r0, &l.r1, &l.r2) + } + return result, nil } @@ -268,3 +278,28 @@ func (p *g2Proj) addMixedStep(evaluations *lineEvaluation, a *G2Affine) { evaluations.r1.Neg(&O) evaluations.r2.Set(&L) } + +// tangentCompute computes the tangent through [2]p in Homogenous projective coordinates. +// It does not compute the resulting point [2]p. +func (p *g2Proj) tangentLine(l *lineEvaluation) { + + // get some Element from our pool + var t1, B, C, D, E, H, I, J fptower.E4 + B.Square(&p.y) + C.Square(&p.z) + D.Double(&C). + Add(&D, &C) + E.MulBybTwistCurveCoeff(&D) + H.Add(&p.y, &p.z). + Square(&H) + t1.Add(&B, &C) + H.Sub(&H, &t1) + I.Sub(&E, &B) + J.Square(&p.x) + + // Line evaluation + l.r0.Set(&I) + l.r1.Double(&J). + Add(&l.r1, &J) + l.r2.Neg(&H) +} diff --git a/ecc/bn254/pairing.go b/ecc/bn254/pairing.go index b297b84fa..1ce75f8e8 100644 --- a/ecc/bn254/pairing.go +++ b/ecc/bn254/pairing.go @@ -203,7 +203,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { l0.r0.MulByElement(&l0.r0, &p[k].Y) l0.r1.MulByElement(&l0.r1, &p[k].X) - qProj[k].addMixedStep(&l, &Q2) + qProj[k].lineCompute(&l, &Q2) l.r0.MulByElement(&l.r0, &p[k].Y) l.r1.MulByElement(&l.r1, &p[k].X) tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) @@ -290,3 +290,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) +} diff --git a/ecc/bw6-633/pairing.go b/ecc/bw6-633/pairing.go index d193ae1dd..8ba93b14c 100644 --- a/ecc/bw6-633/pairing.go +++ b/ecc/bw6-633/pairing.go @@ -243,7 +243,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var tmp G1Affine - for i := len(loopCounter0) - 3; i >= 0; i-- { + for i := len(loopCounter0) - 3; i >= 1; i-- { result.Square(&result) j = loopCounter0[i]*3 + loopCounter1[i] @@ -318,6 +318,20 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } + // i = 0 + result.Square(&result) + for k := 0; k < n; k++ { + pProj0[k].doubleStep(&l0) + l0.r1.Mul(&l0.r1, &q[k].X) + l0.r0.Mul(&l0.r0, &q[k].Y) + + pProj0[k].lineCompute(&l, &p0[k]) + l.r1.Mul(&l.r1, &q[k].X) + l.r0.Mul(&l.r0, &q[k].Y) + ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.Mul(&result, &ss) + } + return result, nil } @@ -402,3 +416,23 @@ func (p *g1Proj) addMixedStep(evaluations *lineEvaluation, a *G1Affine) { 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 *g1Proj) lineCompute(evaluations *lineEvaluation, a *G1Affine) { + + // get some Element from our pool + var Y2Z1, X2Z1, O, L, t2, J fp.Element + 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) +} diff --git a/ecc/bw6-756/pairing.go b/ecc/bw6-756/pairing.go index e2dc002a6..06be02c92 100644 --- a/ecc/bw6-756/pairing.go +++ b/ecc/bw6-756/pairing.go @@ -220,7 +220,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var tmp G1Affine - for i := len(loopCounter0) - 3; i >= 0; i-- { + for i := len(loopCounter0) - 3; i >= 1; i-- { // (∏ᵢfᵢ)² result.Square(&result) @@ -296,6 +296,21 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } + // i = 0 + result.Square(&result) + for k := 0; k < n; k++ { + pProj1[k].doubleStep(&l0) + l0.r1.Mul(&l0.r1, &q[k].X) + l0.r0.Mul(&l0.r0, &q[k].Y) + + tmp.Neg(&p1[k]) + pProj1[k].lineCompute(&l, &tmp) + l.r1.Mul(&l.r1, &q[k].X) + l.r0.Mul(&l.r0, &q[k].Y) + ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.Mul(&result, &ss) + } + return result, nil } @@ -377,3 +392,23 @@ func (p *g1Proj) addMixedStep(evaluations *lineEvaluation, a *G1Affine) { 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 *g1Proj) lineCompute(evaluations *lineEvaluation, a *G1Affine) { + + // get some Element from our pool + var Y2Z1, X2Z1, O, L, t2, J fp.Element + 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) +} diff --git a/ecc/bw6-761/pairing.go b/ecc/bw6-761/pairing.go index f2b151b92..0d87739a8 100644 --- a/ecc/bw6-761/pairing.go +++ b/ecc/bw6-761/pairing.go @@ -218,7 +218,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var tmp G1Affine - for i := len(loopCounter0) - 3; i >= 0; i-- { + for i := len(loopCounter0) - 3; i >= 1; i-- { // (∏ᵢfᵢ)² result.Square(&result) @@ -294,6 +294,20 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } + // i = 0 + result.Square(&result) + for k := 0; k < n; k++ { + pProj1[k].doubleStep(&l0) + l0.r1.Mul(&l0.r1, &q[k].X) + l0.r0.Mul(&l0.r0, &q[k].Y) + tmp.Neg(&p1[k]) + pProj1[k].lineCompute(&l, &tmp) + l.r1.Mul(&l.r1, &q[k].X) + l.r0.Mul(&l.r0, &q[k].Y) + ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.Mul(&result, &ss) + } + return result, nil } @@ -377,3 +391,23 @@ func (p *g1Proj) addMixedStep(evaluations *lineEvaluation, a *G1Affine) { 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 *g1Proj) lineCompute(evaluations *lineEvaluation, a *G1Affine) { + + // get some Element from our pool + var Y2Z1, X2Z1, O, L, t2, J fp.Element + 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) +} From 4cbf9757a9056547e8e7ea58b97fee11502350ad Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 13:29:32 +0000 Subject: [PATCH 03/18] perf(bn254): use Fuentes et al. instead of Duquesne-Ghammam hard part --- ecc/bn254/pairing.go | 55 +++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/ecc/bn254/pairing.go b/ecc/bn254/pairing.go index 1ce75f8e8..2d3b81336 100644 --- a/ecc/bn254/pairing.go +++ b/ecc/bn254/pairing.go @@ -68,52 +68,45 @@ func FinalExponentiation(z *GT, _z ...*GT) GT { result.Mul(&result, e) } - var t [4]GT + var t [5]GT // Easy part // (p⁶-1)(p²+1) t[0].Conjugate(&result) result.Inverse(&result) t[0].Mul(&t[0], &result) - result.FrobeniusSquare(&t[0]). - Mul(&result, &t[0]) + result.FrobeniusSquare(&t[0]).Mul(&result, &t[0]) - // Hard part (up to permutation) - // 2x₀(6x₀²+3x₀+1)(p⁴-p²+1)/r + // Hard part (up to permutation) + // 2x₀(6x₀²+3x₀+1)(p⁴-p²+1)/r // Duquesne and Ghammam // https://eprint.iacr.org/2015/192.pdf - // Fuentes et al. variant (alg. 10) + // Fuentes et al. (alg. 6) t[0].Expt(&result). Conjugate(&t[0]) t[0].CyclotomicSquare(&t[0]) - t[2].Expt(&t[0]). - Conjugate(&t[2]) - t[1].CyclotomicSquare(&t[2]) - t[2].Mul(&t[2], &t[1]) - t[2].Mul(&t[2], &result) - t[1].Expt(&t[2]). - CyclotomicSquare(&t[1]). - Mul(&t[1], &t[2]). - Conjugate(&t[1]) - t[3].Conjugate(&t[1]) t[1].CyclotomicSquare(&t[0]) - t[1].Mul(&t[1], &result) - t[1].Conjugate(&t[1]) - t[1].Mul(&t[1], &t[3]) - t[0].Mul(&t[0], &t[1]) - t[2].Mul(&t[2], &t[1]) - t[3].FrobeniusSquare(&t[1]) + t[1].Mul(&t[0], &t[1]) + t[2].Expt(&t[1]) + t[2].Conjugate(&t[2]) + t[3].Conjugate(&t[1]) + t[1].Mul(&t[2], &t[3]) + t[3].CyclotomicSquare(&t[2]) + t[4].Expt(&t[3]) + t[4].Mul(&t[1], &t[4]) + t[3].Mul(&t[0], &t[4]) + t[0].Mul(&t[2], &t[4]) + t[0].Mul(&result, &t[0]) + t[2].Frobenius(&t[3]) + t[0].Mul(&t[2], &t[0]) + t[2].FrobeniusSquare(&t[4]) + t[0].Mul(&t[2], &t[0]) + t[2].Conjugate(&result) t[2].Mul(&t[2], &t[3]) - t[3].Conjugate(&result) - t[3].Mul(&t[3], &t[0]) - t[1].FrobeniusCube(&t[3]) - t[2].Mul(&t[2], &t[1]) - t[1].Frobenius(&t[0]) - t[1].Mul(&t[1], &t[2]) - - result.Set(&t[1]) + t[2].FrobeniusCube(&t[2]) + t[0].Mul(&t[2], &t[0]) - return result + return t[0] } // MillerLoop computes the multi-Miller loop From f4554f051c55f8ab29a95caa75de11a5aa786841 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 16:16:28 +0000 Subject: [PATCH 04/18] perf(pairings): isolate first iteration to avoid a MulByLine --- ecc/bls12-377/pairing.go | 10 +++++++--- ecc/bls12-378/pairing.go | 20 +++++++++++++++++--- ecc/bls12-381/pairing.go | 17 ++++++++++++++--- ecc/bls24-315/pairing.go | 11 +++++++---- ecc/bls24-317/pairing.go | 10 +++++++--- ecc/bn254/pairing.go | 19 +++++++++++++++++-- ecc/bw6-633/pairing.go | 17 +++++++++++++++-- ecc/bw6-756/pairing.go | 17 +++++++++++++++-- ecc/bw6-761/pairing.go | 17 +++++++++++++++-- 9 files changed, 114 insertions(+), 24 deletions(-) diff --git a/ecc/bls12-377/pairing.go b/ecc/bls12-377/pairing.go index 87c2d502f..500b4fed3 100644 --- a/ecc/bls12-377/pairing.go +++ b/ecc/bls12-377/pairing.go @@ -133,12 +133,16 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result GT - result.SetOne() - var l lineEvaluation // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { + qProj[0].doubleStep(&l) + // line eval + result.C0.B0.MulByElement(&l.r0, &p[0].Y) + result.C1.B0.MulByElement(&l.r1, &p[0].X) + result.C1.B1.Set(&l.r2) + + for k := 1; k < n; k++ { qProj[k].doubleStep(&l) // line eval l.r0.MulByElement(&l.r0, &p[k].Y) diff --git a/ecc/bls12-378/pairing.go b/ecc/bls12-378/pairing.go index 98790088a..194ed4a17 100644 --- a/ecc/bls12-378/pairing.go +++ b/ecc/bls12-378/pairing.go @@ -132,12 +132,26 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result, lines GT - result.SetOne() - var l1, l2 lineEvaluation // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { + // k = 0 + qProj[0].doubleStep(&l1) + // line eval + result.C0.B0.Set(&l1.r0) + result.C0.B1.MulByElement(&l1.r1, &p[0].X) + result.C1.B1.MulByElement(&l1.r2, &p[0].Y) + + if n >= 2 { + // k = 1 + qProj[1].doubleStep(&l1) + // line eval + l1.r1.MulByElement(&l1.r1, &p[1].X) + l1.r2.MulByElement(&l1.r2, &p[1].Y) + result.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) + } + + for k := 2; k < n; k++ { qProj[k].doubleStep(&l1) // line eval l1.r1.MulByElement(&l1.r1, &p[k].X) diff --git a/ecc/bls12-381/pairing.go b/ecc/bls12-381/pairing.go index 55aa072da..df2c2c72d 100644 --- a/ecc/bls12-381/pairing.go +++ b/ecc/bls12-381/pairing.go @@ -132,12 +132,23 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result, lines GT - result.SetOne() - var l1, l2 lineEvaluation // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { + // k = 0 + qProj[0].doubleStep(&l1) + // line eval + result.C0.B0.Set(&l1.r0) + result.C0.B1.MulByElement(&l1.r1, &p[0].X) + result.C1.B1.MulByElement(&l1.r2, &p[0].Y) + + qProj[0].addMixedStep(&l2, &q[0]) + // line eval + l2.r1.MulByElement(&l2.r1, &p[0].X) + l2.r2.MulByElement(&l2.r2, &p[0].Y) + result.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) + + for k := 1; k < n; k++ { qProj[k].doubleStep(&l1) // line eval l1.r1.MulByElement(&l1.r1, &p[k].X) diff --git a/ecc/bls24-315/pairing.go b/ecc/bls24-315/pairing.go index 147a02195..289ca57c4 100644 --- a/ecc/bls24-315/pairing.go +++ b/ecc/bls24-315/pairing.go @@ -143,12 +143,15 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result GT - result.SetOne() - var l lineEvaluation - // len(loopCounter) - 2 - for k := 0; k < n; k++ { + qProj[0].doubleStep(&l) + // line evaluation + result.D0.C0.MulByElement(&l.r0, &p[0].Y) + result.D1.C0.MulByElement(&l.r1, &p[0].X) + result.D1.C1.Set(&l.r2) + + for k := 1; k < n; k++ { qProj[k].doubleStep(&l) // line evaluation l.r0.MulByElement(&l.r0, &p[k].Y) diff --git a/ecc/bls24-317/pairing.go b/ecc/bls24-317/pairing.go index ab3a7a4e9..01c003d0f 100644 --- a/ecc/bls24-317/pairing.go +++ b/ecc/bls24-317/pairing.go @@ -147,12 +147,16 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result GT - result.SetOne() - var l lineEvaluation // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { + qProj[0].doubleStep(&l) + // line evaluation + result.D0.C0.Set(&l.r0) + result.D0.C1.MulByElement(&l.r1, &p[0].X) + result.D1.C1.MulByElement(&l.r2, &p[0].Y) + + for k := 1; k < n; k++ { qProj[k].doubleStep(&l) // line evaluation l.r1.MulByElement(&l.r1, &p[k].X) diff --git a/ecc/bn254/pairing.go b/ecc/bn254/pairing.go index 2d3b81336..c686bf0e5 100644 --- a/ecc/bn254/pairing.go +++ b/ecc/bn254/pairing.go @@ -140,10 +140,25 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { var l, l0 lineEvaluation var tmp, result GT - result.SetOne() // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { + // k = 0 + qProj[0].doubleStep(&l) + // line evaluation + result.C0.B0.MulByElement(&l.r0, &p[0].Y) + result.C1.B0.MulByElement(&l.r1, &p[0].X) + result.C1.B1.Set(&l.r2) + + if n >= 2 { + // k = 1 + qProj[1].doubleStep(&l) + // line evaluation + l.r0.MulByElement(&l.r0, &p[1].Y) + l.r1.MulByElement(&l.r1, &p[1].X) + result.Mul034by034(&l.r0, &l.r1, &l.r2, &result.C0.B0, &result.C1.B0, &result.C1.B1) + } + + for k := 2; k < n; k++ { qProj[k].doubleStep(&l) // line evaluation l.r0.MulByElement(&l.r0, &p[k].Y) diff --git a/ecc/bw6-633/pairing.go b/ecc/bw6-633/pairing.go index 8ba93b14c..6f1170597 100644 --- a/ecc/bw6-633/pairing.go +++ b/ecc/bw6-633/pairing.go @@ -229,13 +229,26 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // f_{a0+\lambda*a1,P}(Q) var result, ss GT - result.SetOne() var l, l0 lineEvaluation var j int8 // i = len(loopCounter)-2 - for k := 0; k < n; k++ { + // k = 0 + pProj0[0].doubleStep(&l0) + result.B1.A0.Mul(&l0.r1, &q[0].X) + result.B0.A0.Mul(&l0.r0, &q[0].Y) + result.B1.A1.Set(&l0.r2) + + // k = 1 + if n >= 2 { + pProj0[1].doubleStep(&l0) + l0.r1.Mul(&l0.r1, &q[1].X) + l0.r0.Mul(&l0.r0, &q[1].Y) + result.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) + } + + for k := 2; k < n; k++ { pProj0[k].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) diff --git a/ecc/bw6-756/pairing.go b/ecc/bw6-756/pairing.go index 06be02c92..5972ad861 100644 --- a/ecc/bw6-756/pairing.go +++ b/ecc/bw6-756/pairing.go @@ -206,13 +206,26 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // f_{a0+lambda*a1,P}(Q) var result, ss GT - result.SetOne() var l, l0 lineEvaluation var j int8 // i = len(loopCounter) - 2 - for k := 0; k < n; k++ { + // k = 0 + pProj1[0].doubleStep(&l0) + result.B1.A0.Mul(&l0.r1, &q[0].X) + result.B0.A0.Mul(&l0.r0, &q[0].Y) + result.B1.A1.Set(&l0.r2) + + // k = 1 + if n >= 2 { + pProj1[1].doubleStep(&l0) + l0.r1.Mul(&l0.r1, &q[1].X) + l0.r0.Mul(&l0.r0, &q[1].Y) + result.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) + } + + for k := 2; k < n; k++ { pProj1[k].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) diff --git a/ecc/bw6-761/pairing.go b/ecc/bw6-761/pairing.go index 0d87739a8..0c5be6ce2 100644 --- a/ecc/bw6-761/pairing.go +++ b/ecc/bw6-761/pairing.go @@ -204,13 +204,26 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // f_{a0+\lambda*a1,P}(Q) var result, ss GT - result.SetOne() var l, l0 lineEvaluation var j int8 // i = len(loopCounter) - 2 - for k := 0; k < n; k++ { + // k = 0 + pProj1[0].doubleStep(&l0) + result.B1.A0.Mul(&l0.r1, &q[0].X) + result.B0.A0.Mul(&l0.r0, &q[0].Y) + result.B1.A1.Set(&l0.r2) + + // k = 1 + if n >= 2 { + pProj1[1].doubleStep(&l0) + l0.r1.Mul(&l0.r1, &q[1].X) + l0.r0.Mul(&l0.r0, &q[1].Y) + result.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) + } + + for k := 2; k < n; k++ { pProj1[k].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) From 0bed7524a9e55040b9f4c6de16ceeba567217873 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 17:52:44 +0000 Subject: [PATCH 05/18] perf(pairing/bn254): use somwewhat-sparse/spare multiplication in ML --- ecc/bn254/internal/fptower/e12_pairing.go | 35 +++++++--- ecc/bn254/pairing.go | 78 ++++++++++++----------- 2 files changed, 68 insertions(+), 45 deletions(-) diff --git a/ecc/bn254/internal/fptower/e12_pairing.go b/ecc/bn254/internal/fptower/e12_pairing.go index a4abaf510..5f1b97344 100644 --- a/ecc/bn254/internal/fptower/e12_pairing.go +++ b/ecc/bn254/internal/fptower/e12_pairing.go @@ -153,8 +153,8 @@ func (z *E12) MulBy034(c0, c3, c4 *E2) *E12 { } // Mul034By034 multiplication of sparse element (c0,0,0,c3,c4,0) by sparse element (d0,0,0,d3,d4,0) -func (z *E12) Mul034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { - var tmp, x0, x3, x4, x04, x03, x34 E2 +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) @@ -174,13 +174,30 @@ func (z *E12) Mul034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { Sub(&x34, &x3). Sub(&x34, &x4) - z.C0.B0.MulByNonResidue(&x4). - Add(&z.C0.B0, &x0) - z.C0.B1.Set(&x3) - z.C0.B2.Set(&x34) - z.C1.B0.Set(&x03) - z.C1.B1.Set(&x04) - z.C1.B2.SetZero() + 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 } diff --git a/ecc/bn254/pairing.go b/ecc/bn254/pairing.go index c686bf0e5..2d019fa6c 100644 --- a/ecc/bn254/pairing.go +++ b/ecc/bn254/pairing.go @@ -138,32 +138,38 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { qNeg[k].Neg(&q[k]) } - var l, l0 lineEvaluation - var tmp, result GT + var result GT + var l2, l1 lineEvaluation + var prodLines [5]E2 // i == len(loopCounter) - 2 // k = 0 - qProj[0].doubleStep(&l) + qProj[0].doubleStep(&l1) // line evaluation - result.C0.B0.MulByElement(&l.r0, &p[0].Y) - result.C1.B0.MulByElement(&l.r1, &p[0].X) - result.C1.B1.Set(&l.r2) + result.C0.B0.MulByElement(&l1.r0, &p[0].Y) + result.C1.B0.MulByElement(&l1.r1, &p[0].X) + result.C1.B1.Set(&l1.r2) if n >= 2 { // k = 1 - qProj[1].doubleStep(&l) + qProj[1].doubleStep(&l1) // line evaluation - l.r0.MulByElement(&l.r0, &p[1].Y) - l.r1.MulByElement(&l.r1, &p[1].X) - result.Mul034by034(&l.r0, &l.r1, &l.r2, &result.C0.B0, &result.C1.B0, &result.C1.B1) + l1.r0.MulByElement(&l1.r0, &p[1].Y) + l1.r1.MulByElement(&l1.r1, &p[1].X) + 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] } for k := 2; k < n; k++ { - qProj[k].doubleStep(&l) + qProj[k].doubleStep(&l1) // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + result.MulBy034(&l1.r0, &l1.r1, &l1.r2) } for i := len(loopCounter) - 3; i >= 0; i-- { @@ -171,28 +177,28 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Square(&result) for k := 0; k < n; k++ { - qProj[k].doubleStep(&l) + qProj[k].doubleStep(&l1) // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) if loopCounter[i] == 1 { - qProj[k].addMixedStep(&l0, &q[k]) + qProj[k].addMixedStep(&l2, &q[k]) // line evaluation - l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &tmp) + 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) + result.MulBy01234(&prodLines) } else if loopCounter[i] == -1 { - qProj[k].addMixedStep(&l0, &qNeg[k]) + qProj[k].addMixedStep(&l2, &qNeg[k]) // line evaluation - l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &tmp) + 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) + result.MulBy01234(&prodLines) } else { - result.MulBy034(&l.r0, &l.r1, &l.r2) + result.MulBy034(&l1.r0, &l1.r1, &l1.r2) } } } @@ -207,15 +213,15 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { Q2.X.MulByNonResidue2Power2(&q[k].X) Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - qProj[k].addMixedStep(&l0, &Q1) - l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1.MulByElement(&l0.r1, &p[k].X) + qProj[k].addMixedStep(&l2, &Q1) + l2.r0.MulByElement(&l2.r0, &p[k].Y) + l2.r1.MulByElement(&l2.r1, &p[k].X) - qProj[k].lineCompute(&l, &Q2) - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &tmp) + qProj[k].lineCompute(&l1, &Q2) + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + prodLines = *fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + result.MulBy01234(&prodLines) } return result, nil From 56d27bd7563a77923e5f608d852798de5f9d6ed5 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 18:17:36 +0000 Subject: [PATCH 06/18] perf(pairing/bls12-381): use somwewhat-sparse/spare multiplication in ML --- ecc/bls12-381/internal/fptower/e12_pairing.go | 35 ++++++++++++++----- ecc/bls12-381/internal/fptower/e6.go | 28 +++++++++++++++ ecc/bls12-381/pairing.go | 18 ++++++---- ecc/bn254/internal/fptower/e12_pairing.go | 4 +-- ecc/bn254/pairing.go | 8 ++--- 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/ecc/bls12-381/internal/fptower/e12_pairing.go b/ecc/bls12-381/internal/fptower/e12_pairing.go index 4aaf83074..880520f81 100644 --- a/ecc/bls12-381/internal/fptower/e12_pairing.go +++ b/ecc/bls12-381/internal/fptower/e12_pairing.go @@ -67,8 +67,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) @@ -88,13 +88,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 } diff --git a/ecc/bls12-381/internal/fptower/e6.go b/ecc/bls12-381/internal/fptower/e6.go index 8ae7216ec..698e6ec15 100644 --- a/ecc/bls12-381/internal/fptower/e6.go +++ b/ecc/bls12-381/internal/fptower/e6.go @@ -180,6 +180,34 @@ func (z *E6) MulBy1(c1 *E2) *E6 { return z } +// MulBy12 multiplication by sparse element (0,b1,b2) +func (x *E6) MulBy12(b1, b2 *E2) *E6 { + var t1, t2, c0, tmp, c1, c2 E2 + t1.Mul(&x.B1, b1) + t2.Mul(&x.B2, b2) + c0.Add(&x.B1, &x.B2) + tmp.Add(b1, b2) + c0.Mul(&c0, &tmp) + c0.Sub(&c0, &t1) + c0.Sub(&c0, &t2) + c0.MulByNonResidue(&c0) + c1.Add(&x.B0, &x.B1) + c1.Mul(&c1, b1) + c1.Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + tmp.Add(&x.B0, &x.B2) + c2.Mul(b2, &tmp) + c2.Sub(&c2, &t2) + c2.Add(&c2, &t1) + + x.B0 = c0 + x.B1 = c1 + x.B2 = c2 + + return x +} + // Mul sets z to the E6 product of x,y, returns z func (z *E6) Mul(x, y *E6) *E6 { // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf diff --git a/ecc/bls12-381/pairing.go b/ecc/bls12-381/pairing.go index df2c2c72d..257dc5b1d 100644 --- a/ecc/bls12-381/pairing.go +++ b/ecc/bls12-381/pairing.go @@ -131,8 +131,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { qProj[k].FromAffine(&q[k]) } - var result, lines GT + var result GT var l1, l2 lineEvaluation + var prodLines [5]E2 // i == len(loopCounter) - 2 // k = 0 @@ -146,7 +147,12 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // line eval l2.r1.MulByElement(&l2.r1, &p[0].X) l2.r2.MulByElement(&l2.r2, &p[0].Y) - result.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) + result.C0.B0 = prodLines[0] + result.C0.B1 = prodLines[1] + result.C0.B2 = prodLines[2] + result.C1.B1 = prodLines[3] + result.C1.B2 = prodLines[4] for k := 1; k < n; k++ { qProj[k].doubleStep(&l1) @@ -159,9 +165,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) // ℓ × ℓ - lines.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &l1.r0, &l1.r1, &l1.r2) // (ℓ × ℓ) × result - result.Mul(&result, &lines) + result.MulBy01245(&prodLines) } for i := len(loopCounter) - 3; i >= 1; i-- { @@ -182,9 +188,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) // ℓ × ℓ - lines.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &l1.r0, &l1.r1, &l1.r2) // (ℓ × ℓ) × result - result.Mul(&result, &lines) + result.MulBy01245(&prodLines) } } } diff --git a/ecc/bn254/internal/fptower/e12_pairing.go b/ecc/bn254/internal/fptower/e12_pairing.go index 5f1b97344..78c94d2f6 100644 --- a/ecc/bn254/internal/fptower/e12_pairing.go +++ b/ecc/bn254/internal/fptower/e12_pairing.go @@ -153,7 +153,7 @@ func (z *E12) MulBy034(c0, c3, c4 *E2) *E12 { } // 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 { +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) @@ -177,7 +177,7 @@ func Mul034By034(d0, d3, d4, c0, c3, c4 *E2) *[5]E2 { z00.MulByNonResidue(&x4). Add(&z00, &x0) - return &[5]E2{z00, x3, x34, x03, x04} + 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) diff --git a/ecc/bn254/pairing.go b/ecc/bn254/pairing.go index 2d019fa6c..a3bdfcb91 100644 --- a/ecc/bn254/pairing.go +++ b/ecc/bn254/pairing.go @@ -156,7 +156,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // line evaluation l1.r0.MulByElement(&l1.r0, &p[1].Y) l1.r1.MulByElement(&l1.r1, &p[1].X) - prodLines = *fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &result.C0.B0, &result.C1.B0, &result.C1.B1) + 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] @@ -187,7 +187,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // line evaluation 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) + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) result.MulBy01234(&prodLines) } else if loopCounter[i] == -1 { @@ -195,7 +195,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // line evaluation 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) + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) result.MulBy01234(&prodLines) } else { result.MulBy034(&l1.r0, &l1.r1, &l1.r2) @@ -220,7 +220,7 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { qProj[k].lineCompute(&l1, &Q2) l1.r0.MulByElement(&l1.r0, &p[k].Y) l1.r1.MulByElement(&l1.r1, &p[k].X) - prodLines = *fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) result.MulBy01234(&prodLines) } From 238ef2c22b1d25bd2933584eaa6e4d57f079bb72 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 18:29:58 +0000 Subject: [PATCH 07/18] perf(pairing/bls12-377): use somwewhat-sparse/spare multiplication in ML --- ecc/bls12-377/internal/fptower/e12_pairing.go | 50 ++++++++++++++ ecc/bls12-377/pairing.go | 65 ++++++++++--------- 2 files changed, 83 insertions(+), 32 deletions(-) diff --git a/ecc/bls12-377/internal/fptower/e12_pairing.go b/ecc/bls12-377/internal/fptower/e12_pairing.go index 86a918d84..6888dfc4f 100644 --- a/ecc/bls12-377/internal/fptower/e12_pairing.go +++ b/ecc/bls12-377/internal/fptower/e12_pairing.go @@ -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 +} diff --git a/ecc/bls12-377/pairing.go b/ecc/bls12-377/pairing.go index 500b4fed3..1af2473e8 100644 --- a/ecc/bls12-377/pairing.go +++ b/ecc/bls12-377/pairing.go @@ -133,21 +133,22 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result GT - var l lineEvaluation + var l1, l2 lineEvaluation + var prodLines [5]E2 // i == len(loopCounter) - 2 - qProj[0].doubleStep(&l) + qProj[0].doubleStep(&l1) // line eval - result.C0.B0.MulByElement(&l.r0, &p[0].Y) - result.C1.B0.MulByElement(&l.r1, &p[0].X) - result.C1.B1.Set(&l.r2) + result.C0.B0.MulByElement(&l1.r0, &p[0].Y) + result.C1.B0.MulByElement(&l1.r1, &p[0].X) + result.C1.B1.Set(&l1.r2) for k := 1; k < n; k++ { - qProj[k].doubleStep(&l) + qProj[k].doubleStep(&l1) // 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) + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + result.MulBy034(&l1.r0, &l1.r1, &l1.r2) } for i := len(loopCounter) - 3; i >= 1; i-- { @@ -155,40 +156,40 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Square(&result) for k := 0; k < n; k++ { - qProj[k].doubleStep(&l) + qProj[k].doubleStep(&l1) // 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) + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + + if loopCounter[i] == 0 { + result.MulBy034(&l1.r0, &l1.r1, &l1.r2) + } else { + qProj[k].addMixedStep(&l2, &q[k]) + // line eval + 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) + 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 result.Square(&result) for k := 0; k < n; k++ { - qProj[k].doubleStep(&l) + qProj[k].doubleStep(&l1) // 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) + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) - qProj[k].lineCompute(&l, &q[k]) + qProj[k].lineCompute(&l2, &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) + 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) + result.MulBy01234(&prodLines) } return result, nil From 6796ddd72f9a1a2ae90d1f5e13eeb63e10f8fc51 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 18:37:05 +0000 Subject: [PATCH 08/18] perf(bn254/pairing): isolate second iteration to avoid a point double --- ecc/bn254/pairing.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/ecc/bn254/pairing.go b/ecc/bn254/pairing.go index a3bdfcb91..319d4ec3e 100644 --- a/ecc/bn254/pairing.go +++ b/ecc/bn254/pairing.go @@ -172,7 +172,23 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.MulBy034(&l1.r0, &l1.r1, &l1.r2) } - for i := len(loopCounter) - 3; i >= 0; i-- { + // i = len(loopCounter) - 3 + result.Square(&result) + for k := 0; k < n; k++ { + qProj[k].lineCompute(&l2, &qNeg[k]) + // line evaluation + l2.r0.MulByElement(&l2.r0, &p[k].Y) + l2.r1.MulByElement(&l2.r1, &p[k].X) + + qProj[k].addMixedStep(&l1, &q[k]) + // line evaluation + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + result.MulBy01234(&prodLines) + } + + for i := len(loopCounter) - 4; i >= 0; i-- { // (∏ᵢfᵢ)² result.Square(&result) From 2f0d46ac839fc4ea4b3ccc7881f1029e2a9c9647 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 18:38:32 +0000 Subject: [PATCH 09/18] perf(bls12-377/pairing): isolate first iteration to avoid a MulByLine --- ecc/bls12-377/pairing.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ecc/bls12-377/pairing.go b/ecc/bls12-377/pairing.go index 1af2473e8..d7cde179e 100644 --- a/ecc/bls12-377/pairing.go +++ b/ecc/bls12-377/pairing.go @@ -143,7 +143,21 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.C1.B0.MulByElement(&l1.r1, &p[0].X) result.C1.B1.Set(&l1.r2) - for k := 1; k < n; k++ { + if n >= 2 { + // k = 1 + qProj[1].doubleStep(&l1) + // line evaluation + l1.r0.MulByElement(&l1.r0, &p[1].Y) + l1.r1.MulByElement(&l1.r1, &p[1].X) + 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] + } + + for k := 2; k < n; k++ { qProj[k].doubleStep(&l1) // line eval l1.r0.MulByElement(&l1.r0, &p[k].Y) From 63938b9cea655da922ee4949ac847262ef6adaea Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 19:25:42 +0000 Subject: [PATCH 10/18] perf(pairing/bls12-378): use somwewhat-sparse/spare multiplication in ML --- ecc/bls12-378/internal/fptower/e12_pairing.go | 35 ++++++++++++++----- ecc/bls12-378/internal/fptower/e6.go | 28 +++++++++++++++ ecc/bls12-378/pairing.go | 18 ++++++---- 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/ecc/bls12-378/internal/fptower/e12_pairing.go b/ecc/bls12-378/internal/fptower/e12_pairing.go index 49d9119ad..64cde6c4f 100644 --- a/ecc/bls12-378/internal/fptower/e12_pairing.go +++ b/ecc/bls12-378/internal/fptower/e12_pairing.go @@ -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) @@ -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 } diff --git a/ecc/bls12-378/internal/fptower/e6.go b/ecc/bls12-378/internal/fptower/e6.go index 8ae7216ec..d4f80de95 100644 --- a/ecc/bls12-378/internal/fptower/e6.go +++ b/ecc/bls12-378/internal/fptower/e6.go @@ -126,6 +126,34 @@ func (z *E6) MulByE2(x *E6, y *E2) *E6 { return z } +// MulBy12 multiplication by sparse element (0,b1,b2) +func (x *E6) MulBy12(b1, b2 *E2) *E6 { + var t1, t2, c0, tmp, c1, c2 E2 + t1.Mul(&x.B1, b1) + t2.Mul(&x.B2, b2) + c0.Add(&x.B1, &x.B2) + tmp.Add(b1, b2) + c0.Mul(&c0, &tmp) + c0.Sub(&c0, &t1) + c0.Sub(&c0, &t2) + c0.MulByNonResidue(&c0) + c1.Add(&x.B0, &x.B1) + c1.Mul(&c1, b1) + c1.Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + tmp.Add(&x.B0, &x.B2) + c2.Mul(b2, &tmp) + c2.Sub(&c2, &t2) + c2.Add(&c2, &t1) + + x.B0 = c0 + x.B1 = c1 + x.B2 = c2 + + return x +} + // MulBy01 multiplication by sparse element (c0,c1,0) func (z *E6) MulBy01(c0, c1 *E2) *E6 { diff --git a/ecc/bls12-378/pairing.go b/ecc/bls12-378/pairing.go index 194ed4a17..fb964a684 100644 --- a/ecc/bls12-378/pairing.go +++ b/ecc/bls12-378/pairing.go @@ -131,8 +131,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { qProj[k].FromAffine(&q[k]) } - var result, lines GT + var result GT var l1, l2 lineEvaluation + var prodLines [5]E2 // i == len(loopCounter) - 2 // k = 0 @@ -148,7 +149,12 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // line eval l1.r1.MulByElement(&l1.r1, &p[1].X) l1.r2.MulByElement(&l1.r2, &p[1].Y) - result.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) + prodLines = fptower.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) + result.C0.B0 = prodLines[0] + result.C0.B1 = prodLines[1] + result.C0.B2 = prodLines[2] + result.C1.B1 = prodLines[3] + result.C1.B2 = prodLines[4] } for k := 2; k < n; k++ { @@ -177,9 +183,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) // ℓ × ℓ - lines.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + prodLines = fptower.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) // (ℓ × ℓ) × result - result.Mul(&result, &lines) + result.MulBy01245(&prodLines) } } } @@ -197,9 +203,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) // ℓ × ℓ - lines.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + prodLines = fptower.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) // (ℓ × ℓ) × result - result.Mul(&result, &lines) + result.MulBy01245(&prodLines) } return result, nil From 6600666e0713ebc5480af21e6f7e9e6868f8665c Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 19:41:23 +0000 Subject: [PATCH 11/18] perf(pairing/bls24-317): use somwewhat-sparse/spare multiplication in ML --- ecc/bls24-317/internal/fptower/e12.go | 28 +++++++ ecc/bls24-317/internal/fptower/e24_pairing.go | 50 ++++++++++++ ecc/bls24-317/pairing.go | 76 ++++++++++++------- 3 files changed, 127 insertions(+), 27 deletions(-) diff --git a/ecc/bls24-317/internal/fptower/e12.go b/ecc/bls24-317/internal/fptower/e12.go index f1f296d74..9f41f03a3 100644 --- a/ecc/bls24-317/internal/fptower/e12.go +++ b/ecc/bls24-317/internal/fptower/e12.go @@ -291,6 +291,34 @@ func (z *E12) Conjugate(x *E12) *E12 { return z } +// MulBy12 multiplication by sparse element (0,b1,b2) +func (x *E12) MulBy12(b1, b2 *E4) *E12 { + var t1, t2, c0, tmp, c1, c2 E4 + t1.Mul(&x.C1, b1) + t2.Mul(&x.C2, b2) + c0.Add(&x.C1, &x.C2) + tmp.Add(b1, b2) + c0.Mul(&c0, &tmp) + c0.Sub(&c0, &t1) + c0.Sub(&c0, &t2) + c0.MulByNonResidue(&c0) + c1.Add(&x.C0, &x.C1) + c1.Mul(&c1, b1) + c1.Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + tmp.Add(&x.C0, &x.C2) + c2.Mul(b2, &tmp) + c2.Sub(&c2, &t2) + c2.Add(&c2, &t1) + + x.C0 = c0 + x.C1 = c1 + x.C2 = c2 + + return x +} + // MulBy01 multiplication by sparse element (c0,c1,0) func (z *E12) MulBy01(c0, c1 *E4) *E12 { diff --git a/ecc/bls24-317/internal/fptower/e24_pairing.go b/ecc/bls24-317/internal/fptower/e24_pairing.go index fb3505eda..4fe79d6cf 100644 --- a/ecc/bls24-317/internal/fptower/e24_pairing.go +++ b/ecc/bls24-317/internal/fptower/e24_pairing.go @@ -98,3 +98,53 @@ func (z *E24) MulBy014(c0, c1, c4 *E4) *E24 { return z } + +// Mul014By014 multiplication of sparse element (c0,c1,0,0,c4,0) by sparse element (d0,d1,0,0,d4,0) +func Mul014By014(d0, d1, d4, c0, c1, c4 *E4) [5]E4 { + var z00, tmp, x0, x1, x4, x04, x01, x14 E4 + x0.Mul(c0, d0) + x1.Mul(c1, d1) + x4.Mul(c4, d4) + tmp.Add(c0, c4) + x04.Add(d0, d4). + Mul(&x04, &tmp). + Sub(&x04, &x0). + Sub(&x04, &x4) + tmp.Add(c0, c1) + x01.Add(d0, d1). + Mul(&x01, &tmp). + Sub(&x01, &x0). + Sub(&x01, &x1) + tmp.Add(c1, c4) + x14.Add(d1, d4). + Mul(&x14, &tmp). + Sub(&x14, &x1). + Sub(&x14, &x4) + + z00.MulByNonResidue(&x4). + Add(&z00, &x0) + + return [5]E4{z00, x01, x1, x04, x14} +} + +// MulBy01245 multiplies z by an E24 sparse element of the form (x0, x1, x2, 0, x4, x5) +func (z *E24) MulBy01245(x *[5]E4) *E24 { + var c1, a, b, c, z0, z1 E12 + c0 := &E12{C0: x[0], C1: x[1], C2: x[2]} + c1.C1 = x[3] + c1.C2 = x[4] + a.Add(&z.D0, &z.D1) + b.Add(c0, &c1) + a.Mul(&a, &b) + b.Mul(&z.D0, c0) + c.Set(&z.D1).MulBy12(&x[3], &x[4]) + z1.Sub(&a, &b) + z1.Sub(&z1, &c) + z0.MulByNonResidue(&c) + z0.Add(&z0, &b) + + z.D0 = z0 + z.D1 = z1 + + return z +} diff --git a/ecc/bls24-317/pairing.go b/ecc/bls24-317/pairing.go index 01c003d0f..fd47b60ad 100644 --- a/ecc/bls24-317/pairing.go +++ b/ecc/bls24-317/pairing.go @@ -147,21 +147,37 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result GT - var l lineEvaluation + var l1, l2 lineEvaluation + var prodLines [5]fptower.E4 // i == len(loopCounter) - 2 - qProj[0].doubleStep(&l) + // k = 0 + qProj[0].doubleStep(&l1) // line evaluation - result.D0.C0.Set(&l.r0) - result.D0.C1.MulByElement(&l.r1, &p[0].X) - result.D1.C1.MulByElement(&l.r2, &p[0].Y) + result.D0.C0.Set(&l1.r0) + result.D0.C1.MulByElement(&l1.r1, &p[0].X) + result.D1.C1.MulByElement(&l1.r2, &p[0].Y) - for k := 1; k < n; k++ { - qProj[k].doubleStep(&l) + if n >= 2 { + // k = 1 + qProj[1].doubleStep(&l1) // line evaluation - l.r1.MulByElement(&l.r1, &p[k].X) - l.r2.MulByElement(&l.r2, &p[k].Y) - result.MulBy014(&l.r0, &l.r1, &l.r2) + l1.r1.MulByElement(&l1.r1, &p[1].X) + l1.r2.MulByElement(&l1.r2, &p[1].Y) + prodLines = fptower.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &result.D0.C0, &result.D0.C1, &result.D1.C1) + result.D0.C0 = prodLines[0] + result.D0.C1 = prodLines[1] + result.D0.C2 = prodLines[2] + result.D1.C1 = prodLines[3] + result.D1.C2 = prodLines[4] + } + + for k := 2; k < n; k++ { + qProj[k].doubleStep(&l1) + // line evaluation + l1.r1.MulByElement(&l1.r1, &p[k].X) + l1.r2.MulByElement(&l1.r2, &p[k].Y) + result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } for i := len(loopCounter) - 3; i >= 1; i-- { @@ -169,25 +185,31 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Square(&result) for k := 0; k < n; k++ { - qProj[k].doubleStep(&l) + qProj[k].doubleStep(&l1) // line evaluation - l.r1.MulByElement(&l.r1, &p[k].X) - l.r2.MulByElement(&l.r2, &p[k].Y) - result.MulBy014(&l.r0, &l.r1, &l.r2) + l1.r1.MulByElement(&l1.r1, &p[k].X) + l1.r2.MulByElement(&l1.r2, &p[k].Y) if loopCounter[i] == 1 { - qProj[k].addMixedStep(&l, &q[k]) + qProj[k].addMixedStep(&l2, &q[k]) // line evaluation - l.r1.MulByElement(&l.r1, &p[k].X) - l.r2.MulByElement(&l.r2, &p[k].Y) - result.MulBy014(&l.r0, &l.r1, &l.r2) - + l2.r1.MulByElement(&l2.r1, &p[k].X) + l2.r2.MulByElement(&l2.r2, &p[k].Y) + // ℓ × ℓ + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &l1.r0, &l1.r1, &l1.r2) + // (ℓ × ℓ) × result + result.MulBy01245(&prodLines) } else if loopCounter[i] == -1 { - qProj[k].addMixedStep(&l, &qNeg[k]) + qProj[k].addMixedStep(&l2, &qNeg[k]) // line evaluation - l.r1.MulByElement(&l.r1, &p[k].X) - l.r2.MulByElement(&l.r2, &p[k].Y) - result.MulBy014(&l.r0, &l.r1, &l.r2) + l2.r1.MulByElement(&l2.r1, &p[k].X) + l2.r2.MulByElement(&l2.r2, &p[k].Y) + // ℓ × ℓ + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &l1.r0, &l1.r1, &l1.r2) + // (ℓ × ℓ) × result + result.MulBy01245(&prodLines) + } else { + result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } } } @@ -195,11 +217,11 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // i = 0 result.Square(&result) for k := 0; k < n; k++ { - qProj[k].tangentLine(&l) + qProj[k].tangentLine(&l1) // line evaluation - l.r1.MulByElement(&l.r1, &p[k].X) - l.r2.MulByElement(&l.r2, &p[k].Y) - result.MulBy014(&l.r0, &l.r1, &l.r2) + l1.r1.MulByElement(&l1.r1, &p[k].X) + l1.r2.MulByElement(&l1.r2, &p[k].Y) + result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } return result, nil From a0181f3cd454c6f5ad384a37b376e1ec18f9cb34 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sat, 25 Mar 2023 11:29:47 +0000 Subject: [PATCH 12/18] perf(pairing/bls24-315): use somwewhat-sparse/spare multiplication in ML --- ecc/bls24-315/internal/fptower/e24_pairing.go | 50 +++++++++++ ecc/bls24-315/pairing.go | 85 ++++++++++++------- 2 files changed, 103 insertions(+), 32 deletions(-) diff --git a/ecc/bls24-315/internal/fptower/e24_pairing.go b/ecc/bls24-315/internal/fptower/e24_pairing.go index 9f175ca94..aa4e3b14b 100644 --- a/ecc/bls24-315/internal/fptower/e24_pairing.go +++ b/ecc/bls24-315/internal/fptower/e24_pairing.go @@ -53,3 +53,53 @@ func (z *E24) MulBy034(c0, c3, c4 *E4) *E24 { 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 *E4) [5]E4 { + var z00, tmp, x0, x3, x4, x04, x03, x34 E4 + 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]E4{z00, x3, x34, x03, x04} +} + +// MulBy01234 multiplies z by an E12 sparse element of the form (x0, x1, x2, x3, x4, 0) +func (z *E24) MulBy01234(x *[5]E4) *E24 { + var c1, a, b, c, z0, z1 E12 + c0 := &E12{C0: x[0], C1: x[1], C2: x[2]} + c1.C0 = x[3] + c1.C1 = x[4] + a.Add(&z.D0, &z.D1) + b.Add(c0, &c1) + a.Mul(&a, &b) + b.Mul(&z.D0, c0) + c.Set(&z.D1).MulBy01(&x[3], &x[4]) + z1.Sub(&a, &b) + z1.Sub(&z1, &c) + z0.MulByNonResidue(&c) + z0.Add(&z0, &b) + + z.D0 = z0 + z.D1 = z1 + + return z +} diff --git a/ecc/bls24-315/pairing.go b/ecc/bls24-315/pairing.go index 289ca57c4..3b9c834bf 100644 --- a/ecc/bls24-315/pairing.go +++ b/ecc/bls24-315/pairing.go @@ -143,20 +143,38 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result GT - var l lineEvaluation + var l1, l2 lineEvaluation + var prodLines [5]fptower.E4 - qProj[0].doubleStep(&l) + // i = len(loopCounter) - 2 + // k = 0 + qProj[0].doubleStep(&l1) // line evaluation - result.D0.C0.MulByElement(&l.r0, &p[0].Y) - result.D1.C0.MulByElement(&l.r1, &p[0].X) - result.D1.C1.Set(&l.r2) + result.D0.C0.MulByElement(&l1.r0, &p[0].Y) + result.D1.C0.MulByElement(&l1.r1, &p[0].X) + result.D1.C1.Set(&l1.r2) - for k := 1; k < n; k++ { - qProj[k].doubleStep(&l) + if n >= 2 { + // k = 1 + qProj[1].doubleStep(&l1) // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) + l1.r0.MulByElement(&l1.r0, &p[1].Y) + l1.r1.MulByElement(&l1.r1, &p[1].X) + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &result.D0.C0, &result.D1.C0, &result.D1.C1) + result.D0.C0 = prodLines[0] + result.D0.C1 = prodLines[1] + result.D0.C2 = prodLines[2] + result.D1.C0 = prodLines[3] + result.D1.C1 = prodLines[4] + } + + // k >= 2 + for k := 2; k < n; k++ { + qProj[k].doubleStep(&l1) + // line evaluation + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + result.MulBy034(&l1.r0, &l1.r1, &l1.r2) } for i := len(loopCounter) - 3; i >= 1; i-- { @@ -164,25 +182,27 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.Square(&result) for k := 0; k < n; k++ { - qProj[k].doubleStep(&l) + qProj[k].doubleStep(&l1) // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) - if loopCounter[i] == 1 { - qProj[k].addMixedStep(&l, &q[k]) + if loopCounter[i] == 0 { + result.MulBy034(&l1.r0, &l1.r1, &l1.r2) + } else if loopCounter[i] == 1 { + qProj[k].addMixedStep(&l2, &q[k]) // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) - + 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) + result.MulBy01234(&prodLines) } else if loopCounter[i] == -1 { - qProj[k].addMixedStep(&l, &qNeg[k]) + qProj[k].addMixedStep(&l2, &qNeg[k]) // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) + 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) + result.MulBy01234(&prodLines) } } } @@ -190,17 +210,18 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // i = 0 result.Square(&result) for k := 0; k < n; k++ { - qProj[k].doubleStep(&l) + qProj[k].doubleStep(&l1) // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) - qProj[k].lineCompute(&l, &qNeg[k]) + qProj[k].lineCompute(&l2, &qNeg[k]) // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) + 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) + result.MulBy01234(&prodLines) } result.Conjugate(&result) From da8e55a2708456a83d8aa44347c80d6f85966057 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sat, 25 Mar 2023 11:49:06 +0000 Subject: [PATCH 13/18] perf(pairing/bw6-761): use somwewhat-sparse/spare multiplication in ML --- ecc/bw6-761/internal/fptower/e6_pairing.go | 35 ++++++++++---- ecc/bw6-761/pairing.go | 54 ++++++++++++---------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/ecc/bw6-761/internal/fptower/e6_pairing.go b/ecc/bw6-761/internal/fptower/e6_pairing.go index b8d2ca40f..2ec55cf6d 100644 --- a/ecc/bw6-761/internal/fptower/e6_pairing.go +++ b/ecc/bw6-761/internal/fptower/e6_pairing.go @@ -109,8 +109,8 @@ func (z *E6) MulBy034(c0, c3, c4 *fp.Element) *E6 { } // Mul034By034 multiplication of sparse element (c0,0,0,c3,c4,0) by sparse element (d0,0,0,d3,d4,0) -func (z *E6) Mul034By034(d0, d3, d4, c0, c3, c4 *fp.Element) *E6 { - var tmp, x0, x3, x4, x04, x03, x34 fp.Element +func Mul034By034(d0, d3, d4, c0, c3, c4 *fp.Element) [5]fp.Element { + var z00, tmp, x0, x3, x4, x04, x03, x34 fp.Element x0.Mul(c0, d0) x3.Mul(c3, d3) x4.Mul(c4, d4) @@ -130,13 +130,30 @@ func (z *E6) Mul034By034(d0, d3, d4, c0, c3, c4 *fp.Element) *E6 { Sub(&x34, &x3). Sub(&x34, &x4) - z.B0.A0.MulByNonResidue(&x4). - Add(&z.B0.A0, &x0) - z.B0.A1.Set(&x3) - z.B0.A2.Set(&x34) - z.B1.A0.Set(&x03) - z.B1.A1.Set(&x04) - z.B1.A2.SetZero() + z00.MulByNonResidue(&x4). + Add(&z00, &x0) + + return [5]fp.Element{z00, x3, x34, x03, x04} +} + +// MulBy01234 multiplies z by an E12 sparse element of the form (x0, x1, x2, x3, x4, 0) +func (z *E6) MulBy01234(x *[5]fp.Element) *E6 { + var c1, a, b, c, z0, z1 E3 + c0 := &E3{A0: x[0], A1: x[1], A2: x[2]} + c1.A0 = x[3] + c1.A1 = x[4] + a.Add(&z.B0, &z.B1) + b.Add(c0, &c1) + a.Mul(&a, &b) + b.Mul(&z.B0, c0) + c.Set(&z.B1).MulBy01(&x[3], &x[4]) + z1.Sub(&a, &b) + z1.Sub(&z1, &c) + z0.MulByNonResidue(&c) + z0.Add(&z0, &b) + + z.B0 = z0 + z.B1 = z1 return z } diff --git a/ecc/bw6-761/pairing.go b/ecc/bw6-761/pairing.go index 0c5be6ce2..0603fac13 100644 --- a/ecc/bw6-761/pairing.go +++ b/ecc/bw6-761/pairing.go @@ -203,8 +203,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { p10 := BatchProjectiveToAffineG1(pProj10) // f_{a0+\lambda*a1,P}(Q) - var result, ss GT + var result GT var l, l0 lineEvaluation + var prodLines [5]fp.Element var j int8 @@ -220,7 +221,12 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { pProj1[1].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[1].X) l0.r0.Mul(&l0.r0, &q[1].Y) - result.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) + prodLines = fptower.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) + result.B0.A0 = prodLines[0] + result.B0.A1 = prodLines[1] + result.B0.A2 = prodLines[2] + result.B1.A0 = prodLines[3] + result.B1.A1 = prodLines[4] } for k := 2; k < n; k++ { @@ -248,59 +254,59 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case -3: tmp.Neg(&p1[k]) pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case -2: pProj1[k].addMixedStep(&l, &p10[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case -1: tmp.Neg(&p0[k]) pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 0: result.MulBy034(&l0.r0, &l0.r1, &l0.r2) case 1: pProj1[k].addMixedStep(&l, &p0[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 2: tmp.Neg(&p10[k]) pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 3: pProj1[k].addMixedStep(&l, &p1[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 4: pProj1[k].addMixedStep(&l, &p01[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) default: return GT{}, errors.New("invalid loopCounter") } @@ -317,8 +323,8 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { pProj1[k].lineCompute(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) } return result, nil From e0aed324beb8e3d25a115a2acac3317062625261 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sat, 25 Mar 2023 11:53:56 +0000 Subject: [PATCH 14/18] perf(pairing/bw6-633): use somwewhat-sparse/spare multiplication in ML --- ecc/bw6-633/internal/fptower/e6_pairing.go | 35 ++++++++++---- ecc/bw6-633/pairing.go | 54 ++++++++++++---------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/ecc/bw6-633/internal/fptower/e6_pairing.go b/ecc/bw6-633/internal/fptower/e6_pairing.go index 691e862bc..661a75519 100644 --- a/ecc/bw6-633/internal/fptower/e6_pairing.go +++ b/ecc/bw6-633/internal/fptower/e6_pairing.go @@ -57,8 +57,8 @@ func (z *E6) MulBy034(c0, c3, c4 *fp.Element) *E6 { } // Mul034By034 multiplication of sparse element (c0,0,0,c3,c4,0) by sparse element (d0,0,0,d3,d4,0) -func (z *E6) Mul034By034(d0, d3, d4, c0, c3, c4 *fp.Element) *E6 { - var tmp, x0, x3, x4, x04, x03, x34 fp.Element +func Mul034By034(d0, d3, d4, c0, c3, c4 *fp.Element) [5]fp.Element { + var z00, tmp, x0, x3, x4, x04, x03, x34 fp.Element x0.Mul(c0, d0) x3.Mul(c3, d3) x4.Mul(c4, d4) @@ -78,13 +78,30 @@ func (z *E6) Mul034By034(d0, d3, d4, c0, c3, c4 *fp.Element) *E6 { Sub(&x34, &x3). Sub(&x34, &x4) - z.B0.A0.MulByNonResidue(&x4). - Add(&z.B0.A0, &x0) - z.B0.A1.Set(&x3) - z.B0.A2.Set(&x34) - z.B1.A0.Set(&x03) - z.B1.A1.Set(&x04) - z.B1.A2.SetZero() + z00.MulByNonResidue(&x4). + Add(&z00, &x0) + + return [5]fp.Element{z00, x3, x34, x03, x04} +} + +// MulBy01234 multiplies z by an E12 sparse element of the form (x0, x1, x2, x3, x4, 0) +func (z *E6) MulBy01234(x *[5]fp.Element) *E6 { + var c1, a, b, c, z0, z1 E3 + c0 := &E3{A0: x[0], A1: x[1], A2: x[2]} + c1.A0 = x[3] + c1.A1 = x[4] + a.Add(&z.B0, &z.B1) + b.Add(c0, &c1) + a.Mul(&a, &b) + b.Mul(&z.B0, c0) + c.Set(&z.B1).MulBy01(&x[3], &x[4]) + z1.Sub(&a, &b) + z1.Sub(&z1, &c) + z0.MulByNonResidue(&c) + z0.Add(&z0, &b) + + z.B0 = z0 + z.B1 = z1 return z } diff --git a/ecc/bw6-633/pairing.go b/ecc/bw6-633/pairing.go index 6f1170597..8cd531b07 100644 --- a/ecc/bw6-633/pairing.go +++ b/ecc/bw6-633/pairing.go @@ -228,8 +228,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { p10 := BatchProjectiveToAffineG1(pProj10) // f_{a0+\lambda*a1,P}(Q) - var result, ss GT + var result GT var l, l0 lineEvaluation + var prodLines [5]fp.Element var j int8 @@ -245,7 +246,12 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { pProj0[1].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[1].X) l0.r0.Mul(&l0.r0, &q[1].Y) - result.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) + prodLines = fptower.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) + result.B0.A0 = prodLines[0] + result.B0.A1 = prodLines[1] + result.B0.A2 = prodLines[2] + result.B1.A0 = prodLines[3] + result.B1.A1 = prodLines[4] } for k := 2; k < n; k++ { @@ -272,59 +278,59 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { pProj0[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case -3: tmp.Neg(&p1[k]) pProj0[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case -2: pProj0[k].addMixedStep(&l, &p10[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l10[k].r0, &l10[k].r1, &l10[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case -1: tmp.Neg(&p0[k]) pProj0[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 0: result.MulBy034(&l0.r0, &l0.r1, &l0.r2) case 1: pProj0[k].addMixedStep(&l, &p0[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 2: tmp.Neg(&p10[k]) pProj0[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l10[k].r0, &l10[k].r1, &l10[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 3: pProj0[k].addMixedStep(&l, &p1[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 4: pProj0[k].addMixedStep(&l, &p01[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) default: return GT{}, errors.New("invalid loopCounter") } @@ -341,8 +347,8 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { pProj0[k].lineCompute(&l, &p0[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) } return result, nil From 7501e6b8b6a0e74347660bcfda9e345ded19fa4a Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sat, 25 Mar 2023 11:57:43 +0000 Subject: [PATCH 15/18] perf(pairing/bw6-756): use somwewhat-sparse/spare multiplication in ML --- ecc/bw6-756/internal/fptower/e6_pairing.go | 35 ++++++++++---- ecc/bw6-756/pairing.go | 55 ++++++++++++---------- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/ecc/bw6-756/internal/fptower/e6_pairing.go b/ecc/bw6-756/internal/fptower/e6_pairing.go index 60358a019..6eb52c190 100644 --- a/ecc/bw6-756/internal/fptower/e6_pairing.go +++ b/ecc/bw6-756/internal/fptower/e6_pairing.go @@ -94,8 +94,8 @@ func (z *E6) MulBy034(c0, c3, c4 *fp.Element) *E6 { } // Mul034By034 multiplication of sparse element (c0,0,0,c3,c4,0) by sparse element (d0,0,0,d3,d4,0) -func (z *E6) Mul034By034(d0, d3, d4, c0, c3, c4 *fp.Element) *E6 { - var tmp, x0, x3, x4, x04, x03, x34 fp.Element +func Mul034By034(d0, d3, d4, c0, c3, c4 *fp.Element) [5]fp.Element { + var z00, tmp, x0, x3, x4, x04, x03, x34 fp.Element x0.Mul(c0, d0) x3.Mul(c3, d3) x4.Mul(c4, d4) @@ -115,13 +115,30 @@ func (z *E6) Mul034By034(d0, d3, d4, c0, c3, c4 *fp.Element) *E6 { Sub(&x34, &x3). Sub(&x34, &x4) - z.B0.A0.MulByNonResidue(&x4). - Add(&z.B0.A0, &x0) - z.B0.A1.Set(&x3) - z.B0.A2.Set(&x34) - z.B1.A0.Set(&x03) - z.B1.A1.Set(&x04) - z.B1.A2.SetZero() + z00.MulByNonResidue(&x4). + Add(&z00, &x0) + + return [5]fp.Element{z00, x3, x34, x03, x04} +} + +// MulBy01234 multiplies z by an E12 sparse element of the form (x0, x1, x2, x3, x4, 0) +func (z *E6) MulBy01234(x *[5]fp.Element) *E6 { + var c1, a, b, c, z0, z1 E3 + c0 := &E3{A0: x[0], A1: x[1], A2: x[2]} + c1.A0 = x[3] + c1.A1 = x[4] + a.Add(&z.B0, &z.B1) + b.Add(c0, &c1) + a.Mul(&a, &b) + b.Mul(&z.B0, c0) + c.Set(&z.B1).MulBy01(&x[3], &x[4]) + z1.Sub(&a, &b) + z1.Sub(&z1, &c) + z0.MulByNonResidue(&c) + z0.Add(&z0, &b) + + z.B0 = z0 + z.B1 = z1 return z } diff --git a/ecc/bw6-756/pairing.go b/ecc/bw6-756/pairing.go index 5972ad861..34ad50ce1 100644 --- a/ecc/bw6-756/pairing.go +++ b/ecc/bw6-756/pairing.go @@ -205,8 +205,9 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { p10 := BatchProjectiveToAffineG1(pProj10) // f_{a0+lambda*a1,P}(Q) - var result, ss GT + var result GT var l, l0 lineEvaluation + var prodLines [5]fp.Element var j int8 @@ -222,9 +223,15 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { pProj1[1].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[1].X) l0.r0.Mul(&l0.r0, &q[1].Y) - result.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) + prodLines = fptower.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) + result.B0.A0 = prodLines[0] + result.B0.A1 = prodLines[1] + result.B0.A2 = prodLines[2] + result.B1.A0 = prodLines[3] + result.B1.A1 = prodLines[4] } + // k >= 2 for k := 2; k < n; k++ { pProj1[k].doubleStep(&l0) l0.r1.Mul(&l0.r1, &q[k].X) @@ -250,59 +257,59 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case -3: tmp.Neg(&p1[k]) pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case -2: pProj1[k].addMixedStep(&l, &p10[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case -1: tmp.Neg(&p0[k]) pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 0: result.MulBy034(&l0.r0, &l0.r1, &l0.r2) case 1: pProj1[k].addMixedStep(&l, &p0[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 2: tmp.Neg(&p10[k]) pProj1[k].addMixedStep(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 3: pProj1[k].addMixedStep(&l, &p1[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) case 4: pProj1[k].addMixedStep(&l, &p01[k]) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) - result.MulBy034(&l0.r0, &l0.r1, &l0.r2). - Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) default: return GT{}, errors.New("invalid loopCounter") } @@ -320,8 +327,8 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { pProj1[k].lineCompute(&l, &tmp) l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) - ss.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &ss) + prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result.MulBy01234(&prodLines) } return result, nil From 3c7c8f8b7e742721836cfe59e4b211fa0b954c3d Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sun, 26 Mar 2023 13:04:20 +0000 Subject: [PATCH 16/18] docs(pairing): add comments --- ecc/bls12-377/pairing.go | 50 ++++++++++++++++++------ ecc/bls12-378/pairing.go | 46 ++++++++++++++++------ ecc/bls12-381/pairing.go | 44 +++++++++++++++------ ecc/bls24-315/pairing.go | 55 ++++++++++++++++++++------- ecc/bls24-317/pairing.go | 48 +++++++++++++++++------ ecc/bn254/pairing.go | 75 ++++++++++++++++++++++++++++-------- ecc/bw6-633/pairing.go | 77 +++++++++++++++++++++++++++++++++++-- ecc/bw6-756/pairing.go | 80 ++++++++++++++++++++++++++++++++++++--- ecc/bw6-761/pairing.go | 82 +++++++++++++++++++++++++++++++++++++--- 9 files changed, 468 insertions(+), 89 deletions(-) diff --git a/ecc/bls12-377/pairing.go b/ecc/bls12-377/pairing.go index d7cde179e..cb60c8dd1 100644 --- a/ecc/bls12-377/pairing.go +++ b/ecc/bls12-377/pairing.go @@ -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) @@ -136,19 +136,30 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { var l1, l2 lineEvaluation var prodLines [5]E2 - // i == len(loopCounter) - 2 + // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } + // 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 eval + // 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) if n >= 2 { - // k = 1 + // 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 + // 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] @@ -157,52 +168,67 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.C1.B1 = prodLines[4] } + // k >= 2 for k := 2; k < n; k++ { + // qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] qProj[k].doubleStep(&l1) - // line eval + // 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) } + // 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] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] qProj[k].doubleStep(&l1) - // line eval + // 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 eval + // 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) } } } - // i = 0 + // 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 eval + // 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 eval + // 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) } diff --git a/ecc/bls12-378/pairing.go b/ecc/bls12-378/pairing.go index fb964a684..ab43ff0c4 100644 --- a/ecc/bls12-378/pairing.go +++ b/ecc/bls12-378/pairing.go @@ -103,7 +103,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) @@ -135,20 +135,30 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { var l1, l2 lineEvaluation var prodLines [5]E2 - // i == len(loopCounter) - 2 - // k = 0 + // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } + // i = 62, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[62] = 0 + // k = 0, separately to avoid MulBy014 (res × ℓ) + // (assign line to res) + + // qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0] qProj[0].doubleStep(&l1) - // line eval + // line evaluation at P[0] (assign) result.C0.B0.Set(&l1.r0) result.C0.B1.MulByElement(&l1.r1, &p[0].X) result.C1.B1.MulByElement(&l1.r2, &p[0].Y) if n >= 2 { - // k = 1 + // k = 1, separately to avoid MulBy014 (res × ℓ) + // (res is also a line at this point, so we use Mul014By014 ℓ × ℓ) + + // qProj[1] ← 2qProj[1] and l1 the tangent ℓ passing 2qProj[1] qProj[1].doubleStep(&l1) - // line eval + // line evaluation at P[1] l1.r1.MulByElement(&l1.r1, &p[1].X) l1.r2.MulByElement(&l1.r2, &p[1].Y) + // ℓ × res prodLines = fptower.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) result.C0.B0 = prodLines[0] result.C0.B1 = prodLines[1] @@ -157,29 +167,38 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.C1.B2 = prodLines[4] } + // k >= 2 for k := 2; k < n; k++ { + // qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] qProj[k].doubleStep(&l1) - // line eval + // line evaluation at P[k] l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) + // ℓ × res result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } + // 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] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] qProj[k].doubleStep(&l1) - // line eval + // line evaluation at P[k] l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) if loopCounter[i] == 0 { + // ℓ × res result.MulBy014(&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 eval + // line evaluation at P[k] l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) // ℓ × ℓ @@ -190,16 +209,19 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } - // i = 0 + // 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 eval + // line evaluation at P[k] l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) + // l2 the line passing qProj[k] and Q qProj[k].lineCompute(&l2, &q[k]) - // line eval + // line evaluation at P[k] l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) // ℓ × ℓ diff --git a/ecc/bls12-381/pairing.go b/ecc/bls12-381/pairing.go index 257dc5b1d..a22b03e00 100644 --- a/ecc/bls12-381/pairing.go +++ b/ecc/bls12-381/pairing.go @@ -103,7 +103,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) @@ -135,18 +135,27 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { var l1, l2 lineEvaluation var prodLines [5]E2 - // i == len(loopCounter) - 2 - // k = 0 + // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } + // i = 62, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[62] = 1 + // k = 0, separately to avoid MulBy014 (res × ℓ) + // (assign line to res) + + // qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0] qProj[0].doubleStep(&l1) - // line eval + // line evaluation at P[0] (assign) result.C0.B0.Set(&l1.r0) result.C0.B1.MulByElement(&l1.r1, &p[0].X) result.C1.B1.MulByElement(&l1.r2, &p[0].Y) + // qProj[0] ← qProj[0]+Q[0] and + // l2 the line ℓ passing qProj[0] and Q[0] qProj[0].addMixedStep(&l2, &q[0]) - // line eval + // line evaluation at P[0] (assign) l2.r1.MulByElement(&l2.r1, &p[0].X) l2.r2.MulByElement(&l2.r2, &p[0].Y) + // ℓ × res prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) result.C0.B0 = prodLines[0] result.C0.B1 = prodLines[1] @@ -154,14 +163,18 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.C1.B1 = prodLines[3] result.C1.B2 = prodLines[4] + // k >= 1 for k := 1; k < n; k++ { + // qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] qProj[k].doubleStep(&l1) - // line eval + // line evaluation at P[k] l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) + // qProj[k] ← qProj[k]+Q[k] and + // l2 the line ℓ passing qProj[k] and Q[k] qProj[k].addMixedStep(&l2, &q[k]) - // line eval + // line evaluation at P[k] l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) // ℓ × ℓ @@ -170,21 +183,27 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.MulBy01245(&prodLines) } + // 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] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] qProj[k].doubleStep(&l1) - // line eval + // line evaluation at P[k] l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) if loopCounter[i] == 0 { + // ℓ × res result.MulBy014(&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 eval + // line evaluation at P[k] l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) // ℓ × ℓ @@ -195,13 +214,16 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } - // i = 0 + // i = 0, separately to avoid a point doubling + // loopCounter[0] = 0 result.Square(&result) for k := 0; k < n; k++ { + // l1 the tangent ℓ passing 2qProj[k] qProj[k].tangentLine(&l1) - // line eval + // line evaluation at P[k] l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) + // ℓ × result result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } diff --git a/ecc/bls24-315/pairing.go b/ecc/bls24-315/pairing.go index 3b9c834bf..e1adc4df8 100644 --- a/ecc/bls24-315/pairing.go +++ b/ecc/bls24-315/pairing.go @@ -146,20 +146,30 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { var l1, l2 lineEvaluation var prodLines [5]fptower.E4 - // i = len(loopCounter) - 2 - // k = 0 + // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } + // i = 31, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[31] = 0 + // k = 0, separately to avoid MulBy014 (res × ℓ) + // (assign line to res) + + // qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0] qProj[0].doubleStep(&l1) qProj[0].doubleStep(&l1) - // line evaluation + // line evaluation at P[0] (assign) result.D0.C0.MulByElement(&l1.r0, &p[0].Y) result.D1.C0.MulByElement(&l1.r1, &p[0].X) result.D1.C1.Set(&l1.r2) if n >= 2 { - // k = 1 + // k = 1, separately to avoid MulBy014 (res × ℓ) + // (res is also a line at this point, so we use Mul014By014 ℓ × ℓ) + + // qProj[1] ← 2qProj[1] and l1 the tangent ℓ passing 2qProj[1] qProj[1].doubleStep(&l1) - // line evaluation + // 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.D0.C0, &result.D1.C0, &result.D1.C1) result.D0.C0 = prodLines[0] result.D0.C1 = prodLines[1] @@ -170,60 +180,79 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // 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 + // 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) } + // i <= 30 for i := len(loopCounter) - 3; i >= 1; i-- { // (∏ᵢfᵢ)² + // mutualize the square among n Miller loops 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 + // 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 { + // ℓ × result result.MulBy034(&l1.r0, &l1.r1, &l1.r2) } else if loopCounter[i] == 1 { + // qProj[k] ← qProj[k]+Q[k] and + // l2 the line ℓ passing qProj[k] and Q[k] qProj[k].addMixedStep(&l2, &q[k]) - // line evaluation + // 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) + // (ℓ × ℓ) × result result.MulBy01234(&prodLines) } else if loopCounter[i] == -1 { + // qProj[k] ← qProj[k]-Q[k] and + // l2 the line ℓ passing qProj[k] and -Q[k] qProj[k].addMixedStep(&l2, &qNeg[k]) - // line evaluation + // 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) + // (ℓ × ℓ) × result result.MulBy01234(&prodLines) } } } - // i = 0 + // 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 + // 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, &qNeg[k]) - // line evaluation + // 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) } + // negative x₀ result.Conjugate(&result) return result, nil diff --git a/ecc/bls24-317/pairing.go b/ecc/bls24-317/pairing.go index fd47b60ad..bffd182f2 100644 --- a/ecc/bls24-317/pairing.go +++ b/ecc/bls24-317/pairing.go @@ -116,7 +116,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) @@ -150,20 +150,30 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { var l1, l2 lineEvaluation var prodLines [5]fptower.E4 - // i == len(loopCounter) - 2 - // k = 0 + // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } + // i = 31, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[31] = 0 + // k = 0, separately to avoid MulBy014 (res × ℓ) + // (assign line to res) + + // qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0] qProj[0].doubleStep(&l1) - // line evaluation + // line evaluation at P[0] (assign) result.D0.C0.Set(&l1.r0) result.D0.C1.MulByElement(&l1.r1, &p[0].X) result.D1.C1.MulByElement(&l1.r2, &p[0].Y) if n >= 2 { - // k = 1 + // k = 1, separately to avoid MulBy014 (res × ℓ) + // (res is also a line at this point, so we use Mul014By014 ℓ × ℓ) + + // qProj[1] ← 2qProj[1] and l1 the tangent ℓ passing 2qProj[1] qProj[1].doubleStep(&l1) - // line evaluation + // line evaluation at P[1] l1.r1.MulByElement(&l1.r1, &p[1].X) l1.r2.MulByElement(&l1.r2, &p[1].Y) + // ℓ × res prodLines = fptower.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &result.D0.C0, &result.D0.C1, &result.D1.C1) result.D0.C0 = prodLines[0] result.D0.C1 = prodLines[1] @@ -172,27 +182,35 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.D1.C2 = prodLines[4] } + // 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 + // line evaluation at P[k] l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) + // ℓ × res result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } + // i <= 30 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] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] qProj[k].doubleStep(&l1) - // line evaluation + // line evaluation at P[k] l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) if loopCounter[i] == 1 { + // qProj[k] ← qProj[k]+Q[k] and + // l2 the line ℓ passing qProj[k] and Q[k] qProj[k].addMixedStep(&l2, &q[k]) - // line evaluation + // line evaluation at P[k] l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) // ℓ × ℓ @@ -200,8 +218,10 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // (ℓ × ℓ) × result result.MulBy01245(&prodLines) } else if loopCounter[i] == -1 { + // qProj[k] ← qProj[k]-Q[k] and + // l2 the line ℓ passing qProj[k] and -Q[k] qProj[k].addMixedStep(&l2, &qNeg[k]) - // line evaluation + // line evaluation at P[k] l2.r1.MulByElement(&l2.r1, &p[k].X) l2.r2.MulByElement(&l2.r2, &p[k].Y) // ℓ × ℓ @@ -209,18 +229,22 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // (ℓ × ℓ) × result result.MulBy01245(&prodLines) } else { + // ℓ × result result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } } } - // i = 0 + // i = 0, separately to avoid a point doubling + // loopCounter[0] = 0 result.Square(&result) for k := 0; k < n; k++ { + // l1 the tangent ℓ passing 2qProj[k] qProj[k].tangentLine(&l1) - // line evaluation + // line evaluation at P[k] l1.r1.MulByElement(&l1.r1, &p[k].X) l1.r2.MulByElement(&l1.r2, &p[k].Y) + // ℓ × result result.MulBy014(&l1.r0, &l1.r1, &l1.r2) } diff --git a/ecc/bn254/pairing.go b/ecc/bn254/pairing.go index 319d4ec3e..e3ec86c59 100644 --- a/ecc/bn254/pairing.go +++ b/ecc/bn254/pairing.go @@ -58,7 +58,7 @@ func PairingCheck(P []G1Affine, Q []G2Affine) (bool, error) { // FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ // where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r // we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r -// where s is the cofactor 2x₀(6x₀²+3x₀+1) (Fuentes et al.) +// where s is the cofactor 2x₀(6x₀²+3x₀+1) func FinalExponentiation(z *GT, _z ...*GT) GT { var result GT @@ -110,7 +110,8 @@ func FinalExponentiation(z *GT, _z ...*GT) GT { } // MillerLoop computes the multi-Miller loop -// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) +// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) = +// ∏ᵢ { fᵢ_{6x₀+2,Qᵢ}(Pᵢ) · ℓᵢ_{[6x₀+2]Qᵢ,π(Qᵢ)}(Pᵢ) · ℓᵢ_{[6x₀+2]Qᵢ+π(Qᵢ),-π²(Qᵢ)}(Pᵢ) } func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { n := len(P) if n == 0 || n != len(Q) { @@ -142,20 +143,30 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { var l2, l1 lineEvaluation var prodLines [5]E2 - // i == len(loopCounter) - 2 - // k = 0 + // Compute ∏ᵢ { fᵢ_{6x₀+2,Q}(P) } + // i = 64, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[64] = 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 + // 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) if n >= 2 { - // k = 1 + // 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 + // 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] @@ -164,61 +175,86 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.C1.B1 = prodLines[4] } + // 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 + // 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) } - // i = len(loopCounter) - 3 + // i = 63, separately to avoid a doubleStep (loopCounter[63]=-1) + // (at this point qProj = 2Q, so 2qProj-Q=3Q is equivalent to qProj+Q=3Q + // this means doubleStep followed by an addMixedStep is equivalent to an + // addMixedStep here) + result.Square(&result) for k := 0; k < n; k++ { + // l2 the line passing qProj[k] and -Q + // (avoids a point addition: qProj[k]-Q) qProj[k].lineCompute(&l2, &qNeg[k]) - // line evaluation + // line evaluation at P[k] l2.r0.MulByElement(&l2.r0, &p[k].Y) l2.r1.MulByElement(&l2.r1, &p[k].X) - + // qProj[k] ← qProj[k]+Q[k] and + // l1 the line ℓ passing qProj[k] and Q[k] qProj[k].addMixedStep(&l1, &q[k]) - // line evaluation + // line evaluation at P[k] l1.r0.MulByElement(&l1.r0, &p[k].Y) l1.r1.MulByElement(&l1.r1, &p[k].X) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) } + // i <= 62 for i := len(loopCounter) - 4; i >= 0; i-- { + // mutualize the square among n Miller loops // (∏ᵢfᵢ)² 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 + // line evaluation at P[k] l1.r0.MulByElement(&l1.r0, &p[k].Y) l1.r1.MulByElement(&l1.r1, &p[k].X) if loopCounter[i] == 1 { + // qProj[k] ← qProj[k]+Q[k] and + // l2 the line ℓ passing qProj[k] and Q[k] qProj[k].addMixedStep(&l2, &q[k]) - // line evaluation + // 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) } else if loopCounter[i] == -1 { + // qProj[k] ← qProj[k]-Q[k] and + // l2 the line ℓ passing qProj[k] and -Q[k] qProj[k].addMixedStep(&l2, &qNeg[k]) - // line evaluation + // 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) } else { + // ℓ × res result.MulBy034(&l1.r0, &l1.r1, &l1.r2) } } } + // Compute ∏ᵢ { ℓᵢ_{[6x₀+2]Q,π(Q)}(P) · ℓᵢ_{[6x₀+2]Q+π(Q),-π²(Q)}(P) } var Q1, Q2 G2Affine for k := 0; k < n; k++ { //Q1 = π(Q) @@ -229,14 +265,23 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { Q2.X.MulByNonResidue2Power2(&q[k].X) Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) + // qProj[k] ← qProj[k]+π(Q) and + // l1 the line passing qProj[k] and π(Q) qProj[k].addMixedStep(&l2, &Q1) + // line evaluation at P[k] l2.r0.MulByElement(&l2.r0, &p[k].Y) l2.r1.MulByElement(&l2.r1, &p[k].X) + // l2 the line passing qProj[k] and -π²(Q) + // (avoids a point addition: qProj[k]-π²(Q)) qProj[k].lineCompute(&l1, &Q2) + // line evaluation at P[k] l1.r0.MulByElement(&l1.r0, &p[k].Y) l1.r1.MulByElement(&l1.r1, &p[k].X) + + // ℓ × ℓ prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) } diff --git a/ecc/bw6-633/pairing.go b/ecc/bw6-633/pairing.go index 8cd531b07..4fefec3ad 100644 --- a/ecc/bw6-633/pairing.go +++ b/ecc/bw6-633/pairing.go @@ -227,25 +227,34 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { p01 := BatchProjectiveToAffineG1(pProj01) p10 := BatchProjectiveToAffineG1(pProj10) - // f_{a0+\lambda*a1,P}(Q) + // f_{a0+λ*a1,P}(Q) var result GT var l, l0 lineEvaluation var prodLines [5]fp.Element var j int8 - // i = len(loopCounter)-2 - // k = 0 + // i = len(loopCounter0) - 2, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // j = 0 + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + + // pProj0[0] ← 2pProj0[0] and l0 the tangent ℓ passing 2pProj0[0] pProj0[0].doubleStep(&l0) + // line evaluation at Q[0] (assign) result.B1.A0.Mul(&l0.r1, &q[0].X) result.B0.A0.Mul(&l0.r0, &q[0].Y) result.B1.A1.Set(&l0.r2) // k = 1 if n >= 2 { + // pProj0[1] ← 2pProj0[1] and l0 the tangent ℓ passing 2pProj0[1] pProj0[1].doubleStep(&l0) + // line evaluation at Q[0] l0.r1.Mul(&l0.r1, &q[1].X) l0.r0.Mul(&l0.r0, &q[1].Y) + // ℓ × res prodLines = fptower.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) result.B0.A0 = prodLines[0] result.B0.A1 = prodLines[1] @@ -254,82 +263,135 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.B1.A1 = prodLines[4] } + // k >= 2 for k := 2; k < n; k++ { + // pProj0[1] ← 2pProj0[1] and l0 the tangent ℓ passing 2pProj0[1] pProj0[k].doubleStep(&l0) + // line evaluation at Q[k] l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) } var tmp G1Affine for i := len(loopCounter0) - 3; i >= 1; i-- { + // (∏ᵢfᵢ)² + // mutualize the square among n Miller loops result.Square(&result) j = loopCounter0[i]*3 + loopCounter1[i] for k := 0; k < n; k++ { + // pProj0[1] ← 2pProj0[1] and l0 the tangent ℓ passing 2pProj0[1] pProj0[k].doubleStep(&l0) + // line evaluation at Q[k] l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) switch j { case -4: tmp.Neg(&p01[k]) + // pProj0[k] ← pProj0[k]-p01[k] and + // l the line ℓ passing pProj0[k] and -p01[k] pProj0[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case -3: tmp.Neg(&p1[k]) + // pProj0[k] ← pProj0[k]-p1[k] and + // l the line ℓ passing pProj0[k] and -p1[k] pProj0[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case -2: + // pProj0[k] ← pProj0[k]+p10[k] and + // l the line ℓ passing pProj0[k] and p10[k] pProj0[k].addMixedStep(&l, &p10[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case -1: tmp.Neg(&p0[k]) + // pProj0[k] ← pProj0[k]-p0[k] and + // l the line ℓ passing pProj0[k] and -p0[k] pProj0[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 0: + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) case 1: + // pProj0[k] ← pProj0[k]+p0[k] and + // l the line ℓ passing pProj0[k] and p0[k] pProj0[k].addMixedStep(&l, &p0[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 2: tmp.Neg(&p10[k]) + // pProj0[k] ← pProj0[k]-p10[k] and + // l the line ℓ passing pProj0[k] and -p10[k] pProj0[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 3: + // pProj0[k] ← pProj0[k]+p1[k] and + // l the line ℓ passing pProj0[k] and p1[k] pProj0[k].addMixedStep(&l, &p1[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // (ℓ × ℓ) × res prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 4: + // pProj0[k] ← pProj0[k]+p01[k] and + // l the line ℓ passing pProj0[k] and p01[k] pProj0[k].addMixedStep(&l, &p01[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) default: return GT{}, errors.New("invalid loopCounter") @@ -337,17 +399,24 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } - // i = 0 + // i = 0, separately to avoid a point addition + // j = 1 result.Square(&result) for k := 0; k < n; k++ { + // pProj0[k] ← 2pProj0[k] and l0 the tangent ℓ passing 2pProj0[k] pProj0[k].doubleStep(&l0) + // line evaluation at Q[k] l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) + // l the line passing pProj0[k] and p0 pProj0[k].lineCompute(&l, &p0[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) } diff --git a/ecc/bw6-756/pairing.go b/ecc/bw6-756/pairing.go index 34ad50ce1..171a19700 100644 --- a/ecc/bw6-756/pairing.go +++ b/ecc/bw6-756/pairing.go @@ -153,7 +153,10 @@ func FinalExponentiation(z *GT, _z ...*GT) GT { } // MillerLoop Optimal Tate alternative (or twisted ate or Eta revisited) -// computes the multi-Miller loop ∏ᵢ MillerLoop(Pᵢ, Qᵢ) +// computes the multi-Miller loop +// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) = +// ∏ᵢ { fᵢ_{x₀+1+λ(x₀³-x₀²-x₀),Pᵢ}(Qᵢ) } +// // Alg.2 in https://eprint.iacr.org/2021/1359.pdf // Eq. (6) in https://hackmd.io/@gnark/BW6-761-changes func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { @@ -204,25 +207,34 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { p01 := BatchProjectiveToAffineG1(pProj01) p10 := BatchProjectiveToAffineG1(pProj10) - // f_{a0+lambda*a1,P}(Q) + // f_{a0+λ*a1,P}(Q) var result GT var l, l0 lineEvaluation var prodLines [5]fp.Element var j int8 - // i = len(loopCounter) - 2 - // k = 0 + // i = len(loopCounter0) - 2, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // j = 0 + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + + // pProj1[0] ← 2pProj1[0] and l0 the tangent ℓ passing 2pProj1[0] pProj1[0].doubleStep(&l0) + // line evaluation at Q[0] (assign) result.B1.A0.Mul(&l0.r1, &q[0].X) result.B0.A0.Mul(&l0.r0, &q[0].Y) result.B1.A1.Set(&l0.r2) // k = 1 if n >= 2 { + // pProj1[1] ← 2pProj1[1] and l0 the tangent ℓ passing 2pProj1[1] pProj1[1].doubleStep(&l0) + // line evaluation at Q[0] l0.r1.Mul(&l0.r1, &q[1].X) l0.r0.Mul(&l0.r0, &q[1].Y) + // ℓ × res prodLines = fptower.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) result.B0.A0 = prodLines[0] result.B0.A1 = prodLines[1] @@ -233,82 +245,133 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // k >= 2 for k := 2; k < n; k++ { + // pProj1[1] ← 2pProj1[1] and l0 the tangent ℓ passing 2pProj1[1] pProj1[k].doubleStep(&l0) + // line evaluation at Q[k] l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) } var tmp G1Affine for i := len(loopCounter0) - 3; i >= 1; i-- { // (∏ᵢfᵢ)² + // mutualize the square among n Miller loops result.Square(&result) j = loopCounter1[i]*3 + loopCounter0[i] for k := 0; k < n; k++ { + // pProj1[1] ← 2pProj1[1] and l0 the tangent ℓ passing 2pProj1[1] pProj1[k].doubleStep(&l0) + // line evaluation at Q[k] l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) switch j { case -4: tmp.Neg(&p01[k]) + // pProj1[k] ← pProj1[k]-p01[k] and + // l the line ℓ passing pProj1[k] and -p01[k] pProj1[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case -3: tmp.Neg(&p1[k]) + // pProj1[k] ← pProj1[k]-p1[k] and + // l the line ℓ passing pProj1[k] and -p1[k] pProj1[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case -2: + // pProj1[k] ← pProj1[k]+p10[k] and + // l the line ℓ passing pProj1[k] and p10[k] pProj1[k].addMixedStep(&l, &p10[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case -1: tmp.Neg(&p0[k]) + // pProj1[k] ← pProj1[k]-p0[k] and + // l the line ℓ passing pProj1[k] and -p0[k] pProj1[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 0: + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) case 1: + // pProj1[k] ← pProj1[k]+p0[k] and + // l the line ℓ passing pProj1[k] and p0[k] pProj1[k].addMixedStep(&l, &p0[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 2: tmp.Neg(&p10[k]) + // pProj1[k] ← pProj1[k]-p10[k] and + // l the line ℓ passing pProj1[k] and -p10[k] pProj1[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 3: + // pProj1[k] ← pProj1[k]+p1[k] and + // l the line ℓ passing pProj1[k] and p1[k] pProj1[k].addMixedStep(&l, &p1[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 4: + // pProj1[k] ← pProj1[k]+p01[k] and + // l the line ℓ passing pProj1[k] and p01[k] pProj1[k].addMixedStep(&l, &p01[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) default: return GT{}, errors.New("invalid loopCounter") @@ -316,18 +379,25 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } - // i = 0 + // i = 0, separately to avoid a point addition + // j = -3 result.Square(&result) for k := 0; k < n; k++ { + // pProj1[k] ← 2pProj1[k] and l0 the tangent ℓ passing 2pProj1[k] pProj1[k].doubleStep(&l0) + // line evaluation at Q[k] l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) tmp.Neg(&p1[k]) + // l the line passing pProj1[k] and -p1 pProj1[k].lineCompute(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) } diff --git a/ecc/bw6-761/pairing.go b/ecc/bw6-761/pairing.go index 0603fac13..efa194ada 100644 --- a/ecc/bw6-761/pairing.go +++ b/ecc/bw6-761/pairing.go @@ -151,7 +151,10 @@ func FinalExponentiation(z *GT, _z ...*GT) GT { } // MillerLoop Optimal Tate alternative (or twisted ate or Eta revisited) -// computes the multi-Miller loop ∏ᵢ MillerLoop(Pᵢ, Qᵢ) +// computes the multi-Miller loop +// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) = +// ∏ᵢ { fᵢ_{x₀+1+λ(x₀³-x₀²-x₀),Pᵢ}(Qᵢ) } +// // Alg.2 in https://eprint.iacr.org/2021/1359.pdf // Eq. (6) in https://hackmd.io/@gnark/BW6-761-changes func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { @@ -202,25 +205,34 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { p01 := BatchProjectiveToAffineG1(pProj01) p10 := BatchProjectiveToAffineG1(pProj10) - // f_{a0+\lambda*a1,P}(Q) + // f_{a0+λ*a1,P}(Q) var result GT var l, l0 lineEvaluation var prodLines [5]fp.Element var j int8 - // i = len(loopCounter) - 2 - // k = 0 + // i = len(loopCounter0) - 2, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // j = 0 + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + + // pProj1[0] ← 2pProj1[0] and l0 the tangent ℓ passing 2pProj1[0] pProj1[0].doubleStep(&l0) + // line evaluation at Q[0] (assign) result.B1.A0.Mul(&l0.r1, &q[0].X) result.B0.A0.Mul(&l0.r0, &q[0].Y) result.B1.A1.Set(&l0.r2) // k = 1 if n >= 2 { + // pProj1[1] ← 2pProj1[1] and l0 the tangent ℓ passing 2pProj1[1] pProj1[1].doubleStep(&l0) + // line evaluation at Q[0] l0.r1.Mul(&l0.r1, &q[1].X) l0.r0.Mul(&l0.r0, &q[1].Y) + // ℓ × res prodLines = fptower.Mul034By034(&l0.r0, &l0.r1, &l0.r2, &result.B0.A0, &result.B1.A0, &result.B1.A1) result.B0.A0 = prodLines[0] result.B0.A1 = prodLines[1] @@ -229,83 +241,135 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { result.B1.A1 = prodLines[4] } + // k >= 2 for k := 2; k < n; k++ { + // pProj1[1] ← 2pProj1[1] and l0 the tangent ℓ passing 2pProj1[1] pProj1[k].doubleStep(&l0) + // line evaluation at Q[k] l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) } var tmp G1Affine for i := len(loopCounter0) - 3; i >= 1; i-- { // (∏ᵢfᵢ)² + // mutualize the square among n Miller loops result.Square(&result) j = loopCounter1[i]*3 + loopCounter0[i] for k := 0; k < n; k++ { + // pProj1[1] ← 2pProj1[1] and l0 the tangent ℓ passing 2pProj1[1] pProj1[k].doubleStep(&l0) + // line evaluation at Q[k] l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) switch j { case -4: tmp.Neg(&p01[k]) + // pProj1[k] ← pProj1[k]-p01[k] and + // l the line ℓ passing pProj1[k] and -p01[k] pProj1[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case -3: tmp.Neg(&p1[k]) + // pProj1[k] ← pProj1[k]-p1[k] and + // l the line ℓ passing pProj1[k] and -p1[k] pProj1[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case -2: + // pProj1[k] ← pProj1[k]+p10[k] and + // l the line ℓ passing pProj1[k] and p10[k] pProj1[k].addMixedStep(&l, &p10[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case -1: tmp.Neg(&p0[k]) + // pProj1[k] ← pProj1[k]-p0[k] and + // l the line ℓ passing pProj1[k] and -p0[k] pProj1[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 0: + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) case 1: + // pProj1[k] ← pProj1[k]+p0[k] and + // l the line ℓ passing pProj1[k] and p0[k] pProj1[k].addMixedStep(&l, &p0[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 2: tmp.Neg(&p10[k]) + // pProj1[k] ← pProj1[k]-p10[k] and + // l the line ℓ passing pProj1[k] and -p10[k] pProj1[k].addMixedStep(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 3: + // pProj1[k] ← pProj1[k]+p1[k] and + // l the line ℓ passing pProj1[k] and p1[k] pProj1[k].addMixedStep(&l, &p1[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) case 4: + // pProj1[k] ← pProj1[k]+p01[k] and + // l the line ℓ passing pProj1[k] and p01[k] pProj1[k].addMixedStep(&l, &p01[k]) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l01[k].r0, &l01[k].r1, &l01[k].r2) + // ℓ × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy01234(&prodLines) default: return GT{}, errors.New("invalid loopCounter") @@ -313,17 +377,25 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } } - // i = 0 + // i = 0, separately to avoid a point addition + // j = -3 result.Square(&result) for k := 0; k < n; k++ { + // pProj1[k] ← 2pProj1[k] and l0 the tangent ℓ passing 2pProj1[k] pProj1[k].doubleStep(&l0) + // line evaluation at Q[k] l0.r1.Mul(&l0.r1, &q[k].X) l0.r0.Mul(&l0.r0, &q[k].Y) + tmp.Neg(&p1[k]) + // l the line passing pProj1[k] and -p1 pProj1[k].lineCompute(&l, &tmp) + // line evaluation at Q[k] l.r1.Mul(&l.r1, &q[k].X) l.r0.Mul(&l.r0, &q[k].Y) + // ℓ × ℓ prodLines = fptower.Mul034By034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + // (ℓ × ℓ) × res result.MulBy034(&l0.r0, &l0.r1, &l0.r2) } From 4163c05ac4f644cd11e591f733ba20f74533985d Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sun, 26 Mar 2023 13:19:25 +0000 Subject: [PATCH 17/18] fix: code generation fp6 --- ecc/bls12-377/internal/fptower/e6.go | 28 ++++++++++ ecc/bls12-381/internal/fptower/e6.go | 56 +++++++++---------- ecc/bn254/internal/fptower/e6.go | 28 ++++++++++ .../tower/template/fq12over6over2/fq6.go.tmpl | 28 ++++++++++ 4 files changed, 112 insertions(+), 28 deletions(-) diff --git a/ecc/bls12-377/internal/fptower/e6.go b/ecc/bls12-377/internal/fptower/e6.go index 8ae7216ec..d4f80de95 100644 --- a/ecc/bls12-377/internal/fptower/e6.go +++ b/ecc/bls12-377/internal/fptower/e6.go @@ -126,6 +126,34 @@ func (z *E6) MulByE2(x *E6, y *E2) *E6 { return z } +// MulBy12 multiplication by sparse element (0,b1,b2) +func (x *E6) MulBy12(b1, b2 *E2) *E6 { + var t1, t2, c0, tmp, c1, c2 E2 + t1.Mul(&x.B1, b1) + t2.Mul(&x.B2, b2) + c0.Add(&x.B1, &x.B2) + tmp.Add(b1, b2) + c0.Mul(&c0, &tmp) + c0.Sub(&c0, &t1) + c0.Sub(&c0, &t2) + c0.MulByNonResidue(&c0) + c1.Add(&x.B0, &x.B1) + c1.Mul(&c1, b1) + c1.Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + tmp.Add(&x.B0, &x.B2) + c2.Mul(b2, &tmp) + c2.Sub(&c2, &t2) + c2.Add(&c2, &t1) + + x.B0 = c0 + x.B1 = c1 + x.B2 = c2 + + return x +} + // MulBy01 multiplication by sparse element (c0,c1,0) func (z *E6) MulBy01(c0, c1 *E2) *E6 { diff --git a/ecc/bls12-381/internal/fptower/e6.go b/ecc/bls12-381/internal/fptower/e6.go index 698e6ec15..d4f80de95 100644 --- a/ecc/bls12-381/internal/fptower/e6.go +++ b/ecc/bls12-381/internal/fptower/e6.go @@ -126,6 +126,34 @@ func (z *E6) MulByE2(x *E6, y *E2) *E6 { return z } +// MulBy12 multiplication by sparse element (0,b1,b2) +func (x *E6) MulBy12(b1, b2 *E2) *E6 { + var t1, t2, c0, tmp, c1, c2 E2 + t1.Mul(&x.B1, b1) + t2.Mul(&x.B2, b2) + c0.Add(&x.B1, &x.B2) + tmp.Add(b1, b2) + c0.Mul(&c0, &tmp) + c0.Sub(&c0, &t1) + c0.Sub(&c0, &t2) + c0.MulByNonResidue(&c0) + c1.Add(&x.B0, &x.B1) + c1.Mul(&c1, b1) + c1.Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + tmp.Add(&x.B0, &x.B2) + c2.Mul(b2, &tmp) + c2.Sub(&c2, &t2) + c2.Add(&c2, &t1) + + x.B0 = c0 + x.B1 = c1 + x.B2 = c2 + + return x +} + // MulBy01 multiplication by sparse element (c0,c1,0) func (z *E6) MulBy01(c0, c1 *E2) *E6 { @@ -180,34 +208,6 @@ func (z *E6) MulBy1(c1 *E2) *E6 { return z } -// MulBy12 multiplication by sparse element (0,b1,b2) -func (x *E6) MulBy12(b1, b2 *E2) *E6 { - var t1, t2, c0, tmp, c1, c2 E2 - t1.Mul(&x.B1, b1) - t2.Mul(&x.B2, b2) - c0.Add(&x.B1, &x.B2) - tmp.Add(b1, b2) - c0.Mul(&c0, &tmp) - c0.Sub(&c0, &t1) - c0.Sub(&c0, &t2) - c0.MulByNonResidue(&c0) - c1.Add(&x.B0, &x.B1) - c1.Mul(&c1, b1) - c1.Sub(&c1, &t1) - tmp.MulByNonResidue(&t2) - c1.Add(&c1, &tmp) - tmp.Add(&x.B0, &x.B2) - c2.Mul(b2, &tmp) - c2.Sub(&c2, &t2) - c2.Add(&c2, &t1) - - x.B0 = c0 - x.B1 = c1 - x.B2 = c2 - - return x -} - // Mul sets z to the E6 product of x,y, returns z func (z *E6) Mul(x, y *E6) *E6 { // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf diff --git a/ecc/bn254/internal/fptower/e6.go b/ecc/bn254/internal/fptower/e6.go index 8ae7216ec..d4f80de95 100644 --- a/ecc/bn254/internal/fptower/e6.go +++ b/ecc/bn254/internal/fptower/e6.go @@ -126,6 +126,34 @@ func (z *E6) MulByE2(x *E6, y *E2) *E6 { return z } +// MulBy12 multiplication by sparse element (0,b1,b2) +func (x *E6) MulBy12(b1, b2 *E2) *E6 { + var t1, t2, c0, tmp, c1, c2 E2 + t1.Mul(&x.B1, b1) + t2.Mul(&x.B2, b2) + c0.Add(&x.B1, &x.B2) + tmp.Add(b1, b2) + c0.Mul(&c0, &tmp) + c0.Sub(&c0, &t1) + c0.Sub(&c0, &t2) + c0.MulByNonResidue(&c0) + c1.Add(&x.B0, &x.B1) + c1.Mul(&c1, b1) + c1.Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + tmp.Add(&x.B0, &x.B2) + c2.Mul(b2, &tmp) + c2.Sub(&c2, &t2) + c2.Add(&c2, &t1) + + x.B0 = c0 + x.B1 = c1 + x.B2 = c2 + + return x +} + // MulBy01 multiplication by sparse element (c0,c1,0) func (z *E6) MulBy01(c0, c1 *E2) *E6 { diff --git a/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl index c48ffe575..347f00f37 100644 --- a/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl @@ -108,6 +108,34 @@ func (z *E6) MulByE2(x *E6, y *E2) *E6 { return z } +// MulBy12 multiplication by sparse element (0,b1,b2) +func (x *E6) MulBy12(b1, b2 *E2) *E6 { + var t1, t2, c0, tmp, c1, c2 E2 + t1.Mul(&x.B1, b1) + t2.Mul(&x.B2, b2) + c0.Add(&x.B1, &x.B2) + tmp.Add(b1, b2) + c0.Mul(&c0, &tmp) + c0.Sub(&c0, &t1) + c0.Sub(&c0, &t2) + c0.MulByNonResidue(&c0) + c1.Add(&x.B0, &x.B1) + c1.Mul(&c1, b1) + c1.Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + tmp.Add(&x.B0, &x.B2) + c2.Mul(b2, &tmp) + c2.Sub(&c2, &t2) + c2.Add(&c2, &t1) + + x.B0 = c0 + x.B1 = c1 + x.B2 = c2 + + return x +} + // MulBy01 multiplication by sparse element (c0,c1,0) func (z *E6) MulBy01(c0, c1 *E2) *E6 { From 0805f8b44439a965406005e3dad00f9a021ad851 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sun, 26 Mar 2023 14:17:28 +0000 Subject: [PATCH 18/18] fix(MillerLoop): return 1 when size(pairs)=0 after infinity filter --- ecc/bls12-377/pairing.go | 27 +++++++++++--------- ecc/bls12-378/pairing.go | 27 +++++++++++--------- ecc/bls12-381/pairing.go | 55 +++++++++++++++++++++------------------- ecc/bls24-315/pairing.go | 27 +++++++++++--------- ecc/bls24-317/pairing.go | 27 +++++++++++--------- ecc/bn254/pairing.go | 27 +++++++++++--------- ecc/bw6-633/pairing.go | 27 +++++++++++--------- ecc/bw6-756/pairing.go | 27 +++++++++++--------- ecc/bw6-761/pairing.go | 27 +++++++++++--------- 9 files changed, 149 insertions(+), 122 deletions(-) diff --git a/ecc/bls12-377/pairing.go b/ecc/bls12-377/pairing.go index cb60c8dd1..ede3a0380 100644 --- a/ecc/bls12-377/pairing.go +++ b/ecc/bls12-377/pairing.go @@ -133,22 +133,25 @@ 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) } - // 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) + 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) + } if n >= 2 { // k = 1, separately to avoid MulBy034 (res × ℓ) diff --git a/ecc/bls12-378/pairing.go b/ecc/bls12-378/pairing.go index ab43ff0c4..179694408 100644 --- a/ecc/bls12-378/pairing.go +++ b/ecc/bls12-378/pairing.go @@ -132,22 +132,25 @@ 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) } - // i = 62, separately to avoid an E12 Square - // (Square(res) = 1² = 1) - // loopCounter[62] = 0 - // k = 0, separately to avoid MulBy014 (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.Set(&l1.r0) - result.C0.B1.MulByElement(&l1.r1, &p[0].X) - result.C1.B1.MulByElement(&l1.r2, &p[0].Y) + if n >= 1 { + // i = 62, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[62] = 0 + // k = 0, separately to avoid MulBy014 (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.Set(&l1.r0) + result.C0.B1.MulByElement(&l1.r1, &p[0].X) + result.C1.B1.MulByElement(&l1.r2, &p[0].Y) + } if n >= 2 { // k = 1, separately to avoid MulBy014 (res × ℓ) diff --git a/ecc/bls12-381/pairing.go b/ecc/bls12-381/pairing.go index a22b03e00..4c2c867f8 100644 --- a/ecc/bls12-381/pairing.go +++ b/ecc/bls12-381/pairing.go @@ -132,36 +132,39 @@ 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) } - // i = 62, separately to avoid an E12 Square - // (Square(res) = 1² = 1) - // loopCounter[62] = 1 - // k = 0, separately to avoid MulBy014 (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.Set(&l1.r0) - result.C0.B1.MulByElement(&l1.r1, &p[0].X) - result.C1.B1.MulByElement(&l1.r2, &p[0].Y) - - // qProj[0] ← qProj[0]+Q[0] and - // l2 the line ℓ passing qProj[0] and Q[0] - qProj[0].addMixedStep(&l2, &q[0]) - // line evaluation at P[0] (assign) - l2.r1.MulByElement(&l2.r1, &p[0].X) - l2.r2.MulByElement(&l2.r2, &p[0].Y) - // ℓ × res - prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) - result.C0.B0 = prodLines[0] - result.C0.B1 = prodLines[1] - result.C0.B2 = prodLines[2] - result.C1.B1 = prodLines[3] - result.C1.B2 = prodLines[4] + if n >= 1 { + // i = 62, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[62] = 1 + // k = 0, separately to avoid MulBy014 (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.Set(&l1.r0) + result.C0.B1.MulByElement(&l1.r1, &p[0].X) + result.C1.B1.MulByElement(&l1.r2, &p[0].Y) + + // qProj[0] ← qProj[0]+Q[0] and + // l2 the line ℓ passing qProj[0] and Q[0] + qProj[0].addMixedStep(&l2, &q[0]) + // line evaluation at P[0] (assign) + l2.r1.MulByElement(&l2.r1, &p[0].X) + l2.r2.MulByElement(&l2.r2, &p[0].Y) + // ℓ × res + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) + result.C0.B0 = prodLines[0] + result.C0.B1 = prodLines[1] + result.C0.B2 = prodLines[2] + result.C1.B1 = prodLines[3] + result.C1.B2 = prodLines[4] + } // k >= 1 for k := 1; k < n; k++ { diff --git a/ecc/bls24-315/pairing.go b/ecc/bls24-315/pairing.go index e1adc4df8..1ef5569e1 100644 --- a/ecc/bls24-315/pairing.go +++ b/ecc/bls24-315/pairing.go @@ -143,22 +143,25 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result GT + result.SetOne() var l1, l2 lineEvaluation var prodLines [5]fptower.E4 // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } - // i = 31, separately to avoid an E12 Square - // (Square(res) = 1² = 1) - // loopCounter[31] = 0 - // k = 0, separately to avoid MulBy014 (res × ℓ) - // (assign line to res) - - // qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0] qProj[0].doubleStep(&l1) - qProj[0].doubleStep(&l1) - // line evaluation at P[0] (assign) - result.D0.C0.MulByElement(&l1.r0, &p[0].Y) - result.D1.C0.MulByElement(&l1.r1, &p[0].X) - result.D1.C1.Set(&l1.r2) + if n >= 1 { + // i = 31, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[31] = 0 + // k = 0, separately to avoid MulBy014 (res × ℓ) + // (assign line to res) + + // qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0] qProj[0].doubleStep(&l1) + qProj[0].doubleStep(&l1) + // line evaluation at P[0] (assign) + result.D0.C0.MulByElement(&l1.r0, &p[0].Y) + result.D1.C0.MulByElement(&l1.r1, &p[0].X) + result.D1.C1.Set(&l1.r2) + } if n >= 2 { // k = 1, separately to avoid MulBy014 (res × ℓ) diff --git a/ecc/bls24-317/pairing.go b/ecc/bls24-317/pairing.go index bffd182f2..c82e7e63f 100644 --- a/ecc/bls24-317/pairing.go +++ b/ecc/bls24-317/pairing.go @@ -147,22 +147,25 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result GT + result.SetOne() var l1, l2 lineEvaluation var prodLines [5]fptower.E4 // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } - // i = 31, separately to avoid an E12 Square - // (Square(res) = 1² = 1) - // loopCounter[31] = 0 - // k = 0, separately to avoid MulBy014 (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.D0.C0.Set(&l1.r0) - result.D0.C1.MulByElement(&l1.r1, &p[0].X) - result.D1.C1.MulByElement(&l1.r2, &p[0].Y) + if n >= 1 { + // i = 31, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[31] = 0 + // k = 0, separately to avoid MulBy014 (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.D0.C0.Set(&l1.r0) + result.D0.C1.MulByElement(&l1.r1, &p[0].X) + result.D1.C1.MulByElement(&l1.r2, &p[0].Y) + } if n >= 2 { // k = 1, separately to avoid MulBy014 (res × ℓ) diff --git a/ecc/bn254/pairing.go b/ecc/bn254/pairing.go index e3ec86c59..44a87ca61 100644 --- a/ecc/bn254/pairing.go +++ b/ecc/bn254/pairing.go @@ -140,22 +140,25 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { } var result GT + result.SetOne() var l2, l1 lineEvaluation var prodLines [5]E2 // Compute ∏ᵢ { fᵢ_{6x₀+2,Q}(P) } - // i = 64, separately to avoid an E12 Square - // (Square(res) = 1² = 1) - // loopCounter[64] = 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) + if n >= 1 { + // i = 64, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[64] = 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) + } if n >= 2 { // k = 1, separately to avoid MulBy034 (res × ℓ) diff --git a/ecc/bw6-633/pairing.go b/ecc/bw6-633/pairing.go index 4fefec3ad..27fb49be9 100644 --- a/ecc/bw6-633/pairing.go +++ b/ecc/bw6-633/pairing.go @@ -229,23 +229,26 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // f_{a0+λ*a1,P}(Q) var result GT + result.SetOne() var l, l0 lineEvaluation var prodLines [5]fp.Element var j int8 - // i = len(loopCounter0) - 2, separately to avoid an E12 Square - // (Square(res) = 1² = 1) - // j = 0 - // k = 0, separately to avoid MulBy034 (res × ℓ) - // (assign line to res) - - // pProj0[0] ← 2pProj0[0] and l0 the tangent ℓ passing 2pProj0[0] - pProj0[0].doubleStep(&l0) - // line evaluation at Q[0] (assign) - result.B1.A0.Mul(&l0.r1, &q[0].X) - result.B0.A0.Mul(&l0.r0, &q[0].Y) - result.B1.A1.Set(&l0.r2) + if n >= 1 { + // i = len(loopCounter0) - 2, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // j = 0 + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + + // pProj0[0] ← 2pProj0[0] and l0 the tangent ℓ passing 2pProj0[0] + pProj0[0].doubleStep(&l0) + // line evaluation at Q[0] (assign) + result.B1.A0.Mul(&l0.r1, &q[0].X) + result.B0.A0.Mul(&l0.r0, &q[0].Y) + result.B1.A1.Set(&l0.r2) + } // k = 1 if n >= 2 { diff --git a/ecc/bw6-756/pairing.go b/ecc/bw6-756/pairing.go index 171a19700..9a3bc5b4c 100644 --- a/ecc/bw6-756/pairing.go +++ b/ecc/bw6-756/pairing.go @@ -209,23 +209,26 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // f_{a0+λ*a1,P}(Q) var result GT + result.SetOne() var l, l0 lineEvaluation var prodLines [5]fp.Element var j int8 - // i = len(loopCounter0) - 2, separately to avoid an E12 Square - // (Square(res) = 1² = 1) - // j = 0 - // k = 0, separately to avoid MulBy034 (res × ℓ) - // (assign line to res) - - // pProj1[0] ← 2pProj1[0] and l0 the tangent ℓ passing 2pProj1[0] - pProj1[0].doubleStep(&l0) - // line evaluation at Q[0] (assign) - result.B1.A0.Mul(&l0.r1, &q[0].X) - result.B0.A0.Mul(&l0.r0, &q[0].Y) - result.B1.A1.Set(&l0.r2) + if n >= 1 { + // i = len(loopCounter0) - 2, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // j = 0 + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + + // pProj1[0] ← 2pProj1[0] and l0 the tangent ℓ passing 2pProj1[0] + pProj1[0].doubleStep(&l0) + // line evaluation at Q[0] (assign) + result.B1.A0.Mul(&l0.r1, &q[0].X) + result.B0.A0.Mul(&l0.r0, &q[0].Y) + result.B1.A1.Set(&l0.r2) + } // k = 1 if n >= 2 { diff --git a/ecc/bw6-761/pairing.go b/ecc/bw6-761/pairing.go index efa194ada..a5bad7733 100644 --- a/ecc/bw6-761/pairing.go +++ b/ecc/bw6-761/pairing.go @@ -207,23 +207,26 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // f_{a0+λ*a1,P}(Q) var result GT + result.SetOne() var l, l0 lineEvaluation var prodLines [5]fp.Element var j int8 - // i = len(loopCounter0) - 2, separately to avoid an E12 Square - // (Square(res) = 1² = 1) - // j = 0 - // k = 0, separately to avoid MulBy034 (res × ℓ) - // (assign line to res) - - // pProj1[0] ← 2pProj1[0] and l0 the tangent ℓ passing 2pProj1[0] - pProj1[0].doubleStep(&l0) - // line evaluation at Q[0] (assign) - result.B1.A0.Mul(&l0.r1, &q[0].X) - result.B0.A0.Mul(&l0.r0, &q[0].Y) - result.B1.A1.Set(&l0.r2) + if n >= 1 { + // i = len(loopCounter0) - 2, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // j = 0 + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + + // pProj1[0] ← 2pProj1[0] and l0 the tangent ℓ passing 2pProj1[0] + pProj1[0].doubleStep(&l0) + // line evaluation at Q[0] (assign) + result.B1.A0.Mul(&l0.r1, &q[0].X) + result.B0.A0.Mul(&l0.r0, &q[0].Y) + result.B1.A1.Set(&l0.r2) + } // k = 1 if n >= 2 {