sha3.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.shake256 = exports.shake128 = exports.keccak_512 = exports.keccak_384 = exports.keccak_256 = exports.keccak_224 = exports.sha3_512 = exports.sha3_384 = exports.sha3_256 = exports.sha3_224 = exports.Keccak = exports.keccakP = void 0;
  4. const _assert_js_1 = require("./_assert.js");
  5. const _u64_js_1 = require("./_u64.js");
  6. const utils_js_1 = require("./utils.js");
  7. // SHA3 (keccak) is based on a new design: basically, the internal state is bigger than output size.
  8. // It's called a sponge function.
  9. // Various per round constants calculations
  10. const SHA3_PI = [];
  11. const SHA3_ROTL = [];
  12. const _SHA3_IOTA = [];
  13. const _0n = /* @__PURE__ */ BigInt(0);
  14. const _1n = /* @__PURE__ */ BigInt(1);
  15. const _2n = /* @__PURE__ */ BigInt(2);
  16. const _7n = /* @__PURE__ */ BigInt(7);
  17. const _256n = /* @__PURE__ */ BigInt(256);
  18. const _0x71n = /* @__PURE__ */ BigInt(0x71);
  19. for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
  20. // Pi
  21. [x, y] = [y, (2 * x + 3 * y) % 5];
  22. SHA3_PI.push(2 * (5 * y + x));
  23. // Rotational
  24. SHA3_ROTL.push((((round + 1) * (round + 2)) / 2) % 64);
  25. // Iota
  26. let t = _0n;
  27. for (let j = 0; j < 7; j++) {
  28. R = ((R << _1n) ^ ((R >> _7n) * _0x71n)) % _256n;
  29. if (R & _2n)
  30. t ^= _1n << ((_1n << /* @__PURE__ */ BigInt(j)) - _1n);
  31. }
  32. _SHA3_IOTA.push(t);
  33. }
  34. const [SHA3_IOTA_H, SHA3_IOTA_L] = /* @__PURE__ */ (0, _u64_js_1.split)(_SHA3_IOTA, true);
  35. // Left rotation (without 0, 32, 64)
  36. const rotlH = (h, l, s) => (s > 32 ? (0, _u64_js_1.rotlBH)(h, l, s) : (0, _u64_js_1.rotlSH)(h, l, s));
  37. const rotlL = (h, l, s) => (s > 32 ? (0, _u64_js_1.rotlBL)(h, l, s) : (0, _u64_js_1.rotlSL)(h, l, s));
  38. // Same as keccakf1600, but allows to skip some rounds
  39. function keccakP(s, rounds = 24) {
  40. const B = new Uint32Array(5 * 2);
  41. // NOTE: all indices are x2 since we store state as u32 instead of u64 (bigints to slow in js)
  42. for (let round = 24 - rounds; round < 24; round++) {
  43. // Theta θ
  44. for (let x = 0; x < 10; x++)
  45. B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
  46. for (let x = 0; x < 10; x += 2) {
  47. const idx1 = (x + 8) % 10;
  48. const idx0 = (x + 2) % 10;
  49. const B0 = B[idx0];
  50. const B1 = B[idx0 + 1];
  51. const Th = rotlH(B0, B1, 1) ^ B[idx1];
  52. const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
  53. for (let y = 0; y < 50; y += 10) {
  54. s[x + y] ^= Th;
  55. s[x + y + 1] ^= Tl;
  56. }
  57. }
  58. // Rho (ρ) and Pi (π)
  59. let curH = s[2];
  60. let curL = s[3];
  61. for (let t = 0; t < 24; t++) {
  62. const shift = SHA3_ROTL[t];
  63. const Th = rotlH(curH, curL, shift);
  64. const Tl = rotlL(curH, curL, shift);
  65. const PI = SHA3_PI[t];
  66. curH = s[PI];
  67. curL = s[PI + 1];
  68. s[PI] = Th;
  69. s[PI + 1] = Tl;
  70. }
  71. // Chi (χ)
  72. for (let y = 0; y < 50; y += 10) {
  73. for (let x = 0; x < 10; x++)
  74. B[x] = s[y + x];
  75. for (let x = 0; x < 10; x++)
  76. s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
  77. }
  78. // Iota (ι)
  79. s[0] ^= SHA3_IOTA_H[round];
  80. s[1] ^= SHA3_IOTA_L[round];
  81. }
  82. B.fill(0);
  83. }
  84. exports.keccakP = keccakP;
  85. class Keccak extends utils_js_1.Hash {
  86. // NOTE: we accept arguments in bytes instead of bits here.
  87. constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
  88. super();
  89. this.blockLen = blockLen;
  90. this.suffix = suffix;
  91. this.outputLen = outputLen;
  92. this.enableXOF = enableXOF;
  93. this.rounds = rounds;
  94. this.pos = 0;
  95. this.posOut = 0;
  96. this.finished = false;
  97. this.destroyed = false;
  98. // Can be passed from user as dkLen
  99. (0, _assert_js_1.number)(outputLen);
  100. // 1600 = 5x5 matrix of 64bit. 1600 bits === 200 bytes
  101. if (0 >= this.blockLen || this.blockLen >= 200)
  102. throw new Error('Sha3 supports only keccak-f1600 function');
  103. this.state = new Uint8Array(200);
  104. this.state32 = (0, utils_js_1.u32)(this.state);
  105. }
  106. keccak() {
  107. if (!utils_js_1.isLE)
  108. (0, utils_js_1.byteSwap32)(this.state32);
  109. keccakP(this.state32, this.rounds);
  110. if (!utils_js_1.isLE)
  111. (0, utils_js_1.byteSwap32)(this.state32);
  112. this.posOut = 0;
  113. this.pos = 0;
  114. }
  115. update(data) {
  116. (0, _assert_js_1.exists)(this);
  117. const { blockLen, state } = this;
  118. data = (0, utils_js_1.toBytes)(data);
  119. const len = data.length;
  120. for (let pos = 0; pos < len;) {
  121. const take = Math.min(blockLen - this.pos, len - pos);
  122. for (let i = 0; i < take; i++)
  123. state[this.pos++] ^= data[pos++];
  124. if (this.pos === blockLen)
  125. this.keccak();
  126. }
  127. return this;
  128. }
  129. finish() {
  130. if (this.finished)
  131. return;
  132. this.finished = true;
  133. const { state, suffix, pos, blockLen } = this;
  134. // Do the padding
  135. state[pos] ^= suffix;
  136. if ((suffix & 0x80) !== 0 && pos === blockLen - 1)
  137. this.keccak();
  138. state[blockLen - 1] ^= 0x80;
  139. this.keccak();
  140. }
  141. writeInto(out) {
  142. (0, _assert_js_1.exists)(this, false);
  143. (0, _assert_js_1.bytes)(out);
  144. this.finish();
  145. const bufferOut = this.state;
  146. const { blockLen } = this;
  147. for (let pos = 0, len = out.length; pos < len;) {
  148. if (this.posOut >= blockLen)
  149. this.keccak();
  150. const take = Math.min(blockLen - this.posOut, len - pos);
  151. out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
  152. this.posOut += take;
  153. pos += take;
  154. }
  155. return out;
  156. }
  157. xofInto(out) {
  158. // Sha3/Keccak usage with XOF is probably mistake, only SHAKE instances can do XOF
  159. if (!this.enableXOF)
  160. throw new Error('XOF is not possible for this instance');
  161. return this.writeInto(out);
  162. }
  163. xof(bytes) {
  164. (0, _assert_js_1.number)(bytes);
  165. return this.xofInto(new Uint8Array(bytes));
  166. }
  167. digestInto(out) {
  168. (0, _assert_js_1.output)(out, this);
  169. if (this.finished)
  170. throw new Error('digest() was already called');
  171. this.writeInto(out);
  172. this.destroy();
  173. return out;
  174. }
  175. digest() {
  176. return this.digestInto(new Uint8Array(this.outputLen));
  177. }
  178. destroy() {
  179. this.destroyed = true;
  180. this.state.fill(0);
  181. }
  182. _cloneInto(to) {
  183. const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
  184. to || (to = new Keccak(blockLen, suffix, outputLen, enableXOF, rounds));
  185. to.state32.set(this.state32);
  186. to.pos = this.pos;
  187. to.posOut = this.posOut;
  188. to.finished = this.finished;
  189. to.rounds = rounds;
  190. // Suffix can change in cSHAKE
  191. to.suffix = suffix;
  192. to.outputLen = outputLen;
  193. to.enableXOF = enableXOF;
  194. to.destroyed = this.destroyed;
  195. return to;
  196. }
  197. }
  198. exports.Keccak = Keccak;
  199. const gen = (suffix, blockLen, outputLen) => (0, utils_js_1.wrapConstructor)(() => new Keccak(blockLen, suffix, outputLen));
  200. exports.sha3_224 = gen(0x06, 144, 224 / 8);
  201. /**
  202. * SHA3-256 hash function
  203. * @param message - that would be hashed
  204. */
  205. exports.sha3_256 = gen(0x06, 136, 256 / 8);
  206. exports.sha3_384 = gen(0x06, 104, 384 / 8);
  207. exports.sha3_512 = gen(0x06, 72, 512 / 8);
  208. exports.keccak_224 = gen(0x01, 144, 224 / 8);
  209. /**
  210. * keccak-256 hash function. Different from SHA3-256.
  211. * @param message - that would be hashed
  212. */
  213. exports.keccak_256 = gen(0x01, 136, 256 / 8);
  214. exports.keccak_384 = gen(0x01, 104, 384 / 8);
  215. exports.keccak_512 = gen(0x01, 72, 512 / 8);
  216. const genShake = (suffix, blockLen, outputLen) => (0, utils_js_1.wrapXOFConstructorWithOpts)((opts = {}) => new Keccak(blockLen, suffix, opts.dkLen === undefined ? outputLen : opts.dkLen, true));
  217. exports.shake128 = genShake(0x1f, 168, 128 / 8);
  218. exports.shake256 = genShake(0x1f, 136, 256 / 8);
  219. //# sourceMappingURL=sha3.js.map