leviathan-crypto 2.1.0 → 3.0.1
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/chacha20.wasm +0 -0
- 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 +47 -69
- 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/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 +73 -25
- 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/kyber.wasm +0 -0
- /package/dist/{ct.wasm → cte.wasm} +0 -0
package/dist/fortuna.js
CHANGED
|
@@ -21,25 +21,26 @@
|
|
|
21
21
|
//
|
|
22
22
|
// src/ts/fortuna.ts
|
|
23
23
|
//
|
|
24
|
-
// Fortuna CSPRNG
|
|
24
|
+
// Fortuna CSPRNG, Ferguson & Schneier, Practical Cryptography (2003), Chapter 9.
|
|
25
25
|
// Backed by a pluggable Generator (cipher PRF) and HashFn (accumulator hash).
|
|
26
26
|
// Requires init() for the modules used by the chosen generator and hash pair.
|
|
27
27
|
import { isInitialized, getInstance } from './init.js';
|
|
28
28
|
import { wipe, utf8ToBytes, concat } from './utils.js';
|
|
29
29
|
const isBrowser = typeof window !== 'undefined';
|
|
30
|
-
const
|
|
30
|
+
const proc = globalThis.process;
|
|
31
|
+
const isNode = typeof proc !== 'undefined' && typeof proc.pid === 'number';
|
|
31
32
|
/**
|
|
32
|
-
* Fortuna CSPRNG
|
|
33
|
+
* Fortuna CSPRNG, spec §9.3-§9.5
|
|
33
34
|
*
|
|
34
35
|
* Use `Fortuna.create({ generator, hash })` to instantiate. Direct construction is not allowed.
|
|
35
36
|
*/
|
|
36
37
|
export class Fortuna {
|
|
37
38
|
// ── Constants ──────────────────────────────────────────────────────────
|
|
38
39
|
static NUM_POOLS = 32;
|
|
39
|
-
static RESEED_LIMIT = 64; // bits
|
|
40
|
-
static MS_PER_RESEED = 100; // ms
|
|
41
|
-
static NODE_STATS_INTERVAL = 1000; // ms
|
|
42
|
-
static CRYPTO_INTERVAL = 3000; // ms
|
|
40
|
+
static RESEED_LIMIT = 64; // bits, pool 0 threshold (spec §9.5)
|
|
41
|
+
static MS_PER_RESEED = 100; // ms, minimum reseed interval (spec §9.5)
|
|
42
|
+
static NODE_STATS_INTERVAL = 1000; // ms, OS stats collector interval
|
|
43
|
+
static CRYPTO_INTERVAL = 3000; // ms, crypto.randomBytes interval
|
|
43
44
|
// ── State ─────────────────────────────────────────────────────────────
|
|
44
45
|
gen;
|
|
45
46
|
hash;
|
|
@@ -74,7 +75,7 @@ export class Fortuna {
|
|
|
74
75
|
}
|
|
75
76
|
const f = new Fortuna(opts.generator, opts.hash, opts.msPerReseed ?? Fortuna.MS_PER_RESEED);
|
|
76
77
|
f.initialize(opts.entropy);
|
|
77
|
-
// Force the first reseed
|
|
78
|
+
// Force the first reseed, pool[0] is saturated by initialize(),
|
|
78
79
|
// so this call triggers an immediate reseed and guarantees get() never
|
|
79
80
|
// returns undefined. The byte is discarded.
|
|
80
81
|
f.get(1);
|
|
@@ -101,14 +102,14 @@ export class Fortuna {
|
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
// ── Public API ────────────────────────────────────────────────────────
|
|
104
|
-
/** Get n random bytes. Always returns Uint8Array
|
|
105
|
+
/** Get n random bytes. Always returns Uint8Array, instance is guaranteed seeded after create(). */
|
|
105
106
|
get(length) {
|
|
106
107
|
if (this.disposed)
|
|
107
108
|
throw new Error('Fortuna instance has been disposed');
|
|
108
|
-
// Capture hrtime jitter at call time (Node.js)
|
|
109
|
+
// Capture hrtime jitter at call time (Node.js), spec §9.5
|
|
109
110
|
if (isNode)
|
|
110
111
|
this.captureHrtime();
|
|
111
|
-
// Check reseed trigger
|
|
112
|
+
// Check reseed trigger, spec §9.5
|
|
112
113
|
if (this.poolEntropy[0] >= Fortuna.RESEED_LIMIT &&
|
|
113
114
|
Date.now() >= this.lastReseed + this.msPerReseed) {
|
|
114
115
|
this.reseedCnt = (this.reseedCnt + 1) >>> 0; // u32 wrap
|
|
@@ -121,7 +122,7 @@ export class Fortuna {
|
|
|
121
122
|
// Pool digest = current chain hash
|
|
122
123
|
seed = concat(seed, this.poolHash[i]);
|
|
123
124
|
strength += this.poolEntropy[i];
|
|
124
|
-
// Reset pool
|
|
125
|
+
// Reset pool, wipe old chain hash before dropping the reference.
|
|
125
126
|
const old = this.poolHash[i];
|
|
126
127
|
this.poolHash[i] = new Uint8Array(this.hash.outputSize);
|
|
127
128
|
wipe(old);
|
|
@@ -152,21 +153,17 @@ export class Fortuna {
|
|
|
152
153
|
stop() {
|
|
153
154
|
if (this.disposed)
|
|
154
155
|
throw new Error('Fortuna instance has been disposed');
|
|
155
|
-
// Mark disposed
|
|
156
|
-
// holds the module; we must not allow get()/addEntropy()/getEntropy() to
|
|
157
|
-
// run on a partially-disposed instance.
|
|
156
|
+
// Mark disposed first so partially-disposed reentry throws cleanly.
|
|
158
157
|
this.disposed = true;
|
|
159
158
|
this.stopCollectors();
|
|
160
159
|
wipe(this.genKey);
|
|
161
160
|
wipe(this.genCnt);
|
|
162
|
-
// Wipe
|
|
161
|
+
// Wipe the 32 pool-hash chain values so residual entropy-bearing
|
|
163
162
|
// bytes do not outlive the instance.
|
|
164
163
|
for (const p of this.poolHash)
|
|
165
164
|
wipe(p);
|
|
166
165
|
this.reseedCnt = 0;
|
|
167
|
-
// Best-effort wipe of WASM scratch
|
|
168
|
-
// generator and hash touched. Surface the first error so the caller
|
|
169
|
-
// knows the WASM scratch leak occurred.
|
|
166
|
+
// Best-effort wipe of WASM scratch; surface the first error.
|
|
170
167
|
const required = new Set([...this.gen.wasmModules, ...this.hash.wasmModules]);
|
|
171
168
|
let err;
|
|
172
169
|
for (const mod of required) {
|
|
@@ -181,24 +178,24 @@ export class Fortuna {
|
|
|
181
178
|
throw err;
|
|
182
179
|
}
|
|
183
180
|
// ── Test-only accessors ───────────────────────────────────────────────
|
|
184
|
-
/** @internal
|
|
181
|
+
/** @internal, exposed for testing key replacement */
|
|
185
182
|
_getGenKey() {
|
|
186
183
|
return this.genKey;
|
|
187
184
|
}
|
|
188
|
-
/** @internal
|
|
185
|
+
/** @internal, exposed for testing pool state */
|
|
189
186
|
_getPoolEntropy() {
|
|
190
187
|
return this.poolEntropy;
|
|
191
188
|
}
|
|
192
|
-
/** @internal
|
|
189
|
+
/** @internal, exposed for testing reseed count */
|
|
193
190
|
_getReseedCnt() {
|
|
194
191
|
return this.reseedCnt;
|
|
195
192
|
}
|
|
196
|
-
/** @internal
|
|
193
|
+
/** @internal, exposed for testing pool-hash backing arrays */
|
|
197
194
|
_getPoolHash() {
|
|
198
195
|
return this.poolHash;
|
|
199
196
|
}
|
|
200
197
|
/**
|
|
201
|
-
* @internal
|
|
198
|
+
* @internal, test-only deterministic factory. Seeds pool[0] with the provided
|
|
202
199
|
* entropy and triggers one reseed directly, bypassing all OS entropy collection
|
|
203
200
|
* and the hrtime jitter capture in get(). This makes KAT vectors reproducible
|
|
204
201
|
* across runs. Not suitable for production use.
|
|
@@ -219,20 +216,20 @@ export class Fortuna {
|
|
|
219
216
|
const f = new Fortuna(opts.generator, opts.hash, 0);
|
|
220
217
|
// Seed pool[0] with the provided entropy, no OS collection.
|
|
221
218
|
f.addRandomEvent(opts.entropy, 0, opts.entropy.length * 8);
|
|
222
|
-
// Manually trigger reseed #1 without calling get()
|
|
219
|
+
// Manually trigger reseed #1 without calling get(), get() calls captureHrtime()
|
|
223
220
|
// in Node.js which adds non-deterministic data before the reseed fires.
|
|
224
221
|
f.reseedFromPool0();
|
|
225
222
|
return f;
|
|
226
223
|
}
|
|
227
224
|
// ── Generator (spec §9.4) ─────────────────────────────────────────────
|
|
228
|
-
/** Get length pseudo-random bytes
|
|
225
|
+
/** Get length pseudo-random bytes., spec §9.4 */
|
|
229
226
|
pseudoRandomData(length) {
|
|
230
227
|
const blocks = Math.ceil(length / this.gen.blockSize);
|
|
231
228
|
const out = this.gen.generate(this.genKey, this.genCnt, length);
|
|
232
|
-
// External counter advance
|
|
229
|
+
// External counter advance, generator is stateless and does not mutate caller's counter
|
|
233
230
|
for (let i = 0; i < blocks; i++)
|
|
234
231
|
this.incrementCounter();
|
|
235
|
-
// Key replacement
|
|
232
|
+
// Key replacement, mandatory forward secrecy (spec §9.4).
|
|
236
233
|
// Wipe the prior key BEFORE dropping its reference so no key bytes are
|
|
237
234
|
// reachable after key replacement; anyone holding a Uint8Array view to
|
|
238
235
|
// the old key now observes zero.
|
|
@@ -243,7 +240,7 @@ export class Fortuna {
|
|
|
243
240
|
this.genKey = newKey;
|
|
244
241
|
return out;
|
|
245
242
|
}
|
|
246
|
-
/** Reseed the generator
|
|
243
|
+
/** Reseed the generator, spec §9.4 */
|
|
247
244
|
reseed(seed) {
|
|
248
245
|
// genKey = hash(genKey ‖ seed). Wipe both the hash input and the
|
|
249
246
|
// prior key before dropping references.
|
|
@@ -252,7 +249,7 @@ export class Fortuna {
|
|
|
252
249
|
wipe(combined);
|
|
253
250
|
wipe(this.genKey);
|
|
254
251
|
this.genKey = newKey;
|
|
255
|
-
// Increment counter
|
|
252
|
+
// Increment counter, makes it nonzero on first reseed, marking generator as seeded
|
|
256
253
|
this.incrementCounter();
|
|
257
254
|
this.lastReseed = Date.now();
|
|
258
255
|
}
|
|
@@ -271,7 +268,7 @@ export class Fortuna {
|
|
|
271
268
|
this.reseed(seed);
|
|
272
269
|
wipe(seed);
|
|
273
270
|
}
|
|
274
|
-
/** Increment little-endian counter
|
|
271
|
+
/** Increment little-endian counter., spec §9.4 */
|
|
275
272
|
incrementCounter() {
|
|
276
273
|
for (let i = 0; i < this.genCnt.length; i++) {
|
|
277
274
|
if (++this.genCnt[i] !== 0)
|
|
@@ -300,7 +297,7 @@ export class Fortuna {
|
|
|
300
297
|
}
|
|
301
298
|
// ── Initialization ────────────────────────────────────────────────────
|
|
302
299
|
initialize(entropy) {
|
|
303
|
-
// Initial seeding
|
|
300
|
+
// Initial seeding, crypto random per pool (spec §9.5)
|
|
304
301
|
for (let i = 0; i < Fortuna.NUM_POOLS * 4; i++) {
|
|
305
302
|
this.collectorCryptoRandom();
|
|
306
303
|
}
|
|
@@ -319,7 +316,7 @@ export class Fortuna {
|
|
|
319
316
|
// runtimes). This post-init check covers all silent-failure paths uniformly.
|
|
320
317
|
if (this.poolEntropy[0] < Fortuna.RESEED_LIMIT)
|
|
321
318
|
throw new Error('leviathan-crypto: Fortuna initialization could not gather sufficient entropy. '
|
|
322
|
-
+ 'No working crypto.getRandomValues
|
|
319
|
+
+ 'No working crypto.getRandomValues in this environment.');
|
|
323
320
|
this.startCollectors();
|
|
324
321
|
}
|
|
325
322
|
// ── Collectors ────────────────────────────────────────────────────────
|
|
@@ -349,7 +346,7 @@ export class Fortuna {
|
|
|
349
346
|
// OS stats timer
|
|
350
347
|
this.timers.push(setInterval(() => this.collectNodeStats(), Fortuna.NODE_STATS_INTERVAL));
|
|
351
348
|
}
|
|
352
|
-
// Crypto timer
|
|
349
|
+
// Crypto timer, both environments
|
|
353
350
|
this.timers.push(setInterval(() => this.collectorCryptoRandom(), Fortuna.CRYPTO_INTERVAL));
|
|
354
351
|
this.active = true;
|
|
355
352
|
}
|
|
@@ -458,27 +455,22 @@ export class Fortuna {
|
|
|
458
455
|
}
|
|
459
456
|
collectorCryptoRandom() {
|
|
460
457
|
try {
|
|
458
|
+
// Web Crypto is the only secure source. No node:crypto fallback: an absent
|
|
459
|
+
// source must fail loud via the init invariant below, never be polyfilled.
|
|
460
|
+
if (typeof globalThis.crypto === 'undefined' || typeof globalThis.crypto.getRandomValues !== 'function')
|
|
461
|
+
return;
|
|
461
462
|
const rnd = new Uint8Array(128);
|
|
462
|
-
|
|
463
|
-
globalThis.crypto.getRandomValues(rnd);
|
|
464
|
-
}
|
|
465
|
-
else if (isNode) {
|
|
466
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
467
|
-
const nodeCrypto = require('node:crypto');
|
|
468
|
-
const buf = nodeCrypto.randomBytes(128);
|
|
469
|
-
rnd.set(new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
|
|
470
|
-
}
|
|
471
|
-
else {
|
|
472
|
-
return; // no crypto source available
|
|
473
|
-
}
|
|
463
|
+
globalThis.crypto.getRandomValues(rnd);
|
|
474
464
|
this.addRandomEvent(rnd, this.robin.rnd, 1024);
|
|
475
465
|
this.robin.rnd = (this.robin.rnd + 1) % Fortuna.NUM_POOLS;
|
|
476
466
|
}
|
|
477
467
|
catch { /* crypto may not be available */ }
|
|
478
468
|
}
|
|
479
469
|
captureHrtime() {
|
|
470
|
+
if (!proc)
|
|
471
|
+
return;
|
|
480
472
|
try {
|
|
481
|
-
const hr =
|
|
473
|
+
const hr = proc.hrtime.bigint();
|
|
482
474
|
const hrBytes = new Uint8Array(8);
|
|
483
475
|
for (let i = 0; i < 8; i++)
|
|
484
476
|
hrBytes[i] = Number((hr >> BigInt(i * 8)) & 0xffn);
|
|
@@ -488,16 +480,18 @@ export class Fortuna {
|
|
|
488
480
|
catch { /* hrtime may not be available */ }
|
|
489
481
|
}
|
|
490
482
|
collectNodeStats() {
|
|
483
|
+
if (!proc)
|
|
484
|
+
return;
|
|
491
485
|
try {
|
|
492
|
-
// hrtime
|
|
493
|
-
const hr =
|
|
486
|
+
// hrtime, nanosecond scheduling jitter
|
|
487
|
+
const hr = proc.hrtime.bigint();
|
|
494
488
|
const hrBytes = new Uint8Array(8);
|
|
495
489
|
for (let i = 0; i < 8; i++)
|
|
496
490
|
hrBytes[i] = Number((hr >> BigInt(i * 8)) & 0xffn);
|
|
497
491
|
this.addRandomEvent(hrBytes, this.robin.time, 8);
|
|
498
492
|
this.robin.time = (this.robin.time + 1) % Fortuna.NUM_POOLS;
|
|
499
|
-
// cpuUsage
|
|
500
|
-
const cpu =
|
|
493
|
+
// cpuUsage, user + system CPU microseconds
|
|
494
|
+
const cpu = proc.cpuUsage();
|
|
501
495
|
const cpuBytes = new Uint8Array(8);
|
|
502
496
|
cpuBytes[0] = cpu.user & 0xff;
|
|
503
497
|
cpuBytes[1] = (cpu.user >>> 8) & 0xff;
|
|
@@ -509,8 +503,8 @@ export class Fortuna {
|
|
|
509
503
|
cpuBytes[7] = (cpu.system >>> 24) & 0xff;
|
|
510
504
|
this.addRandomEvent(cpuBytes, this.robin.rnd, 2);
|
|
511
505
|
this.robin.rnd = (this.robin.rnd + 1) % Fortuna.NUM_POOLS;
|
|
512
|
-
// memoryUsage
|
|
513
|
-
const mem =
|
|
506
|
+
// memoryUsage, heapUsed changes constantly
|
|
507
|
+
const mem = proc.memoryUsage();
|
|
514
508
|
const memVal = mem.heapUsed;
|
|
515
509
|
const memBytes = new Uint8Array(4);
|
|
516
510
|
memBytes[0] = memVal & 0xff;
|
|
@@ -519,22 +513,6 @@ export class Fortuna {
|
|
|
519
513
|
memBytes[3] = (memVal >>> 24) & 0xff;
|
|
520
514
|
this.addRandomEvent(memBytes, this.robin.rnd, 1);
|
|
521
515
|
this.robin.rnd = (this.robin.rnd + 1) % Fortuna.NUM_POOLS;
|
|
522
|
-
// loadavg — slow-changing but real system state
|
|
523
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
524
|
-
const os = require('node:os');
|
|
525
|
-
const la = os.loadavg();
|
|
526
|
-
const laStr = la.map((n) => Math.round(n * 1000).toString()).join('');
|
|
527
|
-
this.addRandomEvent(utf8ToBytes(laStr), this.robin.time, 1);
|
|
528
|
-
this.robin.time = (this.robin.time + 1) % Fortuna.NUM_POOLS;
|
|
529
|
-
// freemem — changes with allocation activity
|
|
530
|
-
const fm = os.freemem();
|
|
531
|
-
const fmBytes = new Uint8Array(4);
|
|
532
|
-
fmBytes[0] = fm & 0xff;
|
|
533
|
-
fmBytes[1] = (fm >>> 8) & 0xff;
|
|
534
|
-
fmBytes[2] = (fm >>> 16) & 0xff;
|
|
535
|
-
fmBytes[3] = (fm >>> 24) & 0xff;
|
|
536
|
-
this.addRandomEvent(fmBytes, this.robin.rnd, 1);
|
|
537
|
-
this.robin.rnd = (this.robin.rnd + 1) % Fortuna.NUM_POOLS;
|
|
538
516
|
}
|
|
539
517
|
catch { /* Node APIs may not be available */ }
|
|
540
518
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { Module } from './init.js';
|
|
2
2
|
import type { WasmSource } from './wasm-source.js';
|
|
3
|
+
/**
|
|
4
|
+
* Top-level init() input. Accepts the canonical module keys plus the
|
|
5
|
+
* `ed25519` and `x25519` aliases; both aliases resolve to the underlying
|
|
6
|
+
* `curve25519` WASM module and are de-duped if given identical sources.
|
|
7
|
+
*/
|
|
8
|
+
export type InitInput = Partial<Record<Module | 'ed25519' | 'x25519', WasmSource>>;
|
|
3
9
|
/**
|
|
4
10
|
* Load one or more WASM modules. Each key is a module name; the value is the
|
|
5
11
|
* WasmSource to load it from (embedded blob, URL, ArrayBuffer, etc.).
|
|
@@ -10,22 +16,45 @@ import type { WasmSource } from './wasm-source.js';
|
|
|
10
16
|
* import { sha2Wasm } from 'leviathan-crypto/sha2/embedded';
|
|
11
17
|
* await init({ serpent: serpentWasm, sha2: sha2Wasm });
|
|
12
18
|
* ```
|
|
19
|
+
*
|
|
20
|
+
* `ed25519` and `x25519` are aliases for the underlying `curve25519`
|
|
21
|
+
* module. `init({ ed25519: src })` and `init({ x25519: src })` both work,
|
|
22
|
+
* and `init({ ed25519: src, x25519: src })` is accepted (single underlying
|
|
23
|
+
* init). Two different sources for the same underlying module is rejected.
|
|
13
24
|
*/
|
|
14
|
-
export declare function init(sources:
|
|
25
|
+
export declare function init(sources: InitInput): Promise<void>;
|
|
15
26
|
export type { Module, WasmSource };
|
|
16
27
|
export { isInitialized } from './init.js';
|
|
17
|
-
export { AuthenticationError } from './errors.js';
|
|
18
|
-
export { serpentInit, Serpent, SerpentCtr, SerpentCbc, SerpentCipher, SerpentGenerator
|
|
19
|
-
export { chacha20Init, ChaCha20, Poly1305, ChaCha20Poly1305, XChaCha20Poly1305, XChaCha20Cipher, ChaCha20Generator
|
|
20
|
-
export { sha2Init, SHA256,
|
|
21
|
-
export { sha3Init, SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, SHAKE256, SHA3_256Hash,
|
|
28
|
+
export { AuthenticationError, SigningError, KeyAgreementError, MerkleCodecError, MerkleLogError } from './errors.js';
|
|
29
|
+
export { serpentInit, Serpent, SerpentCtr, SerpentCbc, SerpentCipher, SerpentGenerator } from './serpent/index.js';
|
|
30
|
+
export { chacha20Init, ChaCha20, Poly1305, ChaCha20Poly1305, XChaCha20Poly1305, XChaCha20Cipher, ChaCha20Generator } from './chacha20/index.js';
|
|
31
|
+
export { sha2Init, SHA256, SHA224, SHA384, SHA512, SHA512_224, SHA512_256, HMAC_SHA256, HMAC_SHA512, HMAC_SHA384, HKDF_SHA256, HKDF_SHA512, SHA256Hash } from './sha2/index.js';
|
|
32
|
+
export { sha3Init, SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHA3_256Stream, SHA3_512Stream, SHAKE128, SHAKE256, SHAKE128Stream, SHAKE256Stream, SHA3_256Hash, CSHAKE128, CSHAKE256, KMAC128, KMAC256, KMACXOF128, KMACXOF256 } from './sha3/index.js';
|
|
22
33
|
export { keccakInit } from './keccak/index.js';
|
|
23
|
-
export {
|
|
24
|
-
export
|
|
34
|
+
export { mlkemInit, MlKem512, MlKem768, MlKem1024, MlKemBase, MlKemSuite } from './mlkem/index.js';
|
|
35
|
+
export { aesInit, AES, AESCbc, AESCtr, AESGCM, AESGCMSIV, AESGenerator, AESGCMSIVCipher } from './aes/index.js';
|
|
36
|
+
export { mldsaInit, MlDsa44, MlDsa65, MlDsa87, MlDsaBase, MLDSA44, MLDSA65, MLDSA87 } from './mldsa/index.js';
|
|
37
|
+
export { slhdsaInit, SlhDsaBase, SlhDsa128f, SlhDsa192f, SlhDsa256f, SLHDSA128F, SLHDSA192F, SLHDSA256F, } from './slhdsa/index.js';
|
|
38
|
+
export { blake3Init, BLAKE3, BLAKE3KeyedHash, BLAKE3DeriveKey, BLAKE3Stream, BLAKE3KeyedHashStream, BLAKE3DeriveKeyStream, BLAKE3OutputReader, BLAKE3Hash, } from './blake3/index.js';
|
|
39
|
+
export { ecdsaP256Init, EcdsaP256, pointDecompress, encodeEcPrivateKey, decodeEcPrivateKey, } from './ecdsa/index.js';
|
|
40
|
+
export type { EcdsaP256KeyPair } from './ecdsa/index.js';
|
|
41
|
+
export { ecdsaSignatureToDer, ecdsaSignatureFromDer } from './ecdsa/der.js';
|
|
42
|
+
export { ed25519Init, Ed25519 } from './ed25519/index.js';
|
|
43
|
+
export type { Ed25519KeyPair } from './ed25519/index.js';
|
|
44
|
+
export { x25519Init, X25519 } from './x25519/index.js';
|
|
45
|
+
export type { X25519KeyPair } from './x25519/index.js';
|
|
46
|
+
export type { MlKemKeyPair, MlKemEncapsulation, MlKemParams } from './mlkem/index.js';
|
|
47
|
+
export type { MlDsaKeyPair, MlDsaParams, PreHashAlgorithm } from './mldsa/index.js';
|
|
48
|
+
export type { SlhDsaKeyPair, SlhDsaParams } from './slhdsa/index.js';
|
|
25
49
|
export { SealStream, OpenStream, Seal, SealStreamPool, FLAG_FRAMED, TAG_DATA, TAG_FINAL, HEADER_SIZE, CHUNK_MIN, CHUNK_MAX } from './stream/index.js';
|
|
26
50
|
export type { CipherSuite, DerivedKeys, SealStreamOpts, PoolOpts } from './stream/index.js';
|
|
51
|
+
export { MemoryStorage, Sha256Hasher, Sha256Tree, Blake3Hasher, Blake3Tree, splitPoint, verifyInclusionProof, verifyConsistencyProof, buildInclusionProof, buildConsistencyProof, serializeCheckpointBody, parseCheckpointBody, emitSignedNote, parseSignedNote, deriveKeyId, suiteFormatEnumToAlgoByte, lookupAlgoEntryByFormatEnum, lookupAlgoEntryByByte, buildCosigSignedMessage, buildCosignedMessage, emitCosigSignaturePayload, parseCosigSignaturePayload, ALGO_BYTE_ED25519_NOTE, ALGO_BYTE_ED25519_COSIG, ALGO_BYTE_MLDSA44_COSIG, SignedLog, MerkleVerifier, MerkleLog, } from './merkle/index.js';
|
|
52
|
+
export type { Hasher, MerkleTree, MerkleStorage, VerifyInclusionInput, VerifyConsistencyInput, BuildInclusionInput, BuildConsistencyInput, GetNode, Checkpoint, SignatureLine, SignedNote, SignedTreeHead, AlgoEntry, MessageConstruction, SignaturePayload, CosignedMessageInput, SignedLogOpts, MerkleVerifierOpts, MerkleLogCreateOpts, MerkleLogGenerateOpts, } from './merkle/index.js';
|
|
53
|
+
export { Sign, SignStream, VerifyStream } from './sign/index.js';
|
|
54
|
+
export type { SignatureSuite, StreamableSignatureSuite, PrehashAlgorithm, } from './sign/index.js';
|
|
55
|
+
export { Ed25519Suite, Ed25519PreHashSuite, EcdsaP256Suite, MlDsa44Suite, MlDsa65Suite, MlDsa87Suite, MlDsa44PreHashSuite, MlDsa65PreHashSuite, MlDsa87PreHashSuite, SlhDsa128fSuite, SlhDsa192fSuite, SlhDsa256fSuite, SlhDsa128fPreHashSuite, SlhDsa192fPreHashSuite, SlhDsa256fPreHashSuite, MlDsa44SlhDsa128fSuite, MlDsa65SlhDsa192fSuite, MlDsa87SlhDsa256fSuite, MlDsa44Ed25519Suite, MlDsa65Ed25519Suite, MlDsa44EcdsaP256Suite, MlDsa65EcdsaP256Suite, } from './sign/index.js';
|
|
27
56
|
export { Fortuna } from './fortuna.js';
|
|
28
57
|
export type { Hash, KeyedHash, Blockcipher, Streamcipher, AEAD, Generator, HashFn } from './types.js';
|
|
29
58
|
export { KDFChain, ratchetInit, kemRatchetEncap, kemRatchetDecap, ratchetReady, SkippedKeyStore, RatchetKeypair, } from './ratchet/index.js';
|
|
30
59
|
export type { RatchetInitResult, KemEncapResult, KemDecapResult, MlKemLike, RatchetMessageHeader, ResolveHandle, SkippedKeyStoreOpts, } from './ratchet/index.js';
|
|
31
|
-
export { hexToBytes, bytesToHex, utf8ToBytes, bytesToUtf8, base64ToBytes, bytesToBase64, constantTimeEqual,
|
|
60
|
+
export { hexToBytes, bytesToHex, utf8ToBytes, bytesToUtf8, base64ToBytes, bytesToBase64, constantTimeEqual, CTE_MAX_BYTES, wipe, xor, concat, randomBytes, hasSIMD, } from './utils.js';
|
package/dist/index.js
CHANGED
|
@@ -19,21 +19,35 @@
|
|
|
19
19
|
// ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
|
|
20
20
|
// ▀█████▀▀
|
|
21
21
|
//
|
|
22
|
-
// Root barrel
|
|
22
|
+
// Root barrel, re-exports everything
|
|
23
23
|
import { serpentInit } from './serpent/index.js';
|
|
24
24
|
import { chacha20Init } from './chacha20/index.js';
|
|
25
25
|
import { sha2Init } from './sha2/index.js';
|
|
26
26
|
import { sha3Init } from './sha3/index.js';
|
|
27
27
|
import { keccakInit } from './keccak/index.js';
|
|
28
|
-
import {
|
|
28
|
+
import { mlkemInit } from './mlkem/index.js';
|
|
29
|
+
import { aesInit } from './aes/index.js';
|
|
30
|
+
import { mldsaInit } from './mldsa/index.js';
|
|
31
|
+
import { slhdsaInit } from './slhdsa/index.js';
|
|
32
|
+
import { blake3Init } from './blake3/index.js';
|
|
33
|
+
import { ecdsaP256Init } from './ecdsa/index.js';
|
|
34
|
+
import { initModule } from './init.js';
|
|
29
35
|
import { hasSIMD } from './utils.js';
|
|
36
|
+
// curve25519 backs ed25519 + x25519. Public surface is the
|
|
37
|
+
// per-primitive alias; 'curve25519' key accepted for Module symmetry.
|
|
30
38
|
const _dispatchers = {
|
|
31
39
|
serpent: serpentInit,
|
|
32
40
|
chacha20: chacha20Init,
|
|
33
41
|
sha2: sha2Init,
|
|
34
42
|
sha3: sha3Init,
|
|
35
43
|
keccak: keccakInit,
|
|
36
|
-
|
|
44
|
+
mlkem: mlkemInit,
|
|
45
|
+
aes: aesInit,
|
|
46
|
+
mldsa: mldsaInit,
|
|
47
|
+
slhdsa: slhdsaInit,
|
|
48
|
+
blake3: blake3Init,
|
|
49
|
+
curve25519: (source) => initModule('curve25519', source),
|
|
50
|
+
p256: ecdsaP256Init,
|
|
37
51
|
};
|
|
38
52
|
/**
|
|
39
53
|
* Load one or more WASM modules. Each key is a module name; the value is the
|
|
@@ -45,30 +59,60 @@ const _dispatchers = {
|
|
|
45
59
|
* import { sha2Wasm } from 'leviathan-crypto/sha2/embedded';
|
|
46
60
|
* await init({ serpent: serpentWasm, sha2: sha2Wasm });
|
|
47
61
|
* ```
|
|
62
|
+
*
|
|
63
|
+
* `ed25519` and `x25519` are aliases for the underlying `curve25519`
|
|
64
|
+
* module. `init({ ed25519: src })` and `init({ x25519: src })` both work,
|
|
65
|
+
* and `init({ ed25519: src, x25519: src })` is accepted (single underlying
|
|
66
|
+
* init). Two different sources for the same underlying module is rejected.
|
|
48
67
|
*/
|
|
49
68
|
export async function init(sources) {
|
|
50
69
|
const entries = Object.entries(sources);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
throw new Error('leviathan-crypto: serpent, chacha20, and kyber require WebAssembly SIMD — '
|
|
54
|
-
+ 'this runtime does not support it');
|
|
55
|
-
for (const [mod, src] of entries) {
|
|
56
|
-
if (!Object.hasOwn(_dispatchers, mod))
|
|
57
|
-
throw new Error(`leviathan-crypto: unknown module "${mod}" — expected one of: ${Object.keys(_dispatchers).join(', ')}`);
|
|
70
|
+
const resolved = new Map();
|
|
71
|
+
for (const [key, src] of entries) {
|
|
58
72
|
if (src == null)
|
|
59
|
-
throw new TypeError(`leviathan-crypto: source for "${
|
|
73
|
+
throw new TypeError(`leviathan-crypto: source for "${key}" is null or undefined`);
|
|
74
|
+
const target = (key === 'ed25519' || key === 'x25519') ? 'curve25519' : key;
|
|
75
|
+
if (!Object.hasOwn(_dispatchers, target))
|
|
76
|
+
throw new Error(`leviathan-crypto: unknown module "${key}", expected one of: `
|
|
77
|
+
+ `${Object.keys(_dispatchers).join(', ')}, ed25519, x25519`);
|
|
78
|
+
const prior = resolved.get(target);
|
|
79
|
+
if (prior !== undefined) {
|
|
80
|
+
if (prior !== src)
|
|
81
|
+
throw new Error('leviathan-crypto: init() called with different sources for "ed25519" and "x25519" '
|
|
82
|
+
+ '(both alias to curve25519, sources must be identical)');
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
resolved.set(target, src);
|
|
60
86
|
}
|
|
61
|
-
|
|
87
|
+
// SIMD preflight for modules that contain v128 instructions
|
|
88
|
+
// (see scripts/lib/modules.ts).
|
|
89
|
+
if ((resolved.has('serpent') || resolved.has('chacha20') || resolved.has('mlkem')
|
|
90
|
+
|| resolved.has('aes') || resolved.has('mldsa') || resolved.has('blake3'))
|
|
91
|
+
&& !hasSIMD())
|
|
92
|
+
throw new Error('leviathan-crypto: serpent, chacha20, mlkem, aes, mldsa, and blake3 require WebAssembly SIMD, '
|
|
93
|
+
+ 'this runtime does not support it');
|
|
94
|
+
await Promise.all(Array.from(resolved.entries()).map(([mod, src]) => _dispatchers[mod](src)));
|
|
62
95
|
}
|
|
63
96
|
export { isInitialized } from './init.js';
|
|
64
|
-
export { AuthenticationError } from './errors.js';
|
|
65
|
-
export { serpentInit, Serpent, SerpentCtr, SerpentCbc, SerpentCipher, SerpentGenerator
|
|
66
|
-
export { chacha20Init, ChaCha20, Poly1305, ChaCha20Poly1305, XChaCha20Poly1305, XChaCha20Cipher, ChaCha20Generator
|
|
67
|
-
export { sha2Init, SHA256,
|
|
68
|
-
export { sha3Init, SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, SHAKE256, SHA3_256Hash,
|
|
97
|
+
export { AuthenticationError, SigningError, KeyAgreementError, MerkleCodecError, MerkleLogError } from './errors.js';
|
|
98
|
+
export { serpentInit, Serpent, SerpentCtr, SerpentCbc, SerpentCipher, SerpentGenerator } from './serpent/index.js';
|
|
99
|
+
export { chacha20Init, ChaCha20, Poly1305, ChaCha20Poly1305, XChaCha20Poly1305, XChaCha20Cipher, ChaCha20Generator } from './chacha20/index.js';
|
|
100
|
+
export { sha2Init, SHA256, SHA224, SHA384, SHA512, SHA512_224, SHA512_256, HMAC_SHA256, HMAC_SHA512, HMAC_SHA384, HKDF_SHA256, HKDF_SHA512, SHA256Hash } from './sha2/index.js';
|
|
101
|
+
export { sha3Init, SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHA3_256Stream, SHA3_512Stream, SHAKE128, SHAKE256, SHAKE128Stream, SHAKE256Stream, SHA3_256Hash, CSHAKE128, CSHAKE256, KMAC128, KMAC256, KMACXOF128, KMACXOF256 } from './sha3/index.js';
|
|
69
102
|
export { keccakInit } from './keccak/index.js';
|
|
70
|
-
export {
|
|
103
|
+
export { mlkemInit, MlKem512, MlKem768, MlKem1024, MlKemBase, MlKemSuite } from './mlkem/index.js';
|
|
104
|
+
export { aesInit, AES, AESCbc, AESCtr, AESGCM, AESGCMSIV, AESGenerator, AESGCMSIVCipher } from './aes/index.js';
|
|
105
|
+
export { mldsaInit, MlDsa44, MlDsa65, MlDsa87, MlDsaBase, MLDSA44, MLDSA65, MLDSA87 } from './mldsa/index.js';
|
|
106
|
+
export { slhdsaInit, SlhDsaBase, SlhDsa128f, SlhDsa192f, SlhDsa256f, SLHDSA128F, SLHDSA192F, SLHDSA256F, } from './slhdsa/index.js';
|
|
107
|
+
export { blake3Init, BLAKE3, BLAKE3KeyedHash, BLAKE3DeriveKey, BLAKE3Stream, BLAKE3KeyedHashStream, BLAKE3DeriveKeyStream, BLAKE3OutputReader, BLAKE3Hash, } from './blake3/index.js';
|
|
108
|
+
export { ecdsaP256Init, EcdsaP256, pointDecompress, encodeEcPrivateKey, decodeEcPrivateKey, } from './ecdsa/index.js';
|
|
109
|
+
export { ecdsaSignatureToDer, ecdsaSignatureFromDer } from './ecdsa/der.js';
|
|
110
|
+
export { ed25519Init, Ed25519 } from './ed25519/index.js';
|
|
111
|
+
export { x25519Init, X25519 } from './x25519/index.js';
|
|
71
112
|
export { SealStream, OpenStream, Seal, SealStreamPool, FLAG_FRAMED, TAG_DATA, TAG_FINAL, HEADER_SIZE, CHUNK_MIN, CHUNK_MAX } from './stream/index.js';
|
|
113
|
+
export { MemoryStorage, Sha256Hasher, Sha256Tree, Blake3Hasher, Blake3Tree, splitPoint, verifyInclusionProof, verifyConsistencyProof, buildInclusionProof, buildConsistencyProof, serializeCheckpointBody, parseCheckpointBody, emitSignedNote, parseSignedNote, deriveKeyId, suiteFormatEnumToAlgoByte, lookupAlgoEntryByFormatEnum, lookupAlgoEntryByByte, buildCosigSignedMessage, buildCosignedMessage, emitCosigSignaturePayload, parseCosigSignaturePayload, ALGO_BYTE_ED25519_NOTE, ALGO_BYTE_ED25519_COSIG, ALGO_BYTE_MLDSA44_COSIG, SignedLog, MerkleVerifier, MerkleLog, } from './merkle/index.js';
|
|
114
|
+
export { Sign, SignStream, VerifyStream } from './sign/index.js';
|
|
115
|
+
export { Ed25519Suite, Ed25519PreHashSuite, EcdsaP256Suite, MlDsa44Suite, MlDsa65Suite, MlDsa87Suite, MlDsa44PreHashSuite, MlDsa65PreHashSuite, MlDsa87PreHashSuite, SlhDsa128fSuite, SlhDsa192fSuite, SlhDsa256fSuite, SlhDsa128fPreHashSuite, SlhDsa192fPreHashSuite, SlhDsa256fPreHashSuite, MlDsa44SlhDsa128fSuite, MlDsa65SlhDsa192fSuite, MlDsa87SlhDsa256fSuite, MlDsa44Ed25519Suite, MlDsa65Ed25519Suite, MlDsa44EcdsaP256Suite, MlDsa65EcdsaP256Suite, } from './sign/index.js';
|
|
72
116
|
export { Fortuna } from './fortuna.js';
|
|
73
117
|
export { KDFChain, ratchetInit, kemRatchetEncap, kemRatchetDecap, ratchetReady, SkippedKeyStore, RatchetKeypair, } from './ratchet/index.js';
|
|
74
|
-
export { hexToBytes, bytesToHex, utf8ToBytes, bytesToUtf8, base64ToBytes, bytesToBase64, constantTimeEqual,
|
|
118
|
+
export { hexToBytes, bytesToHex, utf8ToBytes, bytesToUtf8, base64ToBytes, bytesToBase64, constantTimeEqual, CTE_MAX_BYTES, wipe, xor, concat, randomBytes, hasSIMD, } from './utils.js';
|
package/dist/init.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { WasmSource } from './wasm-source.js';
|
|
2
|
-
export type Module = 'serpent' | 'chacha20' | 'sha2' | 'sha3' | 'keccak' | '
|
|
2
|
+
export type Module = 'serpent' | 'chacha20' | 'sha2' | 'sha3' | 'keccak' | 'mlkem' | 'aes' | 'mldsa' | 'slhdsa' | 'blake3' | 'curve25519' | 'p256';
|
|
3
3
|
export declare function initModule(mod: Module, source: WasmSource): Promise<void>;
|
|
4
4
|
export declare function getInstance(mod: Module): WebAssembly.Instance;
|
|
5
5
|
export declare function isInitialized(mod: Module): boolean;
|
package/dist/init.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { loadWasm } from './loader.js';
|
|
2
2
|
import { hasSIMD } from './utils.js';
|
|
3
|
-
// 'keccak' is an alias for 'sha3'
|
|
3
|
+
// 'keccak' is an alias for 'sha3', same WASM binary, same instance slot
|
|
4
4
|
const ALIASES = { keccak: 'sha3' };
|
|
5
5
|
function resolve(mod) {
|
|
6
6
|
return ALIASES[mod] ?? mod;
|
|
7
7
|
}
|
|
8
|
-
//
|
|
8
|
+
// Per-canonical-module instance cache.
|
|
9
9
|
const instances = new Map();
|
|
10
|
-
//
|
|
10
|
+
// Coalesces concurrent initModule calls.
|
|
11
11
|
const pending = new Map();
|
|
12
|
-
//
|
|
13
|
-
// for its entire lifetime. Prevents shared-WASM-state clobber when two
|
|
14
|
-
// instances from the same module would otherwise trample each other's memory.
|
|
12
|
+
// Per-module exclusivity token held by a stateful wrapper.
|
|
15
13
|
const owners = new Map();
|
|
16
14
|
export async function initModule(mod, source) {
|
|
17
15
|
const resolved = resolve(mod);
|
|
@@ -22,8 +20,8 @@ export async function initModule(mod, source) {
|
|
|
22
20
|
await inflight;
|
|
23
21
|
return;
|
|
24
22
|
}
|
|
25
|
-
if ((resolved === 'serpent' || resolved === 'chacha20' || resolved === '
|
|
26
|
-
throw new Error('leviathan-crypto: serpent, chacha20, and
|
|
23
|
+
if ((resolved === 'serpent' || resolved === 'chacha20' || resolved === 'mlkem' || resolved === 'aes' || resolved === 'mldsa' || resolved === 'blake3') && !hasSIMD())
|
|
24
|
+
throw new Error('leviathan-crypto: serpent, chacha20, mlkem, aes, mldsa, and blake3 require WebAssembly SIMD, '
|
|
27
25
|
+ 'this runtime does not support it');
|
|
28
26
|
const p = loadWasm(source);
|
|
29
27
|
pending.set(resolved, p);
|
|
@@ -41,7 +39,7 @@ export function getInstance(mod) {
|
|
|
41
39
|
throw new Error(`leviathan-crypto: call init({ ${mod}: ... }) before using this class`);
|
|
42
40
|
}
|
|
43
41
|
if (owners.has(r)) {
|
|
44
|
-
throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module
|
|
42
|
+
throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module, `
|
|
45
43
|
+ 'call dispose() on it before constructing a new one');
|
|
46
44
|
}
|
|
47
45
|
return inst;
|
|
@@ -57,7 +55,7 @@ export function isInitialized(mod) {
|
|
|
57
55
|
export function _acquireModule(mod) {
|
|
58
56
|
const r = resolve(mod);
|
|
59
57
|
if (owners.has(r))
|
|
60
|
-
throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module
|
|
58
|
+
throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module, `
|
|
61
59
|
+ 'call dispose() on it before constructing a new one');
|
|
62
60
|
const tok = Symbol(r);
|
|
63
61
|
owners.set(r, tok);
|
|
@@ -80,27 +78,15 @@ export function _releaseModule(mod, tok) {
|
|
|
80
78
|
export function _isModuleBusy(mod) {
|
|
81
79
|
return owners.has(resolve(mod));
|
|
82
80
|
}
|
|
83
|
-
/**
|
|
84
|
-
* Throw if `mod` is currently held by a stateful instance. Called at the top
|
|
85
|
-
* of every atomic WASM-touching method so that cached-exports access paths
|
|
86
|
-
* cannot silently clobber a live stateful instance's WASM state.
|
|
87
|
-
*
|
|
88
|
-
* The error message is intentionally identical to `_acquireModule`'s so that
|
|
89
|
-
* error handlers matching on text work uniformly across construction-time and
|
|
90
|
-
* method-time ownership failures.
|
|
91
|
-
* @internal
|
|
92
|
-
*/
|
|
81
|
+
/** @internal */
|
|
93
82
|
export function _assertNotOwned(mod) {
|
|
94
|
-
// Deliberately unoptimized. Do not add caching or epoch tracking: the
|
|
95
|
-
// check must read current ownership on every call so an atomic op cannot
|
|
96
|
-
// race ahead of a stateful acquirer.
|
|
97
83
|
const r = resolve(mod);
|
|
98
84
|
if (owners.has(r))
|
|
99
|
-
throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module
|
|
85
|
+
throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module, `
|
|
100
86
|
+ 'call dispose() on it before constructing a new one');
|
|
101
87
|
}
|
|
102
88
|
/**
|
|
103
|
-
* Reset all cached instances
|
|
89
|
+
* Reset all cached instances, for testing only. Clears `instances`, `pending`,
|
|
104
90
|
* and `owners` so tests can re-exercise module lifecycle (init, exclusivity,
|
|
105
91
|
* race) from a known-empty state.
|
|
106
92
|
* @internal
|
package/dist/keccak/embedded.js
CHANGED
|
@@ -22,6 +22,6 @@
|
|
|
22
22
|
// src/ts/keccak/embedded.ts
|
|
23
23
|
//
|
|
24
24
|
// Re-exports the sha3 WASM blob under the keccak name.
|
|
25
|
-
// The keccak alias shares the sha3 binary
|
|
25
|
+
// The keccak alias shares the sha3 binary, no separate keccak.wasm exists.
|
|
26
26
|
// Import via `leviathan-crypto/keccak/embedded`.
|
|
27
27
|
export { WASM_GZ_BASE64 as keccakWasm } from '../embedded/sha3.js';
|
package/dist/keccak/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { WasmSource } from '../wasm-source.js';
|
|
2
2
|
export declare function keccakInit(source: WasmSource): Promise<void>;
|
|
3
3
|
export type { WasmSource };
|
|
4
|
+
export { isInitialized } from '../init.js';
|
|
4
5
|
export { SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, SHAKE256 } from '../sha3/index.js';
|
|
6
|
+
export { CSHAKE128, CSHAKE256, KMAC128, KMAC256, KMACXOF128, KMACXOF256 } from '../sha3/index.js';
|
package/dist/keccak/index.js
CHANGED
|
@@ -21,11 +21,13 @@
|
|
|
21
21
|
//
|
|
22
22
|
// src/ts/keccak/index.ts
|
|
23
23
|
//
|
|
24
|
-
// Keccak alias subpath
|
|
25
|
-
// Consumers who prefer the Keccak name (e.g.
|
|
24
|
+
// Keccak alias subpath, resolves to the sha3 WASM module slot.
|
|
25
|
+
// Consumers who prefer the Keccak name (e.g. ML-KEM implementations)
|
|
26
26
|
// can import from `leviathan-crypto/keccak` instead of `leviathan-crypto/sha3`.
|
|
27
27
|
import { initModule } from '../init.js';
|
|
28
28
|
export async function keccakInit(source) {
|
|
29
29
|
return initModule('keccak', source);
|
|
30
30
|
}
|
|
31
|
+
export { isInitialized } from '../init.js';
|
|
31
32
|
export { SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, SHAKE256 } from '../sha3/index.js';
|
|
33
|
+
export { CSHAKE128, CSHAKE256, KMAC128, KMAC256, KMACXOF128, KMACXOF256 } from '../sha3/index.js';
|
package/dist/loader.d.ts
CHANGED
|
@@ -1,24 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Decode a gzip+base64 embedded WASM string to raw bytes.
|
|
4
|
-
* Guards against missing DecompressionStream (Node <18, non-browser runtimes).
|
|
5
|
-
* Exported for pool worker launchers that decode blobs before spawning threads.
|
|
6
|
-
*/
|
|
7
|
-
export declare function decodeWasm(b64: string): Promise<Uint8Array>;
|
|
8
|
-
/**
|
|
9
|
-
* Compile a WASM source to a Module without instantiating.
|
|
10
|
-
* Used by pool infrastructure to send compiled modules to workers.
|
|
11
|
-
*
|
|
12
|
-
* Thenable sources (Promise<Response>, Promise<ArrayBuffer>, etc.) are
|
|
13
|
-
* resolved and then re-dispatched by the runtime type of the resolved value.
|
|
14
|
-
* Depth is capped at `MAX_THENABLE_DEPTH` to prevent runaway recursion.
|
|
15
|
-
*/
|
|
16
|
-
export declare function compileWasm(source: WasmSource, _depth?: number): Promise<WebAssembly.Module>;
|
|
17
|
-
/**
|
|
18
|
-
* Load a WASM module from any accepted source type.
|
|
19
|
-
* The loading strategy is inferred from the argument type — no mode string.
|
|
20
|
-
*
|
|
21
|
-
* Throws `TypeError` for null, numeric, or unrecognised inputs, or if a
|
|
22
|
-
* thenable source nests deeper than `MAX_THENABLE_DEPTH`.
|
|
23
|
-
*/
|
|
24
|
-
export declare function loadWasm(source: WasmSource): Promise<WebAssembly.Instance>;
|
|
1
|
+
export {};
|