_sha2.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.SHA2 = void 0;
  4. const _assert_js_1 = require("./_assert.js");
  5. const utils_js_1 = require("./utils.js");
  6. // Polyfill for Safari 14
  7. function setBigUint64(view, byteOffset, value, isLE) {
  8. if (typeof view.setBigUint64 === 'function')
  9. return view.setBigUint64(byteOffset, value, isLE);
  10. const _32n = BigInt(32);
  11. const _u32_max = BigInt(0xffffffff);
  12. const wh = Number((value >> _32n) & _u32_max);
  13. const wl = Number(value & _u32_max);
  14. const h = isLE ? 4 : 0;
  15. const l = isLE ? 0 : 4;
  16. view.setUint32(byteOffset + h, wh, isLE);
  17. view.setUint32(byteOffset + l, wl, isLE);
  18. }
  19. // Base SHA2 class (RFC 6234)
  20. class SHA2 extends utils_js_1.Hash {
  21. constructor(blockLen, outputLen, padOffset, isLE) {
  22. super();
  23. this.blockLen = blockLen;
  24. this.outputLen = outputLen;
  25. this.padOffset = padOffset;
  26. this.isLE = isLE;
  27. this.finished = false;
  28. this.length = 0;
  29. this.pos = 0;
  30. this.destroyed = false;
  31. this.buffer = new Uint8Array(blockLen);
  32. this.view = (0, utils_js_1.createView)(this.buffer);
  33. }
  34. update(data) {
  35. (0, _assert_js_1.exists)(this);
  36. const { view, buffer, blockLen } = this;
  37. data = (0, utils_js_1.toBytes)(data);
  38. const len = data.length;
  39. for (let pos = 0; pos < len;) {
  40. const take = Math.min(blockLen - this.pos, len - pos);
  41. // Fast path: we have at least one block in input, cast it to view and process
  42. if (take === blockLen) {
  43. const dataView = (0, utils_js_1.createView)(data);
  44. for (; blockLen <= len - pos; pos += blockLen)
  45. this.process(dataView, pos);
  46. continue;
  47. }
  48. buffer.set(data.subarray(pos, pos + take), this.pos);
  49. this.pos += take;
  50. pos += take;
  51. if (this.pos === blockLen) {
  52. this.process(view, 0);
  53. this.pos = 0;
  54. }
  55. }
  56. this.length += data.length;
  57. this.roundClean();
  58. return this;
  59. }
  60. digestInto(out) {
  61. (0, _assert_js_1.exists)(this);
  62. (0, _assert_js_1.output)(out, this);
  63. this.finished = true;
  64. // Padding
  65. // We can avoid allocation of buffer for padding completely if it
  66. // was previously not allocated here. But it won't change performance.
  67. const { buffer, view, blockLen, isLE } = this;
  68. let { pos } = this;
  69. // append the bit '1' to the message
  70. buffer[pos++] = 0b10000000;
  71. this.buffer.subarray(pos).fill(0);
  72. // we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
  73. if (this.padOffset > blockLen - pos) {
  74. this.process(view, 0);
  75. pos = 0;
  76. }
  77. // Pad until full block byte with zeros
  78. for (let i = pos; i < blockLen; i++)
  79. buffer[i] = 0;
  80. // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
  81. // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
  82. // So we just write lowest 64 bits of that value.
  83. setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
  84. this.process(view, 0);
  85. const oview = (0, utils_js_1.createView)(out);
  86. const len = this.outputLen;
  87. // NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
  88. if (len % 4)
  89. throw new Error('_sha2: outputLen should be aligned to 32bit');
  90. const outLen = len / 4;
  91. const state = this.get();
  92. if (outLen > state.length)
  93. throw new Error('_sha2: outputLen bigger than state');
  94. for (let i = 0; i < outLen; i++)
  95. oview.setUint32(4 * i, state[i], isLE);
  96. }
  97. digest() {
  98. const { buffer, outputLen } = this;
  99. this.digestInto(buffer);
  100. const res = buffer.slice(0, outputLen);
  101. this.destroy();
  102. return res;
  103. }
  104. _cloneInto(to) {
  105. to || (to = new this.constructor());
  106. to.set(...this.get());
  107. const { blockLen, buffer, length, finished, destroyed, pos } = this;
  108. to.length = length;
  109. to.pos = pos;
  110. to.finished = finished;
  111. to.destroyed = destroyed;
  112. if (length % blockLen)
  113. to.buffer.set(buffer);
  114. return to;
  115. }
  116. }
  117. exports.SHA2 = SHA2;
  118. //# sourceMappingURL=_sha2.js.map