github.com/ethw3/go-ethereuma@v0.0.0-20221013053120-c14602a4c23c/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{0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 186 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1, 187 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 188 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1} 189 190 // miller implements the Miller loop for calculating the Optimal Ate pairing. 191 // See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf 192 func miller(q *twistPoint, p *curvePoint, pool *bnPool) *gfP12 { 193 ret := newGFp12(pool) 194 ret.SetOne() 195 196 aAffine := newTwistPoint(pool) 197 aAffine.Set(q) 198 aAffine.MakeAffine(pool) 199 200 bAffine := newCurvePoint(pool) 201 bAffine.Set(p) 202 bAffine.MakeAffine(pool) 203 204 minusA := newTwistPoint(pool) 205 minusA.Negative(aAffine, pool) 206 207 r := newTwistPoint(pool) 208 r.Set(aAffine) 209 210 r2 := newGFp2(pool) 211 r2.Square(aAffine.y, pool) 212 213 for i := len(sixuPlus2NAF) - 1; i > 0; i-- { 214 a, b, c, newR := lineFunctionDouble(r, bAffine, pool) 215 if i != len(sixuPlus2NAF)-1 { 216 ret.Square(ret, pool) 217 } 218 219 mulLine(ret, a, b, c, pool) 220 a.Put(pool) 221 b.Put(pool) 222 c.Put(pool) 223 r.Put(pool) 224 r = newR 225 226 switch sixuPlus2NAF[i-1] { 227 case 1: 228 a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2, pool) 229 case -1: 230 a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2, pool) 231 default: 232 continue 233 } 234 235 mulLine(ret, a, b, c, pool) 236 a.Put(pool) 237 b.Put(pool) 238 c.Put(pool) 239 r.Put(pool) 240 r = newR 241 } 242 243 // In order to calculate Q1 we have to convert q from the sextic twist 244 // to the full GF(p^12) group, apply the Frobenius there, and convert 245 // back. 246 // 247 // The twist isomorphism is (x', y') -> (xω², yω³). If we consider just 248 // x for a moment, then after applying the Frobenius, we have x̄ω^(2p) 249 // where x̄ is the conjugate of x. If we are going to apply the inverse 250 // isomorphism we need a value with a single coefficient of ω² so we 251 // rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of 252 // p, 2p-2 is a multiple of six. Therefore we can rewrite as 253 // x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the 254 // ω². 255 // 256 // A similar argument can be made for the y value. 257 258 q1 := newTwistPoint(pool) 259 q1.x.Conjugate(aAffine.x) 260 q1.x.Mul(q1.x, xiToPMinus1Over3, pool) 261 q1.y.Conjugate(aAffine.y) 262 q1.y.Mul(q1.y, xiToPMinus1Over2, pool) 263 q1.z.SetOne() 264 q1.t.SetOne() 265 266 // For Q2 we are applying the p² Frobenius. The two conjugations cancel 267 // out and we are left only with the factors from the isomorphism. In 268 // the case of x, we end up with a pure number which is why 269 // xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We 270 // ignore this to end up with -Q2. 271 272 minusQ2 := newTwistPoint(pool) 273 minusQ2.x.MulScalar(aAffine.x, xiToPSquaredMinus1Over3) 274 minusQ2.y.Set(aAffine.y) 275 minusQ2.z.SetOne() 276 minusQ2.t.SetOne() 277 278 r2.Square(q1.y, pool) 279 a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2, pool) 280 mulLine(ret, a, b, c, pool) 281 a.Put(pool) 282 b.Put(pool) 283 c.Put(pool) 284 r.Put(pool) 285 r = newR 286 287 r2.Square(minusQ2.y, pool) 288 a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2, pool) 289 mulLine(ret, a, b, c, pool) 290 a.Put(pool) 291 b.Put(pool) 292 c.Put(pool) 293 r.Put(pool) 294 r = newR 295 296 aAffine.Put(pool) 297 bAffine.Put(pool) 298 minusA.Put(pool) 299 r.Put(pool) 300 r2.Put(pool) 301 302 return ret 303 } 304 305 // finalExponentiation computes the (p¹²-1)/Order-th power of an element of 306 // GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from 307 // http://cryptojedi.org/papers/dclxvi-20100714.pdf) 308 func finalExponentiation(in *gfP12, pool *bnPool) *gfP12 { 309 t1 := newGFp12(pool) 310 311 // This is the p^6-Frobenius 312 t1.x.Negative(in.x) 313 t1.y.Set(in.y) 314 315 inv := newGFp12(pool) 316 inv.Invert(in, pool) 317 t1.Mul(t1, inv, pool) 318 319 t2 := newGFp12(pool).FrobeniusP2(t1, pool) 320 t1.Mul(t1, t2, pool) 321 322 fp := newGFp12(pool).Frobenius(t1, pool) 323 fp2 := newGFp12(pool).FrobeniusP2(t1, pool) 324 fp3 := newGFp12(pool).Frobenius(fp2, pool) 325 326 fu, fu2, fu3 := newGFp12(pool), newGFp12(pool), newGFp12(pool) 327 fu.Exp(t1, u, pool) 328 fu2.Exp(fu, u, pool) 329 fu3.Exp(fu2, u, pool) 330 331 y3 := newGFp12(pool).Frobenius(fu, pool) 332 fu2p := newGFp12(pool).Frobenius(fu2, pool) 333 fu3p := newGFp12(pool).Frobenius(fu3, pool) 334 y2 := newGFp12(pool).FrobeniusP2(fu2, pool) 335 336 y0 := newGFp12(pool) 337 y0.Mul(fp, fp2, pool) 338 y0.Mul(y0, fp3, pool) 339 340 y1, y4, y5 := newGFp12(pool), newGFp12(pool), newGFp12(pool) 341 y1.Conjugate(t1) 342 y5.Conjugate(fu2) 343 y3.Conjugate(y3) 344 y4.Mul(fu, fu2p, pool) 345 y4.Conjugate(y4) 346 347 y6 := newGFp12(pool) 348 y6.Mul(fu3, fu3p, pool) 349 y6.Conjugate(y6) 350 351 t0 := newGFp12(pool) 352 t0.Square(y6, pool) 353 t0.Mul(t0, y4, pool) 354 t0.Mul(t0, y5, pool) 355 t1.Mul(y3, y5, pool) 356 t1.Mul(t1, t0, pool) 357 t0.Mul(t0, y2, pool) 358 t1.Square(t1, pool) 359 t1.Mul(t1, t0, pool) 360 t1.Square(t1, pool) 361 t0.Mul(t1, y1, pool) 362 t1.Mul(t1, y0, pool) 363 t0.Square(t0, pool) 364 t0.Mul(t0, t1, pool) 365 366 inv.Put(pool) 367 t1.Put(pool) 368 t2.Put(pool) 369 fp.Put(pool) 370 fp2.Put(pool) 371 fp3.Put(pool) 372 fu.Put(pool) 373 fu2.Put(pool) 374 fu3.Put(pool) 375 fu2p.Put(pool) 376 fu3p.Put(pool) 377 y0.Put(pool) 378 y1.Put(pool) 379 y2.Put(pool) 380 y3.Put(pool) 381 y4.Put(pool) 382 y5.Put(pool) 383 y6.Put(pool) 384 385 return t0 386 } 387 388 func optimalAte(a *twistPoint, b *curvePoint, pool *bnPool) *gfP12 { 389 e := miller(a, b, pool) 390 ret := finalExponentiation(e, pool) 391 e.Put(pool) 392 393 if a.IsInfinity() || b.IsInfinity() { 394 ret.SetOne() 395 } 396 return ret 397 }