github.com/consensys/gnark-crypto@v0.14.0/ecc/stark-curve/g1.go (about)

     1  // Copyright 2020 ConsenSys Software Inc.
     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  // FOO
    16  
    17  package starkcurve
    18  
    19  import (
    20  	"math/big"
    21  
    22  	"github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
    23  	"github.com/consensys/gnark-crypto/ecc/stark-curve/fr"
    24  	"github.com/consensys/gnark-crypto/internal/parallel"
    25  )
    26  
    27  // G1Affine is a point in affine coordinates (x,y)
    28  type G1Affine struct {
    29  	X, Y fp.Element
    30  }
    31  
    32  // G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³)
    33  type G1Jac struct {
    34  	X, Y, Z fp.Element
    35  }
    36  
    37  // g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²)
    38  type g1JacExtended struct {
    39  	X, Y, ZZ, ZZZ fp.Element
    40  }
    41  
    42  // -------------------------------------------------------------------------------------------------
    43  // Affine coordinates
    44  
    45  // Set sets p to a in affine coordinates.
    46  func (p *G1Affine) Set(a *G1Affine) *G1Affine {
    47  	p.X, p.Y = a.X, a.Y
    48  	return p
    49  }
    50  
    51  // ScalarMultiplication computes and returns p = [s]a
    52  // where p and a are affine points.
    53  func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine {
    54  	var _p G1Jac
    55  	_p.FromAffine(a)
    56  	_p.mulWindowed(&_p, s)
    57  	p.FromJacobian(&_p)
    58  	return p
    59  }
    60  
    61  // ScalarMultiplicationBase computes and returns p = [s]g
    62  // where g is the affine point generating the prime subgroup.
    63  func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine {
    64  	var _p G1Jac
    65  	_p.mulWindowed(&g1Gen, s)
    66  	p.FromJacobian(&_p)
    67  	return p
    68  }
    69  
    70  // Add adds two points in affine coordinates.
    71  // It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates.
    72  //
    73  // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl
    74  func (p *G1Affine) Add(a, b *G1Affine) *G1Affine {
    75  	var p1, p2 G1Jac
    76  	p1.FromAffine(a)
    77  	p2.FromAffine(b)
    78  	p1.AddAssign(&p2)
    79  	p.FromJacobian(&p1)
    80  	return p
    81  }
    82  
    83  // Sub subtracts two points in affine coordinates.
    84  // It uses a similar approach to Add, but negates the second point before adding.
    85  func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine {
    86  	var p1, p2 G1Jac
    87  	p1.FromAffine(a)
    88  	p2.FromAffine(b)
    89  	p1.SubAssign(&p2)
    90  	p.FromJacobian(&p1)
    91  	return p
    92  }
    93  
    94  // Equal tests if two points in affine coordinates are equal.
    95  func (p *G1Affine) Equal(a *G1Affine) bool {
    96  	return p.X.Equal(&a.X) && p.Y.Equal(&a.Y)
    97  }
    98  
    99  // Neg sets p to the affine negative point -a = (a.X, -a.Y).
   100  func (p *G1Affine) Neg(a *G1Affine) *G1Affine {
   101  	p.X = a.X
   102  	p.Y.Neg(&a.Y)
   103  	return p
   104  }
   105  
   106  // FromJacobian converts a point p1 from Jacobian to affine coordinates.
   107  func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine {
   108  
   109  	var a, b fp.Element
   110  
   111  	if p1.Z.IsZero() {
   112  		p.X.SetZero()
   113  		p.Y.SetZero()
   114  		return p
   115  	}
   116  
   117  	a.Inverse(&p1.Z)
   118  	b.Square(&a)
   119  	p.X.Mul(&p1.X, &b)
   120  	p.Y.Mul(&p1.Y, &b).Mul(&p.Y, &a)
   121  
   122  	return p
   123  }
   124  
   125  // String returns the string representation E(x,y) of the affine point p or "O" if it is infinity.
   126  func (p *G1Affine) String() string {
   127  	if p.IsInfinity() {
   128  		return "O"
   129  	}
   130  	return "E([" + p.X.String() + "," + p.Y.String() + "])"
   131  }
   132  
   133  // IsInfinity checks if the affine point p is infinity, which is encoded as (0,0).
   134  // N.B.: (0,0) is not on the STARK curve (Y²=X³+X+B).
   135  func (p *G1Affine) IsInfinity() bool {
   136  	return p.X.IsZero() && p.Y.IsZero()
   137  }
   138  
   139  // IsOnCurve returns true if the affine point p in on the curve.
   140  func (p *G1Affine) IsOnCurve() bool {
   141  	var point G1Jac
   142  	point.FromAffine(p)
   143  	return point.IsOnCurve() // call this function to handle infinity point
   144  }
   145  
   146  // IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise.
   147  func (p *G1Affine) IsInSubGroup() bool {
   148  	var _p G1Jac
   149  	_p.FromAffine(p)
   150  	return _p.IsInSubGroup()
   151  }
   152  
   153  // -------------------------------------------------------------------------------------------------
   154  // Jacobian coordinates
   155  
   156  // Set sets p to a in Jacobian coordinates.
   157  func (p *G1Jac) Set(q *G1Jac) *G1Jac {
   158  	p.X, p.Y, p.Z = q.X, q.Y, q.Z
   159  	return p
   160  }
   161  
   162  // Equal tests if two points in Jacobian coordinates are equal.
   163  func (p *G1Jac) Equal(a *G1Jac) bool {
   164  
   165  	if p.Z.IsZero() && a.Z.IsZero() {
   166  		return true
   167  	}
   168  	_p := G1Affine{}
   169  	_p.FromJacobian(p)
   170  
   171  	_a := G1Affine{}
   172  	_a.FromJacobian(a)
   173  
   174  	return _p.X.Equal(&_a.X) && _p.Y.Equal(&_a.Y)
   175  }
   176  
   177  // Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z).
   178  func (p *G1Jac) Neg(q *G1Jac) *G1Jac {
   179  	*p = *q
   180  	p.Y.Neg(&q.Y)
   181  	return p
   182  }
   183  
   184  // SubAssign sets p to p-a in Jacobian coordinates.
   185  // It uses a similar approach to AddAssign, but negates the point a before adding.
   186  func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac {
   187  	var tmp G1Jac
   188  	tmp.Set(a)
   189  	tmp.Y.Neg(&tmp.Y)
   190  	p.AddAssign(&tmp)
   191  	return p
   192  }
   193  
   194  // AddAssign sets p to p+a in Jacobian coordinates.
   195  //
   196  // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
   197  func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac {
   198  
   199  	// p is infinity, return a
   200  	if p.Z.IsZero() {
   201  		p.Set(a)
   202  		return p
   203  	}
   204  
   205  	// a is infinity, return p
   206  	if a.Z.IsZero() {
   207  		return p
   208  	}
   209  
   210  	var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element
   211  	Z1Z1.Square(&a.Z)
   212  	Z2Z2.Square(&p.Z)
   213  	U1.Mul(&a.X, &Z2Z2)
   214  	U2.Mul(&p.X, &Z1Z1)
   215  	S1.Mul(&a.Y, &p.Z).
   216  		Mul(&S1, &Z2Z2)
   217  	S2.Mul(&p.Y, &a.Z).
   218  		Mul(&S2, &Z1Z1)
   219  
   220  	// if p == a, we double instead
   221  	if U1.Equal(&U2) && S1.Equal(&S2) {
   222  		return p.DoubleAssign()
   223  	}
   224  
   225  	H.Sub(&U2, &U1)
   226  	I.Double(&H).
   227  		Square(&I)
   228  	J.Mul(&H, &I)
   229  	r.Sub(&S2, &S1).Double(&r)
   230  	V.Mul(&U1, &I)
   231  	p.X.Square(&r).
   232  		Sub(&p.X, &J).
   233  		Sub(&p.X, &V).
   234  		Sub(&p.X, &V)
   235  	p.Y.Sub(&V, &p.X).
   236  		Mul(&p.Y, &r)
   237  	S1.Mul(&S1, &J).Double(&S1)
   238  	p.Y.Sub(&p.Y, &S1)
   239  	p.Z.Add(&p.Z, &a.Z)
   240  	p.Z.Square(&p.Z).
   241  		Sub(&p.Z, &Z1Z1).
   242  		Sub(&p.Z, &Z2Z2).
   243  		Mul(&p.Z, &H)
   244  
   245  	return p
   246  }
   247  
   248  // AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1.
   249  //
   250  // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
   251  func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac {
   252  
   253  	//if a is infinity return p
   254  	if a.IsInfinity() {
   255  		return p
   256  	}
   257  	// p is infinity, return a
   258  	if p.Z.IsZero() {
   259  		p.X = a.X
   260  		p.Y = a.Y
   261  		p.Z.SetOne()
   262  		return p
   263  	}
   264  
   265  	var Z1Z1, U2, S2, H, HH, I, J, r, V fp.Element
   266  	Z1Z1.Square(&p.Z)
   267  	U2.Mul(&a.X, &Z1Z1)
   268  	S2.Mul(&a.Y, &p.Z).
   269  		Mul(&S2, &Z1Z1)
   270  
   271  	// if p == a, we double instead
   272  	if U2.Equal(&p.X) && S2.Equal(&p.Y) {
   273  		return p.DoubleAssign()
   274  	}
   275  
   276  	H.Sub(&U2, &p.X)
   277  	HH.Square(&H)
   278  	I.Double(&HH).Double(&I)
   279  	J.Mul(&H, &I)
   280  	r.Sub(&S2, &p.Y).Double(&r)
   281  	V.Mul(&p.X, &I)
   282  	p.X.Square(&r).
   283  		Sub(&p.X, &J).
   284  		Sub(&p.X, &V).
   285  		Sub(&p.X, &V)
   286  	J.Mul(&J, &p.Y).Double(&J)
   287  	p.Y.Sub(&V, &p.X).
   288  		Mul(&p.Y, &r)
   289  	p.Y.Sub(&p.Y, &J)
   290  	p.Z.Add(&p.Z, &H)
   291  	p.Z.Square(&p.Z).
   292  		Sub(&p.Z, &Z1Z1).
   293  		Sub(&p.Z, &HH)
   294  
   295  	return p
   296  }
   297  
   298  // Double sets p to [2]q in Jacobian coordinates.
   299  //
   300  // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl
   301  func (p *G1Jac) Double(q *G1Jac) *G1Jac {
   302  	p.Set(q)
   303  	p.DoubleAssign()
   304  	return p
   305  }
   306  
   307  // DoubleAssign doubles p in Jacobian coordinates.
   308  //
   309  // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl
   310  func (p *G1Jac) DoubleAssign() *G1Jac {
   311  
   312  	var XX, YY, YYYY, ZZ, S, M, T, ZZZZ fp.Element
   313  
   314  	XX.Square(&p.X)
   315  	YY.Square(&p.Y)
   316  	YYYY.Square(&YY)
   317  	ZZ.Square(&p.Z)
   318  	S.Add(&p.X, &YY)
   319  	S.Square(&S).
   320  		Sub(&S, &XX).
   321  		Sub(&S, &YYYY).
   322  		Double(&S)
   323  	M.Double(&XX).Add(&M, &XX)
   324  	ZZZZ.Square(&ZZ)
   325  	M.Add(&M, &ZZZZ)
   326  	p.Z.Add(&p.Z, &p.Y).
   327  		Square(&p.Z).
   328  		Sub(&p.Z, &YY).
   329  		Sub(&p.Z, &ZZ)
   330  	T.Square(&M)
   331  	p.X = T
   332  	T.Double(&S)
   333  	p.X.Sub(&p.X, &T)
   334  	p.Y.Sub(&S, &p.X).
   335  		Mul(&p.Y, &M)
   336  	YYYY.Double(&YYYY).Double(&YYYY).Double(&YYYY)
   337  	p.Y.Sub(&p.Y, &YYYY)
   338  
   339  	return p
   340  }
   341  
   342  // ScalarMultiplication computes and returns p = [s]a
   343  // using a 2-bits windowed double-and-add method.
   344  func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac {
   345  	return p.mulWindowed(a, s)
   346  }
   347  
   348  // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity.
   349  func (p *G1Jac) String() string {
   350  	_p := G1Affine{}
   351  	_p.FromJacobian(p)
   352  	return _p.String()
   353  }
   354  
   355  // FromAffine converts a point a from affine to Jacobian coordinates.
   356  func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac {
   357  	if Q.IsInfinity() {
   358  		p.Z.SetZero()
   359  		p.X.SetOne()
   360  		p.Y.SetOne()
   361  		return p
   362  	}
   363  	p.Z.SetOne()
   364  	p.X.Set(&Q.X)
   365  	p.Y.Set(&Q.Y)
   366  	return p
   367  }
   368  
   369  // IsOnCurve returns true if p in on the curve
   370  // Y^2=X^3+X*Z^4+b*Z^6
   371  func (p *G1Jac) IsOnCurve() bool {
   372  	var left, right, tmp, u fp.Element
   373  	left.Square(&p.Y)
   374  	right.Square(&p.X).Mul(&right, &p.X)
   375  	tmp.Square(&p.Z).
   376  		Square(&tmp)
   377  	u.Mul(&p.X, &tmp)
   378  	right.Add(&u, &right)
   379  	tmp.Mul(&tmp, &p.Z).
   380  		Mul(&tmp, &p.Z).
   381  		Mul(&tmp, &bCurveCoeff)
   382  	right.Add(&right, &tmp)
   383  	return left.Equal(&right)
   384  }
   385  
   386  // IsInSubGroup returns true if p is on the r-torsion, false otherwise.
   387  // the curve is of prime order i.e. E(𝔽p) is the full group
   388  // so we just check that the point is on the curve.
   389  func (p *G1Jac) IsInSubGroup() bool {
   390  
   391  	return p.IsOnCurve()
   392  
   393  }
   394  
   395  // mulWindowed computes the 2-bits windowed double-and-add scalar
   396  // multiplication p=[s]q in Jacobian coordinates.
   397  func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac {
   398  
   399  	var res G1Jac
   400  	var ops [3]G1Jac
   401  
   402  	res.Set(&g1Infinity)
   403  	ops[0].Set(a)
   404  	ops[1].Double(&ops[0])
   405  	ops[2].Set(&ops[0]).AddAssign(&ops[1])
   406  
   407  	b := s.Bytes()
   408  	for i := range b {
   409  		w := b[i]
   410  		mask := byte(0xc0)
   411  		for j := 0; j < 4; j++ {
   412  			res.DoubleAssign().DoubleAssign()
   413  			c := (w & mask) >> (6 - 2*j)
   414  			if c != 0 {
   415  				res.AddAssign(&ops[c-1])
   416  			}
   417  			mask = mask >> 2
   418  		}
   419  	}
   420  	p.Set(&res)
   421  
   422  	return p
   423  
   424  }
   425  
   426  // JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique
   427  // where g is the prime subgroup generator
   428  func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac {
   429  
   430  	var res, p1, p2 G1Jac
   431  	res.Set(&g1Infinity)
   432  	p1.Set(&g1Gen)
   433  	p2.FromAffine(a)
   434  
   435  	var table [15]G1Jac
   436  
   437  	var k1, k2 big.Int
   438  	if s1.Sign() == -1 {
   439  		k1.Neg(s1)
   440  		table[0].Neg(&p1)
   441  	} else {
   442  		k1.Set(s1)
   443  		table[0].Set(&p1)
   444  	}
   445  	if s2.Sign() == -1 {
   446  		k2.Neg(s2)
   447  		table[3].Neg(&p2)
   448  	} else {
   449  		k2.Set(s2)
   450  		table[3].Set(&p2)
   451  	}
   452  
   453  	// precompute table (2 bits sliding window)
   454  	table[1].Double(&table[0])
   455  	table[2].Set(&table[1]).AddAssign(&table[0])
   456  	table[4].Set(&table[3]).AddAssign(&table[0])
   457  	table[5].Set(&table[3]).AddAssign(&table[1])
   458  	table[6].Set(&table[3]).AddAssign(&table[2])
   459  	table[7].Double(&table[3])
   460  	table[8].Set(&table[7]).AddAssign(&table[0])
   461  	table[9].Set(&table[7]).AddAssign(&table[1])
   462  	table[10].Set(&table[7]).AddAssign(&table[2])
   463  	table[11].Set(&table[7]).AddAssign(&table[3])
   464  	table[12].Set(&table[11]).AddAssign(&table[0])
   465  	table[13].Set(&table[11]).AddAssign(&table[1])
   466  	table[14].Set(&table[11]).AddAssign(&table[2])
   467  
   468  	var s [2]fr.Element
   469  	s[0] = s[0].SetBigInt(&k1).Bits()
   470  	s[1] = s[1].SetBigInt(&k2).Bits()
   471  
   472  	maxBit := k1.BitLen()
   473  	if k2.BitLen() > maxBit {
   474  		maxBit = k2.BitLen()
   475  	}
   476  	hiWordIndex := (maxBit - 1) / 64
   477  
   478  	for i := hiWordIndex; i >= 0; i-- {
   479  		mask := uint64(3) << 62
   480  		for j := 0; j < 32; j++ {
   481  			res.Double(&res).Double(&res)
   482  			b1 := (s[0][i] & mask) >> (62 - 2*j)
   483  			b2 := (s[1][i] & mask) >> (62 - 2*j)
   484  			if b1|b2 != 0 {
   485  				s := (b2<<2 | b1)
   486  				res.AddAssign(&table[s-1])
   487  			}
   488  			mask = mask >> 2
   489  		}
   490  	}
   491  
   492  	p.Set(&res)
   493  	return p
   494  
   495  }
   496  
   497  // JointScalarMultiplication computes [s1]p1+[s2]p1 using Straus-Shamir technique
   498  // where g is the prime subgroup generator
   499  func (p *G1Jac) JointScalarMultiplication(p1, p2 *G1Jac, s1, s2 *big.Int) *G1Jac {
   500  
   501  	var res G1Jac
   502  	res.Set(&g1Infinity)
   503  
   504  	var table [15]G1Jac
   505  
   506  	var k1, k2 big.Int
   507  	if s1.Sign() == -1 {
   508  		k1.Neg(s1)
   509  		table[0].Neg(p1)
   510  	} else {
   511  		k1.Set(s1)
   512  		table[0].Set(p1)
   513  	}
   514  	if s2.Sign() == -1 {
   515  		k2.Neg(s2)
   516  		table[3].Neg(p2)
   517  	} else {
   518  		k2.Set(s2)
   519  		table[3].Set(p2)
   520  	}
   521  
   522  	// precompute table (2 bits sliding window)
   523  	table[1].Double(&table[0])
   524  	table[2].Set(&table[1]).AddAssign(&table[0])
   525  	table[4].Set(&table[3]).AddAssign(&table[0])
   526  	table[5].Set(&table[3]).AddAssign(&table[1])
   527  	table[6].Set(&table[3]).AddAssign(&table[2])
   528  	table[7].Double(&table[3])
   529  	table[8].Set(&table[7]).AddAssign(&table[0])
   530  	table[9].Set(&table[7]).AddAssign(&table[1])
   531  	table[10].Set(&table[7]).AddAssign(&table[2])
   532  	table[11].Set(&table[7]).AddAssign(&table[3])
   533  	table[12].Set(&table[11]).AddAssign(&table[0])
   534  	table[13].Set(&table[11]).AddAssign(&table[1])
   535  	table[14].Set(&table[11]).AddAssign(&table[2])
   536  
   537  	var s [2]fr.Element
   538  	s[0] = s[0].SetBigInt(&k1).Bits()
   539  	s[1] = s[1].SetBigInt(&k2).Bits()
   540  
   541  	maxBit := k1.BitLen()
   542  	if k2.BitLen() > maxBit {
   543  		maxBit = k2.BitLen()
   544  	}
   545  	hiWordIndex := (maxBit - 1) / 64
   546  
   547  	for i := hiWordIndex; i >= 0; i-- {
   548  		mask := uint64(3) << 62
   549  		for j := 0; j < 32; j++ {
   550  			res.Double(&res).Double(&res)
   551  			b1 := (s[0][i] & mask) >> (62 - 2*j)
   552  			b2 := (s[1][i] & mask) >> (62 - 2*j)
   553  			if b1|b2 != 0 {
   554  				s := (b2<<2 | b1)
   555  				res.AddAssign(&table[s-1])
   556  			}
   557  			mask = mask >> 2
   558  		}
   559  	}
   560  
   561  	p.Set(&res)
   562  	return p
   563  
   564  }
   565  
   566  // -------------------------------------------------------------------------------------------------
   567  // extended Jacobian coordinates
   568  
   569  // Set sets p to a in extended Jacobian coordinates.
   570  func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended {
   571  	p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ
   572  	return p
   573  }
   574  
   575  // fromJacExtended converts an extended Jacobian point to an affine point.
   576  func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine {
   577  	if Q.ZZ.IsZero() {
   578  		p.X = fp.Element{}
   579  		p.Y = fp.Element{}
   580  		return p
   581  	}
   582  	p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X)
   583  	p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y)
   584  	return p
   585  }
   586  
   587  // fromJacExtended converts an extended Jacobian point to a Jacobian point.
   588  func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac {
   589  	if Q.ZZ.IsZero() {
   590  		p.Set(&g1Infinity)
   591  		return p
   592  	}
   593  	p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ)
   594  	p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ)
   595  	p.Z.Set(&Q.ZZZ)
   596  	return p
   597  }
   598  
   599  // add sets p to p+q in extended Jacobian coordinates.
   600  //
   601  // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s
   602  func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended {
   603  	//if q is infinity return p
   604  	if q.ZZ.IsZero() {
   605  		return p
   606  	}
   607  	// p is infinity, return q
   608  	if p.ZZ.IsZero() {
   609  		p.Set(q)
   610  		return p
   611  	}
   612  
   613  	var A, B, U1, U2, S1, S2 fp.Element
   614  
   615  	// p2: q, p1: p
   616  	U2.Mul(&q.X, &p.ZZ)
   617  	U1.Mul(&p.X, &q.ZZ)
   618  	A.Sub(&U2, &U1)
   619  	S2.Mul(&q.Y, &p.ZZZ)
   620  	S1.Mul(&p.Y, &q.ZZZ)
   621  	B.Sub(&S2, &S1)
   622  
   623  	if A.IsZero() {
   624  		if B.IsZero() {
   625  			return p.double(q)
   626  
   627  		}
   628  		p.ZZ = fp.Element{}
   629  		p.ZZZ = fp.Element{}
   630  		return p
   631  	}
   632  
   633  	var P, R, PP, PPP, Q, V fp.Element
   634  	P.Sub(&U2, &U1)
   635  	R.Sub(&S2, &S1)
   636  	PP.Square(&P)
   637  	PPP.Mul(&P, &PP)
   638  	Q.Mul(&U1, &PP)
   639  	V.Mul(&S1, &PPP)
   640  
   641  	p.X.Square(&R).
   642  		Sub(&p.X, &PPP).
   643  		Sub(&p.X, &Q).
   644  		Sub(&p.X, &Q)
   645  	p.Y.Sub(&Q, &p.X).
   646  		Mul(&p.Y, &R).
   647  		Sub(&p.Y, &V)
   648  	p.ZZ.Mul(&p.ZZ, &q.ZZ).
   649  		Mul(&p.ZZ, &PP)
   650  	p.ZZZ.Mul(&p.ZZZ, &q.ZZZ).
   651  		Mul(&p.ZZZ, &PPP)
   652  
   653  	return p
   654  }
   655  
   656  // double sets p to [2]q in Jacobian extended coordinates.
   657  //
   658  // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1
   659  // N.B.: since we consider any point on Z=0 as the point at infinity
   660  // this doubling formula works for infinity points as well.
   661  func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended {
   662  	var Z, U, V, W, S, XX, M fp.Element
   663  
   664  	U.Double(&q.Y)
   665  	V.Square(&U)
   666  	W.Mul(&U, &V)
   667  	S.Mul(&q.X, &V)
   668  	XX.Square(&q.X)
   669  	M.Double(&XX).
   670  		Add(&M, &XX)
   671  	Z.Square(&q.ZZ)
   672  	M.Add(&M, &Z)
   673  	U.Mul(&W, &q.Y)
   674  
   675  	p.X.Square(&M).
   676  		Sub(&p.X, &S).
   677  		Sub(&p.X, &S)
   678  	p.Y.Sub(&S, &p.X).
   679  		Mul(&p.Y, &M).
   680  		Sub(&p.Y, &U)
   681  	p.ZZ.Mul(&V, &q.ZZ)
   682  	p.ZZZ.Mul(&W, &q.ZZZ)
   683  
   684  	return p
   685  }
   686  
   687  // subMixed is the same as addMixed, but negates a.Y.
   688  //
   689  // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s
   690  func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended {
   691  
   692  	//if a is infinity return p
   693  	if a.IsInfinity() {
   694  		return p
   695  	}
   696  	// p is infinity, return a
   697  	if p.ZZ.IsZero() {
   698  		p.X = a.X
   699  		p.Y.Neg(&a.Y)
   700  		p.ZZ.SetOne()
   701  		p.ZZZ.SetOne()
   702  		return p
   703  	}
   704  
   705  	var P, R fp.Element
   706  
   707  	// p2: a, p1: p
   708  	P.Mul(&a.X, &p.ZZ)
   709  	P.Sub(&P, &p.X)
   710  
   711  	R.Mul(&a.Y, &p.ZZZ)
   712  	R.Neg(&R)
   713  	R.Sub(&R, &p.Y)
   714  
   715  	if P.IsZero() {
   716  		if R.IsZero() {
   717  			return p.doubleNegMixed(a)
   718  
   719  		}
   720  		p.ZZ = fp.Element{}
   721  		p.ZZZ = fp.Element{}
   722  		return p
   723  	}
   724  
   725  	var PP, PPP, Q, Q2, RR, X3, Y3 fp.Element
   726  
   727  	PP.Square(&P)
   728  	PPP.Mul(&P, &PP)
   729  	Q.Mul(&p.X, &PP)
   730  	RR.Square(&R)
   731  	X3.Sub(&RR, &PPP)
   732  	Q2.Double(&Q)
   733  	p.X.Sub(&X3, &Q2)
   734  	Y3.Sub(&Q, &p.X).Mul(&Y3, &R)
   735  	R.Mul(&p.Y, &PPP)
   736  	p.Y.Sub(&Y3, &R)
   737  	p.ZZ.Mul(&p.ZZ, &PP)
   738  	p.ZZZ.Mul(&p.ZZZ, &PPP)
   739  
   740  	return p
   741  
   742  }
   743  
   744  // addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1.
   745  //
   746  // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s
   747  func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended {
   748  
   749  	//if a is infinity return p
   750  	if a.IsInfinity() {
   751  		return p
   752  	}
   753  	// p is infinity, return a
   754  	if p.ZZ.IsZero() {
   755  		p.X = a.X
   756  		p.Y = a.Y
   757  		p.ZZ.SetOne()
   758  		p.ZZZ.SetOne()
   759  		return p
   760  	}
   761  
   762  	var P, R fp.Element
   763  
   764  	// p2: a, p1: p
   765  	P.Mul(&a.X, &p.ZZ)
   766  	P.Sub(&P, &p.X)
   767  
   768  	R.Mul(&a.Y, &p.ZZZ)
   769  	R.Sub(&R, &p.Y)
   770  
   771  	if P.IsZero() {
   772  		if R.IsZero() {
   773  			return p.doubleMixed(a)
   774  
   775  		}
   776  		p.ZZ = fp.Element{}
   777  		p.ZZZ = fp.Element{}
   778  		return p
   779  	}
   780  
   781  	var PP, PPP, Q, Q2, RR, X3, Y3 fp.Element
   782  
   783  	PP.Square(&P)
   784  	PPP.Mul(&P, &PP)
   785  	Q.Mul(&p.X, &PP)
   786  	RR.Square(&R)
   787  	X3.Sub(&RR, &PPP)
   788  	Q2.Double(&Q)
   789  	p.X.Sub(&X3, &Q2)
   790  	Y3.Sub(&Q, &p.X).Mul(&Y3, &R)
   791  	R.Mul(&p.Y, &PPP)
   792  	p.Y.Sub(&Y3, &R)
   793  	p.ZZ.Mul(&p.ZZ, &PP)
   794  	p.ZZZ.Mul(&p.ZZZ, &PPP)
   795  
   796  	return p
   797  
   798  }
   799  
   800  // doubleNegMixed works the same as double, but negates q.Y.
   801  func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended {
   802  
   803  	var Z, U, V, W, S, XX, M, S2, L fp.Element
   804  
   805  	U.Double(&q.Y)
   806  	U.Neg(&U)
   807  	V.Square(&U)
   808  	W.Mul(&U, &V)
   809  	S.Mul(&q.X, &V)
   810  	XX.Square(&q.X)
   811  	M.Double(&XX).
   812  		Add(&M, &XX)
   813  	Z.Square(&p.ZZ)
   814  	M.Add(&M, &Z)
   815  	S2.Double(&S)
   816  	L.Mul(&W, &q.Y)
   817  
   818  	p.X.Square(&M).
   819  		Sub(&p.X, &S2)
   820  	p.Y.Sub(&S, &p.X).
   821  		Mul(&p.Y, &M).
   822  		Add(&p.Y, &L)
   823  	p.ZZ.Set(&V)
   824  	p.ZZZ.Set(&W)
   825  
   826  	return p
   827  }
   828  
   829  // doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1.
   830  //
   831  // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1
   832  func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended {
   833  
   834  	var Z, U, V, W, S, XX, M, S2, L fp.Element
   835  
   836  	U.Double(&q.Y)
   837  	V.Square(&U)
   838  	W.Mul(&U, &V)
   839  	S.Mul(&q.X, &V)
   840  	XX.Square(&q.X)
   841  	M.Double(&XX).
   842  		Add(&M, &XX)
   843  	Z.Square(&p.ZZ)
   844  	M.Add(&M, &Z)
   845  	S2.Double(&S)
   846  	L.Mul(&W, &q.Y)
   847  
   848  	p.X.Square(&M).
   849  		Sub(&p.X, &S2)
   850  	p.Y.Sub(&S, &p.X).
   851  		Mul(&p.Y, &M).
   852  		Sub(&p.Y, &L)
   853  	p.ZZ.Set(&V)
   854  	p.ZZZ.Set(&W)
   855  
   856  	return p
   857  }
   858  
   859  // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates
   860  // performing a single field inversion using the Montgomery batch inversion trick.
   861  func BatchJacobianToAffineG1(points []G1Jac) []G1Affine {
   862  	result := make([]G1Affine, len(points))
   863  	zeroes := make([]bool, len(points))
   864  	accumulator := fp.One()
   865  
   866  	// batch invert all points[].Z coordinates with Montgomery batch inversion trick
   867  	// (stores points[].Z^-1 in result[i].X to avoid allocating a slice of fr.Elements)
   868  	for i := 0; i < len(points); i++ {
   869  		if points[i].Z.IsZero() {
   870  			zeroes[i] = true
   871  			continue
   872  		}
   873  		result[i].X = accumulator
   874  		accumulator.Mul(&accumulator, &points[i].Z)
   875  	}
   876  
   877  	var accInverse fp.Element
   878  	accInverse.Inverse(&accumulator)
   879  
   880  	for i := len(points) - 1; i >= 0; i-- {
   881  		if zeroes[i] {
   882  			// do nothing, (X=0, Y=0) is infinity point in affine
   883  			continue
   884  		}
   885  		result[i].X.Mul(&result[i].X, &accInverse)
   886  		accInverse.Mul(&accInverse, &points[i].Z)
   887  	}
   888  
   889  	// batch convert to affine.
   890  	parallel.Execute(len(points), func(start, end int) {
   891  		for i := start; i < end; i++ {
   892  			if zeroes[i] {
   893  				// do nothing, (X=0, Y=0) is infinity point in affine
   894  				continue
   895  			}
   896  			var a, b fp.Element
   897  			a = result[i].X
   898  			b.Square(&a)
   899  			result[i].X.Mul(&points[i].X, &b)
   900  			result[i].Y.Mul(&points[i].Y, &b).
   901  				Mul(&result[i].Y, &a)
   902  		}
   903  	})
   904  
   905  	return result
   906  }