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