leviathan-crypto 2.1.0 → 3.0.0
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.
- package/CLAUDE.md +86 -443
- package/README.md +198 -65
- package/dist/aes/aes-cbc.d.ts +40 -0
- package/dist/aes/aes-cbc.js +158 -0
- package/dist/aes/aes-ctr.d.ts +50 -0
- package/dist/aes/aes-ctr.js +141 -0
- package/dist/aes/aes-gcm-siv.d.ts +67 -0
- package/dist/aes/aes-gcm-siv.js +217 -0
- package/dist/aes/aes-gcm.d.ts +61 -0
- package/dist/aes/aes-gcm.js +226 -0
- package/dist/aes/cipher-suite.d.ts +21 -0
- package/dist/aes/cipher-suite.js +179 -0
- package/dist/aes/embedded.d.ts +1 -0
- package/dist/aes/embedded.js +26 -0
- package/dist/aes/generator.d.ts +14 -0
- package/dist/aes/generator.js +103 -0
- package/dist/aes/index.d.ts +58 -0
- package/dist/aes/index.js +125 -0
- package/dist/aes/ops.d.ts +60 -0
- package/dist/aes/ops.js +164 -0
- package/dist/aes/pool-worker.d.ts +1 -0
- package/dist/aes/pool-worker.js +92 -0
- package/dist/aes/types.d.ts +1 -0
- package/dist/aes/types.js +23 -0
- package/dist/aes.wasm +0 -0
- package/dist/blake3/embedded.d.ts +1 -0
- package/dist/blake3/embedded.js +26 -0
- package/dist/blake3/index.d.ts +143 -0
- package/dist/blake3/index.js +620 -0
- package/dist/blake3/types.d.ts +102 -0
- package/dist/blake3/types.js +31 -0
- package/dist/blake3/validate.d.ts +29 -0
- package/dist/blake3/validate.js +80 -0
- package/dist/blake3.wasm +0 -0
- package/dist/chacha20/cipher-suite.js +47 -25
- package/dist/chacha20/generator.d.ts +2 -2
- package/dist/chacha20/generator.js +4 -4
- package/dist/chacha20/index.d.ts +16 -15
- package/dist/chacha20/index.js +52 -46
- package/dist/chacha20/ops.d.ts +7 -7
- package/dist/chacha20/ops.js +34 -34
- package/dist/chacha20/pool-worker.js +5 -3
- package/dist/cte-wasm.d.ts +1 -0
- package/dist/cte-wasm.js +3 -0
- package/dist/curve25519.wasm +0 -0
- package/dist/ecdsa/der.d.ts +23 -0
- package/dist/ecdsa/der.js +192 -0
- package/dist/ecdsa/ecprivatekey-der.d.ts +32 -0
- package/dist/ecdsa/ecprivatekey-der.js +230 -0
- package/dist/ecdsa/embedded.d.ts +1 -0
- package/dist/ecdsa/embedded.js +25 -0
- package/dist/ecdsa/index.d.ts +124 -0
- package/dist/ecdsa/index.js +366 -0
- package/dist/ecdsa/types.d.ts +31 -0
- package/dist/ecdsa/types.js +28 -0
- package/dist/ecdsa/validate.d.ts +18 -0
- package/dist/ecdsa/validate.js +92 -0
- package/dist/ed25519/embedded.d.ts +1 -0
- package/dist/ed25519/embedded.js +31 -0
- package/dist/ed25519/index.d.ts +70 -0
- package/dist/ed25519/index.js +308 -0
- package/dist/ed25519/types.d.ts +27 -0
- package/dist/ed25519/types.js +27 -0
- package/dist/ed25519/validate.d.ts +7 -0
- package/dist/ed25519/validate.js +77 -0
- package/dist/embedded/aes-pool-worker.d.ts +1 -0
- package/dist/embedded/aes-pool-worker.js +5 -0
- package/dist/embedded/aes.d.ts +1 -0
- package/dist/embedded/aes.js +3 -0
- package/dist/embedded/blake3.d.ts +1 -0
- package/dist/embedded/blake3.js +3 -0
- package/dist/embedded/chacha20-pool-worker.d.ts +1 -1
- package/dist/embedded/chacha20-pool-worker.js +2 -2
- package/dist/embedded/chacha20.d.ts +1 -1
- package/dist/embedded/chacha20.js +2 -2
- package/dist/embedded/curve25519.d.ts +1 -0
- package/dist/embedded/curve25519.js +3 -0
- package/dist/embedded/mldsa.d.ts +1 -0
- package/dist/embedded/mldsa.js +3 -0
- package/dist/embedded/mlkem.d.ts +1 -0
- package/dist/embedded/mlkem.js +3 -0
- package/dist/embedded/p256.d.ts +1 -0
- package/dist/embedded/p256.js +3 -0
- package/dist/embedded/serpent-pool-worker.d.ts +1 -1
- package/dist/embedded/serpent-pool-worker.js +2 -2
- package/dist/embedded/serpent.d.ts +1 -1
- package/dist/embedded/serpent.js +2 -2
- package/dist/embedded/sha2.d.ts +1 -1
- package/dist/embedded/sha2.js +2 -2
- package/dist/embedded/sha3.d.ts +1 -1
- package/dist/embedded/sha3.js +2 -2
- package/dist/embedded/slhdsa.d.ts +1 -0
- package/dist/embedded/slhdsa.js +3 -0
- package/dist/errors.d.ts +92 -1
- package/dist/errors.js +111 -1
- package/dist/fortuna.d.ts +5 -5
- package/dist/fortuna.js +37 -64
- package/dist/index.d.ts +38 -9
- package/dist/index.js +63 -19
- package/dist/init.d.ts +1 -1
- package/dist/init.js +11 -25
- package/dist/keccak/embedded.js +1 -1
- package/dist/keccak/index.d.ts +2 -0
- package/dist/keccak/index.js +4 -2
- package/dist/loader.d.ts +1 -24
- package/dist/loader.js +13 -16
- package/dist/merkle/blake3-tree.d.ts +35 -0
- package/dist/merkle/blake3-tree.js +187 -0
- package/dist/merkle/checkpoint.d.ts +58 -0
- package/dist/merkle/checkpoint.js +217 -0
- package/dist/merkle/index.d.ts +19 -0
- package/dist/merkle/index.js +37 -0
- package/dist/merkle/merkle-log.d.ts +130 -0
- package/dist/merkle/merkle-log.js +207 -0
- package/dist/merkle/merkle-verifier.d.ts +126 -0
- package/dist/merkle/merkle-verifier.js +296 -0
- package/dist/merkle/proof.d.ts +70 -0
- package/dist/merkle/proof.js +300 -0
- package/dist/merkle/sha256-tree.d.ts +33 -0
- package/dist/merkle/sha256-tree.js +145 -0
- package/dist/merkle/signed-log.d.ts +156 -0
- package/dist/merkle/signed-log.js +356 -0
- package/dist/merkle/signed-note.d.ts +309 -0
- package/dist/merkle/signed-note.js +648 -0
- package/dist/merkle/sth.d.ts +31 -0
- package/dist/merkle/sth.js +31 -0
- package/dist/merkle/storage.d.ts +40 -0
- package/dist/merkle/storage.js +71 -0
- package/dist/merkle/tree.d.ts +68 -0
- package/dist/merkle/tree.js +94 -0
- package/dist/mldsa/embedded.d.ts +1 -0
- package/dist/{kyber → mldsa}/embedded.js +5 -5
- package/dist/mldsa/expand.d.ts +53 -0
- package/dist/mldsa/expand.js +188 -0
- package/dist/mldsa/format.d.ts +16 -0
- package/dist/mldsa/format.js +68 -0
- package/dist/mldsa/hashvariant.d.ts +32 -0
- package/dist/mldsa/hashvariant.js +248 -0
- package/dist/mldsa/index.d.ts +142 -0
- package/dist/mldsa/index.js +463 -0
- package/dist/mldsa/keygen.d.ts +16 -0
- package/dist/mldsa/keygen.js +232 -0
- package/dist/mldsa/params.d.ts +21 -0
- package/dist/mldsa/params.js +55 -0
- package/dist/mldsa/sha3-helpers.d.ts +30 -0
- package/dist/mldsa/sha3-helpers.js +124 -0
- package/dist/mldsa/sign.d.ts +36 -0
- package/dist/mldsa/sign.js +380 -0
- package/dist/mldsa/types.d.ts +91 -0
- package/dist/mldsa/types.js +25 -0
- package/dist/mldsa/validate.d.ts +55 -0
- package/dist/mldsa/validate.js +125 -0
- package/dist/mldsa/verify.d.ts +29 -0
- package/dist/mldsa/verify.js +269 -0
- package/dist/mldsa.wasm +0 -0
- package/dist/mlkem/embedded.d.ts +1 -0
- package/dist/mlkem/embedded.js +27 -0
- package/dist/mlkem/indcpa.d.ts +49 -0
- package/dist/{kyber → mlkem}/indcpa.js +44 -44
- package/dist/mlkem/index.d.ts +37 -0
- package/dist/{kyber → mlkem}/index.js +24 -34
- package/dist/mlkem/kem.d.ts +21 -0
- package/dist/{kyber → mlkem}/kem.js +44 -64
- package/dist/{kyber → mlkem}/params.d.ts +4 -4
- package/dist/{kyber → mlkem}/params.js +2 -2
- package/dist/mlkem/suite.d.ts +12 -0
- package/dist/{kyber → mlkem}/suite.js +17 -12
- package/dist/{kyber → mlkem}/types.d.ts +3 -3
- package/dist/{kyber → mlkem}/types.js +1 -1
- package/dist/{kyber → mlkem}/validate.d.ts +7 -7
- package/dist/{kyber → mlkem}/validate.js +7 -7
- package/dist/{kyber.wasm → mlkem.wasm} +0 -0
- package/dist/p256.wasm +0 -0
- package/dist/ratchet/index.d.ts +2 -0
- package/dist/ratchet/index.js +1 -0
- package/dist/ratchet/kdf-chain.js +3 -3
- package/dist/ratchet/ratchet-keypair.js +2 -2
- package/dist/ratchet/root-kdf.js +7 -7
- package/dist/ratchet/skipped-key-store.js +4 -4
- package/dist/ratchet/types.d.ts +1 -1
- package/dist/serpent/cipher-suite.js +20 -17
- package/dist/serpent/generator.d.ts +1 -1
- package/dist/serpent/generator.js +2 -2
- package/dist/serpent/index.d.ts +8 -7
- package/dist/serpent/index.js +18 -27
- package/dist/serpent/pool-worker.js +7 -5
- package/dist/serpent/serpent-cbc.d.ts +4 -4
- package/dist/serpent/serpent-cbc.js +11 -8
- package/dist/serpent/shared-ops.d.ts +3 -23
- package/dist/serpent/shared-ops.js +50 -85
- package/dist/serpent.wasm +0 -0
- package/dist/sha2/hkdf.js +5 -5
- package/dist/sha2/index.d.ts +21 -1
- package/dist/sha2/index.js +65 -10
- package/dist/sha2/types.d.ts +41 -2
- package/dist/sha2.wasm +0 -0
- package/dist/sha3/index.d.ts +72 -3
- package/dist/sha3/index.js +240 -14
- package/dist/sha3/kmac.d.ts +121 -0
- package/dist/sha3/kmac.js +800 -0
- package/dist/sha3.wasm +0 -0
- package/dist/shared/pkcs7.d.ts +22 -0
- package/dist/shared/pkcs7.js +84 -0
- package/dist/sign/ctx.d.ts +41 -0
- package/dist/sign/ctx.js +102 -0
- package/dist/sign/envelope.d.ts +45 -0
- package/dist/sign/envelope.js +152 -0
- package/dist/sign/hasher.d.ts +9 -0
- package/dist/sign/hasher.js +132 -0
- package/dist/sign/index.d.ts +11 -0
- package/dist/sign/index.js +34 -0
- package/dist/sign/sign-stream.d.ts +25 -0
- package/dist/sign/sign-stream.js +112 -0
- package/dist/sign/suites/ecdsa-p256.d.ts +2 -0
- package/dist/sign/suites/ecdsa-p256.js +120 -0
- package/dist/sign/suites/ed25519.d.ts +3 -0
- package/dist/sign/suites/ed25519.js +165 -0
- package/dist/sign/suites/hybrid-classical.d.ts +23 -0
- package/dist/sign/suites/hybrid-classical.js +526 -0
- package/dist/sign/suites/hybrid-pq.d.ts +4 -0
- package/dist/sign/suites/hybrid-pq.js +234 -0
- package/dist/sign/suites/mldsa.d.ts +7 -0
- package/dist/sign/suites/mldsa.js +161 -0
- package/dist/sign/suites/slhdsa.d.ts +7 -0
- package/dist/sign/suites/slhdsa.js +176 -0
- package/dist/sign/types.d.ts +106 -0
- package/dist/sign/types.js +28 -0
- package/dist/sign/verify-stream.d.ts +30 -0
- package/dist/sign/verify-stream.js +227 -0
- package/dist/slhdsa/embedded.d.ts +1 -0
- package/dist/slhdsa/embedded.js +26 -0
- package/dist/slhdsa/index.d.ts +149 -0
- package/dist/slhdsa/index.js +493 -0
- package/dist/slhdsa/params.d.ts +26 -0
- package/dist/slhdsa/params.js +70 -0
- package/dist/slhdsa/prehash.d.ts +68 -0
- package/dist/slhdsa/prehash.js +307 -0
- package/dist/slhdsa/sign.d.ts +39 -0
- package/dist/slhdsa/sign.js +116 -0
- package/dist/slhdsa/types.d.ts +129 -0
- package/dist/slhdsa/types.js +27 -0
- package/dist/slhdsa/validate.d.ts +60 -0
- package/dist/slhdsa/validate.js +127 -0
- package/dist/slhdsa/verify.d.ts +32 -0
- package/dist/slhdsa/verify.js +107 -0
- package/dist/slhdsa.wasm +0 -0
- package/dist/stream/header.js +3 -3
- package/dist/stream/index.d.ts +1 -0
- package/dist/stream/index.js +1 -0
- package/dist/stream/open-stream.js +31 -10
- package/dist/stream/seal-stream-pool.d.ts +1 -0
- package/dist/stream/seal-stream-pool.js +63 -26
- package/dist/stream/seal-stream.d.ts +1 -1
- package/dist/stream/seal-stream.js +20 -9
- package/dist/stream/seal.js +6 -6
- package/dist/stream/types.d.ts +3 -1
- package/dist/stream/types.js +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utils.d.ts +3 -3
- package/dist/utils.js +46 -54
- package/dist/wasm-source.d.ts +7 -7
- package/dist/wasm-source.js +1 -1
- package/dist/x25519/embedded.d.ts +1 -0
- package/dist/x25519/embedded.js +31 -0
- package/dist/x25519/index.d.ts +43 -0
- package/dist/x25519/index.js +159 -0
- package/dist/x25519/types.d.ts +25 -0
- package/dist/x25519/types.js +27 -0
- package/dist/x25519/validate.d.ts +2 -0
- package/dist/x25519/validate.js +39 -0
- package/package.json +70 -26
- package/SECURITY.md +0 -163
- package/dist/ct-wasm.d.ts +0 -1
- package/dist/ct-wasm.js +0 -3
- package/dist/docs/aead.md +0 -363
- package/dist/docs/architecture.md +0 -1011
- package/dist/docs/argon2id.md +0 -305
- package/dist/docs/chacha20.md +0 -781
- package/dist/docs/exports.md +0 -277
- package/dist/docs/fortuna.md +0 -530
- package/dist/docs/init.md +0 -301
- package/dist/docs/loader.md +0 -256
- package/dist/docs/serpent.md +0 -617
- package/dist/docs/sha2.md +0 -671
- package/dist/docs/sha3.md +0 -612
- package/dist/docs/types.md +0 -416
- package/dist/docs/utils.md +0 -457
- package/dist/embedded/kyber.d.ts +0 -1
- package/dist/embedded/kyber.js +0 -3
- package/dist/kyber/embedded.d.ts +0 -1
- package/dist/kyber/indcpa.d.ts +0 -49
- package/dist/kyber/index.d.ts +0 -38
- package/dist/kyber/kem.d.ts +0 -21
- package/dist/kyber/suite.d.ts +0 -12
- /package/dist/{ct.wasm → cte.wasm} +0 -0
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
// ▄▄▄▄▄▄▄▄▄▄
|
|
2
|
+
// ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
|
|
3
|
+
// ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
|
|
4
|
+
// ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
|
|
5
|
+
// ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
|
|
6
|
+
// ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
|
|
7
|
+
// ███████▌ ▀██▀ ███
|
|
8
|
+
// ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
|
|
9
|
+
// ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
|
|
10
|
+
// ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
|
|
11
|
+
// ▀████▄ ▄██▄
|
|
12
|
+
// ▐████ ▐███ Author: xero (https://x-e.ro)
|
|
13
|
+
// ▄▄██████████ ▐███ ▄▄ License: MIT
|
|
14
|
+
// ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
|
|
15
|
+
// ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
|
|
16
|
+
// ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
|
|
17
|
+
// ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
|
|
18
|
+
// █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
|
|
19
|
+
// ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
|
|
20
|
+
// ▀█████▀▀
|
|
21
|
+
//
|
|
22
|
+
// src/ts/blake3/index.ts
|
|
23
|
+
//
|
|
24
|
+
// BLAKE3 public API. One-shot and streaming flavours of hash, keyed_hash,
|
|
25
|
+
// derive_key (BLAKE3 §2.3 Modes), and the XOF reader (§2.6). Call
|
|
26
|
+
// `blake3Init(source)` before constructing any class.
|
|
27
|
+
import { getInstance, initModule, isInitialized, _acquireModule, _releaseModule, _assertNotOwned, } from '../init.js';
|
|
28
|
+
import { validateKey, validateContext, validateOutputLen } from './validate.js';
|
|
29
|
+
export { isInitialized };
|
|
30
|
+
export async function blake3Init(source) {
|
|
31
|
+
return initModule('blake3', source);
|
|
32
|
+
}
|
|
33
|
+
function getExports() {
|
|
34
|
+
return getInstance('blake3').exports;
|
|
35
|
+
}
|
|
36
|
+
// Input scratch sits past BUFFER_END from src/asm/blake3/buffers.ts;
|
|
37
|
+
// usable region is 131072 - INPUT_SCRATCH_OFF bytes.
|
|
38
|
+
const INPUT_SCRATCH_OFF = 27648;
|
|
39
|
+
const INPUT_SCRATCH_MAX = 131072 - INPUT_SCRATCH_OFF;
|
|
40
|
+
// One-shot output staging cap; larger XOF reads go through OutputReader.
|
|
41
|
+
const OUTPUT_STAGING_SIZE = 1024;
|
|
42
|
+
// BLAKE3 §2.6: root compress emits 64 bytes per squeeze.
|
|
43
|
+
const ROOT_BLOCK_SIZE = 64;
|
|
44
|
+
function tooBigForScratchError(len) {
|
|
45
|
+
return new RangeError(`leviathan-crypto: blake3 input length ${len} exceeds the per-call `
|
|
46
|
+
+ `WASM input scratch (${INPUT_SCRATCH_MAX} bytes). Split the input or `
|
|
47
|
+
+ 'use the streaming surface (BLAKE3Stream / BLAKE3KeyedHashStream / '
|
|
48
|
+
+ 'BLAKE3DeriveKeyStream).');
|
|
49
|
+
}
|
|
50
|
+
function tooBigForOneShotError(len) {
|
|
51
|
+
return new RangeError(`leviathan-crypto: blake3 outLen ${len} exceeds the per-call output `
|
|
52
|
+
+ `staging size (${OUTPUT_STAGING_SIZE} bytes). For larger XOF reads `
|
|
53
|
+
+ 'use finalizeXof() and BLAKE3OutputReader.read(n).');
|
|
54
|
+
}
|
|
55
|
+
// Stage `input` into INPUT_SCRATCH_OFF and return (offset, length) for
|
|
56
|
+
// the WASM hash() call. Caller is responsible for wiping the scratch
|
|
57
|
+
// region after the WASM call returns (we do that in a finally in each
|
|
58
|
+
// public method so secret-derived inputs do not linger).
|
|
59
|
+
function stageInput(x, input) {
|
|
60
|
+
if (input.length > INPUT_SCRATCH_MAX)
|
|
61
|
+
throw tooBigForScratchError(input.length);
|
|
62
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
63
|
+
mem.set(input, INPUT_SCRATCH_OFF);
|
|
64
|
+
}
|
|
65
|
+
function wipeInput(x, len) {
|
|
66
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
67
|
+
mem.fill(0, INPUT_SCRATCH_OFF, INPUT_SCRATCH_OFF + len);
|
|
68
|
+
}
|
|
69
|
+
// One-shot hash entry, no key / no context. Writes the requested prefix
|
|
70
|
+
// of the BLAKE3 hash output to a fresh Uint8Array and returns it. Wipes
|
|
71
|
+
// the input scratch on the way out.
|
|
72
|
+
function oneShotHash(x, input, outLen) {
|
|
73
|
+
const outOff = x.getOutputStagingOffset();
|
|
74
|
+
stageInput(x, input);
|
|
75
|
+
try {
|
|
76
|
+
x.hash(INPUT_SCRATCH_OFF, input.length, outOff, outLen);
|
|
77
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
78
|
+
return mem.slice(outOff, outOff + outLen);
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
wipeInput(x, input.length);
|
|
82
|
+
x.wipeBuffers();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function oneShotKeyedHash(x, key, input, outLen) {
|
|
86
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
87
|
+
const keyOff = x.getKeyedKeyOffset();
|
|
88
|
+
const outOff = x.getOutputStagingOffset();
|
|
89
|
+
mem.set(key, keyOff);
|
|
90
|
+
stageInput(x, input);
|
|
91
|
+
try {
|
|
92
|
+
x.hashKeyed(keyOff, INPUT_SCRATCH_OFF, input.length, outOff, outLen);
|
|
93
|
+
return mem.slice(outOff, outOff + outLen);
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
mem.fill(0, keyOff, keyOff + 32);
|
|
97
|
+
wipeInput(x, input.length);
|
|
98
|
+
x.wipeBuffers();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function oneShotDeriveKey(x, contextBytes, material, outLen) {
|
|
102
|
+
if (contextBytes.length + material.length > INPUT_SCRATCH_MAX)
|
|
103
|
+
throw tooBigForScratchError(contextBytes.length + material.length);
|
|
104
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
105
|
+
const ctxOff = INPUT_SCRATCH_OFF;
|
|
106
|
+
const matOff = INPUT_SCRATCH_OFF + contextBytes.length;
|
|
107
|
+
const outOff = x.getOutputStagingOffset();
|
|
108
|
+
mem.set(contextBytes, ctxOff);
|
|
109
|
+
mem.set(material, matOff);
|
|
110
|
+
try {
|
|
111
|
+
x.deriveKey(ctxOff, contextBytes.length, matOff, material.length, outOff, outLen);
|
|
112
|
+
return mem.slice(outOff, outOff + outLen);
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
mem.fill(0, ctxOff, matOff + material.length);
|
|
116
|
+
x.wipeBuffers();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// ── BLAKE3 ──────────────────────────────────────────────────────────────────
|
|
120
|
+
/**
|
|
121
|
+
* BLAKE3 default-mode hash (BLAKE3 §2.3 Modes — `hash`).
|
|
122
|
+
*
|
|
123
|
+
* One-shot: `hash(msg, outLen?)` runs the full chunk / tree / root
|
|
124
|
+
* pipeline and returns `outLen` (default 32) bytes of XOF output.
|
|
125
|
+
* Module exclusivity is acquired and released per call.
|
|
126
|
+
*/
|
|
127
|
+
export class BLAKE3 {
|
|
128
|
+
x;
|
|
129
|
+
constructor() {
|
|
130
|
+
this.x = getExports();
|
|
131
|
+
}
|
|
132
|
+
hash(msg, outLen = 32) {
|
|
133
|
+
_assertNotOwned('blake3');
|
|
134
|
+
if (!(msg instanceof Uint8Array))
|
|
135
|
+
throw new TypeError('leviathan-crypto: blake3 message must be a Uint8Array');
|
|
136
|
+
validateOutputLen(outLen);
|
|
137
|
+
if (outLen > OUTPUT_STAGING_SIZE)
|
|
138
|
+
throw tooBigForOneShotError(outLen);
|
|
139
|
+
return oneShotHash(this.x, msg, outLen);
|
|
140
|
+
}
|
|
141
|
+
dispose() {
|
|
142
|
+
_assertNotOwned('blake3');
|
|
143
|
+
try {
|
|
144
|
+
this.x.wipeBuffers();
|
|
145
|
+
}
|
|
146
|
+
catch { /* idempotent */ }
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* BLAKE3 keyed_hash (BLAKE3 §2.3 Modes — `keyed_hash`).
|
|
151
|
+
*
|
|
152
|
+
* The 32-byte key seeds the chunk machine in place of the BLAKE3 IV and
|
|
153
|
+
* every compress carries the KEYED_HASH flag. Use cases include MACs and
|
|
154
|
+
* keyed-pseudorandom generation; the construction is a PRF when the key
|
|
155
|
+
* is uniform and secret.
|
|
156
|
+
*/
|
|
157
|
+
export class BLAKE3KeyedHash {
|
|
158
|
+
x;
|
|
159
|
+
constructor() {
|
|
160
|
+
this.x = getExports();
|
|
161
|
+
}
|
|
162
|
+
hash(key, msg, outLen = 32) {
|
|
163
|
+
_assertNotOwned('blake3');
|
|
164
|
+
validateKey(key);
|
|
165
|
+
if (!(msg instanceof Uint8Array))
|
|
166
|
+
throw new TypeError('leviathan-crypto: blake3 message must be a Uint8Array');
|
|
167
|
+
validateOutputLen(outLen);
|
|
168
|
+
if (outLen > OUTPUT_STAGING_SIZE)
|
|
169
|
+
throw tooBigForOneShotError(outLen);
|
|
170
|
+
return oneShotKeyedHash(this.x, key, msg, outLen);
|
|
171
|
+
}
|
|
172
|
+
dispose() {
|
|
173
|
+
_assertNotOwned('blake3');
|
|
174
|
+
try {
|
|
175
|
+
this.x.wipeBuffers();
|
|
176
|
+
}
|
|
177
|
+
catch { /* idempotent */ }
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* BLAKE3 derive_key (BLAKE3 §2.3 Modes — `derive_key`).
|
|
182
|
+
*
|
|
183
|
+
* Two-pass KDF: pass 1 hashes the context string with the
|
|
184
|
+
* DERIVE_KEY_CONTEXT flag, pass 2 hashes the key material with the
|
|
185
|
+
* DERIVE_KEY_MATERIAL flag using the pass-1 output as its starting CV.
|
|
186
|
+
* Context strings are conventionally hardcoded UTF-8 application
|
|
187
|
+
* constants; empty contexts are rejected by `validateContext`.
|
|
188
|
+
*/
|
|
189
|
+
export class BLAKE3DeriveKey {
|
|
190
|
+
x;
|
|
191
|
+
constructor() {
|
|
192
|
+
this.x = getExports();
|
|
193
|
+
}
|
|
194
|
+
derive(context, material, outLen = 32) {
|
|
195
|
+
_assertNotOwned('blake3');
|
|
196
|
+
const ctxBytes = validateContext(context);
|
|
197
|
+
if (!(material instanceof Uint8Array))
|
|
198
|
+
throw new TypeError('leviathan-crypto: blake3 derive_key material must be a Uint8Array');
|
|
199
|
+
validateOutputLen(outLen);
|
|
200
|
+
if (outLen > OUTPUT_STAGING_SIZE)
|
|
201
|
+
throw tooBigForOneShotError(outLen);
|
|
202
|
+
return oneShotDeriveKey(this.x, ctxBytes, material, outLen);
|
|
203
|
+
}
|
|
204
|
+
dispose() {
|
|
205
|
+
_assertNotOwned('blake3');
|
|
206
|
+
try {
|
|
207
|
+
this.x.wipeBuffers();
|
|
208
|
+
}
|
|
209
|
+
catch { /* idempotent */ }
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// ── Streaming base ─────────────────────────────────────────────────────────
|
|
213
|
+
//
|
|
214
|
+
// Buffer input, run one-shot WASM hash at finalize. Lifecycle mirrors
|
|
215
|
+
// SHA3_256Stream. See docs/architecture.md.
|
|
216
|
+
class StreamState {
|
|
217
|
+
chunks = [];
|
|
218
|
+
totalLen = 0;
|
|
219
|
+
consumed = false;
|
|
220
|
+
pushChunk(chunk) {
|
|
221
|
+
if (this.consumed)
|
|
222
|
+
throw new Error('BLAKE3 stream: update() after finalize/finalizeXof');
|
|
223
|
+
if (!(chunk instanceof Uint8Array))
|
|
224
|
+
throw new TypeError('BLAKE3 stream: chunk must be a Uint8Array');
|
|
225
|
+
if (this.totalLen + chunk.length > INPUT_SCRATCH_MAX)
|
|
226
|
+
throw tooBigForScratchError(this.totalLen + chunk.length);
|
|
227
|
+
this.chunks.push(chunk);
|
|
228
|
+
this.totalLen += chunk.length;
|
|
229
|
+
}
|
|
230
|
+
concat() {
|
|
231
|
+
if (this.chunks.length === 1)
|
|
232
|
+
return this.chunks[0];
|
|
233
|
+
const out = new Uint8Array(this.totalLen);
|
|
234
|
+
let pos = 0;
|
|
235
|
+
for (const c of this.chunks) {
|
|
236
|
+
out.set(c, pos);
|
|
237
|
+
pos += c.length;
|
|
238
|
+
}
|
|
239
|
+
return out;
|
|
240
|
+
}
|
|
241
|
+
wipe() {
|
|
242
|
+
// Drop references; we don't own caller buffers. concat() buffers
|
|
243
|
+
// are wiped by the calling class.
|
|
244
|
+
this.chunks = [];
|
|
245
|
+
this.totalLen = 0;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// ── BLAKE3Stream ───────────────────────────────────────────────────────────
|
|
249
|
+
/**
|
|
250
|
+
* Streaming BLAKE3 default-mode hash (BLAKE3 §2.3 Modes — `hash`).
|
|
251
|
+
*
|
|
252
|
+
* `update()` accepts chunks of any size; `finalize()` returns the
|
|
253
|
+
* `outLen`-byte (default 32) digest and disposes the instance. Holds
|
|
254
|
+
* exclusive access to the `blake3` WASM module from construction until
|
|
255
|
+
* `dispose()` or `finalize()` / `finalizeXof()`.
|
|
256
|
+
*/
|
|
257
|
+
export class BLAKE3Stream {
|
|
258
|
+
x;
|
|
259
|
+
_tok;
|
|
260
|
+
_state = new StreamState();
|
|
261
|
+
constructor() {
|
|
262
|
+
this.x = getExports();
|
|
263
|
+
this._tok = _acquireModule('blake3');
|
|
264
|
+
}
|
|
265
|
+
update(chunk) {
|
|
266
|
+
this._checkLive();
|
|
267
|
+
this._state.pushChunk(chunk);
|
|
268
|
+
return this;
|
|
269
|
+
}
|
|
270
|
+
finalize(outLen = 32) {
|
|
271
|
+
this._checkLive();
|
|
272
|
+
validateOutputLen(outLen);
|
|
273
|
+
if (outLen > OUTPUT_STAGING_SIZE)
|
|
274
|
+
throw tooBigForOneShotError(outLen);
|
|
275
|
+
this._state.consumed = true;
|
|
276
|
+
const full = this._state.concat();
|
|
277
|
+
try {
|
|
278
|
+
return oneShotHash(this.x, full, outLen);
|
|
279
|
+
}
|
|
280
|
+
finally {
|
|
281
|
+
this.dispose();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
finalizeXof() {
|
|
285
|
+
this._checkLive();
|
|
286
|
+
// _checkLive guarantees _tok is set; the local capture lets the type
|
|
287
|
+
// system see this beyond the assignment to undefined on the next line.
|
|
288
|
+
const tok = this._tok;
|
|
289
|
+
this._state.consumed = true;
|
|
290
|
+
// The reader holds the module token for its own lifetime; transfer
|
|
291
|
+
// ownership rather than releasing-then-reacquiring (which would race
|
|
292
|
+
// against any other consumer trying to acquire the module in between).
|
|
293
|
+
this._tok = undefined;
|
|
294
|
+
const full = this._state.concat();
|
|
295
|
+
return new BLAKE3OutputReader('hash', this.x, tok, full);
|
|
296
|
+
}
|
|
297
|
+
dispose() {
|
|
298
|
+
if (this._tok === undefined)
|
|
299
|
+
return;
|
|
300
|
+
this._state.wipe();
|
|
301
|
+
try {
|
|
302
|
+
this.x.wipeBuffers();
|
|
303
|
+
}
|
|
304
|
+
finally {
|
|
305
|
+
_releaseModule('blake3', this._tok);
|
|
306
|
+
this._tok = undefined;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
_checkLive() {
|
|
310
|
+
if (this._tok === undefined)
|
|
311
|
+
throw new Error('BLAKE3Stream: instance has been disposed');
|
|
312
|
+
if (this._state.consumed)
|
|
313
|
+
throw new Error('BLAKE3Stream: stream has been finalized');
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// ── BLAKE3KeyedHashStream ──────────────────────────────────────────────────
|
|
317
|
+
/**
|
|
318
|
+
* Streaming BLAKE3 keyed_hash (BLAKE3 §2.3 Modes). Key is bound at construction
|
|
319
|
+
* time. Same lifecycle as `BLAKE3Stream`.
|
|
320
|
+
*/
|
|
321
|
+
export class BLAKE3KeyedHashStream {
|
|
322
|
+
x;
|
|
323
|
+
_tok;
|
|
324
|
+
_state = new StreamState();
|
|
325
|
+
_key;
|
|
326
|
+
constructor(key) {
|
|
327
|
+
validateKey(key);
|
|
328
|
+
this.x = getExports();
|
|
329
|
+
this._tok = _acquireModule('blake3');
|
|
330
|
+
// Defensive copy: we own this buffer for the lifetime of the stream
|
|
331
|
+
// and wipe it on dispose / finalize.
|
|
332
|
+
this._key = new Uint8Array(32);
|
|
333
|
+
this._key.set(key);
|
|
334
|
+
}
|
|
335
|
+
update(chunk) {
|
|
336
|
+
this._checkLive();
|
|
337
|
+
this._state.pushChunk(chunk);
|
|
338
|
+
return this;
|
|
339
|
+
}
|
|
340
|
+
finalize(outLen = 32) {
|
|
341
|
+
this._checkLive();
|
|
342
|
+
validateOutputLen(outLen);
|
|
343
|
+
if (outLen > OUTPUT_STAGING_SIZE)
|
|
344
|
+
throw tooBigForOneShotError(outLen);
|
|
345
|
+
this._state.consumed = true;
|
|
346
|
+
const full = this._state.concat();
|
|
347
|
+
try {
|
|
348
|
+
return oneShotKeyedHash(this.x, this._key, full, outLen);
|
|
349
|
+
}
|
|
350
|
+
finally {
|
|
351
|
+
this.dispose();
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
finalizeXof() {
|
|
355
|
+
this._checkLive();
|
|
356
|
+
const tok = this._tok;
|
|
357
|
+
this._state.consumed = true;
|
|
358
|
+
this._tok = undefined;
|
|
359
|
+
const full = this._state.concat();
|
|
360
|
+
const reader = new BLAKE3OutputReader('keyed', this.x, tok, full, this._key);
|
|
361
|
+
// Reader owns its own copy of the key; wipe the stream's.
|
|
362
|
+
this._key.fill(0);
|
|
363
|
+
return reader;
|
|
364
|
+
}
|
|
365
|
+
dispose() {
|
|
366
|
+
if (this._tok === undefined)
|
|
367
|
+
return;
|
|
368
|
+
this._key.fill(0);
|
|
369
|
+
this._state.wipe();
|
|
370
|
+
try {
|
|
371
|
+
this.x.wipeBuffers();
|
|
372
|
+
}
|
|
373
|
+
finally {
|
|
374
|
+
_releaseModule('blake3', this._tok);
|
|
375
|
+
this._tok = undefined;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
_checkLive() {
|
|
379
|
+
if (this._tok === undefined)
|
|
380
|
+
throw new Error('BLAKE3KeyedHashStream: instance has been disposed');
|
|
381
|
+
if (this._state.consumed)
|
|
382
|
+
throw new Error('BLAKE3KeyedHashStream: stream has been finalized');
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
// ── BLAKE3DeriveKeyStream ──────────────────────────────────────────────────
|
|
386
|
+
/**
|
|
387
|
+
* Streaming BLAKE3 derive_key (BLAKE3 §2.3 Modes). Context is bound at
|
|
388
|
+
* construction time; updates stream the material; finalize derives.
|
|
389
|
+
* Same lifecycle as `BLAKE3Stream`.
|
|
390
|
+
*/
|
|
391
|
+
export class BLAKE3DeriveKeyStream {
|
|
392
|
+
x;
|
|
393
|
+
_tok;
|
|
394
|
+
_state = new StreamState();
|
|
395
|
+
_ctxBytes;
|
|
396
|
+
constructor(context) {
|
|
397
|
+
this._ctxBytes = validateContext(context);
|
|
398
|
+
this.x = getExports();
|
|
399
|
+
this._tok = _acquireModule('blake3');
|
|
400
|
+
}
|
|
401
|
+
update(chunk) {
|
|
402
|
+
this._checkLive();
|
|
403
|
+
this._state.pushChunk(chunk);
|
|
404
|
+
return this;
|
|
405
|
+
}
|
|
406
|
+
finalize(outLen = 32) {
|
|
407
|
+
this._checkLive();
|
|
408
|
+
validateOutputLen(outLen);
|
|
409
|
+
if (outLen > OUTPUT_STAGING_SIZE)
|
|
410
|
+
throw tooBigForOneShotError(outLen);
|
|
411
|
+
this._state.consumed = true;
|
|
412
|
+
const full = this._state.concat();
|
|
413
|
+
try {
|
|
414
|
+
return oneShotDeriveKey(this.x, this._ctxBytes, full, outLen);
|
|
415
|
+
}
|
|
416
|
+
finally {
|
|
417
|
+
this.dispose();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
finalizeXof() {
|
|
421
|
+
this._checkLive();
|
|
422
|
+
const tok = this._tok;
|
|
423
|
+
this._state.consumed = true;
|
|
424
|
+
this._tok = undefined;
|
|
425
|
+
const full = this._state.concat();
|
|
426
|
+
return new BLAKE3OutputReader('derive', this.x, tok, full, undefined, this._ctxBytes);
|
|
427
|
+
}
|
|
428
|
+
dispose() {
|
|
429
|
+
if (this._tok === undefined)
|
|
430
|
+
return;
|
|
431
|
+
this._state.wipe();
|
|
432
|
+
try {
|
|
433
|
+
this.x.wipeBuffers();
|
|
434
|
+
}
|
|
435
|
+
finally {
|
|
436
|
+
_releaseModule('blake3', this._tok);
|
|
437
|
+
this._tok = undefined;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
_checkLive() {
|
|
441
|
+
if (this._tok === undefined)
|
|
442
|
+
throw new Error('BLAKE3DeriveKeyStream: instance has been disposed');
|
|
443
|
+
if (this._state.consumed)
|
|
444
|
+
throw new Error('BLAKE3DeriveKeyStream: stream has been finalized');
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* BLAKE3 XOF reader (BLAKE3 §2.6 Extendable Output).
|
|
449
|
+
*
|
|
450
|
+
* Sequential `read(nBytes)` calls squeeze the next bytes of XOF output.
|
|
451
|
+
* Constructed via `finalizeXof()` on a streaming class. Holds module
|
|
452
|
+
* exclusivity until `dispose()`.
|
|
453
|
+
*
|
|
454
|
+
* Implementation: the first `read()` runs the underlying hash entry once
|
|
455
|
+
* to populate the WASM-side root-compress snapshot (ROOT_STATE_*), then
|
|
456
|
+
* caches the first 64-byte XOF block. Subsequent reads pump
|
|
457
|
+
* `squeezeXofBlock` on the WASM module with an incrementing counter to
|
|
458
|
+
* lift additional 64-byte blocks off the snapshot. The reader's lifetime
|
|
459
|
+
* coincides with its hold on the module token, so `ROOT_STATE_*` stays
|
|
460
|
+
* intact between read calls (no other consumer can fire a hash that
|
|
461
|
+
* would clobber it).
|
|
462
|
+
*/
|
|
463
|
+
export class BLAKE3OutputReader {
|
|
464
|
+
x;
|
|
465
|
+
_tok;
|
|
466
|
+
_mode;
|
|
467
|
+
_input;
|
|
468
|
+
_key;
|
|
469
|
+
_ctx;
|
|
470
|
+
_blockBuf = new Uint8Array(ROOT_BLOCK_SIZE);
|
|
471
|
+
_blockPos = ROOT_BLOCK_SIZE; // forces refill on first read
|
|
472
|
+
_nextCounter = 0n;
|
|
473
|
+
_populated = false;
|
|
474
|
+
/** @internal Constructed by `finalizeXof()` on a streaming class. */
|
|
475
|
+
constructor(mode, x, tok, input, key, ctx) {
|
|
476
|
+
this._mode = mode;
|
|
477
|
+
this.x = x;
|
|
478
|
+
this._tok = tok;
|
|
479
|
+
this._input = input;
|
|
480
|
+
// Defensive copy of key, the reader outlives the parent stream's
|
|
481
|
+
// _key buffer (which is wiped on transfer).
|
|
482
|
+
if (key) {
|
|
483
|
+
this._key = new Uint8Array(32);
|
|
484
|
+
this._key.set(key);
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
this._key = undefined;
|
|
488
|
+
}
|
|
489
|
+
this._ctx = ctx;
|
|
490
|
+
}
|
|
491
|
+
read(nBytes) {
|
|
492
|
+
if (this._tok === undefined)
|
|
493
|
+
throw new Error('BLAKE3OutputReader: instance has been disposed');
|
|
494
|
+
validateOutputLen(nBytes);
|
|
495
|
+
if (!this._populated) {
|
|
496
|
+
this._populate();
|
|
497
|
+
}
|
|
498
|
+
const out = new Uint8Array(nBytes);
|
|
499
|
+
let pos = 0;
|
|
500
|
+
while (pos < nBytes) {
|
|
501
|
+
if (this._blockPos >= ROOT_BLOCK_SIZE) {
|
|
502
|
+
this._squeezeNextBlock();
|
|
503
|
+
}
|
|
504
|
+
const available = ROOT_BLOCK_SIZE - this._blockPos;
|
|
505
|
+
const take = Math.min(nBytes - pos, available);
|
|
506
|
+
out.set(this._blockBuf.subarray(this._blockPos, this._blockPos + take), pos);
|
|
507
|
+
this._blockPos += take;
|
|
508
|
+
pos += take;
|
|
509
|
+
}
|
|
510
|
+
return out;
|
|
511
|
+
}
|
|
512
|
+
dispose() {
|
|
513
|
+
if (this._tok === undefined)
|
|
514
|
+
return;
|
|
515
|
+
this._blockBuf.fill(0);
|
|
516
|
+
this._blockPos = ROOT_BLOCK_SIZE;
|
|
517
|
+
this._nextCounter = 0n;
|
|
518
|
+
if (this._key)
|
|
519
|
+
this._key.fill(0);
|
|
520
|
+
try {
|
|
521
|
+
this.x.wipeBuffers();
|
|
522
|
+
}
|
|
523
|
+
finally {
|
|
524
|
+
_releaseModule('blake3', this._tok);
|
|
525
|
+
this._tok = undefined;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
// Captures ROOT_STATE_* inside WASM, copies block 0 to _blockBuf.
|
|
529
|
+
// Does NOT call wipeBuffers; that would clear ROOT_STATE_* and break
|
|
530
|
+
// subsequent squeezeXofBlock calls. The reader wipes on dispose.
|
|
531
|
+
_populate() {
|
|
532
|
+
const x = this.x;
|
|
533
|
+
const outOff = x.getOutputStagingOffset();
|
|
534
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
535
|
+
if (this._input.length > INPUT_SCRATCH_MAX)
|
|
536
|
+
throw tooBigForScratchError(this._input.length);
|
|
537
|
+
mem.set(this._input, INPUT_SCRATCH_OFF);
|
|
538
|
+
try {
|
|
539
|
+
switch (this._mode) {
|
|
540
|
+
case 'hash':
|
|
541
|
+
x.hash(INPUT_SCRATCH_OFF, this._input.length, outOff, ROOT_BLOCK_SIZE);
|
|
542
|
+
break;
|
|
543
|
+
case 'keyed': {
|
|
544
|
+
if (!this._key)
|
|
545
|
+
throw new Error('BLAKE3OutputReader: keyed mode without key');
|
|
546
|
+
const keyOff = x.getKeyedKeyOffset();
|
|
547
|
+
mem.set(this._key, keyOff);
|
|
548
|
+
try {
|
|
549
|
+
x.hashKeyed(keyOff, INPUT_SCRATCH_OFF, this._input.length, outOff, ROOT_BLOCK_SIZE);
|
|
550
|
+
}
|
|
551
|
+
finally {
|
|
552
|
+
mem.fill(0, keyOff, keyOff + 32);
|
|
553
|
+
}
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
case 'derive': {
|
|
557
|
+
if (!this._ctx)
|
|
558
|
+
throw new Error('BLAKE3OutputReader: derive mode without context');
|
|
559
|
+
const ctx = this._ctx;
|
|
560
|
+
if (ctx.length + this._input.length > INPUT_SCRATCH_MAX)
|
|
561
|
+
throw tooBigForScratchError(ctx.length + this._input.length);
|
|
562
|
+
// Re-stage with context prefixed in front of material.
|
|
563
|
+
mem.set(ctx, INPUT_SCRATCH_OFF);
|
|
564
|
+
mem.set(this._input, INPUT_SCRATCH_OFF + ctx.length);
|
|
565
|
+
try {
|
|
566
|
+
x.deriveKey(INPUT_SCRATCH_OFF, ctx.length, INPUT_SCRATCH_OFF + ctx.length, this._input.length, outOff, ROOT_BLOCK_SIZE);
|
|
567
|
+
}
|
|
568
|
+
finally {
|
|
569
|
+
mem.fill(0, INPUT_SCRATCH_OFF, INPUT_SCRATCH_OFF + ctx.length);
|
|
570
|
+
}
|
|
571
|
+
break;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
this._blockBuf.set(mem.subarray(outOff, outOff + ROOT_BLOCK_SIZE));
|
|
575
|
+
this._blockPos = 0;
|
|
576
|
+
this._nextCounter = 1n;
|
|
577
|
+
this._populated = true;
|
|
578
|
+
}
|
|
579
|
+
finally {
|
|
580
|
+
const inLen = this._mode === 'derive' && this._ctx
|
|
581
|
+
? this._ctx.length + this._input.length
|
|
582
|
+
: this._input.length;
|
|
583
|
+
mem.fill(0, INPUT_SCRATCH_OFF, INPUT_SCRATCH_OFF + inLen);
|
|
584
|
+
mem.fill(0, outOff, outOff + ROOT_BLOCK_SIZE);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
_squeezeNextBlock() {
|
|
588
|
+
const x = this.x;
|
|
589
|
+
const outOff = x.getOutputStagingOffset();
|
|
590
|
+
const ctr = this._nextCounter;
|
|
591
|
+
const ctrLo = Number(ctr & 0xffffffffn);
|
|
592
|
+
const ctrHi = Number((ctr >> 32n) & 0xffffffffn);
|
|
593
|
+
x.squeezeXofBlock(ctrLo, ctrHi, outOff);
|
|
594
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
595
|
+
this._blockBuf.set(mem.subarray(outOff, outOff + ROOT_BLOCK_SIZE));
|
|
596
|
+
this._blockPos = 0;
|
|
597
|
+
this._nextCounter = ctr + 1n;
|
|
598
|
+
// Scrub the staging slot now that the bytes are in _blockBuf; the
|
|
599
|
+
// reader's wipe-on-dispose covers _blockBuf itself.
|
|
600
|
+
mem.fill(0, outOff, outOff + ROOT_BLOCK_SIZE);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
// ── BLAKE3Hash, Fortuna HashFn const ───────────────────────────────────────
|
|
604
|
+
/**
|
|
605
|
+
* Stateless BLAKE3-256 HashFn. Shape mirrors `SHA256Hash` in
|
|
606
|
+
* `src/ts/sha2/hash.ts`: 32-byte output, single WASM module dependency,
|
|
607
|
+
* `digest(msg)` runs a one-shot hash with default `outLen`.
|
|
608
|
+
*
|
|
609
|
+
* Usable as a Fortuna accumulator / reseed hash when paired with a
|
|
610
|
+
* matching 32-byte-key Generator.
|
|
611
|
+
*/
|
|
612
|
+
export const BLAKE3Hash = {
|
|
613
|
+
outputSize: 32,
|
|
614
|
+
wasmModules: ['blake3'],
|
|
615
|
+
digest(msg) {
|
|
616
|
+
_assertNotOwned('blake3');
|
|
617
|
+
const x = getExports();
|
|
618
|
+
return oneShotHash(x, msg, 32);
|
|
619
|
+
},
|
|
620
|
+
};
|