github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/crypto/bn256/google/optate.go (about)

     1  //  Copyright 2018 The go-ethereum Authors
     2  //  Copyright 2019 The go-aigar Authors
     3  //  This file is part of the go-aigar library.
     4  //
     5  //  The go-aigar library is free software: you can redistribute it and/or modify
     6  //  it under the terms of the GNU Lesser General Public License as published by
     7  //  the Free Software Foundation, either version 3 of the License, or
     8  //  (at your option) any later version.
     9  //
    10  //  The go-aigar library is distributed in the hope that it will be useful,
    11  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  //  GNU Lesser General Public License for more details.
    14  //
    15  //  You should have received a copy of the GNU Lesser General Public License
    16  //  along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package bn256
    19  
    20  func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) {
    21  	// See the mixed addition algorithm from "Faster Computation of the
    22  	// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
    23  
    24  	B := newGFp2(pool).Mul(p.x, r.t, pool)
    25  
    26  	D := newGFp2(pool).Add(p.y, r.z)
    27  	D.Square(D, pool)
    28  	D.Sub(D, r2)
    29  	D.Sub(D, r.t)
    30  	D.Mul(D, r.t, pool)
    31  
    32  	H := newGFp2(pool).Sub(B, r.x)
    33  	I := newGFp2(pool).Square(H, pool)
    34  
    35  	E := newGFp2(pool).Add(I, I)
    36  	E.Add(E, E)
    37  
    38  	J := newGFp2(pool).Mul(H, E, pool)
    39  
    40  	L1 := newGFp2(pool).Sub(D, r.y)
    41  	L1.Sub(L1, r.y)
    42  
    43  	V := newGFp2(pool).Mul(r.x, E, pool)
    44  
    45  	rOut = newTwistPoint(pool)
    46  	rOut.x.Square(L1, pool)
    47  	rOut.x.Sub(rOut.x, J)
    48  	rOut.x.Sub(rOut.x, V)
    49  	rOut.x.Sub(rOut.x, V)
    50  
    51  	rOut.z.Add(r.z, H)
    52  	rOut.z.Square(rOut.z, pool)
    53  	rOut.z.Sub(rOut.z, r.t)
    54  	rOut.z.Sub(rOut.z, I)
    55  
    56  	t := newGFp2(pool).Sub(V, rOut.x)
    57  	t.Mul(t, L1, pool)
    58  	t2 := newGFp2(pool).Mul(r.y, J, pool)
    59  	t2.Add(t2, t2)
    60  	rOut.y.Sub(t, t2)
    61  
    62  	rOut.t.Square(rOut.z, pool)
    63  
    64  	t.Add(p.y, rOut.z)
    65  	t.Square(t, pool)
    66  	t.Sub(t, r2)
    67  	t.Sub(t, rOut.t)
    68  
    69  	t2.Mul(L1, p.x, pool)
    70  	t2.Add(t2, t2)
    71  	a = newGFp2(pool)
    72  	a.Sub(t2, t)
    73  
    74  	c = newGFp2(pool)
    75  	c.MulScalar(rOut.z, q.y)
    76  	c.Add(c, c)
    77  
    78  	b = newGFp2(pool)
    79  	b.SetZero()
    80  	b.Sub(b, L1)
    81  	b.MulScalar(b, q.x)
    82  	b.Add(b, b)
    83  
    84  	B.Put(pool)
    85  	D.Put(pool)
    86  	H.Put(pool)
    87  	I.Put(pool)
    88  	E.Put(pool)
    89  	J.Put(pool)
    90  	L1.Put(pool)
    91  	V.Put(pool)
    92  	t.Put(pool)
    93  	t2.Put(pool)
    94  
    95  	return
    96  }
    97  
    98  func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) {
    99  	// See the doubling algorithm for a=0 from "Faster Computation of the
   100  	// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
   101  
   102  	A := newGFp2(pool).Square(r.x, pool)
   103  	B := newGFp2(pool).Square(r.y, pool)
   104  	C_ := newGFp2(pool).Square(B, pool)
   105  
   106  	D := newGFp2(pool).Add(r.x, B)
   107  	D.Square(D, pool)
   108  	D.Sub(D, A)
   109  	D.Sub(D, C_)
   110  	D.Add(D, D)
   111  
   112  	E := newGFp2(pool).Add(A, A)
   113  	E.Add(E, A)
   114  
   115  	G := newGFp2(pool).Square(E, pool)
   116  
   117  	rOut = newTwistPoint(pool)
   118  	rOut.x.Sub(G, D)
   119  	rOut.x.Sub(rOut.x, D)
   120  
   121  	rOut.z.Add(r.y, r.z)
   122  	rOut.z.Square(rOut.z, pool)
   123  	rOut.z.Sub(rOut.z, B)
   124  	rOut.z.Sub(rOut.z, r.t)
   125  
   126  	rOut.y.Sub(D, rOut.x)
   127  	rOut.y.Mul(rOut.y, E, pool)
   128  	t := newGFp2(pool).Add(C_, C_)
   129  	t.Add(t, t)
   130  	t.Add(t, t)
   131  	rOut.y.Sub(rOut.y, t)
   132  
   133  	rOut.t.Square(rOut.z, pool)
   134  
   135  	t.Mul(E, r.t, pool)
   136  	t.Add(t, t)
   137  	b = newGFp2(pool)
   138  	b.SetZero()
   139  	b.Sub(b, t)
   140  	b.MulScalar(b, q.x)
   141  
   142  	a = newGFp2(pool)
   143  	a.Add(r.x, E)
   144  	a.Square(a, pool)
   145  	a.Sub(a, A)
   146  	a.Sub(a, G)
   147  	t.Add(B, B)
   148  	t.Add(t, t)
   149  	a.Sub(a, t)
   150  
   151  	c = newGFp2(pool)
   152  	c.Mul(rOut.z, r.t, pool)
   153  	c.Add(c, c)
   154  	c.MulScalar(c, q.y)
   155  
   156  	A.Put(pool)
   157  	B.Put(pool)
   158  	C_.Put(pool)
   159  	D.Put(pool)
   160  	E.Put(pool)
   161  	G.Put(pool)
   162  	t.Put(pool)
   163  
   164  	return
   165  }
   166  
   167  func mulLine(ret *gfP12, a, b, c *gfP2, pool *bnPool) {
   168  	a2 := newGFp6(pool)
   169  	a2.x.SetZero()
   170  	a2.y.Set(a)
   171  	a2.z.Set(b)
   172  	a2.Mul(a2, ret.x, pool)
   173  	t3 := newGFp6(pool).MulScalar(ret.y, c, pool)
   174  
   175  	t := newGFp2(pool)
   176  	t.Add(b, c)
   177  	t2 := newGFp6(pool)
   178  	t2.x.SetZero()
   179  	t2.y.Set(a)
   180  	t2.z.Set(t)
   181  	ret.x.Add(ret.x, ret.y)
   182  
   183  	ret.y.Set(t3)
   184  
   185  	ret.x.Mul(ret.x, t2, pool)
   186  	ret.x.Sub(ret.x, a2)
   187  	ret.x.Sub(ret.x, ret.y)
   188  	a2.MulTau(a2, pool)
   189  	ret.y.Add(ret.y, a2)
   190  
   191  	a2.Put(pool)
   192  	t3.Put(pool)
   193  	t2.Put(pool)
   194  	t.Put(pool)
   195  }
   196  
   197  // sixuPlus2NAF is 6u+2 in non-adjacent form.
   198  var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0,
   199  	0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1,
   200  	1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1,
   201  	1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1}
   202  
   203  // miller implements the Miller loop for calculating the Optimal Ate pairing.
   204  // See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf
   205  func miller(q *twistPoint, p *curvePoint, pool *bnPool) *gfP12 {
   206  	ret := newGFp12(pool)
   207  	ret.SetOne()
   208  
   209  	aAffine := newTwistPoint(pool)
   210  	aAffine.Set(q)
   211  	aAffine.MakeAffine(pool)
   212  
   213  	bAffine := newCurvePoint(pool)
   214  	bAffine.Set(p)
   215  	bAffine.MakeAffine(pool)
   216  
   217  	minusA := newTwistPoint(pool)
   218  	minusA.Negative(aAffine, pool)
   219  
   220  	r := newTwistPoint(pool)
   221  	r.Set(aAffine)
   222  
   223  	r2 := newGFp2(pool)
   224  	r2.Square(aAffine.y, pool)
   225  
   226  	for i := len(sixuPlus2NAF) - 1; i > 0; i-- {
   227  		a, b, c, newR := lineFunctionDouble(r, bAffine, pool)
   228  		if i != len(sixuPlus2NAF)-1 {
   229  			ret.Square(ret, pool)
   230  		}
   231  
   232  		mulLine(ret, a, b, c, pool)
   233  		a.Put(pool)
   234  		b.Put(pool)
   235  		c.Put(pool)
   236  		r.Put(pool)
   237  		r = newR
   238  
   239  		switch sixuPlus2NAF[i-1] {
   240  		case 1:
   241  			a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2, pool)
   242  		case -1:
   243  			a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2, pool)
   244  		default:
   245  			continue
   246  		}
   247  
   248  		mulLine(ret, a, b, c, pool)
   249  		a.Put(pool)
   250  		b.Put(pool)
   251  		c.Put(pool)
   252  		r.Put(pool)
   253  		r = newR
   254  	}
   255  
   256  	// In order to calculate Q1 we have to convert q from the sextic twist
   257  	// to the full GF(p^12) group, apply the Frobenius there, and convert
   258  	// back.
   259  	//
   260  	// The twist isomorphism is (x', y') -> (xω², yω³). If we consider just
   261  	// x for a moment, then after applying the Frobenius, we have x̄ω^(2p)
   262  	// where x̄ is the conjugate of x. If we are going to apply the inverse
   263  	// isomorphism we need a value with a single coefficient of ω² so we
   264  	// rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of
   265  	// p, 2p-2 is a multiple of six. Therefore we can rewrite as
   266  	// x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the
   267  	// ω².
   268  	//
   269  	// A similar argument can be made for the y value.
   270  
   271  	q1 := newTwistPoint(pool)
   272  	q1.x.Conjugate(aAffine.x)
   273  	q1.x.Mul(q1.x, xiToPMinus1Over3, pool)
   274  	q1.y.Conjugate(aAffine.y)
   275  	q1.y.Mul(q1.y, xiToPMinus1Over2, pool)
   276  	q1.z.SetOne()
   277  	q1.t.SetOne()
   278  
   279  	// For Q2 we are applying the p² Frobenius. The two conjugations cancel
   280  	// out and we are left only with the factors from the isomorphism. In
   281  	// the case of x, we end up with a pure number which is why
   282  	// xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We
   283  	// ignore this to end up with -Q2.
   284  
   285  	minusQ2 := newTwistPoint(pool)
   286  	minusQ2.x.MulScalar(aAffine.x, xiToPSquaredMinus1Over3)
   287  	minusQ2.y.Set(aAffine.y)
   288  	minusQ2.z.SetOne()
   289  	minusQ2.t.SetOne()
   290  
   291  	r2.Square(q1.y, pool)
   292  	a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2, pool)
   293  	mulLine(ret, a, b, c, pool)
   294  	a.Put(pool)
   295  	b.Put(pool)
   296  	c.Put(pool)
   297  	r.Put(pool)
   298  	r = newR
   299  
   300  	r2.Square(minusQ2.y, pool)
   301  	a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2, pool)
   302  	mulLine(ret, a, b, c, pool)
   303  	a.Put(pool)
   304  	b.Put(pool)
   305  	c.Put(pool)
   306  	r.Put(pool)
   307  	r = newR
   308  
   309  	aAffine.Put(pool)
   310  	bAffine.Put(pool)
   311  	minusA.Put(pool)
   312  	r.Put(pool)
   313  	r2.Put(pool)
   314  
   315  	return ret
   316  }
   317  
   318  // finalExponentiation computes the (p¹²-1)/Order-th power of an element of
   319  // GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from
   320  // http://cryptojedi.org/papers/dclxvi-20100714.pdf)
   321  func finalExponentiation(in *gfP12, pool *bnPool) *gfP12 {
   322  	t1 := newGFp12(pool)
   323  
   324  	// This is the p^6-Frobenius
   325  	t1.x.Negative(in.x)
   326  	t1.y.Set(in.y)
   327  
   328  	inv := newGFp12(pool)
   329  	inv.Invert(in, pool)
   330  	t1.Mul(t1, inv, pool)
   331  
   332  	t2 := newGFp12(pool).FrobeniusP2(t1, pool)
   333  	t1.Mul(t1, t2, pool)
   334  
   335  	fp := newGFp12(pool).Frobenius(t1, pool)
   336  	fp2 := newGFp12(pool).FrobeniusP2(t1, pool)
   337  	fp3 := newGFp12(pool).Frobenius(fp2, pool)
   338  
   339  	fu, fu2, fu3 := newGFp12(pool), newGFp12(pool), newGFp12(pool)
   340  	fu.Exp(t1, u, pool)
   341  	fu2.Exp(fu, u, pool)
   342  	fu3.Exp(fu2, u, pool)
   343  
   344  	y3 := newGFp12(pool).Frobenius(fu, pool)
   345  	fu2p := newGFp12(pool).Frobenius(fu2, pool)
   346  	fu3p := newGFp12(pool).Frobenius(fu3, pool)
   347  	y2 := newGFp12(pool).FrobeniusP2(fu2, pool)
   348  
   349  	y0 := newGFp12(pool)
   350  	y0.Mul(fp, fp2, pool)
   351  	y0.Mul(y0, fp3, pool)
   352  
   353  	y1, y4, y5 := newGFp12(pool), newGFp12(pool), newGFp12(pool)
   354  	y1.Conjugate(t1)
   355  	y5.Conjugate(fu2)
   356  	y3.Conjugate(y3)
   357  	y4.Mul(fu, fu2p, pool)
   358  	y4.Conjugate(y4)
   359  
   360  	y6 := newGFp12(pool)
   361  	y6.Mul(fu3, fu3p, pool)
   362  	y6.Conjugate(y6)
   363  
   364  	t0 := newGFp12(pool)
   365  	t0.Square(y6, pool)
   366  	t0.Mul(t0, y4, pool)
   367  	t0.Mul(t0, y5, pool)
   368  	t1.Mul(y3, y5, pool)
   369  	t1.Mul(t1, t0, pool)
   370  	t0.Mul(t0, y2, pool)
   371  	t1.Square(t1, pool)
   372  	t1.Mul(t1, t0, pool)
   373  	t1.Square(t1, pool)
   374  	t0.Mul(t1, y1, pool)
   375  	t1.Mul(t1, y0, pool)
   376  	t0.Square(t0, pool)
   377  	t0.Mul(t0, t1, pool)
   378  
   379  	inv.Put(pool)
   380  	t1.Put(pool)
   381  	t2.Put(pool)
   382  	fp.Put(pool)
   383  	fp2.Put(pool)
   384  	fp3.Put(pool)
   385  	fu.Put(pool)
   386  	fu2.Put(pool)
   387  	fu3.Put(pool)
   388  	fu2p.Put(pool)
   389  	fu3p.Put(pool)
   390  	y0.Put(pool)
   391  	y1.Put(pool)
   392  	y2.Put(pool)
   393  	y3.Put(pool)
   394  	y4.Put(pool)
   395  	y5.Put(pool)
   396  	y6.Put(pool)
   397  
   398  	return t0
   399  }
   400  
   401  func optimalAte(a *twistPoint, b *curvePoint, pool *bnPool) *gfP12 {
   402  	e := miller(a, b, pool)
   403  	ret := finalExponentiation(e, pool)
   404  	e.Put(pool)
   405  
   406  	if a.IsInfinity() || b.IsInfinity() {
   407  		ret.SetOne()
   408  	}
   409  	return ret
   410  }