optate.go 6.4 KB

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