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 }