github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-377/pairing.go (about)

     1  // Copyright 2020 ConsenSys AG
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package bls12377
    16  
    17  import (
    18  	"errors"
    19  
    20  	"github.com/consensys/gnark-crypto/ecc/bls12-377/fp"
    21  	"github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower"
    22  )
    23  
    24  // GT target group of the pairing
    25  type GT = fptower.E12
    26  
    27  type lineEvaluation struct {
    28  	r0 fptower.E2
    29  	r1 fptower.E2
    30  	r2 fptower.E2
    31  }
    32  
    33  // Pair calculates the reduced pairing for a set of points
    34  // ∏ᵢ e(Pᵢ, Qᵢ).
    35  //
    36  // This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup.
    37  func Pair(P []G1Affine, Q []G2Affine) (GT, error) {
    38  	f, err := MillerLoop(P, Q)
    39  	if err != nil {
    40  		return GT{}, err
    41  	}
    42  	return FinalExponentiation(&f), nil
    43  }
    44  
    45  // PairingCheck calculates the reduced pairing for a set of points and returns True if the result is One
    46  // ∏ᵢ e(Pᵢ, Qᵢ) =? 1
    47  //
    48  // This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup.
    49  func PairingCheck(P []G1Affine, Q []G2Affine) (bool, error) {
    50  	f, err := Pair(P, Q)
    51  	if err != nil {
    52  		return false, err
    53  	}
    54  	var one GT
    55  	one.SetOne()
    56  	return f.Equal(&one), nil
    57  }
    58  
    59  // FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ
    60  // where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r
    61  // we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r
    62  // where s is the cofactor 3 (Hayashida et al.)
    63  func FinalExponentiation(z *GT, _z ...*GT) GT {
    64  
    65  	var result GT
    66  	result.Set(z)
    67  
    68  	for _, e := range _z {
    69  		result.Mul(&result, e)
    70  	}
    71  
    72  	var t [3]GT
    73  
    74  	// Easy part
    75  	// (p⁶-1)(p²+1)
    76  	t[0].Conjugate(&result)
    77  	result.Inverse(&result)
    78  	t[0].Mul(&t[0], &result)
    79  	result.FrobeniusSquare(&t[0]).
    80  		Mul(&result, &t[0])
    81  
    82  	var one GT
    83  	one.SetOne()
    84  	if result.Equal(&one) {
    85  		return result
    86  	}
    87  
    88  	// Hard part (up to permutation)
    89  	// Daiki Hayashida, Kenichiro Hayasaka and Tadanori Teruya
    90  	// https://eprint.iacr.org/2020/875.pdf
    91  	t[0].CyclotomicSquare(&result)
    92  	t[1].Expt(&result)
    93  	t[2].InverseUnitary(&result)
    94  	t[1].Mul(&t[1], &t[2])
    95  	t[2].Expt(&t[1])
    96  	t[1].InverseUnitary(&t[1])
    97  	t[1].Mul(&t[1], &t[2])
    98  	t[2].Expt(&t[1])
    99  	t[1].Frobenius(&t[1])
   100  	t[1].Mul(&t[1], &t[2])
   101  	result.Mul(&result, &t[0])
   102  	t[0].Expt(&t[1])
   103  	t[2].Expt(&t[0])
   104  	t[0].FrobeniusSquare(&t[1])
   105  	t[1].InverseUnitary(&t[1])
   106  	t[1].Mul(&t[1], &t[2])
   107  	t[1].Mul(&t[1], &t[0])
   108  	result.Mul(&result, &t[1])
   109  
   110  	return result
   111  }
   112  
   113  // MillerLoop computes the multi-Miller loop
   114  // ∏ᵢ MillerLoop(Pᵢ, Qᵢ) = ∏ᵢ { fᵢ_{x,Qᵢ}(Pᵢ) }
   115  func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) {
   116  	// check input size match
   117  	n := len(P)
   118  	if n == 0 || n != len(Q) {
   119  		return GT{}, errors.New("invalid inputs sizes")
   120  	}
   121  
   122  	// filter infinity points
   123  	p := make([]G1Affine, 0, n)
   124  	q := make([]G2Affine, 0, n)
   125  
   126  	for k := 0; k < n; k++ {
   127  		if P[k].IsInfinity() || Q[k].IsInfinity() {
   128  			continue
   129  		}
   130  		p = append(p, P[k])
   131  		q = append(q, Q[k])
   132  	}
   133  
   134  	n = len(p)
   135  
   136  	// projective points for Q
   137  	qProj := make([]g2Proj, n)
   138  	for k := 0; k < n; k++ {
   139  		qProj[k].FromAffine(&q[k])
   140  	}
   141  
   142  	var result GT
   143  	result.SetOne()
   144  	var l1, l2 lineEvaluation
   145  	var prodLines [5]E2
   146  
   147  	// Compute ∏ᵢ { fᵢ_{x₀,Q}(P) }
   148  	if n >= 1 {
   149  		// i = 62, separately to avoid an E12 Square
   150  		// (Square(res) = 1² = 1)
   151  		// LoopCounter[62] = 0
   152  		// k = 0, separately to avoid MulBy034 (res × ℓ)
   153  		// (assign line to res)
   154  
   155  		// qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0]
   156  		qProj[0].doubleStep(&l1)
   157  		// line evaluation at P[0] (assign)
   158  		result.C0.B0.MulByElement(&l1.r0, &p[0].Y)
   159  		result.C1.B0.MulByElement(&l1.r1, &p[0].X)
   160  		result.C1.B1.Set(&l1.r2)
   161  	}
   162  
   163  	if n >= 2 {
   164  		// k = 1, separately to avoid MulBy034 (res × ℓ)
   165  		// (res is also a line at this point, so we use Mul034By034 ℓ × ℓ)
   166  
   167  		// qProj[1] ← 2qProj[1] and l1 the tangent ℓ passing 2qProj[1]
   168  		qProj[1].doubleStep(&l1)
   169  		// line evaluation at P[1]
   170  		l1.r0.MulByElement(&l1.r0, &p[1].Y)
   171  		l1.r1.MulByElement(&l1.r1, &p[1].X)
   172  		// ℓ × res
   173  		prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &result.C0.B0, &result.C1.B0, &result.C1.B1)
   174  		result.C0.B0 = prodLines[0]
   175  		result.C0.B1 = prodLines[1]
   176  		result.C0.B2 = prodLines[2]
   177  		result.C1.B0 = prodLines[3]
   178  		result.C1.B1 = prodLines[4]
   179  	}
   180  
   181  	// k >= 2
   182  	for k := 2; k < n; k++ {
   183  		// qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k]
   184  		qProj[k].doubleStep(&l1)
   185  		// line evaluation at P[k]
   186  		l1.r0.MulByElement(&l1.r0, &p[k].Y)
   187  		l1.r1.MulByElement(&l1.r1, &p[k].X)
   188  		// ℓ × res
   189  		result.MulBy034(&l1.r0, &l1.r1, &l1.r2)
   190  	}
   191  
   192  	// i <= 61
   193  	for i := len(LoopCounter) - 3; i >= 1; i-- {
   194  		// mutualize the square among n Miller loops
   195  		// (∏ᵢfᵢ)²
   196  		result.Square(&result)
   197  
   198  		for k := 0; k < n; k++ {
   199  			// qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k]
   200  			qProj[k].doubleStep(&l1)
   201  			// line evaluation at P[k]
   202  			l1.r0.MulByElement(&l1.r0, &p[k].Y)
   203  			l1.r1.MulByElement(&l1.r1, &p[k].X)
   204  
   205  			if LoopCounter[i] == 0 {
   206  				// ℓ × res
   207  				result.MulBy034(&l1.r0, &l1.r1, &l1.r2)
   208  			} else {
   209  				// qProj[k] ← qProj[k]+Q[k] and
   210  				// l2 the line ℓ passing qProj[k] and Q[k]
   211  				qProj[k].addMixedStep(&l2, &q[k])
   212  				// line evaluation at P[k]
   213  				l2.r0.MulByElement(&l2.r0, &p[k].Y)
   214  				l2.r1.MulByElement(&l2.r1, &p[k].X)
   215  				// ℓ × ℓ
   216  				prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2)
   217  				// (ℓ × ℓ) × res
   218  				result.MulBy01234(&prodLines)
   219  			}
   220  		}
   221  
   222  	}
   223  
   224  	// i = 0, separately to avoid a point addition
   225  	// LoopCounter[0] = 1
   226  	result.Square(&result)
   227  	for k := 0; k < n; k++ {
   228  		// qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k]
   229  		qProj[k].doubleStep(&l1)
   230  		// line evaluation at P[k]
   231  		l1.r0.MulByElement(&l1.r0, &p[k].Y)
   232  		l1.r1.MulByElement(&l1.r1, &p[k].X)
   233  
   234  		// l2 the line passing qProj[k] and Q
   235  		qProj[k].lineCompute(&l2, &q[k])
   236  		// line evaluation at P[k]
   237  		l2.r0.MulByElement(&l2.r0, &p[k].Y)
   238  		l2.r1.MulByElement(&l2.r1, &p[k].X)
   239  		// ℓ × ℓ
   240  		prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2)
   241  		// (ℓ × ℓ) × res
   242  		result.MulBy01234(&prodLines)
   243  	}
   244  
   245  	return result, nil
   246  }
   247  
   248  // doubleStep doubles a point in Homogenous projective coordinates, and evaluates the line in Miller loop
   249  // https://eprint.iacr.org/2013/722.pdf (Section 4.3)
   250  func (p *g2Proj) doubleStep(evaluations *lineEvaluation) {
   251  
   252  	// get some Element from our pool
   253  	var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2
   254  	A.Mul(&p.x, &p.y)
   255  	A.Halve()
   256  	B.Square(&p.y)
   257  	C.Square(&p.z)
   258  	D.Double(&C).
   259  		Add(&D, &C)
   260  	E.MulBybTwistCurveCoeff(&D)
   261  	F.Double(&E).
   262  		Add(&F, &E)
   263  	G.Add(&B, &F)
   264  	G.Halve()
   265  	H.Add(&p.y, &p.z).
   266  		Square(&H)
   267  	t1.Add(&B, &C)
   268  	H.Sub(&H, &t1)
   269  	I.Sub(&E, &B)
   270  	J.Square(&p.x)
   271  	EE.Square(&E)
   272  	K.Double(&EE).
   273  		Add(&K, &EE)
   274  
   275  	// X, Y, Z
   276  	p.x.Sub(&B, &F).
   277  		Mul(&p.x, &A)
   278  	p.y.Square(&G).
   279  		Sub(&p.y, &K)
   280  	p.z.Mul(&B, &H)
   281  
   282  	// Line evaluation
   283  	evaluations.r0.Neg(&H)
   284  	evaluations.r1.Double(&J).
   285  		Add(&evaluations.r1, &J)
   286  	evaluations.r2.Set(&I)
   287  }
   288  
   289  // addMixedStep point addition in Mixed Homogenous projective and Affine coordinates
   290  // https://eprint.iacr.org/2013/722.pdf (Section 4.3)
   291  func (p *g2Proj) addMixedStep(evaluations *lineEvaluation, a *G2Affine) {
   292  
   293  	// get some Element from our pool
   294  	var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2
   295  	Y2Z1.Mul(&a.Y, &p.z)
   296  	O.Sub(&p.y, &Y2Z1)
   297  	X2Z1.Mul(&a.X, &p.z)
   298  	L.Sub(&p.x, &X2Z1)
   299  	C.Square(&O)
   300  	D.Square(&L)
   301  	E.Mul(&L, &D)
   302  	F.Mul(&p.z, &C)
   303  	G.Mul(&p.x, &D)
   304  	t0.Double(&G)
   305  	H.Add(&E, &F).
   306  		Sub(&H, &t0)
   307  	t1.Mul(&p.y, &E)
   308  
   309  	// X, Y, Z
   310  	p.x.Mul(&L, &H)
   311  	p.y.Sub(&G, &H).
   312  		Mul(&p.y, &O).
   313  		Sub(&p.y, &t1)
   314  	p.z.Mul(&E, &p.z)
   315  
   316  	t2.Mul(&L, &a.Y)
   317  	J.Mul(&a.X, &O).
   318  		Sub(&J, &t2)
   319  
   320  	// Line evaluation
   321  	evaluations.r0.Set(&L)
   322  	evaluations.r1.Neg(&O)
   323  	evaluations.r2.Set(&J)
   324  }
   325  
   326  // lineCompute computes the line through p in Homogenous projective coordinates
   327  // and a in affine coordinates. It does not compute the resulting point p+a.
   328  func (p *g2Proj) lineCompute(evaluations *lineEvaluation, a *G2Affine) {
   329  
   330  	// get some Element from our pool
   331  	var Y2Z1, X2Z1, O, L, t2, J fptower.E2
   332  	Y2Z1.Mul(&a.Y, &p.z)
   333  	O.Sub(&p.y, &Y2Z1)
   334  	X2Z1.Mul(&a.X, &p.z)
   335  	L.Sub(&p.x, &X2Z1)
   336  	t2.Mul(&L, &a.Y)
   337  	J.Mul(&a.X, &O).
   338  		Sub(&J, &t2)
   339  
   340  	// Line evaluation
   341  	evaluations.r0.Set(&L)
   342  	evaluations.r1.Neg(&O)
   343  	evaluations.r2.Set(&J)
   344  }
   345  
   346  // ----------------------
   347  // Fixed-argument pairing
   348  // ----------------------
   349  
   350  type LineEvaluationAff struct {
   351  	R0 fptower.E2
   352  	R1 fptower.E2
   353  }
   354  
   355  // PairFixedQ calculates the reduced pairing for a set of points
   356  // ∏ᵢ e(Pᵢ, Qᵢ) where Q are fixed points in G2.
   357  //
   358  // This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup.
   359  func PairFixedQ(P []G1Affine, lines [][2][len(LoopCounter) - 1]LineEvaluationAff) (GT, error) {
   360  	f, err := MillerLoopFixedQ(P, lines)
   361  	if err != nil {
   362  		return GT{}, err
   363  	}
   364  	return FinalExponentiation(&f), nil
   365  }
   366  
   367  // PairingCheckFixedQ calculates the reduced pairing for a set of points and returns True if the result is One
   368  // ∏ᵢ e(Pᵢ, Qᵢ) =? 1 where Q are fixed points in G2.
   369  //
   370  // This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup.
   371  func PairingCheckFixedQ(P []G1Affine, lines [][2][len(LoopCounter) - 1]LineEvaluationAff) (bool, error) {
   372  	f, err := PairFixedQ(P, lines)
   373  	if err != nil {
   374  		return false, err
   375  	}
   376  	var one GT
   377  	one.SetOne()
   378  	return f.Equal(&one), nil
   379  }
   380  
   381  // PrecomputeLines precomputes the lines for the fixed-argument Miller loop
   382  func PrecomputeLines(Q G2Affine) (PrecomputedLines [2][len(LoopCounter) - 1]LineEvaluationAff) {
   383  	var accQ G2Affine
   384  	accQ.Set(&Q)
   385  
   386  	for i := len(LoopCounter) - 2; i >= 0; i-- {
   387  		if LoopCounter[i] == 0 {
   388  			accQ.doubleStep(&PrecomputedLines[0][i])
   389  		} else {
   390  			accQ.doubleAndAddStep(&PrecomputedLines[0][i], &PrecomputedLines[1][i], &Q)
   391  		}
   392  	}
   393  	return PrecomputedLines
   394  }
   395  
   396  // MillerLoopFixedQ computes the multi-Miller loop as in MillerLoop
   397  // but Qᵢ are fixed points in G2 known in advance.
   398  func MillerLoopFixedQ(P []G1Affine, lines [][2][len(LoopCounter) - 1]LineEvaluationAff) (GT, error) {
   399  	n := len(P)
   400  	if n == 0 || n != len(lines) {
   401  		return GT{}, errors.New("invalid inputs sizes")
   402  	}
   403  
   404  	// no need to filter infinity points:
   405  	// 		1. if Pᵢ=(0,0) then -x/y=1/y=0 by gnark-crypto convention and so
   406  	// 		lines R0 and R1 are 0. At the end it happens that result will stay
   407  	// 		1 through the Miller loop because MulBy34(1,0,0)==1
   408  	// 		Mul34By34(1,0,0,1,0,0)==1 and MulBy01234(1,0,0,0,0)==1.
   409  	//
   410  	// 		2. if Qᵢ=(0,0) then PrecomputeLines(Qᵢ) will return lines R0 and R1
   411  	// 		that are 0 because of gnark-convention (*/0==0) in doubleStep and
   412  	// 		addStep. Similarly to Pᵢ=(0,0) it happens that result stays 1
   413  	// 		throughout the MillerLoop.
   414  
   415  	// precomputations
   416  	yInv := make([]fp.Element, n)
   417  	xNegOverY := make([]fp.Element, n)
   418  	for k := 0; k < n; k++ {
   419  		yInv[k].Set(&P[k].Y)
   420  	}
   421  	yInv = fp.BatchInvert(yInv)
   422  	for k := 0; k < n; k++ {
   423  		xNegOverY[k].Mul(&P[k].X, &yInv[k]).
   424  			Neg(&xNegOverY[k])
   425  	}
   426  
   427  	var result GT
   428  	result.SetOne()
   429  	var prodLines [5]E2
   430  
   431  	// Compute ∏ᵢ { fᵢ_{x₀,Q}(P) }
   432  	if n >= 1 {
   433  		// i = 62, separately to avoid an E12 Square
   434  		// (Square(res) = 1² = 1)
   435  		// LoopCounter[62] = 0
   436  		// k = 0, separately to avoid MulBy34 (res × ℓ)
   437  		// (assign line to res)
   438  
   439  		// line evaluation at P[0] (assign)
   440  		result.C1.B0.MulByElement(&lines[0][0][62].R0, &xNegOverY[0])
   441  		result.C1.B1.MulByElement(&lines[0][0][62].R1, &yInv[0])
   442  		// the coefficient which MulBy34 sets to 1 happens to be already 1 (result = 1)
   443  	}
   444  
   445  	if n >= 2 {
   446  		// k = 1, separately to avoid MulBy34 (res × ℓ)
   447  		// (res is also a line at this point, so we use Mul34By34 ℓ × ℓ)
   448  		// line evaluation at P[1]
   449  		lines[1][0][62].R0.MulByElement(&lines[1][0][62].R0, &xNegOverY[1])
   450  		lines[1][0][62].R1.MulByElement(&lines[1][0][62].R1, &yInv[1])
   451  		// ℓ × res
   452  		prodLines = fptower.Mul34By34(&lines[1][0][62].R0, &lines[1][0][62].R1, &result.C1.B0, &result.C1.B1)
   453  		result.C0.B0 = prodLines[0]
   454  		result.C0.B1 = prodLines[1]
   455  		result.C0.B2 = prodLines[2]
   456  		result.C1.B0 = prodLines[3]
   457  		result.C1.B1 = prodLines[4]
   458  	}
   459  
   460  	// k >= 2
   461  	for k := 2; k < n; k++ {
   462  		// line evaluation at P[k]
   463  		lines[k][0][62].R0.MulByElement(&lines[k][0][62].R0, &xNegOverY[k])
   464  		lines[k][0][62].R1.MulByElement(&lines[k][0][62].R1, &yInv[k])
   465  		// ℓ × res
   466  		result.MulBy34(
   467  			&lines[k][0][62].R0,
   468  			&lines[k][0][62].R1,
   469  		)
   470  	}
   471  
   472  	for i := len(LoopCounter) - 3; i >= 0; i-- {
   473  		// mutualize the square among n Miller loops
   474  		// (∏ᵢfᵢ)²
   475  		result.Square(&result)
   476  
   477  		for k := 0; k < n; k++ {
   478  			// line evaluation at P[k]
   479  			lines[k][0][i].R0.
   480  				MulByElement(
   481  					&lines[k][0][i].R0,
   482  					&xNegOverY[k],
   483  				)
   484  			lines[k][0][i].R1.
   485  				MulByElement(
   486  					&lines[k][0][i].R1,
   487  					&yInv[k],
   488  				)
   489  
   490  			if LoopCounter[i] == 0 {
   491  				// ℓ × res
   492  				result.MulBy34(
   493  					&lines[k][0][i].R0,
   494  					&lines[k][0][i].R1,
   495  				)
   496  			} else {
   497  				// line evaluation at P[k]
   498  				lines[k][1][i].R0.
   499  					MulByElement(
   500  						&lines[k][1][i].R0,
   501  						&xNegOverY[k],
   502  					)
   503  				lines[k][1][i].R1.
   504  					MulByElement(
   505  						&lines[k][1][i].R1,
   506  						&yInv[k],
   507  					)
   508  				// ℓ × ℓ
   509  				prodLines = fptower.Mul34By34(
   510  					&lines[k][0][i].R0, &lines[k][0][i].R1,
   511  					&lines[k][1][i].R0, &lines[k][1][i].R1,
   512  				)
   513  				// (ℓ × ℓ) × res
   514  				result.MulBy01234(&prodLines)
   515  			}
   516  		}
   517  	}
   518  
   519  	return result, nil
   520  }
   521  
   522  func (p *G2Affine) doubleStep(evaluations *LineEvaluationAff) {
   523  
   524  	var n, d, λ, xr, yr fptower.E2
   525  	// λ = 3x²/2y
   526  	n.Square(&p.X)
   527  	λ.Double(&n).
   528  		Add(&λ, &n)
   529  	d.Double(&p.Y)
   530  	λ.Div(&λ, &d)
   531  
   532  	// xr = λ²-2x
   533  	xr.Square(&λ).
   534  		Sub(&xr, &p.X).
   535  		Sub(&xr, &p.X)
   536  
   537  	// yr = λ(x-xr)-y
   538  	yr.Sub(&p.X, &xr).
   539  		Mul(&yr, &λ).
   540  		Sub(&yr, &p.Y)
   541  
   542  	evaluations.R0.Set(&λ)
   543  	evaluations.R1.Mul(&λ, &p.X).
   544  		Sub(&evaluations.R1, &p.Y)
   545  
   546  	p.X.Set(&xr)
   547  	p.Y.Set(&yr)
   548  }
   549  
   550  func (p *G2Affine) addStep(evaluations *LineEvaluationAff, a *G2Affine) {
   551  	var n, d, λ, λλ, xr, yr fptower.E2
   552  
   553  	// compute λ = (y2-y1)/(x2-x1)
   554  	n.Sub(&a.Y, &p.Y)
   555  	d.Sub(&a.X, &p.X)
   556  	λ.Div(&n, &d)
   557  
   558  	// xr = λ²-x1-x2
   559  	λλ.Square(&λ)
   560  	n.Add(&p.X, &a.X)
   561  	xr.Sub(&λλ, &n)
   562  
   563  	// yr = λ(x1-xr) - y1
   564  	yr.Sub(&p.X, &xr).
   565  		Mul(&yr, &λ).
   566  		Sub(&yr, &p.Y)
   567  
   568  	evaluations.R0.Set(&λ)
   569  	evaluations.R1.Mul(&λ, &p.X).
   570  		Sub(&evaluations.R1, &p.Y)
   571  
   572  	p.X.Set(&xr)
   573  	p.Y.Set(&yr)
   574  }
   575  
   576  func (p *G2Affine) doubleAndAddStep(evaluations1, evaluations2 *LineEvaluationAff, a *G2Affine) {
   577  	var n, d, l1, x3, l2, x4, y4 fptower.E2
   578  
   579  	// compute λ1 = (y2-y1)/(x2-x1)
   580  	n.Sub(&p.Y, &a.Y)
   581  	d.Sub(&p.X, &a.X)
   582  	l1.Div(&n, &d)
   583  
   584  	// compute x3 =λ1²-x1-x2
   585  	x3.Square(&l1)
   586  	x3.Sub(&x3, &p.X)
   587  	x3.Sub(&x3, &a.X)
   588  
   589  	// omit y3 computation
   590  
   591  	// compute line1
   592  	evaluations1.R0.Set(&l1)
   593  	evaluations1.R1.Mul(&l1, &p.X)
   594  	evaluations1.R1.Sub(&evaluations1.R1, &p.Y)
   595  
   596  	// compute λ2 = -λ1-2y1/(x3-x1)
   597  	n.Double(&p.Y)
   598  	d.Sub(&x3, &p.X)
   599  	l2.Div(&n, &d)
   600  	l2.Add(&l2, &l1)
   601  	l2.Neg(&l2)
   602  
   603  	// compute x4 = λ2²-x1-x3
   604  	x4.Square(&l2)
   605  	x4.Sub(&x4, &p.X)
   606  	x4.Sub(&x4, &x3)
   607  
   608  	// compute y4 = λ2(x1 - x4)-y1
   609  	y4.Sub(&p.X, &x4)
   610  	y4.Mul(&l2, &y4)
   611  	y4.Sub(&y4, &p.Y)
   612  
   613  	// compute line2
   614  	evaluations2.R0.Set(&l2)
   615  	evaluations2.R1.Mul(&l2, &p.X)
   616  	evaluations2.R1.Sub(&evaluations2.R1, &p.Y)
   617  
   618  	p.X.Set(&x4)
   619  	p.Y.Set(&y4)
   620  }