github.com/klaytn/klaytn@v1.12.1/crypto/bn256/google/optate.go (about)

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