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