@leofcoin/workers 1.5.39 → 1.5.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,198 +1,443 @@
1
- function bytes(b, ...lengths) {
2
- if (!(b instanceof Uint8Array))
3
- throw new Error('Expected Uint8Array');
4
- if (lengths.length > 0 && !lengths.includes(b.length))
5
- throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
1
+ // Split a JS number into u32 halves without a BigInt allocation. Exact only for integers
2
+ // `0 <= n < 2**53`; callers use it on byte / bit counters, which JS length math caps far below
3
+ // that (an ArrayBuffer cannot exceed 2**53 - 1 bytes).
4
+ const fromNumH = (n) => (n / 2 ** 32) | 0;
5
+ const fromNumL = (n) => n >>> 0;
6
+ // Drop-in replacement for `view.setBigUint64(byteOffset, BigInt(n), isLE)` without the per-call
7
+ // BigInt allocation. Same `n < 2**53` precondition as `fromNumH`/`fromNumL`.
8
+ function setU64FromNum(view, byteOffset, n, isLE) {
9
+ const h = fromNumH(n);
10
+ const l = fromNumL(n);
11
+ view.setUint32(byteOffset, isLE ? l : h, isLE);
12
+ view.setUint32(byteOffset + 4, isLE ? h : l, isLE);
6
13
  }
7
- function exists(instance, checkFinished = true) {
14
+
15
+ /**
16
+ * Checks if something is Uint8Array. Be careful: nodejs Buffer will return true.
17
+ * @param a - value to test
18
+ * @returns `true` when the value is a Uint8Array-compatible view.
19
+ * @example
20
+ * Check whether a value is a Uint8Array-compatible view.
21
+ * ```ts
22
+ * isBytes(new Uint8Array([1, 2, 3]));
23
+ * ```
24
+ */
25
+ function isBytes(a) {
26
+ // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases.
27
+ // The fallback still requires a real ArrayBuffer view, so plain
28
+ // JSON-deserialized `{ constructor: ... }` spoofing is rejected, and
29
+ // `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views.
30
+ return (a instanceof Uint8Array ||
31
+ (ArrayBuffer.isView(a) &&
32
+ a.constructor.name === 'Uint8Array' &&
33
+ 'BYTES_PER_ELEMENT' in a &&
34
+ a.BYTES_PER_ELEMENT === 1));
35
+ }
36
+ // Shared error-message prefix builder. Only called on throw paths, so assert
37
+ // success paths never pay for the string concatenation.
38
+ const atitle = (title) => (title ? `"${title}" ` : '');
39
+ /**
40
+ * Asserts something is Uint8Array.
41
+ * @param value - value to validate
42
+ * @param length - optional exact length constraint
43
+ * @param title - label included in thrown errors
44
+ * @returns The validated byte array.
45
+ * @throws On wrong argument types. {@link TypeError}
46
+ * @throws On wrong argument ranges or values. {@link RangeError}
47
+ * @example
48
+ * Validate that a value is a byte array.
49
+ * ```ts
50
+ * abytes(new Uint8Array([1, 2, 3]));
51
+ * ```
52
+ */
53
+ function abytes(value, length, title = '') {
54
+ // Success path first: this runs at the start of every update() / digestInto(), and the
55
+ // common `abytes(data)` form must not pay for length handling it does not use.
56
+ if (isBytes(value) && (length === undefined))
57
+ return value;
58
+ const bytes = isBytes(value);
59
+ const ofLen = '';
60
+ const got = bytes ? `length=${value.length}` : `type=${typeof value}`;
61
+ const message = atitle(title) + 'expected Uint8Array' + ofLen + ', got ' + got;
62
+ if (!bytes)
63
+ throw new TypeError(message);
64
+ throw new RangeError(message);
65
+ }
66
+ const aobject = (value, label) => {
67
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
68
+ throw new TypeError((label === 'object' ? '' : `"${label}" `) + 'expected object, got type=' + typeof value);
69
+ };
70
+ const aopts = (value, label) => {
71
+ aobject(value, label);
72
+ const proto = Object.getPrototypeOf(value);
73
+ if (proto !== Object.prototype && proto !== null)
74
+ throw new TypeError(`"${label}" expected plain object`);
75
+ // Object.assign() treats an own "__proto__" source key as a write to the target's legacy
76
+ // prototype setter. Reject it before merging so inherited option values cannot be injected.
77
+ if (Object.hasOwn(value, '__proto__'))
78
+ throw new TypeError(`"${label}.__proto__" is not allowed`);
79
+ };
80
+ /**
81
+ * Asserts a hash instance has not been destroyed or finished.
82
+ * @param instance - hash instance to validate
83
+ * @param checkFinished - whether to reject finalized instances
84
+ * @throws If the hash instance has already been destroyed or finalized. {@link Error}
85
+ * @example
86
+ * Validate that a hash instance is still usable.
87
+ * ```ts
88
+ * import { aexists } from '@noble/hashes/utils.js';
89
+ * import { sha256 } from '@noble/hashes/sha2.js';
90
+ * const hash = sha256.create();
91
+ * aexists(hash);
92
+ * ```
93
+ */
94
+ function aexists(instance, checkFinished = true) {
95
+ // Runs on every update()/digestInto(); the flags are library-owned booleans, so only their
96
+ // truthiness is checked - re-validating their type per call was pure hot-path overhead.
8
97
  if (instance.destroyed)
9
- throw new Error('Hash instance has been destroyed');
98
+ throw new Error('hash was destroyed');
10
99
  if (checkFinished && instance.finished)
11
- throw new Error('Hash#digest() has already been called');
100
+ throw new Error('digest() was already called');
12
101
  }
13
- function output(out, instance) {
14
- bytes(out);
102
+ /**
103
+ * Asserts output is a sufficiently-sized byte array.
104
+ * @param out - destination buffer
105
+ * @param instance - hash instance providing output length
106
+ * Oversized buffers are allowed; downstream code only promises to fill the first `outputLen` bytes.
107
+ * @throws On wrong argument types. {@link TypeError}
108
+ * @throws On wrong argument ranges or values. {@link RangeError}
109
+ * @example
110
+ * Validate a caller-provided digest buffer.
111
+ * ```ts
112
+ * import { aoutput } from '@noble/hashes/utils.js';
113
+ * import { sha256 } from '@noble/hashes/sha2.js';
114
+ * const hash = sha256.create();
115
+ * aoutput(new Uint8Array(hash.outputLen), hash);
116
+ * ```
117
+ */
118
+ function aoutput(out, instance) {
119
+ abytes(out, undefined, 'output');
120
+ // `outputLen` is a library-owned readonly number; the negated comparison keeps failing fast
121
+ // when it is missing/NaN (comparisons with undefined/NaN are false) without an anumber() call.
15
122
  const min = instance.outputLen;
16
- if (out.length < min) {
17
- throw new Error(`digestInto() expects output buffer of length at least ${min}`);
123
+ if (!(out.length >= min)) {
124
+ throw new RangeError('"output" expected length >= ' + min);
18
125
  }
19
126
  }
20
-
21
- /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
22
- // We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
23
- // node.js versions earlier than v19 don't declare it in global scope.
24
- // For node.js, package.json#exports field mapping rewrites import
25
- // from `crypto` to `cryptoNode`, which imports native module.
26
- // Makes the utils un-importable in browsers without a bundler.
27
- // Once node.js 18 is deprecated, we can just drop the import.
28
- const u8a = (a) => a instanceof Uint8Array;
29
- // Cast array to view
30
- const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
31
- // The rotate right (circular right shift) operation for uint32
32
- const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
33
- // big-endian hardware is rare. Just in case someone still decides to run hashes:
34
- // early-throw an error because we don't support BE yet.
35
- const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
36
- if (!isLE)
37
- throw new Error('Non little-endian hardware is not supported');
38
127
  /**
39
- * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
128
+ * Zeroizes typed arrays in place. Warning: JS provides no guarantees.
129
+ * @param arrays - arrays to overwrite with zeros
130
+ * @example
131
+ * Zeroize sensitive buffers in place.
132
+ * ```ts
133
+ * clean(new Uint8Array([1, 2, 3]));
134
+ * ```
40
135
  */
41
- function utf8ToBytes(str) {
42
- if (typeof str !== 'string')
43
- throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
44
- return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
136
+ function clean(...arrays) {
137
+ for (let i = 0; i < arrays.length; i++) {
138
+ arrays[i].fill(0);
139
+ }
45
140
  }
46
141
  /**
47
- * Normalizes (non-hex) string or Uint8Array to Uint8Array.
48
- * Warning: when Uint8Array is passed, it would NOT get copied.
49
- * Keep in mind for future mutable operations.
142
+ * Creates a DataView for byte-level manipulation.
143
+ * @param arr - source typed array
144
+ * @returns DataView over the same buffer region.
145
+ * @example
146
+ * Create a DataView over an existing buffer.
147
+ * ```ts
148
+ * createView(new Uint8Array(4));
149
+ * ```
50
150
  */
51
- function toBytes(data) {
52
- if (typeof data === 'string')
53
- data = utf8ToBytes(data);
54
- if (!u8a(data))
55
- throw new Error(`expected Uint8Array, got ${typeof data}`);
56
- return data;
151
+ function createView(arr) {
152
+ return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
57
153
  }
58
- // For runtime check if class implements interface
59
- class Hash {
60
- // Safe version that clones internal state
61
- clone() {
62
- return this._cloneInto();
63
- }
154
+ /**
155
+ * Rotate-right operation for uint32 values.
156
+ * @param word - source word
157
+ * @param shift - shift amount in bits
158
+ * @returns Rotated word.
159
+ * @example
160
+ * Rotate a 32-bit word to the right.
161
+ * ```ts
162
+ * rotr(0x12345678, 8);
163
+ * ```
164
+ */
165
+ function rotr(word, shift) {
166
+ return (word << (32 - shift)) | (word >>> shift);
64
167
  }
65
- function wrapConstructor(hashCons) {
66
- const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
67
- const tmp = hashCons();
168
+ /**
169
+ * Merges default options and passed options.
170
+ * @param defaults - base option object
171
+ * @param opts - user overrides
172
+ * @param title - label included in thrown override errors
173
+ * @returns Fresh merged option object with a null prototype.
174
+ * @throws On wrong argument types. {@link TypeError}
175
+ * @example
176
+ * Merge user overrides onto default options.
177
+ * ```ts
178
+ * checkOpts({ dkLen: 32 }, { asyncTick: 10 });
179
+ * ```
180
+ */
181
+ function checkOpts(defaults, opts, title = 'opts') {
182
+ aopts(defaults, 'defaults');
183
+ if (opts !== undefined)
184
+ aopts(opts, title);
185
+ // Callers read optional fields directly, so omitted values must not fall through to ambient
186
+ // Object.prototype pollution (for example a forged `dkLen` changing SHAKE's default output).
187
+ const merged = Object.assign(Object.create(null), defaults, opts);
188
+ return merged;
189
+ }
190
+ /**
191
+ * Creates a callable hash function from a stateful class constructor.
192
+ * @param hashCons - hash constructor or factory
193
+ * @param info - optional metadata such as DER OID
194
+ * @returns Frozen callable hash wrapper with `.create()`.
195
+ * Wrapper construction eagerly calls `hashCons(undefined)` once to read
196
+ * `outputLen` / `blockLen`, so constructor side effects happen at module
197
+ * init time.
198
+ * @throws On wrong argument types. {@link TypeError}
199
+ * @example
200
+ * Wrap a stateful hash constructor into a callable helper.
201
+ * ```ts
202
+ * import { createHasher } from '@noble/hashes/utils.js';
203
+ * import { sha256 } from '@noble/hashes/sha2.js';
204
+ * const wrapped = createHasher(sha256.create, { oid: sha256.oid });
205
+ * wrapped(new Uint8Array([1]));
206
+ * ```
207
+ */
208
+ function createHasher(hashCons, info = {}) {
209
+ if (typeof hashCons !== 'function')
210
+ throw new TypeError('"hashCons" expected function, got type=' + typeof hashCons);
211
+ info = checkOpts({}, info, 'info');
212
+ const hashC = (msg, opts) => hashCons(opts)
213
+ .update(msg)
214
+ .digest();
215
+ const tmp = hashCons(undefined);
68
216
  hashC.outputLen = tmp.outputLen;
69
217
  hashC.blockLen = tmp.blockLen;
70
- hashC.create = () => hashCons();
71
- return hashC;
218
+ hashC.canXOF = tmp.canXOF;
219
+ hashC.create = (opts) => hashCons(opts);
220
+ Object.assign(hashC, info);
221
+ return Object.freeze(hashC);
72
222
  }
223
+ /**
224
+ * Creates OID metadata for NIST hashes with prefix `06 09 60 86 48 01 65 03 04 02`.
225
+ * @param suffix - final OID byte for the selected hash.
226
+ * The helper accepts any byte even though only the documented NIST hash
227
+ * suffixes are meaningful downstream.
228
+ * @returns Object containing the DER-encoded OID.
229
+ * @example
230
+ * Build OID metadata for a NIST hash.
231
+ * ```ts
232
+ * oidNist(0x01);
233
+ * ```
234
+ */
235
+ const oidNist = (suffix) => ({
236
+ // Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
237
+ // Larger suffix values would need base-128 OID encoding and a different length byte.
238
+ oid: Uint8Array.from([0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, suffix]),
239
+ });
73
240
 
74
- // Polyfill for Safari 14
75
- function setBigUint64(view, byteOffset, value, isLE) {
76
- if (typeof view.setBigUint64 === 'function')
77
- return view.setBigUint64(byteOffset, value, isLE);
78
- const _32n = BigInt(32);
79
- const _u32_max = BigInt(0xffffffff);
80
- const wh = Number((value >> _32n) & _u32_max);
81
- const wl = Number(value & _u32_max);
82
- const h = isLE ? 4 : 0;
83
- const l = isLE ? 0 : 4;
84
- view.setUint32(byteOffset + h, wh, isLE);
85
- view.setUint32(byteOffset + l, wl, isLE);
241
+ /**
242
+ * Internal Merkle-Damgard hash utils.
243
+ * @module
244
+ */
245
+ /**
246
+ * Shared 32-bit conditional boolean primitive reused by SHA-256, SHA-1, and MD5 `F`.
247
+ * Returns bits from `b` when `a` is set, otherwise from `c`.
248
+ * The XOR form is equivalent to MD5's `F(X,Y,Z) = XY v not(X)Z` because the masked terms never
249
+ * set the same bit.
250
+ * @param a - selector word
251
+ * @param b - word chosen when selector bit is set
252
+ * @param c - word chosen when selector bit is clear
253
+ * @returns Mixed 32-bit word.
254
+ * @example
255
+ * Combine three words with the shared 32-bit choice primitive.
256
+ * ```ts
257
+ * Chi(0xffffffff, 0x12345678, 0x87654321);
258
+ * ```
259
+ */
260
+ function Chi(a, b, c) {
261
+ return (a & b) ^ (~a & c);
262
+ }
263
+ /**
264
+ * Shared 32-bit majority primitive reused by SHA-256 and SHA-1.
265
+ * Returns bits shared by at least two inputs.
266
+ * @param a - first input word
267
+ * @param b - second input word
268
+ * @param c - third input word
269
+ * @returns Mixed 32-bit word.
270
+ * @example
271
+ * Combine three words with the shared 32-bit majority primitive.
272
+ * ```ts
273
+ * Maj(0xffffffff, 0x12345678, 0x87654321);
274
+ * ```
275
+ */
276
+ function Maj(a, b, c) {
277
+ return (a & b) ^ (a & c) ^ (b & c);
86
278
  }
87
- // Base SHA2 class (RFC 6234)
88
- class SHA2 extends Hash {
279
+ /**
280
+ * Merkle-Damgard hash construction base class.
281
+ * Could be used to create MD5, RIPEMD, SHA1, SHA2.
282
+ * Accepts only byte-aligned `Uint8Array` input, even when the underlying spec describes bit
283
+ * strings with partial-byte tails.
284
+ * @param blockLen - internal block size in bytes
285
+ * @param outputLen - digest size in bytes
286
+ * @param padOffset - trailing length field size in bytes
287
+ * @param isLE - whether length and state words are encoded in little-endian
288
+ * @example
289
+ * Use a concrete subclass to get the shared Merkle-Damgard update/digest flow.
290
+ * ```ts
291
+ * import { _SHA1 } from '@noble/hashes/legacy.js';
292
+ * const hash = new _SHA1();
293
+ * hash.update(new Uint8Array([97, 98, 99]));
294
+ * hash.digest();
295
+ * ```
296
+ */
297
+ class HashMD {
298
+ blockLen;
299
+ outputLen;
300
+ canXOF = false;
301
+ padOffset;
302
+ isLE;
303
+ // For partial updates less than block size
304
+ buffer;
305
+ view;
306
+ finished = false;
307
+ length = 0;
308
+ pos = 0;
309
+ destroyed = false;
89
310
  constructor(blockLen, outputLen, padOffset, isLE) {
90
- super();
91
311
  this.blockLen = blockLen;
92
312
  this.outputLen = outputLen;
93
313
  this.padOffset = padOffset;
94
314
  this.isLE = isLE;
95
- this.finished = false;
96
- this.length = 0;
97
- this.pos = 0;
98
- this.destroyed = false;
99
315
  this.buffer = new Uint8Array(blockLen);
100
316
  this.view = createView(this.buffer);
101
317
  }
102
318
  update(data) {
103
- exists(this);
319
+ aexists(this);
320
+ abytes(data);
104
321
  const { view, buffer, blockLen } = this;
105
- data = toBytes(data);
106
322
  const len = data.length;
323
+ let processed = false;
107
324
  for (let pos = 0; pos < len;) {
108
325
  const take = Math.min(blockLen - this.pos, len - pos);
109
- // Fast path: we have at least one block in input, cast it to view and process
326
+ // Fast path only when there is no buffered partial block: `take === blockLen` implies
327
+ // `this.pos === 0`, so we can process full blocks directly from the input view.
110
328
  if (take === blockLen) {
111
329
  const dataView = createView(data);
112
330
  for (; blockLen <= len - pos; pos += blockLen)
113
331
  this.process(dataView, pos);
332
+ processed = true;
114
333
  continue;
115
334
  }
116
- buffer.set(data.subarray(pos, pos + take), this.pos);
335
+ // When the whole input is buffered in one go (common for short messages), passing `data`
336
+ // directly avoids allocating a subarray view.
337
+ buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos);
117
338
  this.pos += take;
118
339
  pos += take;
119
340
  if (this.pos === blockLen) {
120
341
  this.process(view, 0);
121
342
  this.pos = 0;
343
+ processed = true;
122
344
  }
123
345
  }
124
346
  this.length += data.length;
125
- this.roundClean();
347
+ // Shared schedule buffers only pick up input-derived words inside process(); if everything
348
+ // was buffered without processing, there is nothing to zero.
349
+ if (processed)
350
+ this.roundClean();
126
351
  return this;
127
352
  }
128
353
  digestInto(out) {
129
- exists(this);
130
- output(out, this);
354
+ aexists(this);
355
+ aoutput(out, this);
131
356
  this.finished = true;
132
357
  // Padding
133
358
  // We can avoid allocation of buffer for padding completely if it
134
359
  // was previously not allocated here. But it won't change performance.
135
360
  const { buffer, view, blockLen, isLE } = this;
136
361
  let { pos } = this;
137
- // append the bit '1' to the message
362
+ // append the bit '1' to the message, then zero-pad the rest of the block
138
363
  buffer[pos++] = 0b10000000;
139
- this.buffer.subarray(pos).fill(0);
140
- // we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
364
+ buffer.fill(0, pos);
365
+ // we have less than padOffset left in buffer, so we cannot put length in
366
+ // current block, need process it and pad again
141
367
  if (this.padOffset > blockLen - pos) {
142
368
  this.process(view, 0);
143
- pos = 0;
369
+ buffer.fill(0);
144
370
  }
145
- // Pad until full block byte with zeros
146
- for (let i = pos; i < blockLen; i++)
147
- buffer[i] = 0;
148
- // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
149
- // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
150
- // So we just write lowest 64 bits of that value.
151
- setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
371
+ // `padOffset` reserves the whole length field. For SHA-384/512 the high 64 bits stay zero from
372
+ // the padding fill above, and JS will overflow before user input can make that half non-zero.
373
+ // So we only need to write the low 64 bits here (`length * 8` only scales the exponent of an
374
+ // integer below 2**53, so the split inside the helper stays exact).
375
+ setU64FromNum(view, blockLen - 8, this.length * 8, isLE);
152
376
  this.process(view, 0);
153
- const oview = createView(out);
377
+ // The final block above is processed outside update(), so the shared message-schedule
378
+ // buffers (e.g. SHA256_W) would otherwise retain input-derived words after digest().
379
+ this.roundClean();
380
+ // digest() passes our own `buffer` as `out`; reuse its cached view instead of allocating one.
381
+ const oview = out === buffer ? view : createView(out);
154
382
  const len = this.outputLen;
155
- // NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
156
- if (len % 4)
157
- throw new Error('_sha2: outputLen should be aligned to 32bit');
383
+ // NOTE: we do division by 4 later, which must be fused in single op with modulo by JIT
158
384
  const outLen = len / 4;
159
385
  const state = this.get();
160
- if (outLen > state.length)
161
- throw new Error('_sha2: outputLen bigger than state');
386
+ // Subclass-misconfiguration invariant: outputLen must be 32-bit aligned and fit the state.
387
+ if (len % 4 || outLen > state.length)
388
+ throw new Error('invalid outputLen');
162
389
  for (let i = 0; i < outLen; i++)
163
390
  oview.setUint32(4 * i, state[i], isLE);
164
391
  }
165
392
  digest() {
166
393
  const { buffer, outputLen } = this;
167
394
  this.digestInto(buffer);
395
+ // Copy before destroy(): subclasses wipe `buffer` during cleanup, but `digest()` must return
396
+ // fresh bytes to the caller.
168
397
  const res = buffer.slice(0, outputLen);
169
398
  this.destroy();
170
399
  return res;
171
400
  }
172
- _cloneInto(to) {
173
- to || (to = new this.constructor());
174
- to.set(...this.get());
175
- const { blockLen, buffer, length, finished, destroyed, pos } = this;
401
+ _cloneIntoMeta(to) {
402
+ const { buffer, length, finished, destroyed, pos } = this;
403
+ to.destroyed = destroyed;
404
+ to.finished = finished;
176
405
  to.length = length;
177
406
  to.pos = pos;
178
- to.finished = finished;
179
- to.destroyed = destroyed;
180
- if (length % blockLen)
181
- to.buffer.set(buffer);
407
+ // Only partial-block bytes need copying: when `length % blockLen === 0`, `pos === 0` and
408
+ // later `update()` / `digestInto()` overwrite `to.buffer` from the start before reading it.
409
+ if (pos)
410
+ to.buffer.set(buffer); // Avoid a hot modulo guard.
182
411
  return to;
183
412
  }
413
+ clone() {
414
+ return this._cloneInto();
415
+ }
184
416
  }
417
+ /**
418
+ * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.
419
+ * Check out `test/misc/sha2-gen-iv.js` for recomputation guide.
420
+ */
421
+ /** Initial SHA256 state from RFC 6234 §6.1: the first 32 bits of the fractional parts of the
422
+ * square roots of the first eight prime numbers. Exported as a shared table; callers must treat
423
+ * it as read-only because constructors copy words from it by index. */
424
+ const SHA256_IV = /* @__PURE__ */ Uint32Array.from([
425
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
426
+ ]);
185
427
 
186
- // SHA2-256 need to try 2^128 hashes to execute birthday attack.
187
- // BTC network is doing 2^67 hashes/sec as per early 2023.
188
- // Choice: a ? b : c
189
- const Chi = (a, b, c) => (a & b) ^ (~a & c);
190
- // Majority function, true if any two inpust is true
191
- const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
192
- // Round constants:
193
- // first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
428
+ /**
429
+ * SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.
430
+ * SHA256 is the fastest hash implementable in JS, even faster than Blake3.
431
+ * Check out {@link https://www.rfc-editor.org/rfc/rfc4634 | RFC 4634} and
432
+ * {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf | FIPS 180-4}.
433
+ * @module
434
+ */
435
+ /**
436
+ * SHA-224 / SHA-256 round constants from RFC 6234 §5.1: the first 32 bits
437
+ * of the cube roots of the first 64 primes (2..311).
438
+ */
194
439
  // prettier-ignore
195
- const SHA256_K = /* @__PURE__ */ new Uint32Array([
440
+ const SHA256_K = /* @__PURE__ */ Uint32Array.from([
196
441
  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
197
442
  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
198
443
  0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
@@ -202,19 +447,24 @@ const SHA256_K = /* @__PURE__ */ new Uint32Array([
202
447
  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
203
448
  0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
204
449
  ]);
205
- // Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
206
- // prettier-ignore
207
- const IV = /* @__PURE__ */ new Uint32Array([
208
- 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
209
- ]);
210
- // Temporary buffer, not used to store anything between runs
211
- // Named this way because it matches specification.
450
+ /** Reusable SHA-224 / SHA-256 message schedule buffer `W_t` from RFC 6234 §6.2 step 1. */
212
451
  const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
213
- class SHA256 extends SHA2 {
214
- constructor() {
215
- super(64, 32, 8, false);
216
- // We cannot use array here since array allows indexing by variable
217
- // which means optimizer/compiler cannot use registers.
452
+ /** Internal SHA-224 / SHA-256 compression engine from RFC 6234 §6.2. */
453
+ class SHA2_32B extends HashMD {
454
+ // We cannot use array here since array allows indexing by variable
455
+ // which means optimizer/compiler cannot use registers.
456
+ // Numeric initializers matter: starting the fields as `undefined` changes
457
+ // V8's field representation and makes sha256 3x slower (measured).
458
+ A = 0;
459
+ B = 0;
460
+ C = 0;
461
+ D = 0;
462
+ E = 0;
463
+ F = 0;
464
+ G = 0;
465
+ H = 0;
466
+ constructor(outputLen, IV) {
467
+ super(64, outputLen, 8, false);
218
468
  this.A = IV[0] | 0;
219
469
  this.B = IV[1] | 0;
220
470
  this.C = IV[2] | 0;
@@ -239,6 +489,10 @@ class SHA256 extends SHA2 {
239
489
  this.G = G | 0;
240
490
  this.H = H | 0;
241
491
  }
492
+ _cloneInto(to) {
493
+ (to ||= new this.constructor()).set(...this.get());
494
+ return this._cloneIntoMeta(to);
495
+ }
242
496
  process(view, offset) {
243
497
  // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
244
498
  for (let i = 0; i < 16; i++, offset += 4)
@@ -278,18 +532,40 @@ class SHA256 extends SHA2 {
278
532
  this.set(A, B, C, D, E, F, G, H);
279
533
  }
280
534
  roundClean() {
281
- SHA256_W.fill(0);
535
+ clean(SHA256_W);
282
536
  }
283
537
  destroy() {
538
+ // HashMD callers route post-destroy usability through `destroyed`; zeroizing alone still leaves
539
+ // update()/digest() callable on reused instances.
540
+ this.destroyed = true;
284
541
  this.set(0, 0, 0, 0, 0, 0, 0, 0);
285
- this.buffer.fill(0);
542
+ clean(this.buffer);
543
+ }
544
+ }
545
+ /** Internal SHA-256 hash class grounded in RFC 6234 §6.2. */
546
+ class _SHA256 extends SHA2_32B {
547
+ constructor() {
548
+ super(32, SHA256_IV);
286
549
  }
287
550
  }
288
551
  /**
289
- * SHA2-256 hash function
290
- * @param message - data that would be hashed
552
+ * SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info:
553
+ *
554
+ * - Trying 2^128 hashes would get 50% chance of collision, using birthday attack.
555
+ * - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.
556
+ * - Each sha256 hash is executing 2^18 bit operations.
557
+ * - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule.
558
+ * @param msg - message bytes to hash
559
+ * @param opts - Reserved hash options.
560
+ * @returns Digest bytes.
561
+ * @example
562
+ * Hash a message with SHA2-256.
563
+ * ```ts
564
+ * sha256(new Uint8Array([97, 98, 99]));
565
+ * ```
291
566
  */
292
- const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
567
+ const sha256 = /* @__PURE__ */ createHasher(() => new _SHA256(),
568
+ /* @__PURE__ */ oidNist(0x01));
293
569
 
294
570
  const encoder = new TextEncoder();
295
571
  const INTEGER_ARRAYS = new Set([