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 }