leviathan-crypto 2.0.1 → 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 +88 -281
- package/LICENSE +4 -0
- package/README.md +275 -87
- 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.d.ts +10 -0
- package/dist/chacha20/cipher-suite.js +98 -13
- package/dist/chacha20/generator.d.ts +12 -0
- package/dist/chacha20/generator.js +91 -0
- package/dist/chacha20/index.d.ts +100 -3
- package/dist/chacha20/index.js +169 -35
- package/dist/chacha20/ops.d.ts +57 -6
- package/dist/chacha20/ops.js +107 -27
- package/dist/chacha20/pool-worker.js +14 -0
- package/dist/chacha20/types.d.ts +1 -32
- package/dist/cte-wasm.d.ts +1 -0
- package/dist/cte-wasm.js +3 -0
- package/dist/cte.wasm +0 -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 -0
- package/dist/embedded/chacha20-pool-worker.js +5 -0
- 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 -0
- package/dist/embedded/serpent-pool-worker.js +5 -0
- 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 +18 -12
- package/dist/fortuna.js +166 -99
- package/dist/index.d.ts +42 -11
- package/dist/index.js +65 -20
- package/dist/init.d.ts +1 -3
- package/dist/init.js +73 -7
- 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 -19
- package/dist/loader.js +26 -32
- 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 +48 -48
- package/dist/mlkem/index.d.ts +37 -0
- package/dist/{kyber → mlkem}/index.js +41 -31
- package/dist/mlkem/kem.d.ts +21 -0
- package/dist/{kyber → mlkem}/kem.js +48 -13
- 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 +4 -3
- package/dist/{kyber → mlkem}/types.js +1 -1
- package/dist/mlkem/validate.d.ts +23 -0
- package/dist/{kyber → mlkem}/validate.js +24 -20
- package/dist/{kyber.wasm → mlkem.wasm} +0 -0
- package/dist/p256.wasm +0 -0
- package/dist/ratchet/index.d.ts +8 -0
- package/dist/ratchet/index.js +38 -0
- package/dist/ratchet/kdf-chain.d.ts +13 -0
- package/dist/ratchet/kdf-chain.js +85 -0
- package/dist/ratchet/ratchet-keypair.d.ts +9 -0
- package/dist/ratchet/ratchet-keypair.js +61 -0
- package/dist/ratchet/root-kdf.d.ts +4 -0
- package/dist/ratchet/root-kdf.js +124 -0
- package/dist/ratchet/skipped-key-store.d.ts +14 -0
- package/dist/ratchet/skipped-key-store.js +154 -0
- package/dist/ratchet/types.d.ts +36 -0
- package/dist/ratchet/types.js +26 -0
- package/dist/serpent/cipher-suite.d.ts +10 -0
- package/dist/serpent/cipher-suite.js +144 -56
- package/dist/serpent/generator.d.ts +12 -0
- package/dist/serpent/generator.js +97 -0
- package/dist/serpent/index.d.ts +62 -1
- package/dist/serpent/index.js +97 -21
- package/dist/serpent/pool-worker.js +28 -102
- package/dist/serpent/serpent-cbc.d.ts +16 -6
- package/dist/serpent/serpent-cbc.js +58 -37
- package/dist/serpent/shared-ops.d.ts +63 -0
- package/dist/serpent/shared-ops.js +178 -0
- package/dist/serpent/types.d.ts +1 -5
- package/dist/serpent.wasm +0 -0
- package/dist/sha2/hash.d.ts +2 -0
- package/dist/sha2/hash.js +53 -0
- package/dist/sha2/hkdf.js +5 -5
- package/dist/sha2/index.d.ts +22 -1
- package/dist/sha2/index.js +80 -11
- package/dist/sha2/types.d.ts +41 -2
- package/dist/sha2.wasm +0 -0
- package/dist/sha3/hash.d.ts +2 -0
- package/dist/sha3/hash.js +53 -0
- package/dist/sha3/index.d.ts +87 -3
- package/dist/sha3/index.js +317 -19
- 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 +8 -8
- package/dist/stream/index.d.ts +1 -0
- package/dist/stream/index.js +1 -0
- package/dist/stream/open-stream.js +65 -22
- package/dist/stream/seal-stream-pool.d.ts +2 -0
- package/dist/stream/seal-stream-pool.js +100 -33
- package/dist/stream/seal-stream.d.ts +1 -1
- package/dist/stream/seal-stream.js +48 -19
- 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 +22 -1
- package/dist/types.js +1 -1
- package/dist/utils.d.ts +9 -10
- package/dist/utils.js +84 -59
- package/dist/wasm-source.d.ts +9 -8
- 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 +123 -64
- package/SECURITY.md +0 -276
- package/dist/ct-wasm.d.ts +0 -1
- package/dist/ct-wasm.js +0 -3
- package/dist/ct.wasm +0 -0
- package/dist/docs/aead.md +0 -323
- package/dist/docs/architecture.md +0 -932
- package/dist/docs/argon2id.md +0 -302
- package/dist/docs/chacha20.md +0 -674
- package/dist/docs/exports.md +0 -241
- package/dist/docs/fortuna.md +0 -313
- package/dist/docs/init.md +0 -302
- package/dist/docs/loader.md +0 -161
- package/dist/docs/serpent.md +0 -519
- package/dist/docs/sha2.md +0 -613
- package/dist/docs/sha3.md +0 -546
- package/dist/docs/types.md +0 -276
- package/dist/docs/utils.md +0 -367
- 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 -13
- package/dist/kyber/validate.d.ts +0 -19
package/dist/docs/exports.md
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
# All Exports
|
|
2
|
-
|
|
3
|
-
> [!NOTE]
|
|
4
|
-
> Complete reference for every public export in leviathan-crypto, grouped by module. Follow the module links for deeper documentation on each class.
|
|
5
|
-
|
|
6
|
-
> ### Table of Contents
|
|
7
|
-
> - [Initialization](#initialization)
|
|
8
|
-
> - [Serpent-256](#serpent-256)
|
|
9
|
-
> - [Stream](#stream)
|
|
10
|
-
> - [Errors](#errors)
|
|
11
|
-
> - [XChaCha20 / Poly1305](#xchacha20--poly1305)
|
|
12
|
-
> - [SHA-2](#sha-2)
|
|
13
|
-
> - [SHA-3](#sha-3)
|
|
14
|
-
> - [Keccak (alias for SHA-3)](#keccak-alias-for-sha-3)
|
|
15
|
-
> - [ML-KEM (Post-quantum KEM)](#ml-kem-post-quantum-kem)
|
|
16
|
-
> - [Fortuna CSPRNG](#fortuna-csprng)
|
|
17
|
-
> - [Types](#types)
|
|
18
|
-
> - [Utilities](#utilities)
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## Initialization
|
|
23
|
-
|
|
24
|
-
Root barrel `leviathan-crypto`. No module required.
|
|
25
|
-
|
|
26
|
-
| Export | Kind | Description |
|
|
27
|
-
|--------|------|-------------|
|
|
28
|
-
| `init` | function | Load and cache WASM modules. `init(sources: Partial<Record<Module, WasmSource>>)`. |
|
|
29
|
-
| `isInitialized` | function | `isInitialized(mod: Module): boolean`. Returns `true` if the given module has been loaded. Useful for diagnostic checks. |
|
|
30
|
-
| `Module` | type | `'serpent' \| 'chacha20' \| 'sha2' \| 'sha3' \| 'keccak' \| 'kyber'` |
|
|
31
|
-
| `WasmSource` | type | Union of all accepted WASM loading strategies. See below. |
|
|
32
|
-
|
|
33
|
-
**`WasmSource`** accepted by every init function:
|
|
34
|
-
|
|
35
|
-
| Value | Strategy |
|
|
36
|
-
|-------|----------|
|
|
37
|
-
| `string` | Decode gzip+base64 embedded blob |
|
|
38
|
-
| `URL` | `fetch` + `instantiateStreaming` |
|
|
39
|
-
| `ArrayBuffer` | Compile from raw WASM bytes |
|
|
40
|
-
| `Uint8Array` | Compile from raw WASM bytes |
|
|
41
|
-
| `WebAssembly.Module` | Instantiate pre-compiled module |
|
|
42
|
-
| `Response` | `instantiateStreaming` from fetch response |
|
|
43
|
-
| `Promise<Response>` | `instantiateStreaming` from deferred fetch |
|
|
44
|
-
|
|
45
|
-
See [init.md](./init.md) for full loading documentation.
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## Serpent-256
|
|
50
|
-
|
|
51
|
-
Requires `init({ serpent: serpentWasm, sha2: sha2Wasm })` for authenticated classes, `init({ serpent: serpentWasm })` for raw modes.
|
|
52
|
-
Subpath: `leviathan-crypto/serpent`. See [serpent.md](./serpent.md).
|
|
53
|
-
|
|
54
|
-
| Export | Kind | Description |
|
|
55
|
-
|--------|------|-------------|
|
|
56
|
-
| `serpentInit` | function | Module-scoped init. `serpentInit(source: WasmSource)` loads only serpent. |
|
|
57
|
-
| `SerpentCipher` | const | `CipherSuite` for Serpent-256 CBC+HMAC-SHA-256. `keygen()` → 32-byte key. `formatEnum: 0x02`, `keySize: 32`, `tagSize: 32`, `padded: true`. Used with `Seal`, `SealStream`, `OpenStream`. |
|
|
58
|
-
| `Serpent` | class | Serpent-256 ECB block cipher. `loadKey()`, `encryptBlock()`, `decryptBlock()`. Unauthenticated. |
|
|
59
|
-
| `SerpentCtr` | class | Serpent-256 CTR mode. `beginEncrypt()`, `encryptChunk()`, `beginDecrypt()`, `decryptChunk()`. Unauthenticated. |
|
|
60
|
-
| `SerpentCbc` | class | Serpent-256 CBC mode with PKCS7 padding. `encrypt(key, iv, plaintext)`, `decrypt(key, iv, ciphertext)`. Unauthenticated. |
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## Stream
|
|
65
|
-
|
|
66
|
-
Cipher-agnostic streaming encryption using the STREAM construction.
|
|
67
|
-
Subpath: `leviathan-crypto/stream`. See [aead.md](./aead.md).
|
|
68
|
-
|
|
69
|
-
| Export | Kind | Description |
|
|
70
|
-
|--------|------|-------------|
|
|
71
|
-
| `Seal` | class (static) | One-shot AEAD. `Seal.encrypt(suite, key, plaintext)` / `Seal.decrypt(suite, key, blob)`. Works with any `CipherSuite` including `KyberSuite`. Never instantiated. |
|
|
72
|
-
| `SealStream` | class | Cipher-agnostic streaming encryption (STREAM construction). `push(chunk)`, `finalize(chunk)`, `toTransformStream()`. |
|
|
73
|
-
| `OpenStream` | class | Cipher-agnostic streaming decryption. `pull(chunk)`, `finalize(chunk)`, `seek(index)`, `toTransformStream()`. |
|
|
74
|
-
| `SealStreamPool` | class | Parallel batch seal/open via Web Workers. `SealStreamPool.create(cipher, key, opts)` static factory. |
|
|
75
|
-
| `CipherSuite` | interface | Cipher-specific logic injected into SealStream/OpenStream. Implementations: `XChaCha20Cipher`, `SerpentCipher`, `KyberSuite`. See [ciphersuite.md](./ciphersuite.md). |
|
|
76
|
-
| `DerivedKeys` | interface | Opaque key material returned by `CipherSuite.deriveKeys()`. |
|
|
77
|
-
| `SealStreamOpts` | type | Options for SealStream: `chunkSize?`, `framed?`. |
|
|
78
|
-
| `PoolOpts` | type | Options for SealStreamPool: `wasm`, `workers?`, `chunkSize?`, `framed?`, `jobTimeout?`. |
|
|
79
|
-
| `HEADER_SIZE` | const | Stream header size in bytes (20). |
|
|
80
|
-
| `CHUNK_MIN` | const | Minimum chunk size (1024). |
|
|
81
|
-
| `CHUNK_MAX` | const | Maximum chunk size (16777215, u24 max). |
|
|
82
|
-
| `FLAG_FRAMED` | const | Header byte 0 framed flag (0x80). |
|
|
83
|
-
| `TAG_DATA` | const | Counter nonce final flag for data chunks (0x00). |
|
|
84
|
-
| `TAG_FINAL` | const | Counter nonce final flag for final chunk (0x01). |
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## Errors
|
|
89
|
-
|
|
90
|
-
| Export | Kind | Description |
|
|
91
|
-
|--------|------|-------------|
|
|
92
|
-
| `AuthenticationError` | class | Thrown on AEAD auth failure. Extends `Error`. Constructor takes cipher name string. |
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## XChaCha20 / Poly1305
|
|
97
|
-
|
|
98
|
-
Requires `init({ chacha20: chacha20Wasm })` or subpath `chacha20Init()`.
|
|
99
|
-
Subpath: `leviathan-crypto/chacha20`. See [chacha20.md](./chacha20.md).
|
|
100
|
-
|
|
101
|
-
| Export | Kind | Description |
|
|
102
|
-
|--------|------|-------------|
|
|
103
|
-
| `chacha20Init` | function | Module-scoped init. `chacha20Init(source: WasmSource)` loads only chacha20. |
|
|
104
|
-
| `XChaCha20Poly1305` | class | XChaCha20-Poly1305 AEAD. 24-byte nonce. `encrypt()` returns single `Uint8Array` (ct‖tag), `decrypt()` accepts same format. Single-use encrypt guard. |
|
|
105
|
-
| `XChaCha20Cipher` | const | `CipherSuite` for XChaCha20-Poly1305. `keygen()` → 32-byte key. `formatEnum: 0x01`, `keySize: 32`, `tagSize: 16`, `padded: false`. Used with `Seal`, `SealStream`, `OpenStream`. |
|
|
106
|
-
| `ChaCha20Poly1305` | class | ChaCha20-Poly1305 AEAD (RFC 8439). 12-byte nonce. `encrypt()` returns single `Uint8Array` (ct‖tag), `decrypt()` accepts same format. Single-use encrypt guard. |
|
|
107
|
-
| `ChaCha20` | class | ChaCha20 stream cipher (RFC 8439). `beginEncrypt()`, `encryptChunk()`. Unauthenticated. |
|
|
108
|
-
| `Poly1305` | class | Poly1305 one-time MAC (RFC 8439). `mac(key, msg)`. |
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
## SHA-2
|
|
113
|
-
|
|
114
|
-
Requires `init({ sha2: sha2Wasm })` or subpath `sha2Init(source)`.
|
|
115
|
-
Subpath: `leviathan-crypto/sha2`. See [sha2.md](./sha2.md).
|
|
116
|
-
|
|
117
|
-
| Export | Kind | Description |
|
|
118
|
-
|--------|------|-------------|
|
|
119
|
-
| `sha2Init` | function | Module-scoped init. `sha2Init(source: WasmSource)` loads only sha2. |
|
|
120
|
-
| `SHA256` | class | SHA-256 hash (FIPS 180-4). `hash(msg)` returns 32 bytes. |
|
|
121
|
-
| `SHA384` | class | SHA-384 hash (FIPS 180-4). `hash(msg)` returns 48 bytes. |
|
|
122
|
-
| `SHA512` | class | SHA-512 hash (FIPS 180-4). `hash(msg)` returns 64 bytes. |
|
|
123
|
-
| `HMAC_SHA256` | class | HMAC-SHA256 (RFC 2104). `hash(key, msg)` returns 32 bytes. |
|
|
124
|
-
| `HMAC_SHA384` | class | HMAC-SHA384 (RFC 2104). `hash(key, msg)` returns 48 bytes. |
|
|
125
|
-
| `HMAC_SHA512` | class | HMAC-SHA512 (RFC 2104). `hash(key, msg)` returns 64 bytes. |
|
|
126
|
-
| `HKDF_SHA256` | class | HKDF with HMAC-SHA256 (RFC 5869). `derive(ikm, salt, info, length)`. |
|
|
127
|
-
| `HKDF_SHA512` | class | HKDF with HMAC-SHA512 (RFC 5869). `derive(ikm, salt, info, length)`. |
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## SHA-3
|
|
132
|
-
|
|
133
|
-
Requires `init({ sha3: sha3Wasm })` or subpath `sha3Init(source)`.
|
|
134
|
-
Subpath: `leviathan-crypto/sha3`. See [sha3.md](./sha3.md).
|
|
135
|
-
|
|
136
|
-
| Export | Kind | Description |
|
|
137
|
-
|--------|------|-------------|
|
|
138
|
-
| `sha3Init` | function | Module-scoped init. `sha3Init(source: WasmSource)` loads only sha3. |
|
|
139
|
-
| `SHA3_224` | class | SHA3-224 hash (FIPS 202). `hash(msg)` returns 28 bytes. |
|
|
140
|
-
| `SHA3_256` | class | SHA3-256 hash (FIPS 202). `hash(msg)` returns 32 bytes. |
|
|
141
|
-
| `SHA3_384` | class | SHA3-384 hash (FIPS 202). `hash(msg)` returns 48 bytes. |
|
|
142
|
-
| `SHA3_512` | class | SHA3-512 hash (FIPS 202). `hash(msg)` returns 64 bytes. |
|
|
143
|
-
| `SHAKE128` | class | SHAKE128 XOF (FIPS 202). Unbounded output. `hash(msg, outputLength)`, `absorb(msg)`, `squeeze(n)`, `reset()`. |
|
|
144
|
-
| `SHAKE256` | class | SHAKE256 XOF (FIPS 202). Unbounded output. `hash(msg, outputLength)`, `absorb(msg)`, `squeeze(n)`, `reset()`. |
|
|
145
|
-
|
|
146
|
-
---
|
|
147
|
-
|
|
148
|
-
## Keccak (alias for SHA-3)
|
|
149
|
-
|
|
150
|
-
`'keccak'` is an alias for `'sha3'`. Same WASM binary, same instance slot.
|
|
151
|
-
Both `init({ sha3: sha3Wasm })` and `init({ keccak: keccakWasm })` load the same module.
|
|
152
|
-
Provided so Kyber/ML-KEM consumers can use the semantically correct primitive name.
|
|
153
|
-
Subpath: `leviathan-crypto/keccak`.
|
|
154
|
-
|
|
155
|
-
| Export | Kind | Description |
|
|
156
|
-
|--------|------|-------------|
|
|
157
|
-
| `keccakInit` | function | Alias init. `keccakInit(source: WasmSource)` loads the sha3 WASM slot via the keccak alias. |
|
|
158
|
-
| `SHA3_224` | class | Re-exported from `leviathan-crypto/sha3`. |
|
|
159
|
-
| `SHA3_256` | class | Re-exported from `leviathan-crypto/sha3`. |
|
|
160
|
-
| `SHA3_384` | class | Re-exported from `leviathan-crypto/sha3`. |
|
|
161
|
-
| `SHA3_512` | class | Re-exported from `leviathan-crypto/sha3`. |
|
|
162
|
-
| `SHAKE128` | class | Re-exported from `leviathan-crypto/sha3`. |
|
|
163
|
-
| `SHAKE256` | class | Re-exported from `leviathan-crypto/sha3`. |
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
## ML-KEM (Post-quantum KEM)
|
|
168
|
-
|
|
169
|
-
Requires `init({ kyber: kyberWasm, sha3: sha3Wasm })`.
|
|
170
|
-
Subpath: `leviathan-crypto/kyber`. See [kyber.md](./kyber.md).
|
|
171
|
-
|
|
172
|
-
| Export | Kind | Description |
|
|
173
|
-
|--------|------|-------------|
|
|
174
|
-
| `kyberInit` | function | Module-scoped init. `kyberInit(source: WasmSource)` loads only kyber WASM. |
|
|
175
|
-
| `MlKemBase` | class | Abstract base class for all ML-KEM variants. Holds `params: KyberParams`. Not normally instantiated directly. Use `MlKem512`, `MlKem768`, or `MlKem1024`. |
|
|
176
|
-
| `MlKem512` | class | ML-KEM-512. k=2, η₁=3. `keygen()`, `encapsulate(ek)`, `decapsulate(dk, c)`, `checkEncapsulationKey(ek)`, `checkDecapsulationKey(dk)`. |
|
|
177
|
-
| `MlKem768` | class | ML-KEM-768. k=3, η₁=2. Recommended default. Same API as MlKem512. |
|
|
178
|
-
| `MlKem1024` | class | ML-KEM-1024. k=4, η₁=2. Same API as MlKem512. |
|
|
179
|
-
| `KyberSuite` | function | Factory. `KyberSuite(kem, innerCipher)` → `CipherSuite & { keygen(): KyberKeyPair }`. Wraps `MlKemBase` + `CipherSuite` into a hybrid KEM+AEAD suite for use with `Seal`, `SealStream`, `OpenStream`. |
|
|
180
|
-
| `KyberKeyPair` | type | `{ encapsulationKey: Uint8Array, decapsulationKey: Uint8Array }` |
|
|
181
|
-
| `KyberEncapsulation` | type | `{ ciphertext: Uint8Array, sharedSecret: Uint8Array }` |
|
|
182
|
-
| `KyberParams` | type | Parameter set configuration (k, η₁, η₂, dᵤ, dᵥ, byte sizes). |
|
|
183
|
-
| `MLKEM512` | const | Parameter set for ML-KEM-512. |
|
|
184
|
-
| `MLKEM768` | const | Parameter set for ML-KEM-768. |
|
|
185
|
-
| `MLKEM1024` | const | Parameter set for ML-KEM-1024. |
|
|
186
|
-
|
|
187
|
-
> [!NOTE]
|
|
188
|
-
> `ntt_scalar` and `invntt_scalar` are scalar NTT references exported for SIMD gate tests. They are not part of the public API.
|
|
189
|
-
|
|
190
|
-
---
|
|
191
|
-
|
|
192
|
-
## Fortuna CSPRNG
|
|
193
|
-
|
|
194
|
-
Requires `init({ serpent: serpentWasm, sha2: sha2Wasm })`. See [fortuna.md](./fortuna.md).
|
|
195
|
-
|
|
196
|
-
| Export | Kind | Description |
|
|
197
|
-
|--------|------|-------------|
|
|
198
|
-
| `Fortuna` | class | Fortuna CSPRNG (Ferguson & Schneier). `Fortuna.create()` static factory, `get(n)`, `addEntropy()`, `stop()`. |
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
## Types
|
|
203
|
-
|
|
204
|
-
No `init()` required. See [types.md](./types.md).
|
|
205
|
-
|
|
206
|
-
| Export | Kind | Description |
|
|
207
|
-
|--------|------|-------------|
|
|
208
|
-
| `Hash` | interface | `hash(msg): Uint8Array`, `dispose()` |
|
|
209
|
-
| `KeyedHash` | interface | `hash(key, msg): Uint8Array`, `dispose()` |
|
|
210
|
-
| `Blockcipher` | interface | `encrypt(block): Uint8Array`, `decrypt(block): Uint8Array`, `dispose()` |
|
|
211
|
-
| `Streamcipher` | interface | `encrypt(msg): Uint8Array`, `decrypt(msg): Uint8Array`, `dispose()` |
|
|
212
|
-
| `AEAD` | interface | `encrypt(msg, aad?): Uint8Array`, `decrypt(ciphertext, aad?): Uint8Array`, `dispose()` |
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## Utilities
|
|
217
|
-
|
|
218
|
-
No `init()` required. See [utils.md](./utils.md).
|
|
219
|
-
|
|
220
|
-
| Export | Kind | Description |
|
|
221
|
-
|--------|------|-------------|
|
|
222
|
-
| `hexToBytes` | function | Hex string to `Uint8Array`. Accepts `0x` prefix, uppercase/lowercase. Throws `RangeError` on odd-length input. |
|
|
223
|
-
| `bytesToHex` | function | `Uint8Array` to lowercase hex string. |
|
|
224
|
-
| `utf8ToBytes` | function | UTF-8 string to `Uint8Array`. |
|
|
225
|
-
| `bytesToUtf8` | function | `Uint8Array` to UTF-8 string. |
|
|
226
|
-
| `base64ToBytes` | function | Base64/base64url string to `Uint8Array`. Returns `undefined` on invalid input. |
|
|
227
|
-
| `bytesToBase64` | function | `Uint8Array` to base64 string. Pass `url=true` for base64url. |
|
|
228
|
-
| `constantTimeEqual` | function | Best-available constant-time byte-array equality. Uses WASM SIMD when available to eliminate JIT timing leaks; falls back to XOR-accumulate in JS. Returns `false` immediately on length mismatch. Throws `RangeError` if either input exceeds `CT_MAX_BYTES`. |
|
|
229
|
-
| `CT_MAX_BYTES` | const | Maximum input size for `constantTimeEqual` per side (32768 bytes, one 64 KiB WASM page split between two buffers). |
|
|
230
|
-
| `wipe` | function | Zero a typed array in place. |
|
|
231
|
-
| `xor` | function | XOR two equal-length `Uint8Array`s, returns new array. |
|
|
232
|
-
| `concat` | function | Concatenate one or more `Uint8Array`s into a new array. Variadic. |
|
|
233
|
-
| `randomBytes` | function | Cryptographically secure random bytes via Web Crypto API. |
|
|
234
|
-
| `hasSIMD` | function | Returns `true` if the runtime supports WebAssembly SIMD. Cached after first call. Used internally for CTR/CBC-decrypt and ChaCha20 dispatch. Exported for informational use. |
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
> ## Cross-References
|
|
239
|
-
>
|
|
240
|
-
> - [index](./README.md) — Project Documentation index
|
|
241
|
-
> - [architecture](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
package/dist/docs/fortuna.md
DELETED
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
# Fortuna CSPRNG
|
|
2
|
-
|
|
3
|
-
> [!NOTE]
|
|
4
|
-
> A CSPRNG that continuously collects entropy from the environment and generates
|
|
5
|
-
> cryptographically secure random bytes, backed by WASM Serpent-256 and SHA-256.
|
|
6
|
-
|
|
7
|
-
> ### Table of Contents
|
|
8
|
-
> - [Overview](#overview)
|
|
9
|
-
> - [Security Notes](#security-notes)
|
|
10
|
-
> - [API Reference](#api-reference)
|
|
11
|
-
> - [Usage Examples](#usage-examples)
|
|
12
|
-
> - [Error Conditions](#error-conditions)
|
|
13
|
-
> - [How It Works (Simplified)](#how-it-works-simplified)
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Overview
|
|
18
|
-
|
|
19
|
-
A cryptographically secure pseudorandom number generator (CSPRNG) produces random
|
|
20
|
-
bytes that are indistinguishable from true randomness to any observer, even one
|
|
21
|
-
with significant computational resources. This matters because many security
|
|
22
|
-
operations require unpredictable randomness: generating encryption keys, initialization vectors, nonces, and tokens. If an attacker can predict
|
|
23
|
-
the output of your random number generator, they can predict your keys, and your
|
|
24
|
-
encryption provides no protection.
|
|
25
|
-
|
|
26
|
-
Fortuna is a CSPRNG designed by Bruce Schneier and Niels Ferguson, published in
|
|
27
|
-
*Practical Cryptography* (2003). It continuously collects entropy from multiple
|
|
28
|
-
sources (mouse movements, keyboard events, system timers, OS randomness) and
|
|
29
|
-
feeds that entropy into 32 independent pools. When you request random bytes,
|
|
30
|
-
Fortuna combines pool contents and uses them to reseed an internal generator
|
|
31
|
-
built on Serpent-256 (block cipher) and SHA-256 (hash function). Both primitives
|
|
32
|
-
run entirely in WebAssembly.
|
|
33
|
-
|
|
34
|
-
Fortuna adds two properties on top of `crypto.getRandomValues()`. First, **forward secrecy**: after every call to `get()`, the
|
|
35
|
-
internal generation key is replaced, so compromising the current state does not
|
|
36
|
-
reveal any past outputs. Second, **defense-in-depth entropy pooling**: Fortuna
|
|
37
|
-
collects entropy from many independent sources and distributes it across 32 pools
|
|
38
|
-
with exponentially increasing reseed intervals, making it resilient to entropy
|
|
39
|
-
estimation attacks and individual source failures.
|
|
40
|
-
|
|
41
|
-
Fortuna is the only class in leviathan-crypto that requires two WASM modules.
|
|
42
|
-
You must initialize both `serpent` and `sha2` before creating an instance, and
|
|
43
|
-
you must use the `Fortuna.create()` static factory rather than `new Fortuna()`.
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## Security Notes
|
|
48
|
-
|
|
49
|
-
**Forward secrecy.** The generation key is replaced after every call to `get()`. If an attacker compromises the internal state at time T, they cannot reconstruct any output produced before time T.
|
|
50
|
-
|
|
51
|
-
**32 entropy pools.** Entropy is distributed across 32 independent pools using round-robin assignment. Pool 0 is used on every reseed, pool 1 on every second reseed, pool 2 on every fourth, and so on. This exponential schedule means that even if an attacker can observe or influence some entropy sources, higher-numbered pools accumulate enough entropy over time to produce a strong reseed eventually.
|
|
52
|
-
|
|
53
|
-
**Immediate usability.** Fortuna seeds itself from `crypto.getRandomValues()` (browser) or `crypto.randomBytes()` (Node.js) during creation. You do not need to wait for entropy to accumulate before calling `get()`.
|
|
54
|
-
|
|
55
|
-
**Browser entropy sources.** Mouse movements, keyboard events, click events, scroll position, touch events, device motion and orientation, `performance.now()` timing, DOM content hash, and periodic `crypto.getRandomValues()`.
|
|
56
|
-
|
|
57
|
-
**Node.js entropy sources.** `crypto.randomBytes()`, `process.hrtime` (nanosecond timing jitter), `process.cpuUsage()`, `process.memoryUsage()`, `os.loadavg()`, `os.freemem()`.
|
|
58
|
-
|
|
59
|
-
**Wipe state when done.** Call `stop()` when you are finished with the instance. This wipes the generation key and counter from memory and stops all background entropy collectors. Key material should not persist longer than necessary.
|
|
60
|
-
|
|
61
|
-
**Output quality depends on entropy.** The initial seed from the OS random source is strong. Over time the additional entropy collectors improve the state further. In environments with limited user interaction (headless servers, automated tests), fewer entropy sources contribute, but the OS random seed still provides a solid baseline.
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## API Reference
|
|
66
|
-
|
|
67
|
-
### `Fortuna.create(opts?)`
|
|
68
|
-
|
|
69
|
-
Static async factory. Returns a `Promise<Fortuna>`. The returned instance is
|
|
70
|
-
guaranteed to be seeded. `create()` forces an initial reseed before resolving,
|
|
71
|
-
so `get()` is immediately usable.
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
static async create(opts?: {
|
|
75
|
-
msPerReseed?: number;
|
|
76
|
-
entropy?: Uint8Array;
|
|
77
|
-
}): Promise<Fortuna>
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
| Parameter | Type | Default | Description |
|
|
81
|
-
|-----------|------|---------|-------------|
|
|
82
|
-
| `opts.msPerReseed` | `number` | `100` | Minimum milliseconds between reseeds. |
|
|
83
|
-
| `opts.entropy` | `Uint8Array` | | Optional extra entropy to mix in during creation. |
|
|
84
|
-
|
|
85
|
-
Throws if `init({ serpent: serpentWasm, sha2: sha2Wasm })` has not been called.
|
|
86
|
-
|
|
87
|
-
Direct construction with `new Fortuna()` is not possible. The constructor is private. Always use `Fortuna.create()`.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
### `get(length)`
|
|
92
|
-
|
|
93
|
-
Generate `length` random bytes.
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
get(length: number): Uint8Array
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
Returns a `Uint8Array` of the requested length. The instance is always seeded
|
|
100
|
-
after `create()` resolves, so this method is guaranteed to return data.
|
|
101
|
-
|
|
102
|
-
After producing the output, the generation key is replaced with fresh
|
|
103
|
-
pseudorandom material. This is the forward secrecy mechanism. The key used to
|
|
104
|
-
produce this output no longer exists.
|
|
105
|
-
|
|
106
|
-
---
|
|
107
|
-
|
|
108
|
-
### `addEntropy(entropy)`
|
|
109
|
-
|
|
110
|
-
Manually add entropy to the pools.
|
|
111
|
-
|
|
112
|
-
```typescript
|
|
113
|
-
addEntropy(entropy: Uint8Array): void
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Use this to feed application-specific randomness into the generator. The entropy
|
|
117
|
-
is distributed across pools using round-robin assignment. Each call advances to
|
|
118
|
-
the next pool.
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
### `getEntropy()`
|
|
123
|
-
|
|
124
|
-
Get the estimated available entropy in bytes.
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
getEntropy(): number
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Returns the estimated total entropy accumulated across all pools, in bytes. This
|
|
131
|
-
is an estimate, not a guarantee. It reflects the sum of entropy credits assigned by each collector.
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
### `stop()`
|
|
136
|
-
|
|
137
|
-
Permanently dispose this Fortuna instance.
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
stop(): void
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
> [!WARNING]
|
|
144
|
-
> Do not attempt to reuse a stopped instance. `stop()` is a permanent dispose
|
|
145
|
-
> operation. If a new Fortuna instance is needed, call `Fortuna.create()`.
|
|
146
|
-
|
|
147
|
-
Call this when you are done with the Fortuna instance. `stop()`:
|
|
148
|
-
- Removes all browser event listeners
|
|
149
|
-
- Clears all background timers (Node.js stats collection, periodic crypto random)
|
|
150
|
-
- Zeroes the generation key and counter
|
|
151
|
-
- Resets the reseed counter to 0
|
|
152
|
-
- Marks the instance as disposed
|
|
153
|
-
|
|
154
|
-
All subsequent method calls (`get()`, `addEntropy()`, `getEntropy()`, `stop()`)
|
|
155
|
-
on a disposed instance throw immediately:
|
|
156
|
-
```
|
|
157
|
-
Error: Fortuna instance has been disposed
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
There is no `start()` or restart capability.
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
## Usage Examples
|
|
165
|
-
|
|
166
|
-
### Basic usage
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
import { init, Fortuna } from 'leviathan-crypto'
|
|
170
|
-
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
171
|
-
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
172
|
-
|
|
173
|
-
// Initialize both WASM modules that Fortuna depends on
|
|
174
|
-
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
175
|
-
|
|
176
|
-
// Create the CSPRNG
|
|
177
|
-
const rng = await Fortuna.create()
|
|
178
|
-
|
|
179
|
-
// Generate 32 random bytes (e.g., for an encryption key)
|
|
180
|
-
const key = rng.get(32)
|
|
181
|
-
|
|
182
|
-
// Generate 12 random bytes (e.g., for a nonce)
|
|
183
|
-
const nonce = rng.get(12)
|
|
184
|
-
|
|
185
|
-
// Clean up when done, wipes key material from memory
|
|
186
|
-
rng.stop()
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### Adding custom entropy
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
import { init, Fortuna, utf8ToBytes } from 'leviathan-crypto'
|
|
193
|
-
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
194
|
-
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
195
|
-
|
|
196
|
-
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
197
|
-
const rng = await Fortuna.create()
|
|
198
|
-
|
|
199
|
-
// Feed application-specific data as additional entropy.
|
|
200
|
-
// This supplements (never replaces) the automatic entropy collection.
|
|
201
|
-
const userData = utf8ToBytes(crypto.randomUUID())
|
|
202
|
-
rng.addEntropy(userData)
|
|
203
|
-
|
|
204
|
-
// Server-side: feed in request-specific data
|
|
205
|
-
const requestEntropy = new Uint8Array(16)
|
|
206
|
-
crypto.getRandomValues(requestEntropy)
|
|
207
|
-
rng.addEntropy(requestEntropy)
|
|
208
|
-
|
|
209
|
-
const token = rng.get(32)
|
|
210
|
-
rng.stop()
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### Browser with automatic entropy collection
|
|
214
|
-
|
|
215
|
-
```typescript
|
|
216
|
-
import { init, Fortuna } from 'leviathan-crypto'
|
|
217
|
-
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
218
|
-
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
219
|
-
|
|
220
|
-
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
221
|
-
|
|
222
|
-
// Fortuna automatically registers browser event listeners on creation:
|
|
223
|
-
// - mousemove (throttled to 50ms)
|
|
224
|
-
// - keydown
|
|
225
|
-
// - click
|
|
226
|
-
// - scroll
|
|
227
|
-
// - touchstart, touchmove, touchend
|
|
228
|
-
// - devicemotion, deviceorientation, orientationchange
|
|
229
|
-
//
|
|
230
|
-
// Every user interaction feeds entropy into the pools.
|
|
231
|
-
// No manual setup is needed, it starts collecting immediately.
|
|
232
|
-
|
|
233
|
-
const rng = await Fortuna.create()
|
|
234
|
-
|
|
235
|
-
// The longer the user interacts with the page before you generate,
|
|
236
|
-
// the more entropy has been accumulated. But the initial OS seed
|
|
237
|
-
// is strong enough for immediate use.
|
|
238
|
-
document.querySelector('#generate')?.addEventListener('click', () => {
|
|
239
|
-
const bytes = rng.get(32)
|
|
240
|
-
console.log('Generated:', bytes)
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
// When the page unloads or the component unmounts, stop the collectors
|
|
244
|
-
window.addEventListener('beforeunload', () => rng.stop())
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### Providing initial entropy at creation
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
import { init, Fortuna } from 'leviathan-crypto'
|
|
251
|
-
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
252
|
-
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
253
|
-
|
|
254
|
-
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
255
|
-
|
|
256
|
-
// You can pass extra entropy at creation time.
|
|
257
|
-
// This is mixed into the pools during initialization, before the
|
|
258
|
-
// generator is first seeded.
|
|
259
|
-
const extraSeed = new Uint8Array(64)
|
|
260
|
-
crypto.getRandomValues(extraSeed)
|
|
261
|
-
|
|
262
|
-
const rng = await Fortuna.create({ entropy: extraSeed })
|
|
263
|
-
const bytes = rng.get(32)
|
|
264
|
-
rng.stop()
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
---
|
|
268
|
-
|
|
269
|
-
## Error Conditions
|
|
270
|
-
|
|
271
|
-
| Condition | What happens |
|
|
272
|
-
|-----------|-------------|
|
|
273
|
-
| `init()` not called | `Fortuna.create()` throws: `leviathan-crypto: call init({ serpent: ..., sha2: ... }) before using Fortuna` |
|
|
274
|
-
| Only one module initialized | Same error. Both `serpent` and `sha2` must be initialized. |
|
|
275
|
-
| `new Fortuna()` | Compile-time error. The constructor is private. TypeScript will not allow it. |
|
|
276
|
-
| Any method after `stop()` | Throws: `Fortuna instance has been disposed`. The instance is permanently disposed. |
|
|
277
|
-
|
|
278
|
-
---
|
|
279
|
-
|
|
280
|
-
## How It Works (Simplified)
|
|
281
|
-
|
|
282
|
-
For readers who want to understand what Fortuna does internally, without needing
|
|
283
|
-
to read the spec:
|
|
284
|
-
|
|
285
|
-
1. **Entropy collection.** Background listeners and timers capture small,
|
|
286
|
-
unpredictable measurements (mouse coordinates, nanosecond timings, memory
|
|
287
|
-
usage) and feed them into 32 separate pools via SHA-256 hash chaining.
|
|
288
|
-
|
|
289
|
-
2. **Reseed.** When pool 0 has accumulated enough entropy and enough time has
|
|
290
|
-
passed since the last reseed, Fortuna combines the contents of eligible pools
|
|
291
|
-
(determined by the reseed counter) into a seed, and derives a new generation
|
|
292
|
-
key: `genKey = SHA-256(genKey || seed)`.
|
|
293
|
-
|
|
294
|
-
3. **Generation.** To produce output, the generator encrypts an incrementing
|
|
295
|
-
counter with Serpent-256 in ECB mode using the current generation key. The
|
|
296
|
-
output is the concatenation of encrypted counter blocks, truncated to the
|
|
297
|
-
requested length.
|
|
298
|
-
|
|
299
|
-
4. **Key replacement.** Immediately after producing output, the generation key
|
|
300
|
-
is replaced with fresh pseudorandom blocks. The old key is gone. This is what
|
|
301
|
-
provides forward secrecy.
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
> ## Cross-References
|
|
306
|
-
>
|
|
307
|
-
> - [index](./README.md) — Project Documentation index
|
|
308
|
-
> - [architecture](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
309
|
-
> - [serpent](./serpent.md) — Serpent-256 TypeScript API (Fortuna uses Serpent ECB internally)
|
|
310
|
-
> - [sha2](./sha2.md) — SHA-256 TypeScript API (Fortuna uses SHA-256 for entropy accumulation)
|
|
311
|
-
> - [asm_serpent](./asm_serpent.md) — Serpent-256 WASM implementation details
|
|
312
|
-
> - [asm_sha2](./asm_sha2.md) — SHA-256 WASM implementation details
|
|
313
|
-
> - [utils](./utils.md) — `randomBytes()` for simpler random generation needs
|