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/CLAUDE.md
CHANGED
|
@@ -1,320 +1,127 @@
|
|
|
1
|
-
# leviathan-crypto
|
|
1
|
+
# leviathan-crypto: AI Assistant Guide
|
|
2
2
|
|
|
3
3
|
> [!NOTE]
|
|
4
|
-
>
|
|
4
|
+
> Ships with the npm package. Inside the repo? Read `AGENTS.md` instead.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
> - [What This Library Is](#what-this-library-is)
|
|
8
|
-
> - [Critical: `init()` is required](#critical-init-is-required)
|
|
9
|
-
> - [Critical: call `dispose()` after use](#critical-call-dispose-after-use)
|
|
10
|
-
> - [Critical: `decrypt()` throws on authentication failure](#critical-decrypt-throws-on-authentication-failure--never-returns-null)
|
|
11
|
-
> - [Critical: subpath init function names](#critical-subpath-init-function-names)
|
|
12
|
-
> - [Which module does each class require?](#which-module-does-each-class-require)
|
|
13
|
-
> - [Recommended patterns](#recommended-patterns)
|
|
14
|
-
> - [`SerpentCbc` arg order](#serpentcbc-arg-order)
|
|
15
|
-
> - [Utilities (no `init()` required)](#utilities-no-init-required)
|
|
16
|
-
> - [Full documentation](#full-documentation)
|
|
6
|
+
## What this is
|
|
17
7
|
|
|
18
|
-
|
|
8
|
+
Zero-dependency WASM crypto for TS/JS. All compute in WASM (outside JS JIT); TS layer = input validation + ergonomics.
|
|
19
9
|
|
|
20
|
-
|
|
10
|
+
| Family | Primitives |
|
|
11
|
+
|---|---|
|
|
12
|
+
| Symmetric AEAD | Serpent-256, XChaCha20-Poly1305, AES-256-GCM-SIV |
|
|
13
|
+
| Post-quantum sig | ML-DSA, SLH-DSA, PQ-only hybrid composites |
|
|
14
|
+
| Classical sig | Ed25519, ECDSA-P256, classical+PQ hybrid composites |
|
|
15
|
+
| Key agreement | ML-KEM, X25519 |
|
|
16
|
+
| Transparency log | Merkle log (C2SP-conformant) |
|
|
17
|
+
| Forward-secret ratchet | Signal SPQR KDF (rule 8) |
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
TypeScript and JavaScript. All cryptographic computation runs in WASM, outside
|
|
24
|
-
the JavaScript JIT. The TypeScript layer provides the public API: input
|
|
25
|
-
validation, type safety, and ergonomics. It never implements cryptographic
|
|
26
|
-
algorithms itself.
|
|
19
|
+
## API shape
|
|
27
20
|
|
|
28
|
-
|
|
21
|
+
Two hierarchies, one suite extension point. Tier = data shape. Suite = crypto choice.
|
|
29
22
|
|
|
30
|
-
|
|
23
|
+
| Tier | AEAD | Signatures |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| One-shot | Seal | Sign |
|
|
26
|
+
| Streaming | SealStream / OpenStream | SignStream / VerifyStream |
|
|
27
|
+
| Parallel | SealStreamPool (Web Workers) | n/a |
|
|
28
|
+
| Suite arg | CipherSuite | SignatureSuite |
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
module is loaded throws immediately with a clear error. Call `init()` once at
|
|
34
|
-
startup, before any cryptographic operations.
|
|
30
|
+
`Seal` blob = single-chunk `SealStream` output (interchangeable). Symmetric: `SerpentCipher`, `XChaCha20Cipher`, `AESGCMSIVCipher`. `MlKemSuite(MlKem*, inner)` wraps any of them for PQ hybrid (same `CipherSuite` interface).
|
|
35
31
|
|
|
36
|
-
|
|
37
|
-
import { init, Serpent } from 'leviathan-crypto'
|
|
38
|
-
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
39
|
-
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
40
|
-
|
|
41
|
-
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
`init()` accepts a `Partial<Record<Module, WasmSource>>`. Each value is a
|
|
45
|
-
`WasmSource`: a gzip+base64 string, `URL`, `ArrayBuffer`, `Uint8Array`,
|
|
46
|
-
pre-compiled `WebAssembly.Module`, `Response`, or `Promise<Response>`.
|
|
47
|
-
|
|
48
|
-
The `/embedded` subpath exports are the simplest WasmSource: they are the
|
|
49
|
-
gzip+base64 blobs for each module, bundled with the package.
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## Critical: call `dispose()` after use
|
|
54
|
-
|
|
55
|
-
Every class holds WASM memory containing key material. Call `dispose()` when
|
|
56
|
-
done; it zeroes that memory. Not calling `dispose()` leaks key material.
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
const cipher = new XChaCha20Poly1305()
|
|
60
|
-
try {
|
|
61
|
-
return cipher.encrypt(key, nonce, plaintext)
|
|
62
|
-
} finally {
|
|
63
|
-
cipher.dispose()
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## Critical: `decrypt()` throws on authentication failure — never returns null
|
|
70
|
-
|
|
71
|
-
All AEAD `decrypt()` methods throw if authentication fails. Do not check for a
|
|
72
|
-
null return; catch the exception.
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
try {
|
|
76
|
-
const plaintext = seal.decrypt(key, ciphertext)
|
|
77
|
-
} catch {
|
|
78
|
-
// wrong key or tampered data
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## Critical: subpath init function names
|
|
85
|
-
|
|
86
|
-
Each subpath export has its own module-specific init function, not `init()`.
|
|
87
|
-
These are only needed for tree-shakeable imports. The root barrel `init()` is
|
|
88
|
-
the normal path.
|
|
89
|
-
|
|
90
|
-
Each init function takes a single `WasmSource` argument. Use the module's
|
|
91
|
-
`/embedded` subpath to get the bundled blob as a ready-to-use WasmSource.
|
|
92
|
-
|
|
93
|
-
| Subpath | Init function | Embedded blob |
|
|
94
|
-
|---------|---------------|---------------|
|
|
95
|
-
| `leviathan-crypto/serpent` | `serpentInit(source)` | `leviathan-crypto/serpent/embedded` → `serpentWasm` |
|
|
96
|
-
| `leviathan-crypto/chacha20` | `chacha20Init(source)` | `leviathan-crypto/chacha20/embedded` → `chacha20Wasm` |
|
|
97
|
-
| `leviathan-crypto/sha2` | `sha2Init(source)` | `leviathan-crypto/sha2/embedded` → `sha2Wasm` |
|
|
98
|
-
| `leviathan-crypto/sha3` | `sha3Init(source)` | `leviathan-crypto/sha3/embedded` → `sha3Wasm` |
|
|
99
|
-
| `leviathan-crypto/keccak` | `keccakInit(source)` | `leviathan-crypto/keccak/embedded` → `keccakWasm` |
|
|
100
|
-
| `leviathan-crypto/kyber` | `kyberInit(source)` | `leviathan-crypto/kyber/embedded` → `kyberWasm` |
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
// Tree-shakeable — loads only serpent WASM
|
|
104
|
-
import { serpentInit, Serpent } from 'leviathan-crypto/serpent'
|
|
105
|
-
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
106
|
-
await serpentInit(serpentWasm)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## Which module does each class require?
|
|
112
|
-
|
|
113
|
-
| Classes | Required modules |
|
|
114
|
-
|---------|-----------------|
|
|
115
|
-
| `Serpent`, `SerpentCtr`, `SerpentCbc`, `SerpentCipher` | `init({ serpent: serpentWasm, sha2: sha2Wasm })` |
|
|
116
|
-
| `SealStream`, `OpenStream`, `SerpentCipher` (when using SerpentCipher) | `init({ serpent: serpentWasm, sha2: sha2Wasm })` |
|
|
117
|
-
| `SealStream`, `OpenStream`, `XChaCha20Cipher` (when using XChaCha20Cipher) | `init({ chacha20: chacha20Wasm, sha2: sha2Wasm })` |
|
|
118
|
-
| `SealStreamPool` | depends on cipher: same modules as the cipher suite + `sha2` |
|
|
119
|
-
| `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305` | `init({ chacha20: chacha20Wasm })` |
|
|
120
|
-
| `SHA256`, `SHA384`, `SHA512`, `HMAC_SHA256`, `HMAC_SHA384`, `HMAC_SHA512`, `HKDF_SHA256`, `HKDF_SHA512` | `init({ sha2: sha2Wasm })` |
|
|
121
|
-
| `SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512`, `SHAKE128`, `SHAKE256` | `init({ sha3: sha3Wasm })` or `init({ keccak: keccakWasm })` — `'keccak'` is an alias for `'sha3'` |
|
|
122
|
-
| `MlKem512`, `MlKem768`, `MlKem1024` | `init({ kyber: kyberWasm, sha3: sha3Wasm })` — both modules required |
|
|
123
|
-
| `Fortuna` | `init({ serpent: serpentWasm, sha2: sha2Wasm })` |
|
|
124
|
-
|
|
125
|
-
---
|
|
126
|
-
|
|
127
|
-
## Recommended patterns
|
|
128
|
-
|
|
129
|
-
### Authenticated encryption (recommended default)
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
import { init, Seal, SerpentCipher, randomBytes } from 'leviathan-crypto'
|
|
133
|
-
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
134
|
-
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
32
|
+
**Prefer the high-level surface (Seal / Sign / Fortuna).** Handles KDF, nonce management, auth, key wipes, counter binding. Rejects tampered/reordered/spliced inputs before plaintext release. Low-level primitives (raw `ChaCha20`, `SerpentCbc`, etc.) require reading their wiki page first.
|
|
135
33
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const key = SerpentCipher.keygen()
|
|
139
|
-
const blob = Seal.encrypt(SerpentCipher, key, plaintext)
|
|
140
|
-
const decrypted = Seal.decrypt(SerpentCipher, key, blob)
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Incremental streaming AEAD
|
|
144
|
-
|
|
145
|
-
Use when you cannot buffer the full message before encrypting.
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
import { init, SealStream, OpenStream, SerpentCipher, randomBytes } from 'leviathan-crypto'
|
|
149
|
-
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
150
|
-
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
151
|
-
|
|
152
|
-
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
153
|
-
|
|
154
|
-
const key = randomBytes(32)
|
|
155
|
-
const sealer = new SealStream(SerpentCipher, key)
|
|
156
|
-
const preamble = sealer.preamble // 20 bytes — send first
|
|
157
|
-
const ct0 = sealer.push(chunk0)
|
|
158
|
-
const ct1 = sealer.push(chunk1)
|
|
159
|
-
const ctLast = sealer.finalize(lastChunk)
|
|
160
|
-
|
|
161
|
-
const opener = new OpenStream(SerpentCipher, key, preamble)
|
|
162
|
-
const pt0 = opener.pull(ct0)
|
|
163
|
-
const pt1 = opener.pull(ct1)
|
|
164
|
-
const ptLast = opener.finalize(ctLast)
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
### Length-prefixed streaming (for files and buffered transports)
|
|
168
|
-
|
|
169
|
-
Pass `{ framed: true }` to `SealStream` for self-delimiting `u32be` length-prefixed
|
|
170
|
-
framing. Use when chunks will be concatenated into a flat byte stream. Omit when the
|
|
171
|
-
transport frames messages itself (WebSocket, IPC).
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
const sealer = new SealStream(SerpentCipher, key, { framed: true })
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### XChaCha20-Poly1305
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
import { init, XChaCha20Poly1305, randomBytes } from 'leviathan-crypto'
|
|
181
|
-
import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
|
|
182
|
-
|
|
183
|
-
await init({ chacha20: chacha20Wasm })
|
|
184
|
-
|
|
185
|
-
const aead = new XChaCha20Poly1305()
|
|
186
|
-
const key = randomBytes(32)
|
|
187
|
-
const nonce = randomBytes(24)
|
|
188
|
-
const sealed = aead.encrypt(key, nonce, plaintext, aad?) // ciphertext || tag
|
|
189
|
-
const plaintext = aead.decrypt(key, nonce, sealed, aad?) // throws on tamper
|
|
190
|
-
aead.dispose()
|
|
191
|
-
```
|
|
34
|
+
## Rules (cross-cutting foot-guns)
|
|
192
35
|
|
|
193
|
-
|
|
194
|
-
`decrypt()` expects the same concatenated format, not separate ciphertext and tag.
|
|
36
|
+
1. **`init()` required.** Nothing works before `init()`. Throws on missing module. Idempotent. Use `/embedded` subpath for bundled gzip+base64 blob.
|
|
195
37
|
|
|
196
|
-
|
|
38
|
+
2. **`dispose()` stateful in `finally`.** Stateful classes hold key material in WASM until `dispose()` zeros it. Wrap in `try { ... } finally { x.dispose() }`. Atomic one-shots (`Seal.encrypt`, `Sign.sign`, hashes, MACs) self-wipe.
|
|
197
39
|
|
|
198
|
-
|
|
199
|
-
import { init, SHA256, HMAC_SHA256 } from 'leviathan-crypto'
|
|
200
|
-
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
40
|
+
3. **Stateful = exclusive module access.** A stateful class (`SHAKE128`, `ChaCha20`, `SerpentCtr/Cbc`, `SealStream`, `MlKem*`, etc.) owns its WASM module for its lifetime. Second stateful instance on same module throws. Atomic methods on same module throw while a stateful holder is alive. Pool workers isolated.
|
|
201
41
|
|
|
202
|
-
|
|
42
|
+
4. **AEAD `decrypt()` throws on auth failure.** `Seal.decrypt`, AEAD `decrypt()`, `OpenStream.pull` never return null or corrupted plaintext. Wrong key, tampered blob, corrupted bytes all surface as exceptions.
|
|
203
43
|
|
|
204
|
-
|
|
205
|
-
const digest = hasher.hash(data) // returns Uint8Array
|
|
206
|
-
hasher.dispose()
|
|
44
|
+
5. **Raw `verify()` returns bool. `Sign.verify` throws.** Raw primitives (`MlDsa*.verify`, `SlhDsa*.verify`, hybrid `verifyPrehashed`) return `false` on bad sig; only contract violations throw. `Sign.verify` envelope throws on bad sig (parity with `Seal.decrypt`).
|
|
207
45
|
|
|
208
|
-
|
|
209
|
-
const tag = mac.hash(key, data)
|
|
210
|
-
mac.dispose()
|
|
211
|
-
```
|
|
46
|
+
6. **Pure-mode and prehash sigs NOT interchangeable.** `dsa.sign` vs `dsa.verifyHash` bind different M' domain bytes (0x00 vs 0x01, FIPS 204 §3.6.4 / FIPS 205 §10.2.2). Sigs don't cross even with identical messages. SignatureSuite enforces at the type level.
|
|
212
47
|
|
|
213
|
-
|
|
48
|
+
7. **v3 sign envelope: `ctx` required.** `Sign.sign` / `Sign.verify` / `SignStream` / `VerifyStream` all require `ctx`. Pass `new Uint8Array()` for empty. Each suite prepends `ctxDomain` (blocks cross-suite verify). Per-call `ctx` ≤ 255 bytes (FIPS 204 §3.6.1); longer throws `SigningError('sig-ctx-too-long')`. Per-call ceiling = `253 - len(ctxDomain)` (221-234 bytes across catalog).
|
|
214
49
|
|
|
215
|
-
|
|
216
|
-
import { init, SHAKE128 } from 'leviathan-crypto'
|
|
217
|
-
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
50
|
+
8. **Ratchet = KDF primitives, not a session.** Forward secrecy + post-compromise security primitives only. State machine, message counters, header format, epoch orchestration, transport = app concerns. NOT a drop-in Signal client.
|
|
218
51
|
|
|
219
|
-
|
|
52
|
+
## Subpath imports
|
|
220
53
|
|
|
221
|
-
|
|
222
|
-
xof.absorb(data)
|
|
223
|
-
const out1 = xof.squeeze(32) // first 32 bytes of output stream
|
|
224
|
-
const out2 = xof.squeeze(32) // next 32 bytes — contiguous XOF stream
|
|
225
|
-
xof.dispose()
|
|
226
|
-
```
|
|
54
|
+
Pattern: `leviathan-crypto/<mod>` exports `<mod>Init(source)`; `leviathan-crypto/<mod>/embedded` exports `<mod>Wasm`. Twelve modules: `serpent`, `chacha20`, `aes`, `sha2`, `sha3`, `keccak`, `mlkem`, `mldsa`, `slhdsa`, `blake3`, `curve25519`, `p256`.
|
|
227
55
|
|
|
228
|
-
|
|
56
|
+
Aliases share binary + instance slot:
|
|
229
57
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
58
|
+
| Alias | Backed by |
|
|
59
|
+
|---|---|
|
|
60
|
+
| keccak | sha3 |
|
|
61
|
+
| ed25519 | curve25519 |
|
|
62
|
+
| x25519 | curve25519 |
|
|
63
|
+
| ecdsa | p256 |
|
|
234
64
|
|
|
235
|
-
|
|
65
|
+
No `/embedded`: `leviathan-crypto/ratchet`, `leviathan-crypto/stream`, `leviathan-crypto/sign`, `leviathan-crypto/merkle`.
|
|
236
66
|
|
|
237
|
-
|
|
238
|
-
const { encapsulationKey, decapsulationKey } = kem.keygen()
|
|
67
|
+
## Class → init modules + wiki
|
|
239
68
|
|
|
240
|
-
|
|
241
|
-
|
|
69
|
+
| Class | init modules | wiki |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| Seal / SealStream / OpenStream / SealStreamPool | varies by suite | https://github.com/xero/leviathan-crypto/wiki/aead |
|
|
72
|
+
| SerpentCipher | serpent, sha2 | https://github.com/xero/leviathan-crypto/wiki/serpent |
|
|
73
|
+
| XChaCha20Cipher | chacha20, sha2 | https://github.com/xero/leviathan-crypto/wiki/chacha20 |
|
|
74
|
+
| AESGCMSIVCipher | aes, sha2 | https://github.com/xero/leviathan-crypto/wiki/aes |
|
|
75
|
+
| MlKemSuite(MlKem*, inner) | mlkem, sha3 + inner | https://github.com/xero/leviathan-crypto/wiki/mlkem |
|
|
76
|
+
| Sign / SignStream / VerifyStream | varies by suite | https://github.com/xero/leviathan-crypto/wiki/signing |
|
|
77
|
+
| MlDsa{44,65,87}Suite (pure, prehash) | mldsa, sha3 (+sha2 for SHA-2 prehash) | https://github.com/xero/leviathan-crypto/wiki/mldsa |
|
|
78
|
+
| SlhDsa{128f,192f,256f}Suite | slhdsa, sha3 (+sha2 for SHA-2 prehash) | https://github.com/xero/leviathan-crypto/wiki/slhdsa |
|
|
79
|
+
| Ed25519Suite / Ed25519PreHashSuite | curve25519 (+sha2 for PreHash) | https://github.com/xero/leviathan-crypto/wiki/ed25519 |
|
|
80
|
+
| EcdsaP256Suite (hedged, low-S) | p256, sha2 | https://github.com/xero/leviathan-crypto/wiki/ecdsa-p256 |
|
|
81
|
+
| MlDsa{44,65}Ed25519Suite (0x20, 0x21) | mldsa, sha3, curve25519, sha2 | https://github.com/xero/leviathan-crypto/wiki/signaturesuite |
|
|
82
|
+
| MlDsa{44,65}EcdsaP256Suite (0x22, 0x23) | mldsa, sha3, p256, sha2 | https://github.com/xero/leviathan-crypto/wiki/signaturesuite |
|
|
83
|
+
| MlDsa{44,65,87}SlhDsa{128f,192f,256f}Suite (0x30-0x32) | mldsa, sha3, slhdsa | https://github.com/xero/leviathan-crypto/wiki/signaturesuite |
|
|
84
|
+
| X25519 | curve25519 | https://github.com/xero/leviathan-crypto/wiki/x25519 |
|
|
85
|
+
| MerkleVerifier / MerkleLog | sha2 + suite (+blake3 if `hashing: 'blake3'`) | https://github.com/xero/leviathan-crypto/wiki/merkle |
|
|
86
|
+
| Sparse PQ Ratchet (KDF, rule 8) | sha2, mlkem, sha3 | https://github.com/xero/leviathan-crypto/wiki/ratchet |
|
|
87
|
+
| Fortuna | one cipher + one hash | https://github.com/xero/leviathan-crypto/wiki/fortuna |
|
|
88
|
+
| SHA-2 / HMAC / HKDF | sha2 | https://github.com/xero/leviathan-crypto/wiki/sha2 |
|
|
89
|
+
| SHA-3 / SHAKE | sha3 | https://github.com/xero/leviathan-crypto/wiki/sha3 |
|
|
90
|
+
| CSHAKE / KMAC / KMACXOF | sha3 | https://github.com/xero/leviathan-crypto/wiki/kmac |
|
|
91
|
+
| BLAKE3 family | blake3 | https://github.com/xero/leviathan-crypto/wiki/blake3 |
|
|
242
92
|
|
|
243
|
-
|
|
244
|
-
const recipientSecret = kem.decapsulate(decapsulationKey, ciphertext)
|
|
93
|
+
Other refs:
|
|
245
94
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
95
|
+
| Topic | wiki |
|
|
96
|
+
|---|---|
|
|
97
|
+
| init() / WasmSource | https://github.com/xero/leviathan-crypto/wiki/init |
|
|
98
|
+
| Loading strategies | https://github.com/xero/leviathan-crypto/wiki/loader |
|
|
99
|
+
| CDN usage | https://github.com/xero/leviathan-crypto/wiki/cdn |
|
|
100
|
+
| Content-Security-Policy | https://github.com/xero/leviathan-crypto/wiki/csp |
|
|
101
|
+
| Worked examples | https://github.com/xero/leviathan-crypto/wiki/examples |
|
|
102
|
+
| Utilities | https://github.com/xero/leviathan-crypto/wiki/utils |
|
|
103
|
+
| Argon2id integration | https://github.com/xero/leviathan-crypto/wiki/argon2id |
|
|
104
|
+
| CipherSuite interface | https://github.com/xero/leviathan-crypto/wiki/ciphersuite |
|
|
105
|
+
| SignatureSuite catalog | https://github.com/xero/leviathan-crypto/wiki/signaturesuite |
|
|
249
106
|
|
|
250
|
-
|
|
251
|
-
a 32-byte shared secret suitable for use as a symmetric key.
|
|
107
|
+
## Canonical example
|
|
252
108
|
|
|
253
|
-
|
|
109
|
+
`Seal` + `SerpentCipher` round-trip:
|
|
254
110
|
|
|
255
111
|
```typescript
|
|
256
|
-
import { init,
|
|
112
|
+
import { init, Seal, SerpentCipher } from 'leviathan-crypto'
|
|
257
113
|
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
258
114
|
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
259
115
|
|
|
260
116
|
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
261
117
|
|
|
262
|
-
const
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
## `SerpentCbc` arg order
|
|
270
|
-
|
|
271
|
-
IV is the **second** argument, not the third:
|
|
272
|
-
|
|
273
|
-
```typescript
|
|
274
|
-
cipher.encrypt(key, iv, plaintext) // correct
|
|
275
|
-
cipher.decrypt(key, iv, ciphertext) // correct
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
`SerpentCbc` is unauthenticated. Always pair with `HMAC_SHA256`
|
|
279
|
-
(Encrypt-then-MAC) or use `Seal` with `SerpentCipher` instead.
|
|
280
|
-
|
|
281
|
-
---
|
|
282
|
-
|
|
283
|
-
## Utilities (no `init()` required)
|
|
284
|
-
|
|
285
|
-
```typescript
|
|
286
|
-
import { hexToBytes, bytesToHex, randomBytes, constantTimeEqual, wipe, hasSIMD } from 'leviathan-crypto'
|
|
287
|
-
|
|
288
|
-
// available immediately — no await init() needed
|
|
289
|
-
const key = randomBytes(32)
|
|
290
|
-
const hex = bytesToHex(key)
|
|
291
|
-
const back = hexToBytes(hex)
|
|
292
|
-
const safe = constantTimeEqual(a, b) // constant-time equality — never use ===
|
|
293
|
-
wipe(key) // zero a Uint8Array in place
|
|
118
|
+
const key = SerpentCipher.keygen()
|
|
119
|
+
const blob = Seal.encrypt(SerpentCipher, key, plaintext)
|
|
120
|
+
try {
|
|
121
|
+
const pt = Seal.decrypt(SerpentCipher, key, blob)
|
|
122
|
+
} catch {
|
|
123
|
+
// wrong key, tampered blob, or corrupted bytes
|
|
124
|
+
}
|
|
294
125
|
```
|
|
295
126
|
|
|
296
|
-
`
|
|
297
|
-
Serpent, ChaCha20, and Kyber modules all require SIMD; `init()` throws
|
|
298
|
-
a clear error on runtimes without support. SIMD has been a baseline
|
|
299
|
-
feature of all major browsers and runtimes since 2021. SHA-2 and SHA-3
|
|
300
|
-
modules run on any WASM-capable runtime.
|
|
301
|
-
|
|
302
|
-
---
|
|
303
|
-
|
|
304
|
-
## Full documentation
|
|
305
|
-
|
|
306
|
-
The complete API reference ships in `docs/` alongside this file:
|
|
307
|
-
|
|
308
|
-
| File | Contents |
|
|
309
|
-
|------|----------|
|
|
310
|
-
| `docs/serpent.md` | `SerpentCipher`, `Serpent`, `SerpentCtr`, `SerpentCbc` |
|
|
311
|
-
| `docs/chacha20.md` | `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, `XChaCha20Cipher` |
|
|
312
|
-
| `docs/sha2.md` | `SHA256`, `SHA384`, `SHA512`, `HMAC_SHA256`, `HMAC_SHA384`, `HMAC_SHA512`, `HKDF_SHA256`, `HKDF_SHA512` |
|
|
313
|
-
| `docs/sha3.md` | `SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512`, `SHAKE128`, `SHAKE256` |
|
|
314
|
-
| `docs/aead.md` | `Seal`, `SealStream`, `OpenStream`, `SealStreamPool`, `CipherSuite` |
|
|
315
|
-
| `docs/kyber.md` | `MlKem512`, `MlKem768`, `MlKem1024`, `KyberSuite` — ML-KEM (FIPS 203) API reference |
|
|
316
|
-
| `docs/fortuna.md` | `Fortuna` CSPRNG |
|
|
317
|
-
| `docs/init.md` | `init()` API, loading modes, subpath imports |
|
|
318
|
-
| `docs/utils.md` | Encoding helpers, `constantTimeEqual`, `wipe`, `randomBytes` |
|
|
319
|
-
| `docs/types.md` | `Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD` interfaces; `CipherSuite`, `DerivedKeys`, `SealStreamOpts`, `PoolOpts`, `WasmSource` |
|
|
320
|
-
| `docs/architecture.md` | Module structure, WASM layer, three-tier design |
|
|
127
|
+
Streaming: `Seal` → `SealStream` + `OpenStream`. PQ hybrid: `SerpentCipher` → `MlKemSuite(new MlKem768(), SerpentCipher)`. Same call site, wire format, catch semantics.
|
package/LICENSE
CHANGED
|
@@ -2,6 +2,10 @@ MIT License
|
|
|
2
2
|
|
|
3
3
|
Copyright (c) 2026 Leviathan Crypto Library
|
|
4
4
|
|
|
5
|
+
https://leviathan.3xi.club
|
|
6
|
+
https://github.com/xero/leviathan-crypto
|
|
7
|
+
https://npmjs.com/package/leviathan-crypto
|
|
8
|
+
|
|
5
9
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
10
|
of this software and associated documentation files (the "Software"), to deal
|
|
7
11
|
in the Software without restriction, including without limitation the rights
|