optate.go 8.5 KB

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