説明なし

ec.js 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /* eslint-disable no-case-declarations, max-len */
  2. const {BigInteger} = require('jsbn')
  3. /**
  4. * thanks for Tom Wu : http://www-cs-students.stanford.edu/~tjw/jsbn/
  5. *
  6. * Basic Javascript Elliptic Curve implementation
  7. * Ported loosely from BouncyCastle's Java EC code
  8. * Only Fp curves implemented for now
  9. */
  10. const TWO = new BigInteger('2')
  11. const THREE = new BigInteger('3')
  12. /**
  13. * 椭圆曲线域元素
  14. */
  15. class ECFieldElementFp {
  16. constructor(q, x) {
  17. this.x = x
  18. this.q = q
  19. // TODO if (x.compareTo(q) >= 0) error
  20. }
  21. /**
  22. * 判断相等
  23. */
  24. equals(other) {
  25. if (other === this) return true
  26. return (this.q.equals(other.q) && this.x.equals(other.x))
  27. }
  28. /**
  29. * 返回具体数值
  30. */
  31. toBigInteger() {
  32. return this.x
  33. }
  34. /**
  35. * 取反
  36. */
  37. negate() {
  38. return new ECFieldElementFp(this.q, this.x.negate().mod(this.q))
  39. }
  40. /**
  41. * 相加
  42. */
  43. add(b) {
  44. return new ECFieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q))
  45. }
  46. /**
  47. * 相减
  48. */
  49. subtract(b) {
  50. return new ECFieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q))
  51. }
  52. /**
  53. * 相乘
  54. */
  55. multiply(b) {
  56. return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q))
  57. }
  58. /**
  59. * 相除
  60. */
  61. divide(b) {
  62. return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q))
  63. }
  64. /**
  65. * 平方
  66. */
  67. square() {
  68. return new ECFieldElementFp(this.q, this.x.square().mod(this.q))
  69. }
  70. }
  71. class ECPointFp {
  72. constructor(curve, x, y, z) {
  73. this.curve = curve
  74. this.x = x
  75. this.y = y
  76. // 标准射影坐标系:zinv == null 或 z * zinv == 1
  77. this.z = z == null ? BigInteger.ONE : z
  78. this.zinv = null
  79. // TODO: compression flag
  80. }
  81. getX() {
  82. if (this.zinv === null) this.zinv = this.z.modInverse(this.curve.q)
  83. return this.curve.fromBigInteger(this.x.toBigInteger().multiply(this.zinv).mod(this.curve.q))
  84. }
  85. getY() {
  86. if (this.zinv === null) this.zinv = this.z.modInverse(this.curve.q)
  87. return this.curve.fromBigInteger(this.y.toBigInteger().multiply(this.zinv).mod(this.curve.q))
  88. }
  89. /**
  90. * 判断相等
  91. */
  92. equals(other) {
  93. if (other === this) return true
  94. if (this.isInfinity()) return other.isInfinity()
  95. if (other.isInfinity()) return this.isInfinity()
  96. // u = y2 * z1 - y1 * z2
  97. const u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q)
  98. if (!u.equals(BigInteger.ZERO)) return false
  99. // v = x2 * z1 - x1 * z2
  100. const v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q)
  101. return v.equals(BigInteger.ZERO)
  102. }
  103. /**
  104. * 是否是无穷远点
  105. */
  106. isInfinity() {
  107. if ((this.x === null) && (this.y === null)) return true
  108. return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO)
  109. }
  110. /**
  111. * 取反,x 轴对称点
  112. */
  113. negate() {
  114. return new ECPointFp(this.curve, this.x, this.y.negate(), this.z)
  115. }
  116. /**
  117. * 相加
  118. *
  119. * 标准射影坐标系:
  120. *
  121. * λ1 = x1 * z2
  122. * λ2 = x2 * z1
  123. * λ3 = λ1 − λ2
  124. * λ4 = y1 * z2
  125. * λ5 = y2 * z1
  126. * λ6 = λ4 − λ5
  127. * λ7 = λ1 + λ2
  128. * λ8 = z1 * z2
  129. * λ9 = λ3^2
  130. * λ10 = λ3 * λ9
  131. * λ11 = λ8 * λ6^2 − λ7 * λ9
  132. * x3 = λ3 * λ11
  133. * y3 = λ6 * (λ9 * λ1 − λ11) − λ4 * λ10
  134. * z3 = λ10 * λ8
  135. */
  136. add(b) {
  137. if (this.isInfinity()) return b
  138. if (b.isInfinity()) return this
  139. const x1 = this.x.toBigInteger()
  140. const y1 = this.y.toBigInteger()
  141. const z1 = this.z
  142. const x2 = b.x.toBigInteger()
  143. const y2 = b.y.toBigInteger()
  144. const z2 = b.z
  145. const q = this.curve.q
  146. const w1 = x1.multiply(z2).mod(q)
  147. const w2 = x2.multiply(z1).mod(q)
  148. const w3 = w1.subtract(w2)
  149. const w4 = y1.multiply(z2).mod(q)
  150. const w5 = y2.multiply(z1).mod(q)
  151. const w6 = w4.subtract(w5)
  152. if (BigInteger.ZERO.equals(w3)) {
  153. if (BigInteger.ZERO.equals(w6)) {
  154. return this.twice() // this == b,计算自加
  155. }
  156. return this.curve.infinity // this == -b,则返回无穷远点
  157. }
  158. const w7 = w1.add(w2)
  159. const w8 = z1.multiply(z2).mod(q)
  160. const w9 = w3.square().mod(q)
  161. const w10 = w3.multiply(w9).mod(q)
  162. const w11 = w8.multiply(w6.square()).subtract(w7.multiply(w9)).mod(q)
  163. const x3 = w3.multiply(w11).mod(q)
  164. const y3 = w6.multiply(w9.multiply(w1).subtract(w11)).subtract(w4.multiply(w10)).mod(q)
  165. const z3 = w10.multiply(w8).mod(q)
  166. return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3)
  167. }
  168. /**
  169. * 自加
  170. *
  171. * 标准射影坐标系:
  172. *
  173. * λ1 = 3 * x1^2 + a * z1^2
  174. * λ2 = 2 * y1 * z1
  175. * λ3 = y1^2
  176. * λ4 = λ3 * x1 * z1
  177. * λ5 = λ2^2
  178. * λ6 = λ1^2 − 8 * λ4
  179. * x3 = λ2 * λ6
  180. * y3 = λ1 * (4 * λ4 − λ6) − 2 * λ5 * λ3
  181. * z3 = λ2 * λ5
  182. */
  183. twice() {
  184. if (this.isInfinity()) return this
  185. if (!this.y.toBigInteger().signum()) return this.curve.infinity
  186. const x1 = this.x.toBigInteger()
  187. const y1 = this.y.toBigInteger()
  188. const z1 = this.z
  189. const q = this.curve.q
  190. const a = this.curve.a.toBigInteger()
  191. const w1 = x1.square().multiply(THREE).add(a.multiply(z1.square())).mod(q)
  192. const w2 = y1.shiftLeft(1).multiply(z1).mod(q)
  193. const w3 = y1.square().mod(q)
  194. const w4 = w3.multiply(x1).multiply(z1).mod(q)
  195. const w5 = w2.square().mod(q)
  196. const w6 = w1.square().subtract(w4.shiftLeft(3)).mod(q)
  197. const x3 = w2.multiply(w6).mod(q)
  198. const y3 = w1.multiply(w4.shiftLeft(2).subtract(w6)).subtract(w5.shiftLeft(1).multiply(w3)).mod(q)
  199. const z3 = w2.multiply(w5).mod(q)
  200. return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3)
  201. }
  202. /**
  203. * 倍点计算
  204. */
  205. multiply(k) {
  206. if (this.isInfinity()) return this
  207. if (!k.signum()) return this.curve.infinity
  208. // 使用加减法
  209. const k3 = k.multiply(THREE)
  210. const neg = this.negate()
  211. let Q = this
  212. for (let i = k3.bitLength() - 2; i > 0; i--) {
  213. Q = Q.twice()
  214. const k3Bit = k3.testBit(i)
  215. const kBit = k.testBit(i)
  216. if (k3Bit !== kBit) {
  217. Q = Q.add(k3Bit ? this : neg)
  218. }
  219. }
  220. return Q
  221. }
  222. }
  223. /**
  224. * 椭圆曲线 y^2 = x^3 + ax + b
  225. */
  226. class ECCurveFp {
  227. constructor(q, a, b) {
  228. this.q = q
  229. this.a = this.fromBigInteger(a)
  230. this.b = this.fromBigInteger(b)
  231. this.infinity = new ECPointFp(this, null, null) // 无穷远点
  232. }
  233. /**
  234. * 判断两个椭圆曲线是否相等
  235. */
  236. equals(other) {
  237. if (other === this) return true
  238. return (this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b))
  239. }
  240. /**
  241. * 生成椭圆曲线域元素
  242. */
  243. fromBigInteger(x) {
  244. return new ECFieldElementFp(this.q, x)
  245. }
  246. /**
  247. * 解析 16 进制串为椭圆曲线点
  248. */
  249. decodePointHex(s) {
  250. switch (parseInt(s.substr(0, 2), 16)) {
  251. // 第一个字节
  252. case 0:
  253. return this.infinity
  254. case 2:
  255. case 3:
  256. // 压缩
  257. const x = this.fromBigInteger(new BigInteger(s.substr(2), 16))
  258. // 对 p ≡ 3 (mod4),即存在正整数 u,使得 p = 4u + 3
  259. // 计算 y = (√ (x^3 + ax + b) % p)^(u + 1) modp
  260. let y = this.fromBigInteger(x.multiply(x.square()).add(
  261. x.multiply(this.a)
  262. ).add(this.b).toBigInteger()
  263. .modPow(
  264. this.q.divide(new BigInteger('4')).add(BigInteger.ONE), this.q
  265. ))
  266. // 算出结果 2 进制最后 1 位不等于第 1 个字节减 2 则取反
  267. if (!y.toBigInteger().mod(TWO).equals(new BigInteger(s.substr(0, 2), 16).subtract(TWO))) {
  268. y = y.negate()
  269. }
  270. return new ECPointFp(this, x, y)
  271. case 4:
  272. case 6:
  273. case 7:
  274. const len = (s.length - 2) / 2
  275. const xHex = s.substr(2, len)
  276. const yHex = s.substr(len + 2, len)
  277. return new ECPointFp(this, this.fromBigInteger(new BigInteger(xHex, 16)), this.fromBigInteger(new BigInteger(yHex, 16)))
  278. default:
  279. // 不支持
  280. return null
  281. }
  282. }
  283. }
  284. module.exports = {
  285. ECPointFp,
  286. ECCurveFp,
  287. }