github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/crypto/bn256/cloudflare/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) (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  	B := (&gfP2{}).Mul(&p.x, &r.t)
    24  
    25  	D := (&gfP2{}).Add(&p.y, &r.z)
    26  	D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t)
    27  
    28  	H := (&gfP2{}).Sub(B, &r.x)
    29  	I := (&gfP2{}).Square(H)
    30  
    31  	E := (&gfP2{}).Add(I, I)
    32  	E.Add(E, E)
    33  
    34  	J := (&gfP2{}).Mul(H, E)
    35  
    36  	L1 := (&gfP2{}).Sub(D, &r.y)
    37  	L1.Sub(L1, &r.y)
    38  
    39  	V := (&gfP2{}).Mul(&r.x, E)
    40  
    41  	rOut = &twistPoint{}
    42  	rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V)
    43  
    44  	rOut.z.Add(&r.z, H).Square(&rOut.z).Sub(&rOut.z, &r.t).Sub(&rOut.z, I)
    45  
    46  	t := (&gfP2{}).Sub(V, &rOut.x)
    47  	t.Mul(t, L1)
    48  	t2 := (&gfP2{}).Mul(&r.y, J)
    49  	t2.Add(t2, t2)
    50  	rOut.y.Sub(t, t2)
    51  
    52  	rOut.t.Square(&rOut.z)
    53  
    54  	t.Add(&p.y, &rOut.z).Square(t).Sub(t, r2).Sub(t, &rOut.t)
    55  
    56  	t2.Mul(L1, &p.x)
    57  	t2.Add(t2, t2)
    58  	a = (&gfP2{}).Sub(t2, t)
    59  
    60  	c = (&gfP2{}).MulScalar(&rOut.z, &q.y)
    61  	c.Add(c, c)
    62  
    63  	b = (&gfP2{}).Neg(L1)
    64  	b.MulScalar(b, &q.x).Add(b, b)
    65  
    66  	return
    67  }
    68  
    69  func lineFunctionDouble(r *twistPoint, q *curvePoint) (a, b, c *gfP2, rOut *twistPoint) {
    70  	// See the doubling algorithm for a=0 from "Faster Computation of the
    71  	// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
    72  	A := (&gfP2{}).Square(&r.x)
    73  	B := (&gfP2{}).Square(&r.y)
    74  	C := (&gfP2{}).Square(B)
    75  
    76  	D := (&gfP2{}).Add(&r.x, B)
    77  	D.Square(D).Sub(D, A).Sub(D, C).Add(D, D)
    78  
    79  	E := (&gfP2{}).Add(A, A)
    80  	E.Add(E, A)
    81  
    82  	G := (&gfP2{}).Square(E)
    83  
    84  	rOut = &twistPoint{}
    85  	rOut.x.Sub(G, D).Sub(&rOut.x, D)
    86  
    87  	rOut.z.Add(&r.y, &r.z).Square(&rOut.z).Sub(&rOut.z, B).Sub(&rOut.z, &r.t)
    88  
    89  	rOut.y.Sub(D, &rOut.x).Mul(&rOut.y, E)
    90  	t := (&gfP2{}).Add(C, C)
    91  	t.Add(t, t).Add(t, t)
    92  	rOut.y.Sub(&rOut.y, t)
    93  
    94  	rOut.t.Square(&rOut.z)
    95  
    96  	t.Mul(E, &r.t).Add(t, t)
    97  	b = (&gfP2{}).Neg(t)
    98  	b.MulScalar(b, &q.x)
    99  
   100  	a = (&gfP2{}).Add(&r.x, E)
   101  	a.Square(a).Sub(a, A).Sub(a, G)
   102  	t.Add(B, B).Add(t, t)
   103  	a.Sub(a, t)
   104  
   105  	c = (&gfP2{}).Mul(&rOut.z, &r.t)
   106  	c.Add(c, c).MulScalar(c, &q.y)
   107  
   108  	return
   109  }
   110  
   111  func mulLine(ret *gfP12, a, b, c *gfP2) {
   112  	a2 := &gfP6{}
   113  	a2.y.Set(a)
   114  	a2.z.Set(b)
   115  	a2.Mul(a2, &ret.x)
   116  	t3 := (&gfP6{}).MulScalar(&ret.y, c)
   117  
   118  	t := (&gfP2{}).Add(b, c)
   119  	t2 := &gfP6{}
   120  	t2.y.Set(a)
   121  	t2.z.Set(t)
   122  	ret.x.Add(&ret.x, &ret.y)
   123  
   124  	ret.y.Set(t3)
   125  
   126  	ret.x.Mul(&ret.x, t2).Sub(&ret.x, a2).Sub(&ret.x, &ret.y)
   127  	a2.MulTau(a2)
   128  	ret.y.Add(&ret.y, a2)
   129  }
   130  
   131  // sixuPlus2NAF is 6u+2 in non-adjacent form.
   132  var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0,
   133  	0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1,
   134  	1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1,
   135  	1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1}
   136  
   137  // miller implements the Miller loop for calculating the Optimal Ate pairing.
   138  // See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf
   139  func miller(q *twistPoint, p *curvePoint) *gfP12 {
   140  	ret := (&gfP12{}).SetOne()
   141  
   142  	aAffine := &twistPoint{}
   143  	aAffine.Set(q)
   144  	aAffine.MakeAffine()
   145  
   146  	bAffine := &curvePoint{}
   147  	bAffine.Set(p)
   148  	bAffine.MakeAffine()
   149  
   150  	minusA := &twistPoint{}
   151  	minusA.Neg(aAffine)
   152  
   153  	r := &twistPoint{}
   154  	r.Set(aAffine)
   155  
   156  	r2 := (&gfP2{}).Square(&aAffine.y)
   157  
   158  	for i := len(sixuPlus2NAF) - 1; i > 0; i-- {
   159  		a, b, c, newR := lineFunctionDouble(r, bAffine)
   160  		if i != len(sixuPlus2NAF)-1 {
   161  			ret.Square(ret)
   162  		}
   163  
   164  		mulLine(ret, a, b, c)
   165  		r = newR
   166  
   167  		switch sixuPlus2NAF[i-1] {
   168  		case 1:
   169  			a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2)
   170  		case -1:
   171  			a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2)
   172  		default:
   173  			continue
   174  		}
   175  
   176  		mulLine(ret, a, b, c)
   177  		r = newR
   178  	}
   179  
   180  	// In order to calculate Q1 we have to convert q from the sextic twist
   181  	// to the full GF(p^12) group, apply the Frobenius there, and convert
   182  	// back.
   183  	//
   184  	// The twist isomorphism is (x', y') -> (xω², yω³). If we consider just
   185  	// x for a moment, then after applying the Frobenius, we have x̄ω^(2p)
   186  	// where x̄ is the conjugate of x. If we are going to apply the inverse
   187  	// isomorphism we need a value with a single coefficient of ω² so we
   188  	// rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of
   189  	// p, 2p-2 is a multiple of six. Therefore we can rewrite as
   190  	// x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the
   191  	// ω².
   192  	//
   193  	// A similar argument can be made for the y value.
   194  
   195  	q1 := &twistPoint{}
   196  	q1.x.Conjugate(&aAffine.x).Mul(&q1.x, xiToPMinus1Over3)
   197  	q1.y.Conjugate(&aAffine.y).Mul(&q1.y, xiToPMinus1Over2)
   198  	q1.z.SetOne()
   199  	q1.t.SetOne()
   200  
   201  	// For Q2 we are applying the p² Frobenius. The two conjugations cancel
   202  	// out and we are left only with the factors from the isomorphism. In
   203  	// the case of x, we end up with a pure number which is why
   204  	// xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We
   205  	// ignore this to end up with -Q2.
   206  
   207  	minusQ2 := &twistPoint{}
   208  	minusQ2.x.MulScalar(&aAffine.x, xiToPSquaredMinus1Over3)
   209  	minusQ2.y.Set(&aAffine.y)
   210  	minusQ2.z.SetOne()
   211  	minusQ2.t.SetOne()
   212  
   213  	r2.Square(&q1.y)
   214  	a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2)
   215  	mulLine(ret, a, b, c)
   216  	r = newR
   217  
   218  	r2.Square(&minusQ2.y)
   219  	a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2)
   220  	mulLine(ret, a, b, c)
   221  	r = newR
   222  
   223  	return ret
   224  }
   225  
   226  // finalExponentiation computes the (p¹²-1)/Order-th power of an element of
   227  // GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from
   228  // http://cryptojedi.org/papers/dclxvi-20100714.pdf)
   229  func finalExponentiation(in *gfP12) *gfP12 {
   230  	t1 := &gfP12{}
   231  
   232  	// This is the p^6-Frobenius
   233  	t1.x.Neg(&in.x)
   234  	t1.y.Set(&in.y)
   235  
   236  	inv := &gfP12{}
   237  	inv.Invert(in)
   238  	t1.Mul(t1, inv)
   239  
   240  	t2 := (&gfP12{}).FrobeniusP2(t1)
   241  	t1.Mul(t1, t2)
   242  
   243  	fp := (&gfP12{}).Frobenius(t1)
   244  	fp2 := (&gfP12{}).FrobeniusP2(t1)
   245  	fp3 := (&gfP12{}).Frobenius(fp2)
   246  
   247  	fu := (&gfP12{}).Exp(t1, u)
   248  	fu2 := (&gfP12{}).Exp(fu, u)
   249  	fu3 := (&gfP12{}).Exp(fu2, u)
   250  
   251  	y3 := (&gfP12{}).Frobenius(fu)
   252  	fu2p := (&gfP12{}).Frobenius(fu2)
   253  	fu3p := (&gfP12{}).Frobenius(fu3)
   254  	y2 := (&gfP12{}).FrobeniusP2(fu2)
   255  
   256  	y0 := &gfP12{}
   257  	y0.Mul(fp, fp2).Mul(y0, fp3)
   258  
   259  	y1 := (&gfP12{}).Conjugate(t1)
   260  	y5 := (&gfP12{}).Conjugate(fu2)
   261  	y3.Conjugate(y3)
   262  	y4 := (&gfP12{}).Mul(fu, fu2p)
   263  	y4.Conjugate(y4)
   264  
   265  	y6 := (&gfP12{}).Mul(fu3, fu3p)
   266  	y6.Conjugate(y6)
   267  
   268  	t0 := (&gfP12{}).Square(y6)
   269  	t0.Mul(t0, y4).Mul(t0, y5)
   270  	t1.Mul(y3, y5).Mul(t1, t0)
   271  	t0.Mul(t0, y2)
   272  	t1.Square(t1).Mul(t1, t0).Square(t1)
   273  	t0.Mul(t1, y1)
   274  	t1.Mul(t1, y0)
   275  	t0.Square(t0).Mul(t0, t1)
   276  
   277  	return t0
   278  }
   279  
   280  func optimalAte(a *twistPoint, b *curvePoint) *gfP12 {
   281  	e := miller(a, b)
   282  	ret := finalExponentiation(e)
   283  
   284  	if a.IsInfinity() || b.IsInfinity() {
   285  		ret.SetOne()
   286  	}
   287  	return ret
   288  }