From 7cbc2eecd28b6a0369f3a413848560dc5597fdf1c204baeaa9b8d7e8f9ad2c24 Mon Sep 17 00:00:00 2001 From: jhkaktus Date: Sun, 11 Oct 2026 00:01:33 +0200 Subject: [PATCH] chore: remove leftover stray vendor files from earlier fetch attempt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿค– Generated with Codebuff Co-Authored-By: Codebuff --- backend/static/vendor/noble-ciphers-utils.js | 896 ------------------- backend/static/vendor/noble-ciphers.js | 460 ---------- backend/static/vendor/noble-hashes-sha2.js | 446 --------- backend/static/vendor/noble-hashes-utils.js | 687 -------------- backend/static/vendor/noble-hashes.js | 577 ------------ 5 files changed, 3066 deletions(-) delete mode 100644 backend/static/vendor/noble-ciphers-utils.js delete mode 100644 backend/static/vendor/noble-ciphers.js delete mode 100644 backend/static/vendor/noble-hashes-sha2.js delete mode 100644 backend/static/vendor/noble-hashes-utils.js delete mode 100644 backend/static/vendor/noble-hashes.js diff --git a/backend/static/vendor/noble-ciphers-utils.js b/backend/static/vendor/noble-ciphers-utils.js deleted file mode 100644 index 19eee88..0000000 --- a/backend/static/vendor/noble-ciphers-utils.js +++ /dev/null @@ -1,896 +0,0 @@ -/** - * Utilities for hex, bytes, CSPRNG. - * @module - */ -/*! noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com) */ -export function aarray(item, title, inner = () => { }) { - if (!Array.isArray(item)) - throw new TypeError(`"${title}" expected array, got type=${typeof item}`); - for (let i = 0; i < item.length; i++) - inner(item[i], `${title}[${i}]`); - return item; -} -/** - * Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. - * @param a - Value to inspect. - * @returns `true` when the value is a Uint8Array view, including Node's `Buffer`. - * @example - * Guards a value before treating it as raw key material. - * - * ```ts - * isBytes(new Uint8Array()); - * ``` - */ -export function isBytes(a) { - // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / - // cross-realm cases. The fallback still requires a real ArrayBuffer view - // so plain JSON-deserialized `{ constructor: ... }` - // spoofing is rejected, and `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views. - return (a instanceof Uint8Array || - (ArrayBuffer.isView(a) && - a.constructor.name === 'Uint8Array' && - 'BYTES_PER_ELEMENT' in a && - a.BYTES_PER_ELEMENT === 1)); -} -// Shared error-message prefix builder. Only called on throw paths, so assert -// success paths never pay for the string concatenation. -const atitle = (title) => (title ? `"${title}" ` : ''); -/** - * Asserts something is boolean. - * @param value - Value to validate. - * @returns The validated boolean. - * @throws On wrong argument types. {@link TypeError} - * @example - * Validates a boolean option before branching on it. - * - * ```ts - * abool(true); - * ``` - */ -export function abool(value, title = '') { - if (typeof value !== 'boolean') - throw new TypeError(atitle(title) + 'expected boolean, got type=' + typeof value); - return value; -} -/** - * Asserts something is a non-negative safe integer. - * @param n - Value to validate. - * @returns The validated number. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Validates a non-negative length or counter. - * - * ```ts - * anumber(1); - * ``` - */ -export function anumber(n, title = '') { - if (typeof n !== 'number') - throw new TypeError(atitle(title) + 'expected number, got ' + typeof n); - if (!Number.isSafeInteger(n) || n < 0) - throw new RangeError(atitle(title) + 'expected integer >= 0, got ' + n); - return n; -} -/** - * Asserts something is Uint8Array. - * @param value - Value to validate. - * @param length - Expected byte length. - * @param title - Optional label used in error messages. - * @returns The validated byte array. - * On Node, `Buffer` is accepted too because it is a Uint8Array view. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument lengths. {@link RangeError} - * @example - * Validates a fixed-length nonce or key buffer. - * - * ```ts - * abytes(new Uint8Array([1, 2]), 2); - * ``` - */ -export function abytes(value, length, title = '') { - // Success path first: this runs at the start of every update() / digestInto(), and the - // common `abytes(data)` form must not pay for length handling it does not use. - if (isBytes(value) && (length === undefined || value.length === length)) - return value; - // Error path: recompute freely to build the exact message. - if (length !== undefined) - anumber(length, 'length'); - const bytes = isBytes(value); - const ofLen = length !== undefined ? ` of length ${length}` : ''; - const got = bytes ? `length=${value.length}` : `type=${typeof value}`; - const message = atitle(title) + 'expected Uint8Array' + ofLen + ', got ' + got; - if (!bytes) - throw new TypeError(message); - throw new RangeError(message); -} -const aobject = (value, label) => { - if (value === null || typeof value !== 'object' || Array.isArray(value)) - throw new TypeError(label === 'object' - ? 'expected valid options object' - : `"${label}" expected object, got type=${typeof value}`); -}; -/** - * Asserts a hash- or MAC-like instance has not been destroyed or finished. - * @param instance - Stateful instance to validate. - * @param checkFinished - Whether to reject finished instances. - * When `false`, only `destroyed` is checked. - * @throws If the hash instance has already been destroyed or finalized. {@link Error} - * @example - * Guards against calling `update()` or `digest()` on a finished hash. - * - * ```ts - * aexists({ destroyed: false, finished: false }); - * ``` - */ -export function aexists(instance, checkFinished = true) { - // Runs on every update()/digestInto(); the flags are library-owned booleans, so only their - // truthiness is checked - re-validating their type per call was pure hot-path overhead. - if (instance.destroyed) - throw new Error('hash was destroyed'); - if (checkFinished && instance.finished) - throw new Error('digest() was already called'); -} -/** - * Asserts output is a sufficiently-sized byte array. - * @param out - Output buffer to validate. - * @param instance - Hash-like instance providing `outputLen`. - * This is the relaxed `digestInto()`-style contract: output must be at least `outputLen`, - * unlike one-shot cipher helpers elsewhere in the repo that often require exact lengths. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong output buffer lengths. {@link RangeError} - * @example - * Verifies that a caller-provided output buffer is large enough. - * - * ```ts - * aoutput(new Uint8Array(16), { outputLen: 16 }); - * ``` - */ -export function aoutput(out, instance) { - abytes(out, undefined, 'output'); - // `outputLen` is a library-owned readonly number; the negated comparison keeps failing fast - // when it is missing/NaN (comparisons with undefined/NaN are false) without an anumber() call. - const min = instance.outputLen; - if (!(out.length >= min)) { - throw new RangeError('"output" expected length >= ' + min); - } -} -/** - * Asserts output is a sufficiently-sized, 4-byte-aligned byte array. - * {@link aoutput} plus an {@link isAligned32} check, for `digestInto()` paths - * that write through zero-allocation `u32` word views. - * @param out - Output buffer to validate. - * @param instance - Hash-like instance providing `outputLen`. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong output buffer lengths. {@link RangeError} - * @throws On wrong output buffer alignment. {@link Error} - * @example - * Verifies that a caller-provided output buffer is large enough and aligned. - * - * ```ts - * aoutput32(new Uint8Array(16), { outputLen: 16 }); - * ``` - */ -export function aoutput32(out, instance) { - aoutput(out, instance); - if (!isAligned32(out)) - throw new Error('invalid output, must be aligned'); -} -/** - * Casts a typed-array view to Uint8Array. - * @param arr - Typed-array view to reinterpret. - * @returns Uint8Array view over the same bytes. - * @example - * Views 32-bit words as raw bytes without copying. - * - * ```ts - * u8(new Uint32Array([1])); - * ``` - */ -export function u8(arr) { - return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength); -} -/** - * Casts a typed-array view to Uint32Array. - * @param arr - Typed-array view to reinterpret. - * @returns Uint32Array view over the same bytes. Callers are expected to provide a - * 4-byte-aligned offset; trailing `1..3` bytes are silently dropped. - * @example - * Views a byte buffer as 32-bit words for block processing. - * - * ```ts - * u32(new Uint8Array(4)); - * ``` - */ -export function u32(arr) { - return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); -} -/** - * Zeroizes typed arrays in place. - * Warning: JS provides no guarantees. - * @param arrays - Arrays to wipe. - * @example - * Wipes a temporary key buffer after use. - * - * ```ts - * const bytes = new Uint8Array([1]); - * clean(bytes); - * ``` - */ -export function clean(...arrays) { - for (let i = 0; i < arrays.length; i++) { - arrays[i].fill(0); - } -} -/** - * Creates a DataView for byte-level manipulation. - * @param arr - Typed-array view to wrap. - * @returns DataView over the same bytes. - * @example - * Creates an endian-aware view for length encoding. - * - * ```ts - * createView(new Uint8Array(4)); - * ``` - */ -export function createView(arr) { - return new DataView(arr.buffer, arr.byteOffset, arr.byteLength); -} -/** - * Whether the current platform is little-endian. - * Most are; some IBM systems are not. - */ -export const isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)(); -/** - * Reverses byte order of one 32-bit word. - * @param word - Unsigned 32-bit word to swap. - * @returns The same word with bytes reversed. - * @example - * Swaps a big-endian word into little-endian byte order. - * - * ```ts - * byteSwap(0x11223344); - * ``` - */ -export function byteSwap(word) { - return (((word << 24) & 0xff000000) | - ((word << 8) & 0xff0000) | - ((word >>> 8) & 0xff00) | - ((word >>> 24) & 0xff)); -} -/** - * Normalizes one 32-bit word to the little-endian representation expected by cipher cores. - * @param n - Unsigned 32-bit word to normalize. - * @returns Little-endian normalized word on big-endian hosts, else the input word unchanged. - * @example - * Normalizes a host-endian word before passing it into an ARX/AES core. - * - * ```ts - * swap8IfBE(0x11223344); - * ``` - */ -export const swap8IfBE = isLE - ? (n) => n - : (n) => byteSwap(n) >>> 0; -/** - * Byte-swaps every word of a Uint32Array in place. - * @param arr - Uint32Array whose words should be swapped. - * @returns The same array after in-place byte swapping. - * @example - * Swaps every 32-bit word in a word-view buffer. - * - * ```ts - * byteSwap32(new Uint32Array([0x11223344])); - * ``` - */ -export function byteSwap32(arr) { - for (let i = 0; i < arr.length; i++) { - arr[i] = byteSwap(arr[i]); - } - return arr; -} -/** - * Normalizes a Uint32Array view to the little-endian representation expected by cipher cores. - * @param u - Word view to normalize in place. - * @returns Little-endian normalized word view. - * @example - * Normalizes a word-view buffer before block processing. - * - * ```ts - * swap32IfBE(new Uint32Array([0x11223344])); - * ``` - */ -export const swap32IfBE = isLE - ? (u) => u - : byteSwap32; -// Built-in hex conversion: -// {@link https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex | caniuse entry} -const hasHexBuiltin = /* @__PURE__ */ (() => -// @ts-ignore -typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')(); -// Array where index 0xf0 (240) is mapped to string 'f0' -const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0')); -/** - * Convert byte array to hex string. Uses built-in function, when available. - * @param bytes - Bytes to encode. - * @returns Lowercase hexadecimal string. - * @throws On wrong argument types. {@link TypeError} - * @example - * Formats ciphertext bytes for logs or test vectors. - * - * ```ts - * bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])); // 'cafe0123' - * ``` - */ -export function bytesToHex(bytes) { - abytes(bytes); - // @ts-ignore - if (hasHexBuiltin) - return bytes.toHex(); - // pre-caching improves the speed 6x - let hex = ''; - for (let i = 0; i < bytes.length; i++) { - hex += hexes[bytes[i]]; - } - return hex; -} -// Strict ASCII nibble parser: non-ASCII hex lookalikes are rejected as undefined. -// ASCII codes: '0'..'9' = 48..57, 'A'..'F' = 65..70, 'a'..'f' = 97..102. -// prettier-ignore -function asciiToBase16(ch) { - return ch >= 48 && ch <= 57 ? ch - 48 // '2' => 50-48 - : ch >= 65 && ch <= 70 ? ch - (65 - 10) // 'B' => 66-(65-10) - : ch >= 97 && ch <= 102 ? ch - (97 - 10) // 'b' => 98-(97-10) - : undefined; -} -/** - * Convert hex string to byte array. Uses built-in function, when available. - * @param hex - hexadecimal string to decode - * @returns Decoded bytes. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Decode lowercase hexadecimal into bytes. - * ```ts - * hexToBytes('cafe0123'); // Uint8Array.from([0xca, 0xfe, 0x01, 0x23]) - * ``` - */ -export function hexToBytes(hex) { - if (typeof hex !== 'string') - throw new TypeError('hex string expected, got ' + typeof hex); - if (hasHexBuiltin) { - try { - return Uint8Array.fromHex(hex); - } - catch (error) { - if (error instanceof SyntaxError) - throw new RangeError(error.message); - throw error; - } - } - const hl = hex.length; - const al = hl / 2; - if (hl % 2) - throw new RangeError('hex string expected, got unpadded hex of length ' + hl); - const array = new Uint8Array(al); - for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) { - const n1 = asciiToBase16(hex.charCodeAt(hi)); // parse first char, multiply it by 16 - const n2 = asciiToBase16(hex.charCodeAt(hi + 1)); // parse second char - if (n1 === undefined || n2 === undefined) { - const char = hex[hi] + hex[hi + 1]; - throw new RangeError('hex string expected, got non-hex character "' + char + '" at index ' + hi); - } - array[ai] = n1 * 16 + n2; // example: 'A9' => 10*16 + 9 - } - return array; -} -const _0n = /* @__PURE__ */ BigInt(0); -// Used in ff1, via bytesToNumberBE -/** - * Converts a big-endian hex string into bigint. - * @param hex - Hexadecimal string without `0x`. - * @returns Parsed bigint value. The empty string is treated as `0n`. - * @throws On wrong argument types. {@link TypeError} - * @example - * Parses a big-endian field element or counter from hex. - * - * ```ts - * hexToNumber('ff'); - * ``` - */ -export function hexToNumber(hex) { - if (typeof hex !== 'string') - throw new TypeError('hex string expected, got ' + typeof hex); - // Numeric parser, not byte-hex decoder: odd-length forms like 'f' are valid, - // and malformed syntax follows BigInt's native error behavior. - return hex === '' ? _0n : BigInt('0x' + hex); // Big Endian -} -// Used in ff1 -// BE: Big Endian, LE: Little Endian -/** - * Converts big-endian bytes into bigint. - * @param bytes - Big-endian bytes. - * @returns Parsed bigint value. Empty input is treated as `0n`. - * @throws On invalid byte input passed to the internal hex conversion. {@link TypeError} - * @example - * Reads a big-endian integer from serialized bytes. - * - * ```ts - * bytesToNumberBE(new Uint8Array([1, 0])); - * ``` - */ -export function bytesToNumberBE(bytes) { - return hexToNumber(bytesToHex(bytes)); -} -/** - * Validates that a value is a non-negative bigint or safe integer. - * @param n - Value to validate. - * @returns The same validated value. - * @throws On wrong argument ranges or values. {@link RangeError} - */ -function abignumber(n) { - if (typeof n === 'bigint') { - if (!(_0n <= n)) - throw new RangeError('positive bigint expected, got ' + n); - } - else - anumber(n); - return n; -} -// Used in ff1 -/** - * Converts a number into big-endian bytes of fixed length. - * @param n - Number to encode. - * @param len - Output length in bytes. Must be greater than zero. - * @returns Big-endian bytes padded to `len`. - * Negative values, `len = 0`, and values that do not fit are rejected before - * downstream hex parsing. - * @throws On wrong argument ranges or values. {@link RangeError} - * @throws If a documented runtime validation or state check fails. {@link Error} - * @example - * Encodes a counter as fixed-width big-endian bytes. - * - * ```ts - * numberToBytesBE(1, 2); - * ``` - */ -export function numberToBytesBE(n, len) { - anumber(len); - if (len === 0) - throw new Error('zero output length is invalid'); - n = abignumber(n); - const expectedLen = len * 2; - const hex = n.toString(16); - // Detect overflow before hex parsing so oversized values don't leak the shared odd-hex error. - if (hex.length > expectedLen) - throw new RangeError('number is too large'); - return hexToBytes(hex.padStart(expectedLen, '0')); -} -/** - * Converts string to bytes using UTF8 encoding. - * @param str - String to encode. - * @returns UTF-8 bytes in a detached fresh Uint8Array copy. - * @throws On wrong argument types. {@link TypeError} - * @example - * Encodes application text before encryption or MACing. - * - * ```ts - * utf8ToBytes('abc'); // new Uint8Array([97, 98, 99]) - * ``` - */ -export function utf8ToBytes(str) { - if (typeof str !== 'string') - throw new TypeError('string expected'); - return new Uint8Array(new TextEncoder().encode(str)); // {@link https://bugzil.la/1681809 | Firefox bug 1681809} -} -/** - * Converts bytes to string using UTF8 encoding. - * @param bytes - UTF-8 bytes. - * @returns Decoded string. Input validation is delegated to `TextDecoder`, and malformed - * UTF-8 is replacement-decoded instead of rejected. - * @example - * Decodes UTF-8 plaintext back into a string. - * - * ```ts - * bytesToUtf8(new Uint8Array([97, 98, 99])); // 'abc' - * ``` - */ -export function bytesToUtf8(bytes) { - return new TextDecoder().decode(bytes); -} -/** - * Checks if two U8A use same underlying buffer and overlaps. - * This is invalid and can corrupt data. - * @param a - First byte view. - * @param b - Second byte view. - * @returns `true` when the views overlap in memory. - * @example - * Detects whether two slices alias the same backing buffer. - * - * ```ts - * overlapBytes(new Uint8Array(4), new Uint8Array(4)); - * ``` - */ -export function overlapBytes(a, b) { - // Zero-length views cannot overwrite anything, even if their offset sits inside another range. - if (!a.byteLength || !b.byteLength) - return false; - return (a.buffer === b.buffer && // best we can do, may fail with an obscure Proxy - a.byteOffset < b.byteOffset + b.byteLength && // a starts before b end - b.byteOffset < a.byteOffset + a.byteLength // b starts before a end - ); -} -/** - * If input and output overlap and input starts before output, we will overwrite end of input before - * we start processing it, so this is not supported by forward-processing ciphers. - * @param input - Input bytes. - * @param output - Output bytes. - * @throws If the output view would overwrite unread input bytes. {@link Error} - * @example - * Rejects an in-place layout that would overwrite unread input bytes. - * - * ```ts - * const buffer = new Uint8Array(8); - * complexOverlapBytes(buffer.subarray(0, 4), buffer.subarray(2, 6)); - * ``` - */ -export function complexOverlapBytes(input, output) { - // This is very cursed. It works somehow, but I'm completely unsure, - // reasoning about overlapping aligned windows is very hard. - if (overlapBytes(input, output) && input.byteOffset < output.byteOffset) - throw new Error('complex overlap of input and output is not supported'); -} -/** - * Copies several Uint8Arrays into one. - * @param arrays - Byte arrays to concatenate. - * @returns Combined byte array. - * @throws On wrong argument types inside the byte-array list. {@link TypeError} - * @example - * Builds a `nonce || ciphertext` style buffer. - * - * ```ts - * concatBytes(new Uint8Array([1]), new Uint8Array([2])); - * ``` - */ -export function concatBytes(...arrays) { - let sum = 0; - for (let i = 0; i < arrays.length; i++) { - const a = arrays[i]; - abytes(a); - sum += a.length; - } - const res = new Uint8Array(sum); - for (let i = 0, pad = 0; i < arrays.length; i++) { - const a = arrays[i]; - res.set(a, pad); - pad += a.length; - } - return res; -} -/** - * Merges user options into defaults. - * @param defaults - Default option values. - * @param opts - User-provided overrides. - * @returns Combined options object. - * `defaults` is a library-owned mutable object; user-provided `opts` only need to be - * object-shaped, since "plain object" checks reject valid proxy/cross-realm containers. - * The merge mutates `defaults` in place and returns the same object, so direct callers - * should pass a fresh defaults object unless they intentionally want shared state updated. - * @throws If options are missing or not an object. {@link Error} - * @example - * Applies user overrides to the default cipher options. - * - * ```ts - * checkOpts({ rounds: 20 }, { rounds: 8 }); - * ``` - */ -export function checkOpts(defaults, opts) { - aobject(defaults, 'defaults'); - aobject(opts, 'opts'); - // Mutates defaults by design. __proto__ follows Object.assign semantics here and can only - // affect this local option object; callers already control this low-level options surface. - const merged = Object.assign(defaults, opts); - return merged; -} -/** - * Compares two byte arrays in kinda constant time once lengths already match. - * @param a - First byte array. - * @param b - Second byte array. - * @returns `true` when the arrays contain the same bytes. Different lengths still return early. - * @example - * Compares an expected authentication tag with the received one. - * - * ```ts - * equalBytes(new Uint8Array([1]), new Uint8Array([1])); - * ``` - */ -export function equalBytes(a, b) { - a = abytes(a); - b = abytes(b); - if (a.length !== b.length) - return false; - let diff = 0; - for (let i = 0; i < a.length; i++) - diff |= a[i] ^ b[i]; - return diff === 0; -} -/** - * Wraps a keyed MAC constructor into a one-shot helper with `.create()`. - * @param keyLen - Valid probe-key length used to read static metadata once. - * The probe key is only used for `outputLen` / `blockLen`, so callers with several valid key sizes - * can pass any representative size as long as those values stay fixed. - * @param macCons - Keyed MAC constructor or factory. - * @param fromMsg - Optional adapter that derives extra constructor args from the one-shot message. - * @returns Callable MAC helper with `.create()`. - */ -export function wrapMacConstructor(keyLen, macCons, fromMsg) { - const mac = macCons; - const getArgs = (fromMsg || (() => [])); - const macC = (msg, key) => mac(key, ...getArgs(msg)) - .update(msg) - .digest(); - const tmp = mac(new Uint8Array(keyLen), ...getArgs(new Uint8Array(0))); - macC.outputLen = tmp.outputLen; - macC.blockLen = tmp.blockLen; - macC.create = (key, ...args) => mac(key, ...args); - return macC; -} -/** - * Wraps a cipher: validates args, ensures encrypt() can only be called once. - * Used internally by the exported cipher constructors. - * Output-buffer support is inferred from the wrapped `encrypt` / `decrypt` - * arity (`fn.length === 2`), so wrapped output-capable methods must use a normal - * second parameter, not a default/rest parameter. AAD support is explicit in - * `params.withAAD`; optional AAD starts after the nonce slot when one is present. - * @__NO_SIDE_EFFECTS__ - * @param params - Static cipher metadata. See {@link CipherParams}. - * @param constructor - Cipher constructor. - * @returns Wrapped constructor with validation. - */ -export const wrapCipher = (params, constructor) => { - function wrappedCipher(key, ...args) { - // Validate key - abytes(key, undefined, 'key'); - // Validate nonce if nonceLength is present - if (params.nonceLength !== undefined) { - const nonce = args[0]; - abytes(nonce, params.varSizeNonce ? undefined : params.nonceLength, 'nonce'); - } - // Keep tag length available for decrypt-size checks after constructor validation. - const tagl = params.tagLength; - const aadStart = params.nonceLength !== undefined ? 1 : 0; - // No-AAD constructors otherwise silently ignore byte args meant as AAD. - if (!params.withAAD) { - for (let i = aadStart; i < args.length; i++) - if (isBytes(args[i])) - throw new Error('AAD not supported'); - } - // Validate the first AAD slot early; rest-arg AAD constructors validate the tail themselves. - if (params.withAAD && args[aadStart] !== undefined) - abytes(args[aadStart], undefined, 'AAD'); - const cipher = constructor(key, ...args); - const checkOutput = (fnLength, output) => { - if (output !== undefined) { - if (fnLength !== 2) - throw new Error('cipher output not supported'); - abytes(output, undefined, 'output'); - } - }; - // Create wrapped cipher with validation and single-use encryption - let called = false; - const wrCipher = { - encrypt(data, output) { - if (called) - throw new Error('cannot encrypt() twice with same key + nonce'); - // Any encrypt attempt consumes the instance, even if validation rejects below. - called = true; - abytes(data, undefined, 'data'); - checkOutput(cipher.encrypt.length, output); - return cipher.encrypt(data, output); - }, - decrypt(data, output) { - abytes(data, undefined, 'data'); - if (tagl && data.length < tagl) - throw new Error('"ciphertext" expected length >= tagLength=' + tagl); - checkOutput(cipher.decrypt.length, output); - return cipher.decrypt(data, output); - }, - }; - return wrCipher; - } - Object.assign(wrappedCipher, params); - return wrappedCipher; -}; -/** - * By default, returns u8a of length. - * When out is available, it checks it for validity and uses it. - * @param expectedLength - Required output length. - * @param out - Optional destination buffer. - * @param onlyAligned - Whether `out` must be 4-byte aligned. - * @returns Output buffer ready for writing. - * @throws On wrong argument types. {@link TypeError} - * @throws If the provided output buffer has the wrong size. {@link RangeError} - * @throws If the provided output buffer has the wrong alignment. {@link Error} - * @example - * Reuses a caller-provided output buffer when lengths match. - * - * ```ts - * getOutput(16, new Uint8Array(16)); - * ``` - */ -export function getOutput(expectedLength, out, onlyAligned = true) { - if (out === undefined) - return new Uint8Array(expectedLength); - // Keep Buffer/cross-realm Uint8Array support here instead of trusting a shape-compatible object. - abytes(out, expectedLength, 'output'); - if (onlyAligned && !isAligned32(out)) - throw new Error('invalid output, must be aligned'); - return out; -} -/** - * Encodes data and AAD lengths into a 16-byte buffer. - * @param dataLength - Data length. Units are caller-defined: GCM passes bit - * lengths, ChaCha20-Poly1305 passes byte lengths โ€” the helper writes the raw values. - * @param aadLength - AAD length, same unit convention as `dataLength`. - * The serialized block is still `aadLength || dataLength`, matching GCM/Poly1305 - * conventions even though the helper parameter order is `(dataLength, aadLength)`. - * @param isLE - Whether to encode lengths as little-endian. - * @returns 16-byte length block. - * @throws On wrong argument types passed to the endian validator. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Builds the length block appended by GCM and Poly1305. - * - * ```ts - * u64Lengths(16, 8, true); - * ``` - */ -export function u64Lengths(dataLength, aadLength, isLE) { - // Reject coercible non-number lengths like '10' and true before BigInt(...) accepts them. - anumber(dataLength); - anumber(aadLength); - abool(isLE); - const num = new Uint8Array(16); - const view = createView(num); - view.setBigUint64(0, BigInt(aadLength), isLE); - view.setBigUint64(8, BigInt(dataLength), isLE); - return num; -} -/** - * Checks whether a byte array is aligned to a 4-byte offset. - * @param bytes - Byte array to inspect. - * @returns `true` when the view is 4-byte aligned. - * @example - * Checks whether a buffer can be safely viewed as Uint32Array. - * - * ```ts - * isAligned32(new Uint8Array(4)); - * ``` - */ -export function isAligned32(bytes) { - return bytes.byteOffset % 4 === 0; -} -/** - * Copies bytes into a new Uint8Array. - * @param bytes - Bytes to copy. - * @returns Copied byte array. - * @throws On wrong argument types. {@link TypeError} - * @example - * Copies input into an aligned Uint8Array before block processing. - * - * ```ts - * copyBytes(new Uint8Array([1, 2])); - * ``` - */ -export function copyBytes(bytes) { - // `Uint8Array.from(...)` would also accept arrays / other typed arrays. Keep this helper strict - // because callers use it at byte-validation boundaries before mutating the detached copy. - return Uint8Array.from(abytes(bytes)); -} -/** - * Cryptographically secure PRNG backed by `crypto.getRandomValues`. - * @param bytesLength - number of random bytes to generate - * @returns Random bytes. - * The platform `getRandomValues()` implementation still defines any - * single-call length cap, and this helper rejects oversize requests - * with a stable library `RangeError` instead of host-specific errors. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @throws If the current runtime does not provide `crypto.getRandomValues`. {@link Error} - * @example - * Generate a fresh random key or nonce. - * ```ts - * const key = randomBytes(16); - * ``` - */ -export function randomBytes(bytesLength = 32) { - // Match the repo's other length-taking helpers instead of relying on Uint8Array coercion. - anumber(bytesLength, 'bytesLength'); - const cr = typeof globalThis === 'object' ? globalThis.crypto : null; - if (typeof cr?.getRandomValues !== 'function') - throw new Error('crypto.getRandomValues must be defined'); - // Web Cryptography API Level 2 ยง10.1.1: - // if `byteLength > 65536`, throw `QuotaExceededError`. - // Keep the guard explicit so callers can see the quota in code - // instead of discovering it by reading the spec or host errors. - // This wrapper surfaces the same quota as a stable library RangeError. - if (bytesLength > 65536) - throw new RangeError(`"bytesLength" expected <= 65536, got ${bytesLength}`); - return cr.getRandomValues(new Uint8Array(bytesLength)); -} -/** - * Uses CSPRNG for nonce, nonce injected in ciphertext. - * For `encrypt`, a `nonceBytes`-length buffer is fetched from CSPRNG and - * prepended to encrypted ciphertext. For `decrypt`, first `nonceBytes` of ciphertext - * are treated as nonce. The wrapper always allocates a fresh `nonce || ciphertext` - * buffer on encrypt and intentionally does not support caller-provided destination buffers. - * Too-short decrypt inputs are split into short/empty nonce views and then delegated - * to the wrapped cipher instead of being rejected here first. - * - * NOTE: Under the same key, using random nonces (e.g. `managedNonce`) with AES-GCM and ChaCha - * should be limited to `2**23` (8M) messages to get a collision chance of - * `2**-50`. Stretching to `2**32` (4B) messages would raise that chance to - * `2**-33`, still negligible but creeping up. - * @param fn - Cipher constructor that expects a nonce. - * @param randomBytes_ - Random-byte source used for nonce generation. - * @returns Cipher constructor that prepends the nonce to ciphertext. - * @throws On wrong argument types. {@link TypeError} - * @throws On invalid nonce lengths observed at wrapper construction or use. {@link RangeError} - * @example - * Prepends a fresh random nonce to every ciphertext. - * - * ```ts - * import { gcm } from '@noble/ciphers/aes.js'; - * import { managedNonce, randomBytes } from '@noble/ciphers/utils.js'; - * const wrapped = managedNonce(gcm); - * const key = randomBytes(16); - * const ciphertext = wrapped(key).encrypt(new Uint8Array([1, 2, 3])); - * wrapped(key).decrypt(ciphertext); - * ``` - */ -export function managedNonce(fn, randomBytes_ = randomBytes) { - if (typeof fn !== 'function') - throw new TypeError('"fn" expected cipher constructor, got type=' + typeof fn); - if (typeof randomBytes_ !== 'function') - throw new TypeError('"randomBytes_" expected function, got type=' + typeof randomBytes_); - const { nonceLength } = fn; - anumber(nonceLength, 'fn.nonceLength'); - const addNonce = (nonce, ciphertext, plaintext) => { - const out = concatBytes(nonce, ciphertext); - // Wrapped ciphers may alias caller plaintext on encrypt(); never zero - // caller-owned buffers here. - if (!overlapBytes(plaintext, ciphertext)) - ciphertext.fill(0); - return out; - }; - // NOTE: we cannot support DST here, it would be mistake: - // - we don't know how much dst length cipher requires - // - nonce may unalign dst and break everything - // - we create new u8a anyway (concatBytes) - // - previously we passed all args to cipher, but that was mistake! - const res = ((key, ...args) => ({ - encrypt(plaintext) { - abytes(plaintext, undefined, 'data'); - const nonce = randomBytes_(nonceLength); - const encrypted = fn(key, nonce, ...args).encrypt(plaintext); - // @ts-ignore - if (encrypted instanceof Promise) - return encrypted.then((ct) => addNonce(nonce, ct, plaintext)); - return addNonce(nonce, encrypted, plaintext); - }, - decrypt(ciphertext) { - abytes(ciphertext, undefined, 'data'); - const nonce = ciphertext.subarray(0, nonceLength); - const decrypted = ciphertext.subarray(nonceLength); - return fn(key, nonce, ...args).decrypt(decrypted); - }, - })); - // Auto-nonce wrappers still preserve the wrapped payload geometry. - if ('blockSize' in fn) - res.blockSize = fn.blockSize; - if ('tagLength' in fn) - res.tagLength = fn.tagLength; - if ('withAAD' in fn) - res.withAAD = fn.withAAD; - return res; -} diff --git a/backend/static/vendor/noble-ciphers.js b/backend/static/vendor/noble-ciphers.js deleted file mode 100644 index d170396..0000000 --- a/backend/static/vendor/noble-ciphers.js +++ /dev/null @@ -1,460 +0,0 @@ -/** - * ChaCha stream cipher, released - * in 2008. Developed after Salsa20, ChaCha aims to increase diffusion per round. - * It was standardized in - * {@link https://www.rfc-editor.org/rfc/rfc8439 | RFC 8439} and - * is now used in TLS 1.3. - * - * {@link https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha | XChaCha20} - * extended-nonce variant is also provided. Similar to XSalsa, it's safe to use with - * randomly-generated nonces. - * - * Check out - * {@link http://cr.yp.to/chacha/chacha-20080128.pdf | PDF}, - * {@link https://en.wikipedia.org/wiki/Salsa20 | wiki}, and - * {@link https://cr.yp.to/chacha.html | website}. - * - * @module - */ -import { createCipher, createPRG, rotl } from "./_arx.js"; -import { poly1305 } from "./_poly1305.js"; -import { abytes, clean, equalBytes, getOutput, isLE, swap32IfBE, u64Lengths, wrapCipher, } from "./utils.js"; -/** - * ChaCha core function. Uses an unrolled loop (chachaCore, hchacha) - 4x - * faster than a simple loop, but larger & harder to read. A simple-loop - * reference version lives in `test/misc/micro-ciphers.ts`; - * `test/arx.test.ts` keeps the two aligned. - * The specific implementation is selected in `createCipher` below. - */ -/** RFC 8439 ยง2.3 block core for `state = constants | key | counter | nonce`. */ -// prettier-ignore -function chachaCore(s, k, n, out, cnt, rounds = 20) { - let y00 = s[0], y01 = s[1], y02 = s[2], y03 = s[3], // "expa" "nd 3" "2-by" "te k" - y04 = k[0], y05 = k[1], y06 = k[2], y07 = k[3], // Key Key Key Key - y08 = k[4], y09 = k[5], y10 = k[6], y11 = k[7], // Key Key Key Key - y12 = cnt, y13 = n[0], y14 = n[1], y15 = n[2]; // Counter Nonce Nonce Nonce - // Save state to temporary variables - let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15; - for (let r = 0; r < rounds; r += 2) { - x00 = (x00 + x04) | 0; - x12 = rotl(x12 ^ x00, 16); - x08 = (x08 + x12) | 0; - x04 = rotl(x04 ^ x08, 12); - x00 = (x00 + x04) | 0; - x12 = rotl(x12 ^ x00, 8); - x08 = (x08 + x12) | 0; - x04 = rotl(x04 ^ x08, 7); - x01 = (x01 + x05) | 0; - x13 = rotl(x13 ^ x01, 16); - x09 = (x09 + x13) | 0; - x05 = rotl(x05 ^ x09, 12); - x01 = (x01 + x05) | 0; - x13 = rotl(x13 ^ x01, 8); - x09 = (x09 + x13) | 0; - x05 = rotl(x05 ^ x09, 7); - x02 = (x02 + x06) | 0; - x14 = rotl(x14 ^ x02, 16); - x10 = (x10 + x14) | 0; - x06 = rotl(x06 ^ x10, 12); - x02 = (x02 + x06) | 0; - x14 = rotl(x14 ^ x02, 8); - x10 = (x10 + x14) | 0; - x06 = rotl(x06 ^ x10, 7); - x03 = (x03 + x07) | 0; - x15 = rotl(x15 ^ x03, 16); - x11 = (x11 + x15) | 0; - x07 = rotl(x07 ^ x11, 12); - x03 = (x03 + x07) | 0; - x15 = rotl(x15 ^ x03, 8); - x11 = (x11 + x15) | 0; - x07 = rotl(x07 ^ x11, 7); - x00 = (x00 + x05) | 0; - x15 = rotl(x15 ^ x00, 16); - x10 = (x10 + x15) | 0; - x05 = rotl(x05 ^ x10, 12); - x00 = (x00 + x05) | 0; - x15 = rotl(x15 ^ x00, 8); - x10 = (x10 + x15) | 0; - x05 = rotl(x05 ^ x10, 7); - x01 = (x01 + x06) | 0; - x12 = rotl(x12 ^ x01, 16); - x11 = (x11 + x12) | 0; - x06 = rotl(x06 ^ x11, 12); - x01 = (x01 + x06) | 0; - x12 = rotl(x12 ^ x01, 8); - x11 = (x11 + x12) | 0; - x06 = rotl(x06 ^ x11, 7); - x02 = (x02 + x07) | 0; - x13 = rotl(x13 ^ x02, 16); - x08 = (x08 + x13) | 0; - x07 = rotl(x07 ^ x08, 12); - x02 = (x02 + x07) | 0; - x13 = rotl(x13 ^ x02, 8); - x08 = (x08 + x13) | 0; - x07 = rotl(x07 ^ x08, 7); - x03 = (x03 + x04) | 0; - x14 = rotl(x14 ^ x03, 16); - x09 = (x09 + x14) | 0; - x04 = rotl(x04 ^ x09, 12); - x03 = (x03 + x04) | 0; - x14 = rotl(x14 ^ x03, 8); - x09 = (x09 + x14) | 0; - x04 = rotl(x04 ^ x09, 7); - } - // RFC 8439 ยง2.3 / ยง2.3.1: add the original state words back in state order. - let oi = 0; - out[oi++] = (y00 + x00) | 0; - out[oi++] = (y01 + x01) | 0; - out[oi++] = (y02 + x02) | 0; - out[oi++] = (y03 + x03) | 0; - out[oi++] = (y04 + x04) | 0; - out[oi++] = (y05 + x05) | 0; - out[oi++] = (y06 + x06) | 0; - out[oi++] = (y07 + x07) | 0; - out[oi++] = (y08 + x08) | 0; - out[oi++] = (y09 + x09) | 0; - out[oi++] = (y10 + x10) | 0; - out[oi++] = (y11 + x11) | 0; - out[oi++] = (y12 + x12) | 0; - out[oi++] = (y13 + x13) | 0; - out[oi++] = (y14 + x14) | 0; - out[oi++] = (y15 + x15) | 0; -} -/** - * hchacha hashes key and nonce into key' and nonce' for xchacha20. - * Algorithmically identical to `hchacha_small` from `test/misc/micro-ciphers.ts`, - * but this exported path normalizes word order on big-endian hosts. - * Reuses `chachaCore` and subtracts its feed-forward, keeping the hot per-block - * path untouched. - * @param s - Sigma constants as 32-bit words. - * @param k - Key words. - * @param i - Nonce-prefix words. - * @param out - Output buffer for the derived subkey. - * @example - * Derives the XChaCha subkey from sigma, key, and nonce-prefix words. - * - * ```ts - * const sigma = new Uint32Array(4); - * const key = new Uint32Array(8); - * const nonce = new Uint32Array(4); - * const out = new Uint32Array(8); - * hchacha(sigma, key, nonce, out); - * ``` - */ -// prettier-ignore -export function hchacha(s, k, i, out) { - // Runs the shared chachaCore permutation, then subtracts the RFC 8439 feed-forward - // it applies, recovering the raw permutation words hchacha needs. - // LE hosts read the caller arrays in place (no copies); BE hosts get - // byte-swapped scratch copies, wiped before returning. - const s2 = isLE ? s : swap32IfBE(s.slice(0, 4)); - const k2 = isLE ? k : swap32IfBE(k.slice(0, 8)); - const i2 = isLE ? i : swap32IfBE(i.slice(0, 4)); - const t = new Uint32Array(16); - chachaCore(s2, k2, i2.subarray(1), t, i2[0]); - let oi = 0; - out[oi++] = (t[0] - s2[0]) | 0; - out[oi++] = (t[1] - s2[1]) | 0; - out[oi++] = (t[2] - s2[2]) | 0; - out[oi++] = (t[3] - s2[3]) | 0; - out[oi++] = (t[12] - i2[0]) | 0; - out[oi++] = (t[13] - i2[1]) | 0; - out[oi++] = (t[14] - i2[2]) | 0; - out[oi++] = (t[15] - i2[3]) | 0; - swap32IfBE(out); - if (!isLE) - clean(s2, k2, i2); - clean(t); -} -/** - * Original, non-RFC chacha20 from DJB. 8-byte nonce, 8-byte counter. - * The nonce/counter layout still reserves 8 counter bytes internally, but the shared public - * `counter` argument follows noble's strict non-wrapping 32-bit policy. See `src/_arx.ts` - * near `MAX_COUNTER` for the full counter-policy rationale. - * @param key - 16-byte or 32-byte key. - * @param nonce - 8-byte nonce. - * @param data - Input bytes to xor with the keystream. - * @param output - Optional destination buffer. - * @param counter - Initial block counter. - * @returns Encrypted or decrypted bytes. - * @example - * Encrypts bytes with the original 8-byte-nonce ChaCha variant and a fresh key/nonce. - * - * ```ts - * import { chacha20orig } from '@noble/ciphers/chacha.js'; - * import { randomBytes } from '@noble/ciphers/utils.js'; - * const key = randomBytes(32); - * const nonce = randomBytes(8); - * chacha20orig(key, nonce, new Uint8Array(4)); - * ``` - */ -export const chacha20orig = /* @__PURE__ */ createCipher(chachaCore, { - counterRight: false, - counterLength: 8, - allowShortKeys: true, -}); -/** - * ChaCha stream cipher. Conforms to RFC 8439 (IETF, TLS). 12-byte nonce, 4-byte counter. - * With smaller nonce, it's not safe to make it random (CSPRNG), due to collision chance. - * @param key - 32-byte key. - * @param nonce - 12-byte nonce. - * @param data - Input bytes to xor with the keystream. - * @param output - Optional destination buffer. - * @param counter - Initial block counter. - * @returns Encrypted or decrypted bytes. - * @example - * Encrypts bytes with the RFC 8439 ChaCha20 stream cipher and a fresh key/nonce. - * - * ```ts - * import { chacha20 } from '@noble/ciphers/chacha.js'; - * import { randomBytes } from '@noble/ciphers/utils.js'; - * const key = randomBytes(32); - * const nonce = randomBytes(12); - * chacha20(key, nonce, new Uint8Array(4)); - * ``` - */ -export const chacha20 = /* @__PURE__ */ createCipher(chachaCore, { - counterRight: false, - counterLength: 4, - allowShortKeys: false, -}); -/** - * XChaCha eXtended-nonce ChaCha. With 24-byte nonce, it's safe to make it random (CSPRNG). - * See {@link https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha | the IRTF draft}. - * The nonce/counter layout still reserves 8 counter bytes internally, but the shared public - * `counter` argument follows noble's strict non-wrapping 32-bit policy. See `src/_arx.ts` - * near `MAX_COUNTER` for the full counter-policy rationale. - * @param key - 32-byte key. - * @param nonce - 24-byte extended nonce. - * @param data - Input bytes to xor with the keystream. - * @param output - Optional destination buffer. - * @param counter - Initial block counter. - * @returns Encrypted or decrypted bytes. - * @example - * Encrypts bytes with XChaCha20 using a fresh key and random 24-byte nonce. - * - * ```ts - * import { xchacha20 } from '@noble/ciphers/chacha.js'; - * import { randomBytes } from '@noble/ciphers/utils.js'; - * const key = randomBytes(32); - * const nonce = randomBytes(24); - * xchacha20(key, nonce, new Uint8Array(4)); - * ``` - */ -export const xchacha20 = /* @__PURE__ */ createCipher(chachaCore, { - counterRight: false, - counterLength: 8, - extendNonceFn: hchacha, - allowShortKeys: false, -}); -/** - * Reduced 8-round chacha, described in original paper. - * @param key - 32-byte key. - * @param nonce - 12-byte nonce. - * @param data - Input bytes to xor with the keystream. - * @param output - Optional destination buffer. - * @param counter - Initial block counter. - * @returns Encrypted or decrypted bytes. - * @example - * Uses the reduced 8-round variant for non-critical workloads with a fresh key/nonce. - * - * ```ts - * import { chacha8 } from '@noble/ciphers/chacha.js'; - * import { randomBytes } from '@noble/ciphers/utils.js'; - * const key = randomBytes(32); - * const nonce = randomBytes(12); - * chacha8(key, nonce, new Uint8Array(4)); - * ``` - */ -export const chacha8 = /* @__PURE__ */ createCipher(chachaCore, { - counterRight: false, - counterLength: 4, - rounds: 8, -}); -/** - * Reduced 12-round chacha, described in original paper. - * @param key - 32-byte key. - * @param nonce - 12-byte nonce. - * @param data - Input bytes to xor with the keystream. - * @param output - Optional destination buffer. - * @param counter - Initial block counter. - * @returns Encrypted or decrypted bytes. - * @example - * Uses the reduced 12-round variant for non-critical workloads with a fresh key/nonce. - * - * ```ts - * import { chacha12 } from '@noble/ciphers/chacha.js'; - * import { randomBytes } from '@noble/ciphers/utils.js'; - * const key = randomBytes(32); - * const nonce = randomBytes(12); - * chacha12(key, nonce, new Uint8Array(4)); - * ``` - */ -export const chacha12 = /* @__PURE__ */ createCipher(chachaCore, { - counterRight: false, - counterLength: 4, - rounds: 12, -}); -// Test-only hook: exposes the unrolled production core so tests can compare it -// with the simple/reference core from `test/misc/micro-ciphers.ts`. -export const __TESTS = /* @__PURE__ */ Object.freeze({ chachaCore }); -// RFC 8439 ยง2.8.1 pad16(x): shared zero block for AAD/ciphertext padding. -const ZEROS16 = /* @__PURE__ */ new Uint8Array(16); -// RFC 8439 ยง2.8 / ยง2.8.1: aligned inputs add nothing, otherwise append 16-(len%16) zero bytes. -const updatePadded = (h, msg) => { - h.update(msg); - const leftover = msg.length % 16; - if (leftover) - h.update(ZEROS16.subarray(leftover)); -}; -// RFC 8439 ยง2.6.1 poly1305_key_gen returns `block[0..31]`, so AEAD key -// generation only needs 32 zero bytes. -const ZEROS32 = /* @__PURE__ */ new Uint8Array(32); -function computeTag(fn, key, nonce, ciphertext, AAD) { - if (AAD !== undefined) - abytes(AAD, undefined, 'AAD'); - // RFC 8439 ยง2.6 / ยง2.8: derive the Poly1305 one-time key from counter 0, - // then MAC AAD || pad16(AAD) || ciphertext || pad16(ciphertext) || len(AAD) || len(ciphertext). - const authKey = fn(key, nonce, ZEROS32); - const lengths = u64Lengths(ciphertext.length, AAD ? AAD.length : 0, true); - // Methods below can be replaced with - // `return poly1305_computeTag_small(authKey, lengths, ciphertext, AAD)` - // from `test/misc/micro-ciphers.ts`. - const h = poly1305.create(authKey); - if (AAD) - updatePadded(h, AAD); - updatePadded(h, ciphertext); - h.update(lengths); - const res = h.digest(); - clean(authKey, lengths); - return res; -} -/** - * AEAD algorithm from RFC 8439. - * Salsa20 and chacha (RFC 8439) use poly1305 differently. - * We could have composed them, but it's hard because of authKey: - * In salsa20, authKey changes position in salsa stream. - * In chacha, authKey can't be computed inside computeTag, it modifies the counter. - */ -export const _poly1305_aead = (xorStream) => (key, nonce, AAD) => { - // This borrows caller key/nonce/AAD buffers by reference; mutating them after construction - // changes future encrypt/decrypt results. - const tagLength = 16; - return { - encrypt(plaintext, output) { - const plength = plaintext.length; - output = getOutput(plength + tagLength, output, false); - output.set(plaintext); - const oPlain = output.subarray(0, -tagLength); - // RFC 8439 ยง2.8: payload encryption starts at counter 1 because counter 0 produced the OTK. - xorStream(key, nonce, oPlain, oPlain, 1); - const tag = computeTag(xorStream, key, nonce, oPlain, AAD); - output.set(tag, plength); // append tag - clean(tag); - return output; - }, - decrypt(ciphertext, output) { - output = getOutput(ciphertext.length - tagLength, output, false); - const data = ciphertext.subarray(0, -tagLength); - const passedTag = ciphertext.subarray(-tagLength); - const tag = computeTag(xorStream, key, nonce, data, AAD); - // RFC 8439 ยง2.8 / ยง4: authenticate ciphertext before decrypting it, and compare tags with - // the constant-time equalBytes() helper rather than decrypting speculative plaintext first. - if (!equalBytes(passedTag, tag)) { - clean(tag); - throw new Error('invalid tag'); - } - output.set(ciphertext.subarray(0, -tagLength)); - // Actual decryption - xorStream(key, nonce, output, output, 1); // start stream with i=1 - clean(tag); - return output; - }, - }; -}; -/** - * ChaCha20-Poly1305 from RFC 8439. - * - * Unsafe to use random nonces under the same key, due to collision chance. - * Prefer XChaCha instead. - * @param key - 32-byte key. - * @param nonce - 12-byte nonce. - * @param AAD - Additional authenticated data. - * @returns AEAD cipher instance. - * @example - * Encrypts and authenticates plaintext with a fresh key and nonce. - * - * ```ts - * import { chacha20poly1305 } from '@noble/ciphers/chacha.js'; - * import { randomBytes } from '@noble/ciphers/utils.js'; - * const key = randomBytes(32); - * const nonce = randomBytes(12); - * const aad = new TextEncoder().encode('session metadata'); - * const cipher = chacha20poly1305(key, nonce, aad); - * cipher.encrypt(new Uint8Array([1, 2, 3])); - * ``` - */ -export const chacha20poly1305 = /* @__PURE__ */ wrapCipher({ blockSize: 64, nonceLength: 12, tagLength: 16, withAAD: true }, -/* @__PURE__ */ _poly1305_aead(chacha20)); -/** - * XChaCha20-Poly1305 extended-nonce chacha. - * - * Can be safely used with random nonces (CSPRNG). - * See {@link https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha | the IRTF draft}. - * @param key - 32-byte key. - * @param nonce - 24-byte nonce. - * @param AAD - Additional authenticated data. - * @returns AEAD cipher instance. - * @example - * Encrypts and authenticates plaintext with a fresh key and random 24-byte nonce. - * - * ```ts - * import { xchacha20poly1305 } from '@noble/ciphers/chacha.js'; - * import { randomBytes } from '@noble/ciphers/utils.js'; - * const key = randomBytes(32); - * const nonce = randomBytes(24); - * const aad = new TextEncoder().encode('session metadata'); - * const cipher = xchacha20poly1305(key, nonce, aad); - * cipher.encrypt(new Uint8Array([1, 2, 3])); - * ``` - */ -export const xchacha20poly1305 = /* @__PURE__ */ wrapCipher({ blockSize: 64, nonceLength: 24, tagLength: 16, withAAD: true }, -/* @__PURE__ */ _poly1305_aead(xchacha20)); -/** - * Chacha20 CSPRNG (cryptographically secure pseudorandom number generator). - * It's best to limit usage to non-production, non-critical cases: for example, test-only. - * Compatible with libtomcrypt. It does not have a specification, so unclear how secure it is. - * @param seed - Optional seed bytes mixed into the internal `key || nonce` state. When omitted, - * only 32 random bytes are mixed into the 40-byte state. - * @returns Seeded concrete `_XorStreamPRG` instance, including `clone()`. - * @example - * Seeds the test-only ChaCha20 DRBG from fresh entropy. - * - * ```ts - * import { rngChacha20 } from '@noble/ciphers/chacha.js'; - * import { randomBytes } from '@noble/ciphers/utils.js'; - * const seed = randomBytes(32); - * const prg = rngChacha20(seed); - * prg.randomBytes(8); - * ``` - */ -export const rngChacha20 = /* @__PURE__ */ createPRG(chacha20orig, 64, 32, 8); -/** - * Chacha20/8 CSPRNG (cryptographically secure pseudorandom number generator). - * It's best to limit usage to non-production, non-critical cases: for example, test-only. - * Faster than `rngChacha20`. - * @param seed - Optional seed bytes mixed into the internal `key || nonce` state. When omitted, - * only 32 random bytes are mixed into the 44-byte state. - * @returns Seeded concrete `_XorStreamPRG` instance, including `clone()`. - * @example - * Seeds the faster test-only ChaCha8 DRBG from fresh entropy. - * - * ```ts - * import { rngChacha8 } from '@noble/ciphers/chacha.js'; - * import { randomBytes } from '@noble/ciphers/utils.js'; - * const seed = randomBytes(32); - * const prg = rngChacha8(seed); - * prg.randomBytes(8); - * ``` - */ -export const rngChacha8 = /* @__PURE__ */ createPRG(chacha8, 64, 32, 12); diff --git a/backend/static/vendor/noble-hashes-sha2.js b/backend/static/vendor/noble-hashes-sha2.js deleted file mode 100644 index 4d05c82..0000000 --- a/backend/static/vendor/noble-hashes-sha2.js +++ /dev/null @@ -1,446 +0,0 @@ -/** - * SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256. - * SHA256 is the fastest hash implementable in JS, even faster than Blake3. - * Check out {@link https://www.rfc-editor.org/rfc/rfc4634 | RFC 4634} and - * {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf | FIPS 180-4}. - * @module - */ -import { Chi, HashMD, Maj, SHA224_IV, SHA256_IV, SHA384_IV, SHA512_IV } from "./_md.js"; -import * as u64 from "./_u64.js"; -import { clean, createHasher, oidNist, rotr } from "./utils.js"; -/** - * SHA-224 / SHA-256 round constants from RFC 6234 ยง5.1: the first 32 bits - * of the cube roots of the first 64 primes (2..311). - */ -// prettier-ignore -const SHA256_K = /* @__PURE__ */ Uint32Array.from([ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -]); -/** Reusable SHA-224 / SHA-256 message schedule buffer `W_t` from RFC 6234 ยง6.2 step 1. */ -const SHA256_W = /* @__PURE__ */ new Uint32Array(64); -/** Internal SHA-224 / SHA-256 compression engine from RFC 6234 ยง6.2. */ -class SHA2_32B extends HashMD { - // We cannot use array here since array allows indexing by variable - // which means optimizer/compiler cannot use registers. - // Numeric initializers matter: starting the fields as `undefined` changes - // V8's field representation and makes sha256 3x slower (measured). - A = 0; - B = 0; - C = 0; - D = 0; - E = 0; - F = 0; - G = 0; - H = 0; - constructor(outputLen, IV) { - super(64, outputLen, 8, false); - this.A = IV[0] | 0; - this.B = IV[1] | 0; - this.C = IV[2] | 0; - this.D = IV[3] | 0; - this.E = IV[4] | 0; - this.F = IV[5] | 0; - this.G = IV[6] | 0; - this.H = IV[7] | 0; - } - get() { - const { A, B, C, D, E, F, G, H } = this; - return [A, B, C, D, E, F, G, H]; - } - // prettier-ignore - set(A, B, C, D, E, F, G, H) { - this.A = A | 0; - this.B = B | 0; - this.C = C | 0; - this.D = D | 0; - this.E = E | 0; - this.F = F | 0; - this.G = G | 0; - this.H = H | 0; - } - _cloneInto(to) { - (to ||= new this.constructor()).set(...this.get()); - return this._cloneIntoMeta(to); - } - process(view, offset) { - // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array - for (let i = 0; i < 16; i++, offset += 4) - SHA256_W[i] = view.getUint32(offset, false); - for (let i = 16; i < 64; i++) { - const W15 = SHA256_W[i - 15]; - const W2 = SHA256_W[i - 2]; - const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3); - const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10); - SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0; - } - // Compression function main loop, 64 rounds - let { A, B, C, D, E, F, G, H } = this; - for (let i = 0; i < 64; i++) { - const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25); - const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0; - const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22); - const T2 = (sigma0 + Maj(A, B, C)) | 0; - H = G; - G = F; - F = E; - E = (D + T1) | 0; - D = C; - C = B; - B = A; - A = (T1 + T2) | 0; - } - // Add the compressed chunk to the current hash value - A = (A + this.A) | 0; - B = (B + this.B) | 0; - C = (C + this.C) | 0; - D = (D + this.D) | 0; - E = (E + this.E) | 0; - F = (F + this.F) | 0; - G = (G + this.G) | 0; - H = (H + this.H) | 0; - this.set(A, B, C, D, E, F, G, H); - } - roundClean() { - clean(SHA256_W); - } - destroy() { - // HashMD callers route post-destroy usability through `destroyed`; zeroizing alone still leaves - // update()/digest() callable on reused instances. - this.destroyed = true; - this.set(0, 0, 0, 0, 0, 0, 0, 0); - clean(this.buffer); - } -} -/** Internal SHA-256 hash class grounded in RFC 6234 ยง6.2. */ -export class _SHA256 extends SHA2_32B { - constructor() { - super(32, SHA256_IV); - } -} -/** Internal SHA-224 hash class grounded in RFC 6234 ยง6.2 and ยง8.5. */ -export class _SHA224 extends SHA2_32B { - constructor() { - super(28, SHA224_IV); - } -} -// SHA2-512 is slower than sha256 in js because u64 operations are slow. -// SHA-384 / SHA-512 round constants from RFC 6234 ยง5.2: -// 80 full 64-bit words split into high/low halves. -// prettier-ignore -const K512 = /* @__PURE__ */ (() => u64.split([ - '0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc', - '0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118', - '0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2', - '0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694', - '0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65', - '0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5', - '0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4', - '0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70', - '0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df', - '0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b', - '0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30', - '0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8', - '0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8', - '0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3', - '0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec', - '0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b', - '0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178', - '0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b', - '0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c', - '0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817' -].map(n => BigInt(n))))(); -const SHA512_Kh = /* @__PURE__ */ (() => K512[0])(); -const SHA512_Kl = /* @__PURE__ */ (() => K512[1])(); -// Reusable high-half schedule buffer for the RFC 6234 ยง6.4 64-bit `W_t` words. -const SHA512_W_H = /* @__PURE__ */ new Uint32Array(80); -// Reusable low-half schedule buffer for the RFC 6234 ยง6.4 64-bit `W_t` words. -const SHA512_W_L = /* @__PURE__ */ new Uint32Array(80); -/** Internal SHA-384 / SHA-512 compression engine from RFC 6234 ยง6.4. */ -class SHA2_64B extends HashMD { - // We cannot use array here since array allows indexing by variable - // which means optimizer/compiler cannot use registers. - // h -- high 32 bits, l -- low 32 bits - // Numeric initializers matter: starting the fields as `undefined` changes - // V8's field representation and slows hashing down (measured on sha256). - Ah = 0; - Al = 0; - Bh = 0; - Bl = 0; - Ch = 0; - Cl = 0; - Dh = 0; - Dl = 0; - Eh = 0; - El = 0; - Fh = 0; - Fl = 0; - Gh = 0; - Gl = 0; - Hh = 0; - Hl = 0; - constructor(outputLen, IV) { - super(128, outputLen, 16, false); - this.Ah = IV[0] | 0; - this.Al = IV[1] | 0; - this.Bh = IV[2] | 0; - this.Bl = IV[3] | 0; - this.Ch = IV[4] | 0; - this.Cl = IV[5] | 0; - this.Dh = IV[6] | 0; - this.Dl = IV[7] | 0; - this.Eh = IV[8] | 0; - this.El = IV[9] | 0; - this.Fh = IV[10] | 0; - this.Fl = IV[11] | 0; - this.Gh = IV[12] | 0; - this.Gl = IV[13] | 0; - this.Hh = IV[14] | 0; - this.Hl = IV[15] | 0; - } - // prettier-ignore - get() { - const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; - return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl]; - } - // prettier-ignore - set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) { - this.Ah = Ah | 0; - this.Al = Al | 0; - this.Bh = Bh | 0; - this.Bl = Bl | 0; - this.Ch = Ch | 0; - this.Cl = Cl | 0; - this.Dh = Dh | 0; - this.Dl = Dl | 0; - this.Eh = Eh | 0; - this.El = El | 0; - this.Fh = Fh | 0; - this.Fl = Fl | 0; - this.Gh = Gh | 0; - this.Gl = Gl | 0; - this.Hh = Hh | 0; - this.Hl = Hl | 0; - } - _cloneInto(to) { - (to ||= new this.constructor()).set(...this.get()); - return this._cloneIntoMeta(to); - } - process(view, offset) { - // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array - for (let i = 0; i < 16; i++, offset += 4) { - SHA512_W_H[i] = view.getUint32(offset); - SHA512_W_L[i] = view.getUint32((offset += 4)); - } - for (let i = 16; i < 80; i++) { - // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7) - const W15h = SHA512_W_H[i - 15] | 0; - const W15l = SHA512_W_L[i - 15] | 0; - const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7); - const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7); - // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6) - const W2h = SHA512_W_H[i - 2] | 0; - const W2l = SHA512_W_L[i - 2] | 0; - const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6); - const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6); - // SHA512_W[i] = s0 + s1 + SHA512_W[i - 7] + SHA512_W[i - 16]; - const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]); - const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]); - SHA512_W_H[i] = SUMh | 0; - SHA512_W_L[i] = SUMl | 0; - } - let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; - // Compression function main loop, 80 rounds - for (let i = 0; i < 80; i++) { - // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41) - const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41); - const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41); - //const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0; - const CHIh = (Eh & Fh) ^ (~Eh & Gh); - const CHIl = (El & Fl) ^ (~El & Gl); - // T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i] - // prettier-ignore - const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]); - const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]); - const T1l = T1ll | 0; - // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39) - const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39); - const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39); - const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch); - const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl); - Hh = Gh | 0; - Hl = Gl | 0; - Gh = Fh | 0; - Gl = Fl | 0; - Fh = Eh | 0; - Fl = El | 0; - ({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0)); - Dh = Ch | 0; - Dl = Cl | 0; - Ch = Bh | 0; - Cl = Bl | 0; - Bh = Ah | 0; - Bl = Al | 0; - const All = u64.add3L(T1l, sigma0l, MAJl); - Ah = u64.add3H(All, T1h, sigma0h, MAJh); - Al = All | 0; - } - // Add the compressed chunk to the current hash value - ({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0)); - ({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0)); - ({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0)); - ({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0)); - ({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0)); - ({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0)); - ({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0)); - ({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0)); - this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl); - } - roundClean() { - clean(SHA512_W_H, SHA512_W_L); - } - destroy() { - // HashMD callers route post-destroy usability through `destroyed`; zeroizing alone still leaves - // update()/digest() callable on reused instances. - this.destroyed = true; - clean(this.buffer); - this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } -} -/** Internal SHA-512 hash class grounded in RFC 6234 ยง6.3 and ยง6.4. */ -export class _SHA512 extends SHA2_64B { - constructor() { - super(64, SHA512_IV); - } -} -/** Internal SHA-384 hash class grounded in RFC 6234 ยง6.3 and ยง6.4. */ -export class _SHA384 extends SHA2_64B { - constructor() { - super(48, SHA384_IV); - } -} -/** - * Truncated SHA512/256 and SHA512/224. - * SHA512_IV is XORed with 0xa5a5a5a5a5a5a5a5, then used as "intermediary" IV of SHA512/t. - * Then t hashes string to produce result IV. - * See the repo-side derivation recipe in `test/misc/sha2-gen-iv.js`. - * These IV literals are checked against that script rather than a dedicated - * local RFC section. - */ -/** SHA-512/224 IV derived by the SHA-512/t recipe in `test/misc/sha2-gen-iv.js` and - * stored as sixteen big-endian 32-bit halves. */ -const T224_IV = /* @__PURE__ */ Uint32Array.from([ - 0x8c3d37c8, 0x19544da2, 0x73e19966, 0x89dcd4d6, 0x1dfab7ae, 0x32ff9c82, 0x679dd514, 0x582f9fcf, - 0x0f6d2b69, 0x7bd44da8, 0x77e36f73, 0x04c48942, 0x3f9d85a8, 0x6a1d36c8, 0x1112e6ad, 0x91d692a1, -]); -/** SHA-512/256 IV derived by the SHA-512/t recipe in `test/misc/sha2-gen-iv.js` and - * stored as sixteen big-endian 32-bit halves. */ -const T256_IV = /* @__PURE__ */ Uint32Array.from([ - 0x22312194, 0xfc2bf72c, 0x9f555fa3, 0xc84c64c2, 0x2393b86b, 0x6f53b151, 0x96387719, 0x5940eabd, - 0x96283ee2, 0xa88effe3, 0xbe5e1e25, 0x53863992, 0x2b0199fc, 0x2c85b8aa, 0x0eb72ddc, 0x81c52ca2, -]); -/** Internal SHA-512/224 hash class using the derived `T224_IV` and the shared - * RFC 6234 ยง6.4 compression engine. */ -export class _SHA512_224 extends SHA2_64B { - constructor() { - super(28, T224_IV); - } -} -/** Internal SHA-512/256 hash class using the derived `T256_IV` and the shared - * RFC 6234 ยง6.4 compression engine. */ -export class _SHA512_256 extends SHA2_64B { - constructor() { - super(32, T256_IV); - } -} -/** - * SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info: - * - * - Trying 2^128 hashes would get 50% chance of collision, using birthday attack. - * - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025. - * - Each sha256 hash is executing 2^18 bit operations. - * - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule. - * @param msg - message bytes to hash - * @param opts - Reserved hash options. - * @returns Digest bytes. - * @example - * Hash a message with SHA2-256. - * ```ts - * sha256(new Uint8Array([97, 98, 99])); - * ``` - */ -export const sha256 = /* @__PURE__ */ createHasher(() => new _SHA256(), -/* @__PURE__ */ oidNist(0x01)); -/** - * SHA2-224 hash function from RFC 4634. - * @param msg - message bytes to hash - * @param opts - Reserved hash options. - * @returns Digest bytes. - * @example - * Hash a message with SHA2-224. - * ```ts - * sha224(new Uint8Array([97, 98, 99])); - * ``` - */ -export const sha224 = /* @__PURE__ */ createHasher(() => new _SHA224(), -/* @__PURE__ */ oidNist(0x04)); -/** - * SHA2-512 hash function from RFC 4634. - * @param msg - message bytes to hash - * @param opts - Reserved hash options. - * @returns Digest bytes. - * @example - * Hash a message with SHA2-512. - * ```ts - * sha512(new Uint8Array([97, 98, 99])); - * ``` - */ -export const sha512 = /* @__PURE__ */ createHasher(() => new _SHA512(), -/* @__PURE__ */ oidNist(0x03)); -/** - * SHA2-384 hash function from RFC 4634. - * @param msg - message bytes to hash - * @param opts - Reserved hash options. - * @returns Digest bytes. - * @example - * Hash a message with SHA2-384. - * ```ts - * sha384(new Uint8Array([97, 98, 99])); - * ``` - */ -export const sha384 = /* @__PURE__ */ createHasher(() => new _SHA384(), -/* @__PURE__ */ oidNist(0x02)); -/** - * SHA2-512/256 "truncated" hash function, with improved resistance to length extension attacks. - * See the paper on {@link https://eprint.iacr.org/2010/548.pdf | truncated SHA512}. - * @param msg - message bytes to hash - * @param opts - Reserved hash options. - * @returns Digest bytes. - * @example - * Hash a message with SHA2-512/256. - * ```ts - * sha512_256(new Uint8Array([97, 98, 99])); - * ``` - */ -export const sha512_256 = /* @__PURE__ */ createHasher(() => new _SHA512_256(), -/* @__PURE__ */ oidNist(0x06)); -/** - * SHA2-512/224 "truncated" hash function, with improved resistance to length extension attacks. - * See the paper on {@link https://eprint.iacr.org/2010/548.pdf | truncated SHA512}. - * @param msg - message bytes to hash - * @param opts - Reserved hash options. - * @returns Digest bytes. - * @example - * Hash a message with SHA2-512/224. - * ```ts - * sha512_224(new Uint8Array([97, 98, 99])); - * ``` - */ -export const sha512_224 = /* @__PURE__ */ createHasher(() => new _SHA512_224(), -/* @__PURE__ */ oidNist(0x05)); diff --git a/backend/static/vendor/noble-hashes-utils.js b/backend/static/vendor/noble-hashes-utils.js deleted file mode 100644 index 3a4aab2..0000000 --- a/backend/static/vendor/noble-hashes-utils.js +++ /dev/null @@ -1,687 +0,0 @@ -/** - * Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. - * @param a - value to test - * @returns `true` when the value is a Uint8Array-compatible view. - * @example - * Check whether a value is a Uint8Array-compatible view. - * ```ts - * isBytes(new Uint8Array([1, 2, 3])); - * ``` - */ -export function isBytes(a) { - // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases. - // The fallback still requires a real ArrayBuffer view, so plain - // JSON-deserialized `{ constructor: ... }` spoofing is rejected, and - // `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views. - return (a instanceof Uint8Array || - (ArrayBuffer.isView(a) && - a.constructor.name === 'Uint8Array' && - 'BYTES_PER_ELEMENT' in a && - a.BYTES_PER_ELEMENT === 1)); -} -// Shared error-message prefix builder. Only called on throw paths, so assert -// success paths never pay for the string concatenation. -const atitle = (title) => (title ? `"${title}" ` : ''); -/** - * Asserts something is a non-negative integer. - * @param n - number to validate - * @param title - label included in thrown errors - * @returns The validated number. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Validate a non-negative integer option. - * ```ts - * anumber(32, 'length'); - * ``` - */ -export function anumber(n, title = '') { - if (typeof n !== 'number') - throw new TypeError(atitle(title) + 'expected number, got ' + typeof n); - if (!Number.isSafeInteger(n) || n < 0) - throw new RangeError(atitle(title) + 'expected integer >= 0, got ' + n); - return n; -} -/** - * Asserts something is a boolean. - * @param value - value to validate - * @param title - label included in thrown errors - * @returns The validated boolean. - * @throws On wrong argument types. {@link TypeError} - * @example - * Validate a boolean option. - * ```ts - * abool(true, 'enableXOF'); - * ``` - */ -export function abool(value, title = '') { - if (typeof value !== 'boolean') - throw new TypeError(atitle(title) + 'expected boolean, got type=' + typeof value); - return value; -} -/** - * Asserts something is Uint8Array. - * @param value - value to validate - * @param length - optional exact length constraint - * @param title - label included in thrown errors - * @returns The validated byte array. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Validate that a value is a byte array. - * ```ts - * abytes(new Uint8Array([1, 2, 3])); - * ``` - */ -export function abytes(value, length, title = '') { - // Success path first: this runs at the start of every update() / digestInto(), and the - // common `abytes(data)` form must not pay for length handling it does not use. - if (isBytes(value) && (length === undefined || value.length === length)) - return value; - // Error path: recompute freely to build the exact message. - if (length !== undefined) - anumber(length, 'length'); - const bytes = isBytes(value); - const ofLen = length !== undefined ? ` of length ${length}` : ''; - const got = bytes ? `length=${value.length}` : `type=${typeof value}`; - const message = atitle(title) + 'expected Uint8Array' + ofLen + ', got ' + got; - if (!bytes) - throw new TypeError(message); - throw new RangeError(message); -} -/** - * Copies bytes into a fresh Uint8Array. - * Buffer-style slices can alias the same backing store, so callers that need ownership should copy. - * @param bytes - source bytes to clone - * @returns Freshly allocated copy of `bytes`. - * @throws On wrong argument types. {@link TypeError} - * @example - * Clone a byte array before mutating it. - * ```ts - * const copy = copyBytes(new Uint8Array([1, 2, 3])); - * ``` - */ -export function copyBytes(bytes) { - // `Uint8Array.from(...)` would also accept arrays / other typed arrays. Keep this helper strict - // because callers use it at byte-validation boundaries before mutating the detached copy. - return Uint8Array.from(abytes(bytes)); -} -/** - * Asserts something is a wrapped hash constructor. - * @param h - hash constructor to validate - * @throws On wrong argument types or invalid hash wrapper shape. {@link TypeError} - * @throws On invalid hash metadata ranges or values. {@link RangeError} - * @throws If the hash metadata allows empty outputs or block sizes. {@link Error} - * @example - * Validate a callable hash wrapper. - * ```ts - * import { ahash } from '@noble/hashes/utils.js'; - * import { sha256 } from '@noble/hashes/sha2.js'; - * ahash(sha256); - * ``` - */ -export function ahash(h) { - if (typeof h !== 'function' || typeof h.create !== 'function') - throw new TypeError('expected hash wrapped by utils.createHasher'); - anumber(h.outputLen); - anumber(h.blockLen); - // HMAC and KDF callers treat these as real byte lengths; allowing zero lets fake wrappers pass - // validation and can produce empty outputs instead of failing fast. - if (h.outputLen < 1 || h.blockLen < 1) - throw new Error('hash blockLen / outputLen must be >= 1'); -} -const aobject = (value, label) => { - if (value === null || typeof value !== 'object' || Array.isArray(value)) - throw new TypeError((label === 'object' ? '' : `"${label}" `) + 'expected object, got type=' + typeof value); -}; -const aopts = (value, label) => { - aobject(value, label); - const proto = Object.getPrototypeOf(value); - if (proto !== Object.prototype && proto !== null) - throw new TypeError(`"${label}" expected plain object`); - // Object.assign() treats an own "__proto__" source key as a write to the target's legacy - // prototype setter. Reject it before merging so inherited option values cannot be injected. - if (Object.hasOwn(value, '__proto__')) - throw new TypeError(`"${label}.__proto__" is not allowed`); -}; -/** - * Asserts a hash instance has not been destroyed or finished. - * @param instance - hash instance to validate - * @param checkFinished - whether to reject finalized instances - * @throws If the hash instance has already been destroyed or finalized. {@link Error} - * @example - * Validate that a hash instance is still usable. - * ```ts - * import { aexists } from '@noble/hashes/utils.js'; - * import { sha256 } from '@noble/hashes/sha2.js'; - * const hash = sha256.create(); - * aexists(hash); - * ``` - */ -export function aexists(instance, checkFinished = true) { - // Runs on every update()/digestInto(); the flags are library-owned booleans, so only their - // truthiness is checked - re-validating their type per call was pure hot-path overhead. - if (instance.destroyed) - throw new Error('hash was destroyed'); - if (checkFinished && instance.finished) - throw new Error('digest() was already called'); -} -/** - * Asserts output is a sufficiently-sized byte array. - * @param out - destination buffer - * @param instance - hash instance providing output length - * Oversized buffers are allowed; downstream code only promises to fill the first `outputLen` bytes. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Validate a caller-provided digest buffer. - * ```ts - * import { aoutput } from '@noble/hashes/utils.js'; - * import { sha256 } from '@noble/hashes/sha2.js'; - * const hash = sha256.create(); - * aoutput(new Uint8Array(hash.outputLen), hash); - * ``` - */ -export function aoutput(out, instance) { - abytes(out, undefined, 'output'); - // `outputLen` is a library-owned readonly number; the negated comparison keeps failing fast - // when it is missing/NaN (comparisons with undefined/NaN are false) without an anumber() call. - const min = instance.outputLen; - if (!(out.length >= min)) { - throw new RangeError('"output" expected length >= ' + min); - } -} -/** - * Casts a typed array view to Uint8Array. - * @param arr - source typed array - * @returns Uint8Array view over the same buffer. - * @example - * Reinterpret a typed array as bytes. - * ```ts - * u8(new Uint32Array([1, 2])); - * ``` - */ -export function u8(arr) { - return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength); -} -/** - * Casts a typed array view to Uint32Array. - * `arr.byteOffset` must already be 4-byte aligned or the platform - * Uint32Array constructor will throw. - * @param arr - source typed array - * @returns Uint32Array view over the same buffer. - * @example - * Reinterpret a byte array as 32-bit words. - * ```ts - * u32(new Uint8Array(8)); - * ``` - */ -export function u32(arr) { - return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); -} -/** - * Zeroizes typed arrays in place. Warning: JS provides no guarantees. - * @param arrays - arrays to overwrite with zeros - * @example - * Zeroize sensitive buffers in place. - * ```ts - * clean(new Uint8Array([1, 2, 3])); - * ``` - */ -export function clean(...arrays) { - for (let i = 0; i < arrays.length; i++) { - arrays[i].fill(0); - } -} -/** - * Creates a DataView for byte-level manipulation. - * @param arr - source typed array - * @returns DataView over the same buffer region. - * @example - * Create a DataView over an existing buffer. - * ```ts - * createView(new Uint8Array(4)); - * ``` - */ -export function createView(arr) { - return new DataView(arr.buffer, arr.byteOffset, arr.byteLength); -} -/** - * Rotate-right operation for uint32 values. - * @param word - source word - * @param shift - shift amount in bits - * @returns Rotated word. - * @example - * Rotate a 32-bit word to the right. - * ```ts - * rotr(0x12345678, 8); - * ``` - */ -export function rotr(word, shift) { - return (word << (32 - shift)) | (word >>> shift); -} -/** - * Rotate-left operation for uint32 values. - * @param word - source word - * @param shift - shift amount in bits - * @returns Rotated word. - * @example - * Rotate a 32-bit word to the left. - * ```ts - * rotl(0x12345678, 8); - * ``` - */ -export function rotl(word, shift) { - return (word << shift) | ((word >>> (32 - shift)) >>> 0); -} -/** Whether the current platform is little-endian. */ -export const isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)(); -/** - * Byte-swap operation for uint32 values. - * @param word - source word - * @returns Word with reversed byte order. - * @example - * Reverse the byte order of a 32-bit word. - * ```ts - * byteSwap(0x11223344); - * ``` - */ -export function byteSwap(word) { - return (((word << 24) & 0xff000000) | - ((word << 8) & 0xff0000) | - ((word >>> 8) & 0xff00) | - ((word >>> 24) & 0xff)); -} -/** - * Conditionally byte-swaps one 32-bit word on big-endian platforms. - * @param n - source word - * @returns Original or byte-swapped word depending on platform endianness. - * @example - * Normalize a 32-bit word for host endianness. - * ```ts - * swap8IfBE(0x11223344); - * ``` - */ -export const swap8IfBE = isLE - ? (n) => n - : (n) => byteSwap(n) >>> 0; -/** - * Byte-swaps every word of a Uint32Array in place. - * @param arr - array to mutate - * @returns The same array after mutation; callers pass live state arrays here. - * @example - * Reverse the byte order of every word in place. - * ```ts - * byteSwap32(new Uint32Array([0x11223344])); - * ``` - */ -export function byteSwap32(arr) { - for (let i = 0; i < arr.length; i++) { - arr[i] = byteSwap(arr[i]); - } - return arr; -} -/** - * Conditionally byte-swaps a Uint32Array on big-endian platforms. - * @param u - array to normalize for host endianness - * @returns Original or byte-swapped array depending on platform endianness. - * On big-endian runtimes this mutates `u` in place via `byteSwap32(...)`. - * @example - * Normalize a word array for host endianness. - * ```ts - * swap32IfBE(new Uint32Array([0x11223344])); - * ``` - */ -export const swap32IfBE = isLE - ? (u) => u - : byteSwap32; -// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex -const hasHexBuiltin = /* @__PURE__ */ (() => -// @ts-ignore -typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')(); -// Array where index 0xf0 (240) is mapped to string 'f0' -const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0')); -/** - * Convert byte array to hex string. - * Uses the built-in function when available and assumes it matches the tested - * fallback semantics. - * @param bytes - bytes to encode - * @returns Lowercase hexadecimal string. - * @throws On wrong argument types. {@link TypeError} - * @example - * Convert bytes to lowercase hexadecimal. - * ```ts - * bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])); // 'cafe0123' - * ``` - */ -export function bytesToHex(bytes) { - abytes(bytes); - // @ts-ignore - if (hasHexBuiltin) - return bytes.toHex(); - // pre-caching improves the speed 6x - let hex = ''; - for (let i = 0; i < bytes.length; i++) { - hex += hexes[bytes[i]]; - } - return hex; -} -// Strict ASCII nibble parser: non-ASCII hex lookalikes are rejected as undefined. -// ASCII codes: '0'..'9' = 48..57, 'A'..'F' = 65..70, 'a'..'f' = 97..102. -// prettier-ignore -function asciiToBase16(ch) { - return ch >= 48 && ch <= 57 ? ch - 48 // '2' => 50-48 - : ch >= 65 && ch <= 70 ? ch - (65 - 10) // 'B' => 66-(65-10) - : ch >= 97 && ch <= 102 ? ch - (97 - 10) // 'b' => 98-(97-10) - : undefined; -} -/** - * Convert hex string to byte array. Uses built-in function, when available. - * @param hex - hexadecimal string to decode - * @returns Decoded bytes. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Decode lowercase hexadecimal into bytes. - * ```ts - * hexToBytes('cafe0123'); // Uint8Array.from([0xca, 0xfe, 0x01, 0x23]) - * ``` - */ -export function hexToBytes(hex) { - if (typeof hex !== 'string') - throw new TypeError('hex string expected, got ' + typeof hex); - if (hasHexBuiltin) { - try { - return Uint8Array.fromHex(hex); - } - catch (error) { - if (error instanceof SyntaxError) - throw new RangeError(error.message); - throw error; - } - } - const hl = hex.length; - const al = hl / 2; - if (hl % 2) - throw new RangeError('hex string expected, got unpadded hex of length ' + hl); - const array = new Uint8Array(al); - for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) { - const n1 = asciiToBase16(hex.charCodeAt(hi)); // parse first char, multiply it by 16 - const n2 = asciiToBase16(hex.charCodeAt(hi + 1)); // parse second char - if (n1 === undefined || n2 === undefined) { - const char = hex[hi] + hex[hi + 1]; - throw new RangeError('hex string expected, got non-hex character "' + char + '" at index ' + hi); - } - array[ai] = n1 * 16 + n2; // example: 'A9' => 10*16 + 9 - } - return array; -} -/** - * Yields to the host task scheduler so timers, I/O, and rendering can make progress. - * Uses the Web Scheduling API when available or `setTimeout` as a cross-platform fallback. - * Host-task yields are much slower than microtasks (roughly 1ms with the timer fallback), so - * async loops should use `asyncTick >= 10` to amortize scheduling overhead to about 10% while - * still allowing other event-loop work to proceed. - * @param onReject - optional cleanup invoked only if the host yield fails - * @example - * Yield to the next scheduler tick. - * ```ts - * await nextTick(); - * ``` - */ -export function nextTick(onReject) { - const host = globalThis; - if (typeof host.scheduler?.yield === 'function') { - const promise = host.scheduler.yield(); - // Keep the original scheduler rejection; this handler exists only for cleanup. - if (onReject) - promise.catch(onReject); - return promise; - } - return new Promise((resolve) => host.setTimeout(resolve, 0)); -} -/** - * Returns control to the host event loop every `tick` milliseconds to avoid blocking long loops. - * @param iters - number of loop iterations to run - * @param tick - maximum time slice in milliseconds - * @param cb - callback executed on each iteration - * @param onReject - optional cleanup invoked only if a host yield fails - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @example - * Run a loop that periodically yields back to the event loop. - * ```ts - * await asyncLoop(2, 0, () => {}); - * ``` - */ -export async function asyncLoop(iters, tick, cb, onReject) { - anumber(iters, 'iters'); - anumber(tick, 'tick'); - if (typeof cb !== 'function') - throw new TypeError('callback must be a function'); - // Callback is synchronous by contract; asyncLoop only yields between sync work windows. - let ts = Date.now(); - for (let i = 0; i < iters; i++) { - cb(i); - // Date.now() is not monotonic, so in case if clock goes backwards we return return control too - const diff = Date.now() - ts; - if (diff >= 0 && diff < tick) - continue; - await nextTick(onReject); - // Track only synchronous work time; scheduler delay after yielding is outside our budget. - ts = Date.now(); - } -} -/** - * Converts string to bytes using UTF8 encoding. - * Built-in doesn't validate input to be string: we do the check. - * Non-ASCII details are delegated to the platform `TextEncoder`. - * @param str - string to encode - * @returns UTF-8 encoded bytes. - * @throws On wrong argument types. {@link TypeError} - * @example - * Encode a string as UTF-8 bytes. - * ```ts - * utf8ToBytes('abc'); // Uint8Array.from([97, 98, 99]) - * ``` - */ -export function utf8ToBytes(str) { - if (typeof str !== 'string') - throw new TypeError('string expected'); - const encoded = new TextEncoder().encode(str); - try { - // Copy into the current realm for Firefox extension contexts. Callers that own the returned - // buffer can then wipe it independently of TextEncoder's temporary result. - return new Uint8Array(encoded); // https://bugzil.la/1681809 - } - finally { - clean(encoded); - } -} -/** - * Helper for KDFs: consumes Uint8Array or string. - * String inputs are UTF-8 encoded; byte-array inputs stay aliased to the caller buffer. - * @param data - user-provided KDF input - * @param errorTitle - label included in thrown errors - * @returns Byte representation of the input. - * @throws On wrong argument types. {@link TypeError} - * @example - * Normalize KDF input to bytes. - * ```ts - * kdfInputToBytes('password'); - * ``` - */ -export function kdfInputToBytes(data, errorTitle = '') { - if (typeof data === 'string') - return utf8ToBytes(data); - return abytes(data, undefined, errorTitle); -} -/** - * Copies several Uint8Arrays into one. - * @param arrays - arrays to concatenate - * @returns Concatenated byte array. - * @throws On wrong argument types. {@link TypeError} - * @example - * Concatenate multiple byte arrays. - * ```ts - * concatBytes(new Uint8Array([1]), new Uint8Array([2])); - * ``` - */ -export function concatBytes(...arrays) { - let sum = 0; - for (let i = 0; i < arrays.length; i++) { - const a = arrays[i]; - abytes(a); - sum += a.length; - } - const res = new Uint8Array(sum); - for (let i = 0, pad = 0; i < arrays.length; i++) { - const a = arrays[i]; - res.set(a, pad); - pad += a.length; - } - return res; -} -/** - * Validates declared required and optional field types on a plain object. - * This walks field schemas and formats detailed errors, so avoid it on hot paths; use direct - * one-line guards such as `abytes()`, `abool()`, or `anumber()` instead. - * @param object - object to validate - * @param fields - map of required field names to expected types - * @param optFields - map of optional field names to expected types - * @param title - label included in thrown errors - * @throws On wrong argument types. {@link TypeError} - * @example - * Validate required and optional option fields. - * ```ts - * validateObject({ N: 1024, dkLen: 32 }, { N: 'number' }, { dkLen: 'number' }); - * ``` - */ -export const validateObject = (object, fields = {}, optFields = {}, title = 'object') => { - aobject(object, title); - aobject(fields, 'fields'); - aobject(optFields, 'optFields'); - function checkField(fieldName, expectedType, isOpt) { - const label = title === 'object' ? `param "${String(fieldName)}"` : `"${title}.${String(fieldName)}"`; - // Config fields must be explicit own properties. Optional inherited values are rejected too - // because callers keep reading the same options object after validation. - const val = object[fieldName]; - // Runtime objects such as Field instances intentionally satisfy required method slots - // via their shared prototype. - if (!Object.hasOwn(object, fieldName) && - (isOpt ? val !== undefined : expectedType !== 'function')) { - throw new TypeError(`${label} is invalid: expected own property`); - } - if (isOpt && val === undefined) - return; - const current = typeof val; - if (current !== expectedType || val === null) - throw new TypeError(`${label} is invalid: expected ${expectedType}, got ${current}`); - } - const iter = (f, isOpt) => Object.entries(f).forEach(([k, v]) => checkField(k, v, isOpt)); - iter(fields, false); - iter(optFields, true); -}; -/** - * Merges default options and passed options. - * @param defaults - base option object - * @param opts - user overrides - * @param title - label included in thrown override errors - * @returns Fresh merged option object with a null prototype. - * @throws On wrong argument types. {@link TypeError} - * @example - * Merge user overrides onto default options. - * ```ts - * checkOpts({ dkLen: 32 }, { asyncTick: 10 }); - * ``` - */ -export function checkOpts(defaults, opts, title = 'opts') { - aopts(defaults, 'defaults'); - if (opts !== undefined) - aopts(opts, title); - // Callers read optional fields directly, so omitted values must not fall through to ambient - // Object.prototype pollution (for example a forged `dkLen` changing SHAKE's default output). - const merged = Object.assign(Object.create(null), defaults, opts); - return merged; -} -/** - * Creates a callable hash function from a stateful class constructor. - * @param hashCons - hash constructor or factory - * @param info - optional metadata such as DER OID - * @returns Frozen callable hash wrapper with `.create()`. - * Wrapper construction eagerly calls `hashCons(undefined)` once to read - * `outputLen` / `blockLen`, so constructor side effects happen at module - * init time. - * @throws On wrong argument types. {@link TypeError} - * @example - * Wrap a stateful hash constructor into a callable helper. - * ```ts - * import { createHasher } from '@noble/hashes/utils.js'; - * import { sha256 } from '@noble/hashes/sha2.js'; - * const wrapped = createHasher(sha256.create, { oid: sha256.oid }); - * wrapped(new Uint8Array([1])); - * ``` - */ -export function createHasher(hashCons, info = {}) { - if (typeof hashCons !== 'function') - throw new TypeError('"hashCons" expected function, got type=' + typeof hashCons); - info = checkOpts({}, info, 'info'); - const hashC = (msg, opts) => hashCons(opts) - .update(msg) - .digest(); - const tmp = hashCons(undefined); - hashC.outputLen = tmp.outputLen; - hashC.blockLen = tmp.blockLen; - hashC.canXOF = tmp.canXOF; - hashC.create = (opts) => hashCons(opts); - Object.assign(hashC, info); - return Object.freeze(hashC); -} -/** - * Cryptographically secure PRNG backed by `crypto.getRandomValues`. - * @param bytesLength - number of random bytes to generate - * @returns Random bytes. - * The platform `getRandomValues()` implementation still defines any - * single-call length cap, and this helper rejects oversize requests - * with a stable library `RangeError` instead of host-specific errors. - * @throws On wrong argument types. {@link TypeError} - * @throws On wrong argument ranges or values. {@link RangeError} - * @throws If the current runtime does not provide `crypto.getRandomValues`. {@link Error} - * @example - * Generate a fresh random key or nonce. - * ```ts - * const key = randomBytes(16); - * ``` - */ -export function randomBytes(bytesLength = 32) { - // Match the repo's other length-taking helpers instead of relying on Uint8Array coercion. - anumber(bytesLength, 'bytesLength'); - const cr = typeof globalThis === 'object' ? globalThis.crypto : null; - if (typeof cr?.getRandomValues !== 'function') - throw new Error('crypto.getRandomValues must be defined'); - // Web Cryptography API Level 2 ยง10.1.1: - // if `byteLength > 65536`, throw `QuotaExceededError`. - // Keep the guard explicit so callers can see the quota in code - // instead of discovering it by reading the spec or host errors. - // This wrapper surfaces the same quota as a stable library RangeError. - if (bytesLength > 65536) - throw new RangeError(`"bytesLength" expected <= 65536, got ${bytesLength}`); - return cr.getRandomValues(new Uint8Array(bytesLength)); -} -/** - * Creates OID metadata for NIST hashes with prefix `06 09 60 86 48 01 65 03 04 02`. - * @param suffix - final OID byte for the selected hash. - * The helper accepts any byte even though only the documented NIST hash - * suffixes are meaningful downstream. - * @returns Object containing the DER-encoded OID. - * @example - * Build OID metadata for a NIST hash. - * ```ts - * oidNist(0x01); - * ``` - */ -export const oidNist = (suffix) => ({ - // Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet. - // Larger suffix values would need base-128 OID encoding and a different length byte. - oid: Uint8Array.from([0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, suffix]), -}); diff --git a/backend/static/vendor/noble-hashes.js b/backend/static/vendor/noble-hashes.js deleted file mode 100644 index d09e2b8..0000000 --- a/backend/static/vendor/noble-hashes.js +++ /dev/null @@ -1,577 +0,0 @@ -/** - * Argon2 KDF from RFC 9106. Can be used to create a key from password and salt. - * We suggest to use Scrypt. JS Argon is 2-10x slower than native code because of 64-bitness: - * * argon uses uint64, but JS doesn't have fast uint64array - * * uint64 multiplication is 1/3 of time - * * `P` function would be very nice with u64, because most of value will be in registers, - * hovewer with u32 it will require 32 registers, which is too much. - * * JS arrays do slow bound checks, so reading from `A2_BUF` slows it down - * @module - */ -import { blake2b } from "./blake2.js"; -import { anumber, checkOpts, clean, kdfInputToBytes, nextTick, swap32IfBE, swap8IfBE, u32, u8, } from "./utils.js"; -// RFC 9106 ยง3.1 type `y`: 0 = Argon2d, 1 = Argon2i, 2 = Argon2id. The numeric values are the -// spec-bound part here; the object keys are internal labels. -const AT = { Argon2d: 0, Argon2i: 1, Argon2id: 2 }; -// RFC 9106 sync points constant `SL = 4`, fixed by the design rather than exposed as a tuning knob. -const ARGON2_SYNC_POINTS = 4; -// Preserve Argon2's `LE32(len(X)) || X` encoding for omitted -// optional fields by emitting empty bytes. -const abytesOrZero = (buf, errorTitle = '') => { - if (buf === undefined) - return Uint8Array.of(); - return kdfInputToBytes(buf, errorTitle); -}; -// Temporary block buffer. -// 1024-byte block: 256 u32 = 128 interleaved low/high halves = RFC's -// 8x8 matrix of 16-byte registers. -const A2_BUF = new Uint32Array(256); -// Quarter-round over 64-bit word indices into `A2_BUF`; each index maps to adjacent low/high u32s. -// Each BlaMka step `X = X + Y + 2 * trunc(X) * trunc(Y)` (trunc = low 32 bits) starts -// with an exact low product from `Math.imul`. The rounded double product is within 1024 of the -// exact u64 product; subtracting that exact low half and rounding to the nearest multiple of -// 2^32 therefore recovers the exact high half. RFC 9106 Figure 19 GB then rotates by 32, 24, -// 16, and 63 bits after each XOR. -function G(a, b, c, d) { - let Al = A2_BUF[2 * a], Ah = A2_BUF[2 * a + 1]; // prettier-ignore - let Bl = A2_BUF[2 * b], Bh = A2_BUF[2 * b + 1]; // prettier-ignore - let Cl = A2_BUF[2 * c], Ch = A2_BUF[2 * c + 1]; // prettier-ignore - let Dl = A2_BUF[2 * d], Dh = A2_BUF[2 * d + 1]; // prettier-ignore - let ml = 0, mh = 0, rl = 0, xh = 0, xl = 0; // prettier-ignore - // A = blamka(A, B); D = rotr64(D ^ A, 32) - ml = Math.imul(Al, Bl); - mh = (((Al >>> 0) * (Bl >>> 0) - (ml >>> 0)) / 0x100000000 + 0.5) | 0; // prettier-ignore - rl = (Al >>> 0) + (Bl >>> 0) + ((ml << 1) >>> 0); - Ah = (Ah + Bh + ((mh << 1) | (ml >>> 31)) + ((rl / 0x100000000) | 0)) | 0; - Al = rl | 0; // prettier-ignore - xh = Dh ^ Ah; - xl = Dl ^ Al; // prettier-ignore - Dh = xl; - Dl = xh; // prettier-ignore - // C = blamka(C, D); B = rotr64(B ^ C, 24) - ml = Math.imul(Cl, Dl); - mh = (((Cl >>> 0) * (Dl >>> 0) - (ml >>> 0)) / 0x100000000 + 0.5) | 0; // prettier-ignore - rl = (Cl >>> 0) + (Dl >>> 0) + ((ml << 1) >>> 0); - Ch = (Ch + Dh + ((mh << 1) | (ml >>> 31)) + ((rl / 0x100000000) | 0)) | 0; - Cl = rl | 0; // prettier-ignore - xh = Bh ^ Ch; - xl = Bl ^ Cl; // prettier-ignore - Bh = (xh >>> 24) | (xl << 8); - Bl = (xh << 8) | (xl >>> 24); // prettier-ignore - // A = blamka(A, B); D = rotr64(D ^ A, 16) - ml = Math.imul(Al, Bl); - mh = (((Al >>> 0) * (Bl >>> 0) - (ml >>> 0)) / 0x100000000 + 0.5) | 0; // prettier-ignore - rl = (Al >>> 0) + (Bl >>> 0) + ((ml << 1) >>> 0); - Ah = (Ah + Bh + ((mh << 1) | (ml >>> 31)) + ((rl / 0x100000000) | 0)) | 0; - Al = rl | 0; // prettier-ignore - xh = Dh ^ Ah; - xl = Dl ^ Al; // prettier-ignore - Dh = (xh >>> 16) | (xl << 16); - Dl = (xh << 16) | (xl >>> 16); // prettier-ignore - // C = blamka(C, D); B = rotr64(B ^ C, 63) - ml = Math.imul(Cl, Dl); - mh = (((Cl >>> 0) * (Dl >>> 0) - (ml >>> 0)) / 0x100000000 + 0.5) | 0; // prettier-ignore - rl = (Cl >>> 0) + (Dl >>> 0) + ((ml << 1) >>> 0); - Ch = (Ch + Dh + ((mh << 1) | (ml >>> 31)) + ((rl / 0x100000000) | 0)) | 0; - Cl = rl | 0; // prettier-ignore - xh = Bh ^ Ch; - xl = Bl ^ Cl; // prettier-ignore - Bh = (xh << 1) | (xl >>> 31); - Bl = (xh >>> 31) | (xl << 1); // prettier-ignore - ((A2_BUF[2 * a] = Al), (A2_BUF[2 * a + 1] = Ah)); - ((A2_BUF[2 * b] = Bl), (A2_BUF[2 * b + 1] = Bh)); - ((A2_BUF[2 * c] = Cl), (A2_BUF[2 * c + 1] = Ch)); - ((A2_BUF[2 * d] = Dl), (A2_BUF[2 * d + 1] = Dh)); -} -// Argon2 permutation over 16 register indices into `A2_BUF`, not the register values themselves. -// RFC 9106 Figure 17: these arguments are the 16 `v0..v15` 64-bit word -// indices inside eight 16-byte inputs, not copied word values. -// prettier-ignore -function P(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14, v15) { - // RFC 9106 Figure 18: first apply GB across rows, then across columns of the 8x8 register matrix. - G(v00, v04, v08, v12); - G(v01, v05, v09, v13); - G(v02, v06, v10, v14); - G(v03, v07, v11, v15); - G(v00, v05, v10, v15); - G(v01, v06, v11, v12); - G(v02, v07, v08, v13); - G(v03, v04, v09, v14); -} -function block(x, xPos, yPos, outPos, needXor) { - // Stage R = X xor Y in the destination before permuting it. This avoids rereading both source - // blocks when folding R into the permuted scratch block below. - if (needXor) { - for (let i = 0; i < 256; i++) { - const r = x[xPos + i] ^ x[yPos + i]; - A2_BUF[i] = r; - x[outPos + i] ^= r; - } - } - else { - for (let i = 0; i < 256; i++) { - const r = x[xPos + i] ^ x[yPos + i]; - A2_BUF[i] = r; - x[outPos + i] = r; - } - } - // rows (8 consecutive 16-register groups) - for (let i = 0; i < 128; i += 16) { - // prettier-ignore - P(i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, i + 10, i + 11, i + 12, i + 13, i + 14, i + 15); - } - // columns (8 strided 16-register groups) - for (let i = 0; i < 16; i += 2) { - // prettier-ignore - P(i, i + 1, i + 16, i + 17, i + 32, i + 33, i + 48, i + 49, i + 64, i + 65, i + 80, i + 81, i + 96, i + 97, i + 112, i + 113); - } - // RFC 9106 step 6: passes after the first XOR the old destination block into the new G(X, Y). - for (let i = 0; i < 256; i++) - x[outPos + i] ^= A2_BUF[i]; - clean(A2_BUF); -} -// Variable-Length Hash Function H' -// Returns bytes, not words; 1024-byte block callers explicitly reinterpret with `u32(...)`. -function Hp(A, dkLen) { - const A8 = u8(A); - const T = new Uint32Array(1); - const T8 = u8(T); - // Argon2 H' prefixes dkLen as LE32; native Uint32Array writes would serialize as BE on s390x. - T[0] = swap8IfBE(dkLen); - // Fast path - if (dkLen <= 64) - return blake2b.create({ dkLen }).update(T8).update(A8).digest(); - const out = new Uint8Array(dkLen); - let V = blake2b.create({}).update(T8).update(A8).digest(); - let pos = 0; - // RFC 9106 Figure 8: each intermediate `V_i` contributes only `W_i`, its first 32 bytes; only - // `V_{r+1}` is emitted in full at the remaining length. - out.set(V.subarray(0, 32)); - pos += 32; - // Rest blocks - for (; dkLen - pos > 64; pos += 32) { - const Vh = blake2b.create({}).update(V); - Vh.digestInto(V); - Vh.destroy(); - out.set(V.subarray(0, 32), pos); - } - // Last block - out.set(blake2b(V, { dkLen: dkLen - pos }), pos); - clean(V, T); - // H' is byte-oriented; returning `u32(out)` would silently drop dkLen % 4 tail bytes. - return out; -} -// Used only inside argon2Blocks! -function indexAlpha(r, s, laneLen, segmentLen, index, randL, sameLane = false) { - // RFC 9106 ยง3.4.2 Figures 12-13: map `J1` / `J2` into the current lane's reference area `W`. - let area; - if (r === 0) { - if (s === 0) - area = index - 1; - else if (sameLane) - area = s * segmentLen + index - 1; - else - area = s * segmentLen + (index == 0 ? -1 : 0); - } - else if (sameLane) - area = laneLen - segmentLen + index - 1; - else - area = laneLen - segmentLen + (index == 0 ? -1 : 0); - const startPos = r !== 0 && s !== ARGON2_SYNC_POINTS - 1 ? (s + 1) * segmentLen : 0; - // Use the same exact-high recovery as G. `areaHigh` is floor(|W| * J1^2/2^32 / 2^32). - const randLow = Math.imul(randL, randL); - const randHigh = (((randL >>> 0) * (randL >>> 0) - (randLow >>> 0)) / 0x100000000 + 0.5) | 0; - const areaLow = Math.imul(area, randHigh); - const areaHigh = (((area >>> 0) * (randHigh >>> 0) - (areaLow >>> 0)) / 0x100000000 + 0.5) | 0; - const rel = area - 1 - areaHigh; - return (startPos + rel) % laneLen; -} -// Exclusive `2^32` sentinel used by `isU32(...)`, not the inclusive maximum u32 value. -const maxUint32 = Math.pow(2, 32); -const ARGON2_DEFAULT_MEMORY = 1024 ** 2; // KiB: 1 GiB -const ARGON2_DEFAULT_MAXMEM = ARGON2_DEFAULT_MEMORY * 1024; -// Validate safe JS integers in `[0, 2^32 - 1]`. -function isU32(num) { - return Number.isSafeInteger(num) && num >= 0 && num < maxUint32; -} -function argon2Opts(opts = {}) { - opts = checkOpts({}, opts); - const merged = { - t: 3, - m: ARGON2_DEFAULT_MEMORY, - p: 1, - version: 0x13, - dkLen: 32, - maxmem: ARGON2_DEFAULT_MAXMEM, - asyncTick: 10, - }; - // Unknown keys are copied through unchanged here and later ignored unless - // destructuring consumes them. - for (let [k, v] of Object.entries(opts)) - if (v !== undefined) - merged[k] = v; - const { dkLen, p, m, t, version, onProgress, asyncTick } = merged; - // RFC 9106 ยง3.1: tag length `T` MUST be an integer number of bytes from 4 to 2^32-1. - if (!isU32(dkLen) || dkLen < 4) - throw new Error('"dkLen" must be 4..'); - if (!isU32(p) || p < 1 || p >= Math.pow(2, 24)) - throw new Error('"p" must be 1..2^24'); - if (!isU32(m)) - throw new Error('"m" must be 0..2^32'); - if (!isU32(t) || t < 1) - throw new Error('"t" (iterations) must be 1..2^32'); - if (onProgress !== undefined && typeof onProgress !== 'function') - throw new Error('"onProgress" must be a function'); - anumber(asyncTick, 'asyncTick'); - /* - Memory size m MUST be an integer number of kibibytes from 8*p - to 2^(32)-1. The actual number of blocks is m', which is m - rounded down to the nearest multiple of 4*p. - */ - if (!isU32(m) || m < 8 * p) - throw new Error('"m" (memory) must be at least 8*p bytes'); - // Accept legacy `0x10` for compatibility even though RFC 9106 profiles standardize `0x13`. - if (version !== 0x10 && version !== 0x13) - throw new Error('"version" must be 0x10 or 0x13, got ' + version); - return merged; -} -function argon2InitialHash(password, salt, type, opts) { - const ownedInputs = []; - const BUF = new Uint32Array(1); - const BUF8 = u8(BUF); - let h; - let H0; - let succeeded = false; - const rememberOwned = (input, bytes) => { - if (typeof input === 'string') - ownedInputs.push(bytes); - return bytes; - }; - try { - const passwordBytes = rememberOwned(password, kdfInputToBytes(password, 'password')); - const saltBytes = rememberOwned(salt, kdfInputToBytes(salt, 'salt')); - if (!isU32(passwordBytes.length)) - throw new Error('"password" must be less of length 1..4Gb'); - // RFC 9106 ยง3.1 only requires S <= 2^32-1 bytes and says 16 bytes is RECOMMENDED for password - // hashing; this library intentionally takes the stricter common >=8-byte salt path. - if (!isU32(saltBytes.length) || saltBytes.length < 8) - throw new Error('"salt" must be of length 8..4Gb'); - if (!Object.values(AT).includes(type)) - throw new Error('"type" was invalid'); - let { p, dkLen, m, t, version, key, personalization, maxmem, onProgress, asyncTick } = argon2Opts(opts); - // Validation - const keyInput = key; - key = rememberOwned(keyInput, abytesOrZero(keyInput, 'key')); - const personalizationInput = personalization; - personalization = rememberOwned(personalizationInput, abytesOrZero(personalizationInput, 'personalization')); - // H_0 = H^(64)(LE32(p) || LE32(T) || LE32(m) || LE32(t) || - // LE32(v) || LE32(y) || LE32(length(P)) || P || - // LE32(length(S)) || S || LE32(length(K)) || K || - // LE32(length(X)) || X) - h = blake2b.create(); - for (let item of [p, dkLen, m, t, version, type]) { - // RFC 9106 H0 encodes these scalars as LE32, so normalize the host word before - // exposing bytes. - BUF[0] = swap8IfBE(item); - h.update(BUF8); - } - for (let i of [passwordBytes, saltBytes, key, personalization]) { - BUF[0] = swap8IfBE(i.length); // BUF is u32 array, this is valid once normalized to LE bytes - h.update(BUF8).update(i); - } - // Reserve two extra LE32 words after the 64-byte `H_0` so Figures 3-4 can append - // `LE32(0 or 1) || LE32(i)` in place for the lane-starting blocks. - H0 = new Uint32Array(18); - h.digestInto(u8(H0)); - succeeded = true; - return { H0, p, dkLen, m, t, version, maxmem, onProgress, asyncTick }; - } - finally { - // digestInto() does not destroy BLAKE2 state. It and all string-derived inputs contain secrets. - if (h) - h.destroy(); - clean(BUF, ...ownedInputs); - if (!succeeded && H0) - clean(H0); - } -} -function argon2Init(password, salt, type, opts) { - const { H0, p, dkLen, m, t, version, maxmem, onProgress, asyncTick } = argon2InitialHash(password, salt, type, opts); - // 256 u32 = 1024 (BLOCK_SIZE), fills A2_BUF on processing - try { - // Params - const lanes = p; - // m' = 4 * p * floor (m / 4p) - const mP = 4 * p * Math.floor(m / (ARGON2_SYNC_POINTS * p)); - //q = m' / p columns - const laneLen = Math.floor(mP / p); - const segmentLen = Math.floor(laneLen / ARGON2_SYNC_POINTS); - // `maxmem` is documented in bytes; compare against the actual 1024-byte block allocation. - const memUsed = mP * 1024; - if (!isU32(maxmem)) - throw new Error('"maxmem" expected <2**32, got ' + maxmem); - if (memUsed > maxmem) - throw new Error('"maxmem" limit was hit: memUsed(mP*1024)=' + memUsed + ', maxmem=' + maxmem); - const B = new Uint32Array(memUsed / 4); - // Fill first blocks - for (let l = 0; l < p; l++) { - const i = 256 * laneLen * l; - // B[i][0] = H'^(1024)(H_0 || LE32(0) || LE32(i)) - H0[17] = swap8IfBE(l); - H0[16] = swap8IfBE(0); - B.set(swap32IfBE(u32(Hp(H0, 1024))), i); - // B[i][1] = H'^(1024)(H_0 || LE32(1) || LE32(i)) - H0[16] = swap8IfBE(1); - B.set(swap32IfBE(u32(Hp(H0, 1024))), i + 256); - } - let perBlock = () => { }; - if (onProgress) { - // The first segment of the first pass skips two preinitialized blocks per lane. - const totalBlock = t * ARGON2_SYNC_POINTS * p * segmentLen - 2 * p; - // Invoke callback if progress changes from 10.01 to 10.02 - // Allows to draw smooth progress bar on up to 8K screen - const callbackPer = Math.max(Math.floor(totalBlock / 10000), 1); - let blockCnt = 0; - perBlock = () => { - blockCnt++; - if (onProgress && (!(blockCnt % callbackPer) || blockCnt === totalBlock)) - onProgress(blockCnt / totalBlock); - }; - } - return { type, mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock, asyncTick }; - } - finally { - clean(H0); - } -} -function argon2Output(B, p, laneLen, dkLen) { - const B_final = new Uint32Array(256); - for (let l = 0; l < p; l++) - for (let j = 0; j < 256; j++) - B_final[j] ^= B[256 * (laneLen * l + laneLen - 1) + j]; - // RFC 9106 steps 7-8 feed the byte string `C` into `H'^T(C)`, so normalize the xor'ed words - // back to spec byte order before `Hp(...)` reinterprets them as bytes. - const res = Hp(swap32IfBE(B_final), dkLen); - // Wipe both the xor scratch and the full working matrix once final digest bytes exist. - // JS cleanup is still only best-effort, but this local buffer is no longer needed here. - clean(B, B_final); - return res; -} -/** - * Fills every Argon2 block for all passes / slices / lanes, yielding once per - * processed block so callers control pacing: the sync driver just drains the - * generator, while the async driver awaits `nextTick()` between time slices. - */ -function* argon2Blocks(ctx, address) { - const { type, mP, p, t, version, B, laneLen, lanes, segmentLen, perBlock } = ctx; - // [address, input, zero_block] format so we can pass single U32 to block function - address[256 + 6] = mP; - address[256 + 8] = t; - address[256 + 10] = type; - for (let r = 0; r < t; r++) { - // RFC 9106 step 6 applies the XOR-on-later-passes rule only for version `0x13`; legacy - // `0x10` keeps the older overwrite behavior used by the v16 test vectors. - const needXor = r !== 0 && version === 0x13; - address[256 + 0] = r; - for (let s = 0; s < ARGON2_SYNC_POINTS; s++) { - address[256 + 4] = s; - // RFC 9106 ยง3.4.1.3: Argon2id uses Argon2i's data-independent `J1` / `J2` generation only - // in pass 0, slices 0 and 1; Argon2i uses it in every segment. - const dataIndependent = type == AT.Argon2i || (type == AT.Argon2id && r === 0 && s < 2); - for (let l = 0; l < p; l++) { - address[256 + 2] = l; - address[256 + 12] = 0; - let startPos = 0; - if (r === 0 && s === 0) { - startPos = 2; - if (dataIndependent) { - address[256 + 12]++; - block(address, 256, 2 * 256, 0, false); - block(address, 0, 2 * 256, 0, false); - } - } - // current block position - let offset = l * laneLen + s * segmentLen + startPos; - for (let index = startPos; index < segmentLen; index++, offset++) { - perBlock(); - // Previous block position: wraps to the lane's last block only at lane start, - // which can happen here only for the first block of slice 0 on passes > 0. - const prev = offset % laneLen ? offset - 1 : offset + laneLen - 1; - let randL, randH; - if (dataIndependent) { - let i128 = index % 128; - // RFC 9106 ยง3.4.1.2: each 1024-byte address block yields 128 `(J1, J2)` pairs, so - // regenerate it whenever the segment index crosses a multiple of 128. - if (i128 === 0) { - address[256 + 12]++; - block(address, 256, 2 * 256, 0, false); - block(address, 0, 2 * 256, 0, false); - } - randL = address[2 * i128]; - randH = address[2 * i128 + 1]; - } - else { - const T = 256 * prev; - randL = B[T]; - randH = B[T + 1]; - } - // Address-block path selects `J1` / `J2`, then maps them to the reference - // lane/block per RFC 9106 ยง3.4. - const refLane = r === 0 && s === 0 ? l : randH % lanes; - const refPos = indexAlpha(r, s, laneLen, segmentLen, index, randL, refLane == l); - const refBlock = laneLen * refLane + refPos; - // B[i][j] = G(B[i][j-1], B[l][z]) - block(B, 256 * prev, 256 * refBlock, offset * 256, needXor); - yield; - } - } - } - } - clean(address); -} -function argon2(type, password, salt, opts) { - const ctx = argon2Init(password, salt, type, opts); - const blocks = argon2Blocks(ctx, new Uint32Array(3 * 256)); - while (!blocks.next().done) { } - return argon2Output(ctx.B, ctx.p, ctx.laneLen, ctx.dkLen); -} -/** - * Argon2d GPU-resistant version. - * @param password - password or input key material - * @param salt - unique salt value - * @param opts - Argon2 cost and optional tuning parameters. See {@link ArgonOpts}. - * @returns Derived key bytes. - * @throws If the Argon2 input or cost parameters are invalid. {@link Error} - * @example - * Derive a key with Argon2d. - * ```ts - * argon2d('password', 'salt1234', { t: 1, m: 8, p: 1, dkLen: 32 }); - * ``` - * @example - * Derive a key with optional secret and scheduler controls. - * ```ts - * const progressLog: number[] = []; - * argon2d('password', 'salt1234', { - * t: 1, - * m: 8, - * p: 1, - * dkLen: 32, - * version: 0x13, - * key: 'secret', - * personalization: 'application', - * maxmem: 1024 * 1024, - * asyncTick: 1, - * onProgress(progress) { - * progressLog.push(progress); - * }, - * }); - * ``` - */ -export const argon2d = (password, salt, opts = {}) => argon2(AT.Argon2d, password, salt, opts); -/** - * Argon2i side-channel-resistant version. - * @param password - password or input key material - * @param salt - unique salt value - * @param opts - Argon2 cost and optional tuning parameters. See {@link ArgonOpts}. - * @returns Derived key bytes. - * @throws If the Argon2 input or cost parameters are invalid. {@link Error} - * @example - * Derive a key with Argon2i. - * ```ts - * argon2i('password', 'salt1234', { t: 1, m: 8, p: 1, dkLen: 32 }); - * ``` - */ -export const argon2i = (password, salt, opts = {}) => argon2(AT.Argon2i, password, salt, opts); -/** - * Argon2id, combining i+d, the most popular version from RFC 9106. - * @param password - password or input key material - * @param salt - unique salt value - * @param opts - Argon2 cost and optional tuning parameters. See {@link ArgonOpts}. - * @returns Derived key bytes. - * @throws If the Argon2 input or cost parameters are invalid. {@link Error} - * @example - * Derive a key with Argon2id. - * ```ts - * argon2id('password', 'salt1234', { t: 1, m: 8, p: 1, dkLen: 32 }); - * ``` - */ -export const argon2id = (password, salt, opts = {}) => argon2(AT.Argon2id, password, salt, opts); -async function argon2Async(type, password, salt, opts) { - const ctx = argon2Init(password, salt, type, opts); - // Keep the generator-local address block reachable so an aborted scheduler yield can wipe it. - const address = new Uint32Array(3 * 256); - const blocks = argon2Blocks(ctx, address); - const abort = () => clean(address, ctx.B); - let ts = Date.now(); - while (!blocks.next().done) { - // Date.now() is not monotonic. If the clock goes backwards, - // still yield control. - const diff = Date.now() - ts; - if (diff >= 0 && diff < ctx.asyncTick) - continue; - await nextTick(abort); - // Scheduler delay is outside the synchronous work budget. - ts = Date.now(); - } - return argon2Output(ctx.B, ctx.p, ctx.laneLen, ctx.dkLen); -} -/** - * Argon2d async GPU-resistant version. - * @param password - password or input key material - * @param salt - unique salt value - * @param opts - Argon2 cost and optional tuning parameters. See {@link ArgonOpts}. - * @returns Promise resolving to derived key bytes. - * @throws If the Argon2 input or cost parameters are invalid. {@link Error} - * @example - * Derive a key with Argon2d asynchronously. - * ```ts - * await argon2dAsync('password', 'salt1234', { t: 1, m: 8, p: 1, dkLen: 32 }); - * ``` - * @example - * Derive a key asynchronously with optional secret and scheduler controls. - * ```ts - * await argon2dAsync('password', 'salt1234', { - * t: 1, - * m: 8, - * p: 1, - * dkLen: 32, - * version: 0x13, - * key: 'secret', - * personalization: 'application', - * maxmem: 1024 * 1024, - * asyncTick: 1, - * onProgress(progress) { - * if (progress > 1) throw new Error('invalid progress'); - * }, - * }); - * ``` - */ -export const argon2dAsync = (password, salt, opts = {}) => argon2Async(AT.Argon2d, password, salt, opts); -/** - * Argon2i async side-channel-resistant version. - * @param password - password or input key material - * @param salt - unique salt value - * @param opts - Argon2 cost and optional tuning parameters. See {@link ArgonOpts}. - * @returns Promise resolving to derived key bytes. - * @throws If the Argon2 input or cost parameters are invalid. {@link Error} - * @example - * Derive a key with Argon2i asynchronously. - * ```ts - * await argon2iAsync('password', 'salt1234', { t: 1, m: 8, p: 1, dkLen: 32 }); - * ``` - */ -export const argon2iAsync = (password, salt, opts = {}) => argon2Async(AT.Argon2i, password, salt, opts); -/** - * Argon2id async, combining i+d, the most popular version from RFC 9106. - * @param password - password or input key material - * @param salt - unique salt value - * @param opts - Argon2 cost and optional tuning parameters. See {@link ArgonOpts}. - * @returns Promise resolving to derived key bytes. - * @throws If the Argon2 input or cost parameters are invalid. {@link Error} - * @example - * Derive a key with Argon2id asynchronously. - * ```ts - * await argon2idAsync('password', 'salt1234', { t: 1, m: 8, p: 1, dkLen: 32 }); - * ``` - */ -export const argon2idAsync = (password, salt, opts = {}) => argon2Async(AT.Argon2id, password, salt, opts);