You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

278 lines
5.3 KiB

  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. import (
  6. "math/big"
  7. )
  8. // curvePoint implements the elliptic curve y²=x³+3. Points are kept in
  9. // Jacobian form and t=z² when valid. G₁ is the set of points of this curve on
  10. // GF(p).
  11. type curvePoint struct {
  12. x, y, z, t *big.Int
  13. }
  14. var curveB = new(big.Int).SetInt64(3)
  15. // curveGen is the generator of G₁.
  16. var curveGen = &curvePoint{
  17. new(big.Int).SetInt64(1),
  18. new(big.Int).SetInt64(-2),
  19. new(big.Int).SetInt64(1),
  20. new(big.Int).SetInt64(1),
  21. }
  22. func newCurvePoint(pool *bnPool) *curvePoint {
  23. return &curvePoint{
  24. pool.Get(),
  25. pool.Get(),
  26. pool.Get(),
  27. pool.Get(),
  28. }
  29. }
  30. func (c *curvePoint) String() string {
  31. c.MakeAffine(new(bnPool))
  32. return "(" + c.x.String() + ", " + c.y.String() + ")"
  33. }
  34. func (c *curvePoint) Put(pool *bnPool) {
  35. pool.Put(c.x)
  36. pool.Put(c.y)
  37. pool.Put(c.z)
  38. pool.Put(c.t)
  39. }
  40. func (c *curvePoint) Set(a *curvePoint) {
  41. c.x.Set(a.x)
  42. c.y.Set(a.y)
  43. c.z.Set(a.z)
  44. c.t.Set(a.t)
  45. }
  46. // IsOnCurve returns true iff c is on the curve where c must be in affine form.
  47. func (c *curvePoint) IsOnCurve() bool {
  48. yy := new(big.Int).Mul(c.y, c.y)
  49. xxx := new(big.Int).Mul(c.x, c.x)
  50. xxx.Mul(xxx, c.x)
  51. yy.Sub(yy, xxx)
  52. yy.Sub(yy, curveB)
  53. if yy.Sign() < 0 || yy.Cmp(p) >= 0 {
  54. yy.Mod(yy, p)
  55. }
  56. return yy.Sign() == 0
  57. }
  58. func (c *curvePoint) SetInfinity() {
  59. c.z.SetInt64(0)
  60. }
  61. func (c *curvePoint) IsInfinity() bool {
  62. return c.z.Sign() == 0
  63. }
  64. func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) {
  65. if a.IsInfinity() {
  66. c.Set(b)
  67. return
  68. }
  69. if b.IsInfinity() {
  70. c.Set(a)
  71. return
  72. }
  73. // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
  74. // Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
  75. // by [u1:s1:z1·z2] and [u2:s2:z1·z2]
  76. // where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
  77. z1z1 := pool.Get().Mul(a.z, a.z)
  78. z1z1.Mod(z1z1, p)
  79. z2z2 := pool.Get().Mul(b.z, b.z)
  80. z2z2.Mod(z2z2, p)
  81. u1 := pool.Get().Mul(a.x, z2z2)
  82. u1.Mod(u1, p)
  83. u2 := pool.Get().Mul(b.x, z1z1)
  84. u2.Mod(u2, p)
  85. t := pool.Get().Mul(b.z, z2z2)
  86. t.Mod(t, p)
  87. s1 := pool.Get().Mul(a.y, t)
  88. s1.Mod(s1, p)
  89. t.Mul(a.z, z1z1)
  90. t.Mod(t, p)
  91. s2 := pool.Get().Mul(b.y, t)
  92. s2.Mod(s2, p)
  93. // Compute x = (2h)²(s²-u1-u2)
  94. // where s = (s2-s1)/(u2-u1) is the slope of the line through
  95. // (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
  96. // This is also:
  97. // 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
  98. // = r² - j - 2v
  99. // with the notations below.
  100. h := pool.Get().Sub(u2, u1)
  101. xEqual := h.Sign() == 0
  102. t.Add(h, h)
  103. // i = 4h²
  104. i := pool.Get().Mul(t, t)
  105. i.Mod(i, p)
  106. // j = 4h³
  107. j := pool.Get().Mul(h, i)
  108. j.Mod(j, p)
  109. t.Sub(s2, s1)
  110. yEqual := t.Sign() == 0
  111. if xEqual && yEqual {
  112. c.Double(a, pool)
  113. return
  114. }
  115. r := pool.Get().Add(t, t)
  116. v := pool.Get().Mul(u1, i)
  117. v.Mod(v, p)
  118. // t4 = 4(s2-s1)²
  119. t4 := pool.Get().Mul(r, r)
  120. t4.Mod(t4, p)
  121. t.Add(v, v)
  122. t6 := pool.Get().Sub(t4, j)
  123. c.x.Sub(t6, t)
  124. // Set y = -(2h)³(s1 + s*(x/4h²-u1))
  125. // This is also
  126. // y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
  127. t.Sub(v, c.x) // t7
  128. t4.Mul(s1, j) // t8
  129. t4.Mod(t4, p)
  130. t6.Add(t4, t4) // t9
  131. t4.Mul(r, t) // t10
  132. t4.Mod(t4, p)
  133. c.y.Sub(t4, t6)
  134. // Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
  135. t.Add(a.z, b.z) // t11
  136. t4.Mul(t, t) // t12
  137. t4.Mod(t4, p)
  138. t.Sub(t4, z1z1) // t13
  139. t4.Sub(t, z2z2) // t14
  140. c.z.Mul(t4, h)
  141. c.z.Mod(c.z, p)
  142. pool.Put(z1z1)
  143. pool.Put(z2z2)
  144. pool.Put(u1)
  145. pool.Put(u2)
  146. pool.Put(t)
  147. pool.Put(s1)
  148. pool.Put(s2)
  149. pool.Put(h)
  150. pool.Put(i)
  151. pool.Put(j)
  152. pool.Put(r)
  153. pool.Put(v)
  154. pool.Put(t4)
  155. pool.Put(t6)
  156. }
  157. func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
  158. // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
  159. A := pool.Get().Mul(a.x, a.x)
  160. A.Mod(A, p)
  161. B := pool.Get().Mul(a.y, a.y)
  162. B.Mod(B, p)
  163. C := pool.Get().Mul(B, B)
  164. C.Mod(C, p)
  165. t := pool.Get().Add(a.x, B)
  166. t2 := pool.Get().Mul(t, t)
  167. t2.Mod(t2, p)
  168. t.Sub(t2, A)
  169. t2.Sub(t, C)
  170. d := pool.Get().Add(t2, t2)
  171. t.Add(A, A)
  172. e := pool.Get().Add(t, A)
  173. f := pool.Get().Mul(e, e)
  174. f.Mod(f, p)
  175. t.Add(d, d)
  176. c.x.Sub(f, t)
  177. t.Add(C, C)
  178. t2.Add(t, t)
  179. t.Add(t2, t2)
  180. c.y.Sub(d, c.x)
  181. t2.Mul(e, c.y)
  182. t2.Mod(t2, p)
  183. c.y.Sub(t2, t)
  184. t.Mul(a.y, a.z)
  185. t.Mod(t, p)
  186. c.z.Add(t, t)
  187. pool.Put(A)
  188. pool.Put(B)
  189. pool.Put(C)
  190. pool.Put(t)
  191. pool.Put(t2)
  192. pool.Put(d)
  193. pool.Put(e)
  194. pool.Put(f)
  195. }
  196. func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoint {
  197. sum := newCurvePoint(pool)
  198. sum.SetInfinity()
  199. t := newCurvePoint(pool)
  200. for i := scalar.BitLen(); i >= 0; i-- {
  201. t.Double(sum, pool)
  202. if scalar.Bit(i) != 0 {
  203. sum.Add(t, a, pool)
  204. } else {
  205. sum.Set(t)
  206. }
  207. }
  208. c.Set(sum)
  209. sum.Put(pool)
  210. t.Put(pool)
  211. return c
  212. }
  213. func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint {
  214. if words := c.z.Bits(); len(words) == 1 && words[0] == 1 {
  215. return c
  216. }
  217. zInv := pool.Get().ModInverse(c.z, p)
  218. t := pool.Get().Mul(c.y, zInv)
  219. t.Mod(t, p)
  220. zInv2 := pool.Get().Mul(zInv, zInv)
  221. zInv2.Mod(zInv2, p)
  222. c.y.Mul(t, zInv2)
  223. c.y.Mod(c.y, p)
  224. t.Mul(c.x, zInv2)
  225. t.Mod(t, p)
  226. c.x.Set(t)
  227. c.z.SetInt64(1)
  228. c.t.SetInt64(1)
  229. pool.Put(zInv)
  230. pool.Put(t)
  231. pool.Put(zInv2)
  232. return c
  233. }
  234. func (c *curvePoint) Negative(a *curvePoint) {
  235. c.x.Set(a.x)
  236. c.y.Neg(a.y)
  237. c.z.Set(a.z)
  238. c.t.SetInt64(0)
  239. }