123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.HashMD = exports.Maj = exports.Chi = void 0;
- const _assert_js_1 = require("./_assert.js");
- const utils_js_1 = require("./utils.js");
- // Polyfill for Safari 14
- function setBigUint64(view, byteOffset, value, isLE) {
- if (typeof view.setBigUint64 === 'function')
- return view.setBigUint64(byteOffset, value, isLE);
- const _32n = BigInt(32);
- const _u32_max = BigInt(0xffffffff);
- const wh = Number((value >> _32n) & _u32_max);
- const wl = Number(value & _u32_max);
- const h = isLE ? 4 : 0;
- const l = isLE ? 0 : 4;
- view.setUint32(byteOffset + h, wh, isLE);
- view.setUint32(byteOffset + l, wl, isLE);
- }
- // Choice: a ? b : c
- const Chi = (a, b, c) => (a & b) ^ (~a & c);
- exports.Chi = Chi;
- // Majority function, true if any two inpust is true
- const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
- exports.Maj = Maj;
- /**
- * Merkle-Damgard hash construction base class.
- * Could be used to create MD5, RIPEMD, SHA1, SHA2.
- */
- class HashMD extends utils_js_1.Hash {
- constructor(blockLen, outputLen, padOffset, isLE) {
- super();
- this.blockLen = blockLen;
- this.outputLen = outputLen;
- this.padOffset = padOffset;
- this.isLE = isLE;
- this.finished = false;
- this.length = 0;
- this.pos = 0;
- this.destroyed = false;
- this.buffer = new Uint8Array(blockLen);
- this.view = (0, utils_js_1.createView)(this.buffer);
- }
- update(data) {
- (0, _assert_js_1.exists)(this);
- const { view, buffer, blockLen } = this;
- data = (0, utils_js_1.toBytes)(data);
- const len = data.length;
- for (let pos = 0; pos < len;) {
- const take = Math.min(blockLen - this.pos, len - pos);
- // Fast path: we have at least one block in input, cast it to view and process
- if (take === blockLen) {
- const dataView = (0, utils_js_1.createView)(data);
- for (; blockLen <= len - pos; pos += blockLen)
- this.process(dataView, pos);
- continue;
- }
- buffer.set(data.subarray(pos, pos + take), this.pos);
- this.pos += take;
- pos += take;
- if (this.pos === blockLen) {
- this.process(view, 0);
- this.pos = 0;
- }
- }
- this.length += data.length;
- this.roundClean();
- return this;
- }
- digestInto(out) {
- (0, _assert_js_1.exists)(this);
- (0, _assert_js_1.output)(out, this);
- this.finished = true;
- // Padding
- // We can avoid allocation of buffer for padding completely if it
- // was previously not allocated here. But it won't change performance.
- const { buffer, view, blockLen, isLE } = this;
- let { pos } = this;
- // append the bit '1' to the message
- buffer[pos++] = 0b10000000;
- this.buffer.subarray(pos).fill(0);
- // we have less than padOffset left in buffer, so we cannot put length in
- // current block, need process it and pad again
- if (this.padOffset > blockLen - pos) {
- this.process(view, 0);
- pos = 0;
- }
- // Pad until full block byte with zeros
- for (let i = pos; i < blockLen; i++)
- buffer[i] = 0;
- // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
- // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
- // So we just write lowest 64 bits of that value.
- setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
- this.process(view, 0);
- const oview = (0, utils_js_1.createView)(out);
- const len = this.outputLen;
- // NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
- if (len % 4)
- throw new Error('_sha2: outputLen should be aligned to 32bit');
- const outLen = len / 4;
- const state = this.get();
- if (outLen > state.length)
- throw new Error('_sha2: outputLen bigger than state');
- for (let i = 0; i < outLen; i++)
- oview.setUint32(4 * i, state[i], isLE);
- }
- digest() {
- const { buffer, outputLen } = this;
- this.digestInto(buffer);
- const res = buffer.slice(0, outputLen);
- this.destroy();
- return res;
- }
- _cloneInto(to) {
- to || (to = new this.constructor());
- to.set(...this.get());
- const { blockLen, buffer, length, finished, destroyed, pos } = this;
- to.length = length;
- to.pos = pos;
- to.finished = finished;
- to.destroyed = destroyed;
- if (length % blockLen)
- to.buffer.set(buffer);
- return to;
- }
- }
- exports.HashMD = HashMD;
- //# sourceMappingURL=_md.js.map
|