Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

js.js 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. const BN = require('bn.js')
  2. const EC = require('elliptic').ec
  3. const secp256k1 = new EC('secp256k1')
  4. const deterministicGenerateK = require('./rfc6979')
  5. const ZERO32 = Buffer.alloc(32, 0)
  6. const EC_GROUP_ORDER = Buffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 'hex')
  7. const EC_P = Buffer.from('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 'hex')
  8. const n = secp256k1.curve.n
  9. const nDiv2 = n.shrn(1)
  10. const G = secp256k1.curve.g
  11. const THROW_BAD_PRIVATE = 'Expected Private'
  12. const THROW_BAD_POINT = 'Expected Point'
  13. const THROW_BAD_TWEAK = 'Expected Tweak'
  14. const THROW_BAD_HASH = 'Expected Hash'
  15. const THROW_BAD_SIGNATURE = 'Expected Signature'
  16. const THROW_BAD_EXTRA_DATA = 'Expected Extra Data (32 bytes)'
  17. function isScalar (x) {
  18. return Buffer.isBuffer(x) && x.length === 32
  19. }
  20. function isOrderScalar (x) {
  21. if (!isScalar(x)) return false
  22. return x.compare(EC_GROUP_ORDER) < 0 // < G
  23. }
  24. function isPoint (p) {
  25. if (!Buffer.isBuffer(p)) return false
  26. if (p.length < 33) return false
  27. const t = p[0]
  28. const x = p.slice(1, 33)
  29. if (x.compare(ZERO32) === 0) return false
  30. if (x.compare(EC_P) >= 0) return false
  31. if ((t === 0x02 || t === 0x03) && p.length === 33) {
  32. try { decodeFrom(p) } catch (e) { return false } // TODO: temporary
  33. return true
  34. }
  35. const y = p.slice(33)
  36. if (y.compare(ZERO32) === 0) return false
  37. if (y.compare(EC_P) >= 0) return false
  38. if (t === 0x04 && p.length === 65) return true
  39. return false
  40. }
  41. function __isPointCompressed (p) {
  42. return p[0] !== 0x04
  43. }
  44. function isPointCompressed (p) {
  45. if (!isPoint(p)) return false
  46. return __isPointCompressed(p)
  47. }
  48. function isPrivate (x) {
  49. if (!isScalar(x)) return false
  50. return x.compare(ZERO32) > 0 && // > 0
  51. x.compare(EC_GROUP_ORDER) < 0 // < G
  52. }
  53. function isSignature (value) {
  54. const r = value.slice(0, 32)
  55. const s = value.slice(32, 64)
  56. return Buffer.isBuffer(value) && value.length === 64 &&
  57. r.compare(EC_GROUP_ORDER) < 0 &&
  58. s.compare(EC_GROUP_ORDER) < 0
  59. }
  60. function assumeCompression (value, pubkey) {
  61. if (value === undefined && pubkey !== undefined) return __isPointCompressed(pubkey)
  62. if (value === undefined) return true
  63. return value
  64. }
  65. function fromBuffer (d) { return new BN(d) }
  66. function toBuffer (d) { return d.toArrayLike(Buffer, 'be', 32) }
  67. function decodeFrom (P) { return secp256k1.curve.decodePoint(P) }
  68. function getEncoded (P, compressed) { return Buffer.from(P._encode(compressed)) }
  69. function pointAdd (pA, pB, __compressed) {
  70. if (!isPoint(pA)) throw new TypeError(THROW_BAD_POINT)
  71. if (!isPoint(pB)) throw new TypeError(THROW_BAD_POINT)
  72. const a = decodeFrom(pA)
  73. const b = decodeFrom(pB)
  74. const pp = a.add(b)
  75. if (pp.isInfinity()) return null
  76. const compressed = assumeCompression(__compressed, pA)
  77. return getEncoded(pp, compressed)
  78. }
  79. function pointAddScalar (p, tweak, __compressed) {
  80. if (!isPoint(p)) throw new TypeError(THROW_BAD_POINT)
  81. if (!isOrderScalar(tweak)) throw new TypeError(THROW_BAD_TWEAK)
  82. const compressed = assumeCompression(__compressed, p)
  83. const pp = decodeFrom(p)
  84. if (tweak.compare(ZERO32) === 0) return getEncoded(pp, compressed)
  85. const tt = fromBuffer(tweak)
  86. const qq = G.mul(tt)
  87. const uu = pp.add(qq)
  88. if (uu.isInfinity()) return null
  89. return getEncoded(uu, compressed)
  90. }
  91. function pointCompress (p, __compressed) {
  92. if (!isPoint(p)) throw new TypeError(THROW_BAD_POINT)
  93. const pp = decodeFrom(p)
  94. if (pp.isInfinity()) throw new TypeError(THROW_BAD_POINT)
  95. const compressed = assumeCompression(__compressed, p)
  96. return getEncoded(pp, compressed)
  97. }
  98. function pointFromScalar (d, __compressed) {
  99. if (!isPrivate(d)) throw new TypeError(THROW_BAD_PRIVATE)
  100. const dd = fromBuffer(d)
  101. const pp = G.mul(dd)
  102. if (pp.isInfinity()) return null
  103. const compressed = assumeCompression(__compressed)
  104. return getEncoded(pp, compressed)
  105. }
  106. function pointMultiply (p, tweak, __compressed) {
  107. if (!isPoint(p)) throw new TypeError(THROW_BAD_POINT)
  108. if (!isOrderScalar(tweak)) throw new TypeError(THROW_BAD_TWEAK)
  109. const compressed = assumeCompression(__compressed, p)
  110. const pp = decodeFrom(p)
  111. const tt = fromBuffer(tweak)
  112. const qq = pp.mul(tt)
  113. if (qq.isInfinity()) return null
  114. return getEncoded(qq, compressed)
  115. }
  116. function privateAdd (d, tweak) {
  117. if (!isPrivate(d)) throw new TypeError(THROW_BAD_PRIVATE)
  118. if (!isOrderScalar(tweak)) throw new TypeError(THROW_BAD_TWEAK)
  119. const dd = fromBuffer(d)
  120. const tt = fromBuffer(tweak)
  121. const dt = toBuffer(dd.add(tt).umod(n))
  122. if (!isPrivate(dt)) return null
  123. return dt
  124. }
  125. function privateSub (d, tweak) {
  126. if (!isPrivate(d)) throw new TypeError(THROW_BAD_PRIVATE)
  127. if (!isOrderScalar(tweak)) throw new TypeError(THROW_BAD_TWEAK)
  128. const dd = fromBuffer(d)
  129. const tt = fromBuffer(tweak)
  130. const dt = toBuffer(dd.sub(tt).umod(n))
  131. if (!isPrivate(dt)) return null
  132. return dt
  133. }
  134. function sign (hash, x) {
  135. return __sign(hash, x)
  136. }
  137. function signWithEntropy (hash, x, addData) {
  138. return __sign(hash, x, addData)
  139. }
  140. function __sign (hash, x, addData) {
  141. if (!isScalar(hash)) throw new TypeError(THROW_BAD_HASH)
  142. if (!isPrivate(x)) throw new TypeError(THROW_BAD_PRIVATE)
  143. if (addData !== undefined && !isScalar(addData)) throw new TypeError(THROW_BAD_EXTRA_DATA)
  144. const d = fromBuffer(x)
  145. const e = fromBuffer(hash)
  146. let r, s
  147. const checkSig = function (k) {
  148. const kI = fromBuffer(k)
  149. const Q = G.mul(kI)
  150. if (Q.isInfinity()) return false
  151. r = Q.x.umod(n)
  152. if (r.isZero() === 0) return false
  153. s = kI
  154. .invm(n)
  155. .mul(e.add(d.mul(r)))
  156. .umod(n)
  157. if (s.isZero() === 0) return false
  158. return true
  159. }
  160. deterministicGenerateK(hash, x, checkSig, isPrivate, addData)
  161. // enforce low S values, see bip62: 'low s values in signatures'
  162. if (s.cmp(nDiv2) > 0) {
  163. s = n.sub(s)
  164. }
  165. const buffer = Buffer.allocUnsafe(64)
  166. toBuffer(r).copy(buffer, 0)
  167. toBuffer(s).copy(buffer, 32)
  168. return buffer
  169. }
  170. function verify (hash, q, signature, strict) {
  171. if (!isScalar(hash)) throw new TypeError(THROW_BAD_HASH)
  172. if (!isPoint(q)) throw new TypeError(THROW_BAD_POINT)
  173. // 1.4.1 Enforce r and s are both integers in the interval [1, n − 1] (1, isSignature enforces '< n - 1')
  174. if (!isSignature(signature)) throw new TypeError(THROW_BAD_SIGNATURE)
  175. const Q = decodeFrom(q)
  176. const r = fromBuffer(signature.slice(0, 32))
  177. const s = fromBuffer(signature.slice(32, 64))
  178. if (strict && s.cmp(nDiv2) > 0) {
  179. return false
  180. }
  181. // 1.4.1 Enforce r and s are both integers in the interval [1, n − 1] (2, enforces '> 0')
  182. if (r.gtn(0) <= 0 /* || r.compareTo(n) >= 0 */) return false
  183. if (s.gtn(0) <= 0 /* || s.compareTo(n) >= 0 */) return false
  184. // 1.4.2 H = Hash(M), already done by the user
  185. // 1.4.3 e = H
  186. const e = fromBuffer(hash)
  187. // Compute s^-1
  188. const sInv = s.invm(n)
  189. // 1.4.4 Compute u1 = es^−1 mod n
  190. // u2 = rs^−1 mod n
  191. const u1 = e.mul(sInv).umod(n)
  192. const u2 = r.mul(sInv).umod(n)
  193. // 1.4.5 Compute R = (xR, yR)
  194. // R = u1G + u2Q
  195. const R = G.mulAdd(u1, Q, u2)
  196. // 1.4.5 (cont.) Enforce R is not at infinity
  197. if (R.isInfinity()) return false
  198. // 1.4.6 Convert the field element R.x to an integer
  199. const xR = R.x
  200. // 1.4.7 Set v = xR mod n
  201. const v = xR.umod(n)
  202. // 1.4.8 If v = r, output "valid", and if v != r, output "invalid"
  203. return v.eq(r)
  204. }
  205. module.exports = {
  206. isPoint,
  207. isPointCompressed,
  208. isPrivate,
  209. pointAdd,
  210. pointAddScalar,
  211. pointCompress,
  212. pointFromScalar,
  213. pointMultiply,
  214. privateAdd,
  215. privateSub,
  216. sign,
  217. signWithEntropy,
  218. verify
  219. }