_blake.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.BLAKE = exports.SIGMA = void 0;
  4. const _assert_js_1 = require("./_assert.js");
  5. const utils_js_1 = require("./utils.js");
  6. // Blake is based on ChaCha permutation.
  7. // For BLAKE2b, the two extra permutations for rounds 10 and 11 are SIGMA[10..11] = SIGMA[0..1].
  8. // prettier-ignore
  9. exports.SIGMA = new Uint8Array([
  10. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  11. 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
  12. 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
  13. 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
  14. 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
  15. 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
  16. 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
  17. 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
  18. 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
  19. 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
  20. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  21. 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
  22. ]);
  23. class BLAKE extends utils_js_1.Hash {
  24. constructor(blockLen, outputLen, opts = {}, keyLen, saltLen, persLen) {
  25. super();
  26. this.blockLen = blockLen;
  27. this.outputLen = outputLen;
  28. this.length = 0;
  29. this.pos = 0;
  30. this.finished = false;
  31. this.destroyed = false;
  32. (0, _assert_js_1.number)(blockLen);
  33. (0, _assert_js_1.number)(outputLen);
  34. (0, _assert_js_1.number)(keyLen);
  35. if (outputLen < 0 || outputLen > keyLen)
  36. throw new Error('outputLen bigger than keyLen');
  37. if (opts.key !== undefined && (opts.key.length < 1 || opts.key.length > keyLen))
  38. throw new Error(`key must be up 1..${keyLen} byte long or undefined`);
  39. if (opts.salt !== undefined && opts.salt.length !== saltLen)
  40. throw new Error(`salt must be ${saltLen} byte long or undefined`);
  41. if (opts.personalization !== undefined && opts.personalization.length !== persLen)
  42. throw new Error(`personalization must be ${persLen} byte long or undefined`);
  43. this.buffer32 = (0, utils_js_1.u32)((this.buffer = new Uint8Array(blockLen)));
  44. }
  45. update(data) {
  46. (0, _assert_js_1.exists)(this);
  47. // Main difference with other hashes: there is flag for last block,
  48. // so we cannot process current block before we know that there
  49. // is the next one. This significantly complicates logic and reduces ability
  50. // to do zero-copy processing
  51. const { blockLen, buffer, buffer32 } = this;
  52. data = (0, utils_js_1.toBytes)(data);
  53. const len = data.length;
  54. const offset = data.byteOffset;
  55. const buf = data.buffer;
  56. for (let pos = 0; pos < len;) {
  57. // If buffer is full and we still have input (don't process last block, same as blake2s)
  58. if (this.pos === blockLen) {
  59. if (!utils_js_1.isLE)
  60. (0, utils_js_1.byteSwap32)(buffer32);
  61. this.compress(buffer32, 0, false);
  62. if (!utils_js_1.isLE)
  63. (0, utils_js_1.byteSwap32)(buffer32);
  64. this.pos = 0;
  65. }
  66. const take = Math.min(blockLen - this.pos, len - pos);
  67. const dataOffset = offset + pos;
  68. // full block && aligned to 4 bytes && not last in input
  69. if (take === blockLen && !(dataOffset % 4) && pos + take < len) {
  70. const data32 = new Uint32Array(buf, dataOffset, Math.floor((len - pos) / 4));
  71. if (!utils_js_1.isLE)
  72. (0, utils_js_1.byteSwap32)(data32);
  73. for (let pos32 = 0; pos + blockLen < len; pos32 += buffer32.length, pos += blockLen) {
  74. this.length += blockLen;
  75. this.compress(data32, pos32, false);
  76. }
  77. if (!utils_js_1.isLE)
  78. (0, utils_js_1.byteSwap32)(data32);
  79. continue;
  80. }
  81. buffer.set(data.subarray(pos, pos + take), this.pos);
  82. this.pos += take;
  83. this.length += take;
  84. pos += take;
  85. }
  86. return this;
  87. }
  88. digestInto(out) {
  89. (0, _assert_js_1.exists)(this);
  90. (0, _assert_js_1.output)(out, this);
  91. const { pos, buffer32 } = this;
  92. this.finished = true;
  93. // Padding
  94. this.buffer.subarray(pos).fill(0);
  95. if (!utils_js_1.isLE)
  96. (0, utils_js_1.byteSwap32)(buffer32);
  97. this.compress(buffer32, 0, true);
  98. if (!utils_js_1.isLE)
  99. (0, utils_js_1.byteSwap32)(buffer32);
  100. const out32 = (0, utils_js_1.u32)(out);
  101. this.get().forEach((v, i) => (out32[i] = (0, utils_js_1.byteSwapIfBE)(v)));
  102. }
  103. digest() {
  104. const { buffer, outputLen } = this;
  105. this.digestInto(buffer);
  106. const res = buffer.slice(0, outputLen);
  107. this.destroy();
  108. return res;
  109. }
  110. _cloneInto(to) {
  111. const { buffer, length, finished, destroyed, outputLen, pos } = this;
  112. to || (to = new this.constructor({ dkLen: outputLen }));
  113. to.set(...this.get());
  114. to.length = length;
  115. to.finished = finished;
  116. to.destroyed = destroyed;
  117. to.outputLen = outputLen;
  118. to.buffer.set(buffer);
  119. to.pos = pos;
  120. return to;
  121. }
  122. }
  123. exports.BLAKE = BLAKE;
  124. //# sourceMappingURL=_blake.js.map