signature.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. 'use strict';
  2. var BN = require('bn.js');
  3. var elliptic = require('../../elliptic');
  4. var utils = elliptic.utils;
  5. var assert = utils.assert;
  6. function Signature(options, enc) {
  7. if (options instanceof Signature)
  8. return options;
  9. if (this._importDER(options, enc))
  10. return;
  11. assert(options.r && options.s, 'Signature without r or s');
  12. this.r = new BN(options.r, 16);
  13. this.s = new BN(options.s, 16);
  14. if (options.recoveryParam === undefined)
  15. this.recoveryParam = null;
  16. else
  17. this.recoveryParam = options.recoveryParam;
  18. }
  19. module.exports = Signature;
  20. function Position() {
  21. this.place = 0;
  22. }
  23. function getLength(buf, p) {
  24. var initial = buf[p.place++];
  25. if (!(initial & 0x80)) {
  26. return initial;
  27. }
  28. var octetLen = initial & 0xf;
  29. var val = 0;
  30. for (var i = 0, off = p.place; i < octetLen; i++, off++) {
  31. val <<= 8;
  32. val |= buf[off];
  33. }
  34. p.place = off;
  35. return val;
  36. }
  37. function rmPadding(buf) {
  38. var i = 0;
  39. var len = buf.length - 1;
  40. while (!buf[i] && !(buf[i + 1] & 0x80) && i < len) {
  41. i++;
  42. }
  43. if (i === 0) {
  44. return buf;
  45. }
  46. return buf.slice(i);
  47. }
  48. Signature.prototype._importDER = function _importDER(data, enc) {
  49. data = utils.toArray(data, enc);
  50. var p = new Position();
  51. if (data[p.place++] !== 0x30) {
  52. return false;
  53. }
  54. var len = getLength(data, p);
  55. if ((len + p.place) !== data.length) {
  56. return false;
  57. }
  58. if (data[p.place++] !== 0x02) {
  59. return false;
  60. }
  61. var rlen = getLength(data, p);
  62. var r = data.slice(p.place, rlen + p.place);
  63. p.place += rlen;
  64. if (data[p.place++] !== 0x02) {
  65. return false;
  66. }
  67. var slen = getLength(data, p);
  68. if (data.length !== slen + p.place) {
  69. return false;
  70. }
  71. var s = data.slice(p.place, slen + p.place);
  72. if (r[0] === 0 && (r[1] & 0x80)) {
  73. r = r.slice(1);
  74. }
  75. if (s[0] === 0 && (s[1] & 0x80)) {
  76. s = s.slice(1);
  77. }
  78. this.r = new BN(r);
  79. this.s = new BN(s);
  80. this.recoveryParam = null;
  81. return true;
  82. };
  83. function constructLength(arr, len) {
  84. if (len < 0x80) {
  85. arr.push(len);
  86. return;
  87. }
  88. var octets = 1 + (Math.log(len) / Math.LN2 >>> 3);
  89. arr.push(octets | 0x80);
  90. while (--octets) {
  91. arr.push((len >>> (octets << 3)) & 0xff);
  92. }
  93. arr.push(len);
  94. }
  95. Signature.prototype.toDER = function toDER(enc) {
  96. var r = this.r.toArray();
  97. var s = this.s.toArray();
  98. // Pad values
  99. if (r[0] & 0x80)
  100. r = [ 0 ].concat(r);
  101. // Pad values
  102. if (s[0] & 0x80)
  103. s = [ 0 ].concat(s);
  104. r = rmPadding(r);
  105. s = rmPadding(s);
  106. while (!s[0] && !(s[1] & 0x80)) {
  107. s = s.slice(1);
  108. }
  109. var arr = [ 0x02 ];
  110. constructLength(arr, r.length);
  111. arr = arr.concat(r);
  112. arr.push(0x02);
  113. constructLength(arr, s.length);
  114. var backHalf = arr.concat(s);
  115. var res = [ 0x30 ];
  116. constructLength(res, backHalf.length);
  117. res = res.concat(backHalf);
  118. return utils.encode(res, enc);
  119. };