UNPKG

@hpke/common

Version:

A Hybrid Public Key Encryption (HPKE) internal-use common module for @hpke family modules.

255 lines (254 loc) 9.08 kB
(function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "../utils/noble.js"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SHA512_IV = exports.SHA384_IV = exports.SHA256_IV = exports.HashMD = void 0; exports.Chi = Chi; exports.Maj = Maj; // deno-lint-ignore-file no-explicit-any /** * This file is based on noble-hashes (https://github.com/paulmillr/noble-hashes). * * noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) * * The original file is located at: * https://github.com/paulmillr/noble-hashes/blob/2e0c00e1aa134082ba1380bf3afb8b1641f60fed/src/_md.ts */ /** * Internal Merkle-Damgard hash utils. * @module */ const noble_js_1 = require("../utils/noble.js"); /** Choice: a ? b : c */ function Chi(a, b, c) { return (a & b) ^ (~a & c); } /** Majority function, true if any two inputs is true. */ function Maj(a, b, c) { return (a & b) ^ (a & c) ^ (b & c); } /** * Merkle-Damgard hash construction base class. * Could be used to create MD5, RIPEMD, SHA1, SHA2. */ class HashMD { constructor(blockLen, outputLen, padOffset, isLE) { Object.defineProperty(this, "blockLen", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "outputLen", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "padOffset", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "isLE", { enumerable: true, configurable: true, writable: true, value: void 0 }); // For partial updates less than block size Object.defineProperty(this, "buffer", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "view", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "finished", { enumerable: true, configurable: true, writable: true, value: false }); Object.defineProperty(this, "length", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "pos", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "destroyed", { enumerable: true, configurable: true, writable: true, value: false }); this.blockLen = blockLen; this.outputLen = outputLen; this.padOffset = padOffset; this.isLE = isLE; this.buffer = new Uint8Array(blockLen); this.view = (0, noble_js_1.createView)(this.buffer); } update(data) { (0, noble_js_1.aexists)(this); (0, noble_js_1.abytes)(data); const { view, buffer, blockLen } = this; 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, noble_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, noble_js_1.aexists)(this); (0, noble_js_1.aoutput)(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; (0, noble_js_1.clean)(this.buffer.subarray(pos)); // 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. view.setBigUint64(blockLen - 8, (0, noble_js_1.numberToBigint)(this.length * 8), isLE); this.process(view, 0); const oview = (0, noble_js_1.createView)(out); const len = this.outputLen; // NOTE: we do division by 4 later, which must be fused in single op with modulo by JIT if (len % 4) throw new Error("_sha2: outputLen must 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 ||= new this.constructor(); to.set(...this.get()); const { blockLen, buffer, length, finished, destroyed, pos } = this; to.destroyed = destroyed; to.finished = finished; to.length = length; to.pos = pos; if (length % blockLen) to.buffer.set(buffer); return to; } clone() { return this._cloneInto(); } } exports.HashMD = HashMD; /** * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53. * Check out `test/misc/sha2-gen-iv.js` for recomputation guide. */ /** Initial SHA256 state. Bits 0..32 of frac part of sqrt of primes 2..19 */ exports.SHA256_IV = Uint32Array.from([ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, ]); /** Initial SHA384 state. Bits 0..64 of frac part of sqrt of primes 23..53 */ exports.SHA384_IV = Uint32Array.from([ 0xcbbb9d5d, 0xc1059ed8, 0x629a292a, 0x367cd507, 0x9159015a, 0x3070dd17, 0x152fecd8, 0xf70e5939, 0x67332667, 0xffc00b31, 0x8eb44a87, 0x68581511, 0xdb0c2e0d, 0x64f98fa7, 0x47b5481d, 0xbefa4fa4, ]); /** Initial SHA512 state. Bits 0..64 of frac part of sqrt of primes 2..19 */ exports.SHA512_IV = Uint32Array.from([ 0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1, 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179, ]); });