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