leviathan-crypto 1.4.0 → 2.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 +129 -94
- package/README.md +166 -223
- package/SECURITY.md +90 -45
- package/dist/chacha20/cipher-suite.d.ts +4 -0
- package/dist/chacha20/cipher-suite.js +79 -0
- package/dist/chacha20/embedded.d.ts +1 -0
- package/dist/chacha20/embedded.js +27 -0
- package/dist/chacha20/index.d.ts +20 -27
- package/dist/chacha20/index.js +40 -59
- package/dist/chacha20/ops.d.ts +1 -1
- package/dist/chacha20/ops.js +19 -18
- package/dist/chacha20/pool-worker.js +77 -0
- package/dist/ct-wasm.d.ts +1 -0
- package/dist/ct-wasm.js +3 -0
- package/dist/ct.wasm +0 -0
- package/dist/docs/aead.md +323 -0
- package/dist/docs/architecture.md +427 -292
- package/dist/docs/argon2id.md +42 -30
- package/dist/docs/chacha20.md +192 -266
- package/dist/docs/exports.md +241 -0
- package/dist/docs/fortuna.md +60 -69
- package/dist/docs/init.md +172 -178
- package/dist/docs/loader.md +87 -142
- package/dist/docs/serpent.md +134 -583
- package/dist/docs/sha2.md +91 -103
- package/dist/docs/sha3.md +70 -36
- package/dist/docs/types.md +94 -16
- package/dist/docs/utils.md +109 -32
- package/dist/embedded/kyber.d.ts +1 -0
- package/dist/embedded/kyber.js +3 -0
- package/dist/embedded/serpent.d.ts +1 -1
- package/dist/embedded/serpent.js +1 -1
- package/dist/errors.d.ts +10 -0
- package/dist/errors.js +38 -0
- package/dist/fortuna.d.ts +0 -6
- package/dist/fortuna.js +5 -5
- package/dist/index.d.ts +25 -9
- package/dist/index.js +36 -7
- package/dist/init.d.ts +3 -7
- package/dist/init.js +18 -35
- package/dist/keccak/embedded.d.ts +1 -0
- package/dist/keccak/embedded.js +27 -0
- package/dist/keccak/index.d.ts +4 -0
- package/dist/keccak/index.js +31 -0
- package/dist/kyber/embedded.d.ts +1 -0
- package/dist/kyber/embedded.js +27 -0
- package/dist/kyber/indcpa.d.ts +49 -0
- package/dist/kyber/indcpa.js +352 -0
- package/dist/kyber/index.d.ts +38 -0
- package/dist/kyber/index.js +150 -0
- package/dist/kyber/kem.d.ts +21 -0
- package/dist/kyber/kem.js +160 -0
- package/dist/kyber/params.d.ts +14 -0
- package/dist/kyber/params.js +37 -0
- package/dist/kyber/suite.d.ts +13 -0
- package/dist/kyber/suite.js +94 -0
- package/dist/kyber/types.d.ts +98 -0
- package/dist/kyber/types.js +25 -0
- package/dist/kyber/validate.d.ts +19 -0
- package/dist/kyber/validate.js +68 -0
- package/dist/kyber.wasm +0 -0
- package/dist/loader.d.ts +15 -6
- package/dist/loader.js +65 -21
- package/dist/serpent/cipher-suite.d.ts +4 -0
- package/dist/serpent/cipher-suite.js +122 -0
- package/dist/serpent/embedded.d.ts +1 -0
- package/dist/serpent/embedded.js +27 -0
- package/dist/serpent/index.d.ts +6 -37
- package/dist/serpent/index.js +9 -118
- package/dist/serpent/pool-worker.d.ts +1 -0
- package/dist/serpent/pool-worker.js +208 -0
- package/dist/serpent/serpent-cbc.d.ts +30 -0
- package/dist/serpent/serpent-cbc.js +142 -0
- package/dist/serpent.wasm +0 -0
- package/dist/sha2/embedded.d.ts +1 -0
- package/dist/sha2/embedded.js +27 -0
- package/dist/sha2/hkdf.js +6 -2
- package/dist/sha2/index.d.ts +3 -2
- package/dist/sha2/index.js +3 -4
- package/dist/sha3/embedded.d.ts +1 -0
- package/dist/sha3/embedded.js +27 -0
- package/dist/sha3/index.d.ts +3 -2
- package/dist/sha3/index.js +3 -4
- package/dist/stream/constants.d.ts +6 -0
- package/dist/stream/constants.js +30 -0
- package/dist/stream/header.d.ts +9 -0
- package/dist/stream/header.js +77 -0
- package/dist/stream/index.d.ts +7 -0
- package/dist/stream/index.js +27 -0
- package/dist/stream/open-stream.d.ts +21 -0
- package/dist/stream/open-stream.js +146 -0
- package/dist/stream/seal-stream-pool.d.ts +38 -0
- package/dist/stream/seal-stream-pool.js +400 -0
- package/dist/stream/seal-stream.d.ts +20 -0
- package/dist/stream/seal-stream.js +142 -0
- package/dist/stream/seal.d.ts +9 -0
- package/dist/stream/seal.js +75 -0
- package/dist/stream/types.d.ts +25 -0
- package/dist/stream/types.js +26 -0
- package/dist/utils.d.ts +7 -2
- package/dist/utils.js +49 -3
- package/dist/wasm-source.d.ts +12 -0
- package/dist/wasm-source.js +26 -0
- package/package.json +13 -5
- package/dist/chacha20/pool.d.ts +0 -52
- package/dist/chacha20/pool.js +0 -178
- package/dist/chacha20/pool.worker.js +0 -37
- package/dist/chacha20/stream-sealer.d.ts +0 -49
- package/dist/chacha20/stream-sealer.js +0 -327
- package/dist/docs/chacha20_pool.md +0 -309
- package/dist/docs/wasm.md +0 -194
- package/dist/serpent/seal.d.ts +0 -8
- package/dist/serpent/seal.js +0 -72
- package/dist/serpent/stream-pool.d.ts +0 -48
- package/dist/serpent/stream-pool.js +0 -275
- package/dist/serpent/stream-sealer.d.ts +0 -55
- package/dist/serpent/stream-sealer.js +0 -342
- package/dist/serpent/stream.d.ts +0 -28
- package/dist/serpent/stream.js +0 -205
- package/dist/serpent/stream.worker.d.ts +0 -32
- package/dist/serpent/stream.worker.js +0 -117
- /package/dist/chacha20/{pool.worker.d.ts → pool-worker.d.ts} +0 -0
package/CLAUDE.md
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
# leviathan-crypto — AI Assistant Guide
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Full API documentation is in the `docs/` directory alongside this file.
|
|
3
|
+
> [!NOTE]
|
|
4
|
+
> This file ships with the package to help AI assistants use this library correctly. Full API documentation is in the `docs/` directory alongside this file.
|
|
5
|
+
|
|
6
|
+
> ### Table of Contents
|
|
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)
|
|
5
17
|
|
|
6
18
|
---
|
|
7
19
|
|
|
@@ -9,7 +21,7 @@ Full API documentation is in the `docs/` directory alongside this file.
|
|
|
9
21
|
|
|
10
22
|
`leviathan-crypto` is a zero-dependency WebAssembly cryptography library for
|
|
11
23
|
TypeScript and JavaScript. All cryptographic computation runs in WASM, outside
|
|
12
|
-
the JavaScript JIT. The TypeScript layer provides the public API
|
|
24
|
+
the JavaScript JIT. The TypeScript layer provides the public API: input
|
|
13
25
|
validation, type safety, and ergonomics. It never implements cryptographic
|
|
14
26
|
algorithms itself.
|
|
15
27
|
|
|
@@ -22,24 +34,31 @@ module is loaded throws immediately with a clear error. Call `init()` once at
|
|
|
22
34
|
startup, before any cryptographic operations.
|
|
23
35
|
|
|
24
36
|
```typescript
|
|
25
|
-
import { init,
|
|
37
|
+
import { init, Serpent } from 'leviathan-crypto'
|
|
38
|
+
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
39
|
+
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
26
40
|
|
|
27
|
-
await init(
|
|
41
|
+
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
28
42
|
```
|
|
29
43
|
|
|
30
|
-
|
|
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.
|
|
31
50
|
|
|
32
51
|
---
|
|
33
52
|
|
|
34
53
|
## Critical: call `dispose()` after use
|
|
35
54
|
|
|
36
55
|
Every class holds WASM memory containing key material. Call `dispose()` when
|
|
37
|
-
done
|
|
56
|
+
done; it zeroes that memory. Not calling `dispose()` leaks key material.
|
|
38
57
|
|
|
39
58
|
```typescript
|
|
40
|
-
const cipher = new
|
|
59
|
+
const cipher = new XChaCha20Poly1305()
|
|
41
60
|
try {
|
|
42
|
-
return cipher.encrypt(key, plaintext)
|
|
61
|
+
return cipher.encrypt(key, nonce, plaintext)
|
|
43
62
|
} finally {
|
|
44
63
|
cipher.dispose()
|
|
45
64
|
}
|
|
@@ -50,7 +69,7 @@ try {
|
|
|
50
69
|
## Critical: `decrypt()` throws on authentication failure — never returns null
|
|
51
70
|
|
|
52
71
|
All AEAD `decrypt()` methods throw if authentication fails. Do not check for a
|
|
53
|
-
null return
|
|
72
|
+
null return; catch the exception.
|
|
54
73
|
|
|
55
74
|
```typescript
|
|
56
75
|
try {
|
|
@@ -64,34 +83,44 @@ try {
|
|
|
64
83
|
|
|
65
84
|
## Critical: subpath init function names
|
|
66
85
|
|
|
67
|
-
Each subpath export has its own module-specific init function
|
|
86
|
+
Each subpath export has its own module-specific init function, not `init()`.
|
|
68
87
|
These are only needed for tree-shakeable imports. The root barrel `init()` is
|
|
69
88
|
the normal path.
|
|
70
89
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
|
75
|
-
|
|
76
|
-
| `leviathan-crypto/
|
|
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` |
|
|
77
101
|
|
|
78
102
|
```typescript
|
|
79
103
|
// Tree-shakeable — loads only serpent WASM
|
|
80
|
-
import { serpentInit,
|
|
81
|
-
|
|
104
|
+
import { serpentInit, Serpent } from 'leviathan-crypto/serpent'
|
|
105
|
+
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
106
|
+
await serpentInit(serpentWasm)
|
|
82
107
|
```
|
|
83
108
|
|
|
84
109
|
---
|
|
85
110
|
|
|
86
111
|
## Which module does each class require?
|
|
87
112
|
|
|
88
|
-
| Classes |
|
|
89
|
-
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
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 })` |
|
|
95
124
|
|
|
96
125
|
---
|
|
97
126
|
|
|
@@ -100,16 +129,15 @@ await serpentInit()
|
|
|
100
129
|
### Authenticated encryption (recommended default)
|
|
101
130
|
|
|
102
131
|
```typescript
|
|
103
|
-
import { init,
|
|
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'
|
|
104
135
|
|
|
105
|
-
await init(
|
|
136
|
+
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
106
137
|
|
|
107
|
-
const key
|
|
108
|
-
const
|
|
109
|
-
const
|
|
110
|
-
const decrypted = seal.decrypt(key, ciphertext) // throws on tamper
|
|
111
|
-
// Optional AAD: seal.encrypt(key, plaintext, aad) / seal.decrypt(key, ciphertext, aad)
|
|
112
|
-
seal.dispose()
|
|
138
|
+
const key = SerpentCipher.keygen()
|
|
139
|
+
const blob = Seal.encrypt(SerpentCipher, key, plaintext)
|
|
140
|
+
const decrypted = Seal.decrypt(SerpentCipher, key, blob)
|
|
113
141
|
```
|
|
114
142
|
|
|
115
143
|
### Incremental streaming AEAD
|
|
@@ -117,67 +145,42 @@ seal.dispose()
|
|
|
117
145
|
Use when you cannot buffer the full message before encrypting.
|
|
118
146
|
|
|
119
147
|
```typescript
|
|
120
|
-
import { init,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
const
|
|
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)
|
|
134
165
|
```
|
|
135
166
|
|
|
136
167
|
### Length-prefixed streaming (for files and buffered transports)
|
|
137
168
|
|
|
138
|
-
Pass `{ framed: true }` to `
|
|
139
|
-
|
|
140
|
-
|
|
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).
|
|
141
172
|
|
|
142
173
|
```typescript
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
await init(['serpent', 'sha2'])
|
|
146
|
-
|
|
147
|
-
const key = randomBytes(64)
|
|
148
|
-
const sealer = new SerpentStreamSealer(key, 65536, { framed: true })
|
|
149
|
-
const header = sealer.header()
|
|
150
|
-
|
|
151
|
-
const frame0 = sealer.seal(data0) // u32be(len) || sealed chunk
|
|
152
|
-
const last = sealer.final(tail)
|
|
153
|
-
|
|
154
|
-
const opener = new SerpentStreamOpener(key, header, { framed: true })
|
|
155
|
-
const chunks = opener.feed(frame0) // Uint8Array[] — throws on auth failure
|
|
174
|
+
const sealer = new SealStream(SerpentCipher, key, { framed: true })
|
|
156
175
|
```
|
|
157
176
|
|
|
158
|
-
### XChaCha20Seal (recommended)
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
import { init, XChaCha20Seal, randomBytes } from 'leviathan-crypto'
|
|
162
|
-
|
|
163
|
-
await init(['chacha20'])
|
|
164
|
-
|
|
165
|
-
const seal = new XChaCha20Seal(randomBytes(32)) // 32-byte key
|
|
166
|
-
const ct = seal.encrypt(plaintext) // nonce(24) || ct || tag(16)
|
|
167
|
-
const pt = seal.decrypt(ct) // throws on tamper
|
|
168
|
-
seal.dispose()
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
Binds key at construction, generates a fresh nonce per `encrypt()` call. No nonce
|
|
172
|
-
management needed. For protocol interop requiring explicit nonces, use
|
|
173
|
-
`XChaCha20Poly1305` directly.
|
|
174
|
-
|
|
175
177
|
### XChaCha20-Poly1305
|
|
176
178
|
|
|
177
179
|
```typescript
|
|
178
180
|
import { init, XChaCha20Poly1305, randomBytes } from 'leviathan-crypto'
|
|
181
|
+
import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
|
|
179
182
|
|
|
180
|
-
await init(
|
|
183
|
+
await init({ chacha20: chacha20Wasm })
|
|
181
184
|
|
|
182
185
|
const aead = new XChaCha20Poly1305()
|
|
183
186
|
const key = randomBytes(32)
|
|
@@ -188,14 +191,15 @@ aead.dispose()
|
|
|
188
191
|
```
|
|
189
192
|
|
|
190
193
|
Note: `encrypt()` returns ciphertext with the 16-byte Poly1305 tag appended.
|
|
191
|
-
`decrypt()` expects the same concatenated format
|
|
194
|
+
`decrypt()` expects the same concatenated format, not separate ciphertext and tag.
|
|
192
195
|
|
|
193
196
|
### Hashing
|
|
194
197
|
|
|
195
198
|
```typescript
|
|
196
199
|
import { init, SHA256, HMAC_SHA256 } from 'leviathan-crypto'
|
|
200
|
+
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
197
201
|
|
|
198
|
-
await init(
|
|
202
|
+
await init({ sha2: sha2Wasm })
|
|
199
203
|
|
|
200
204
|
const hasher = new SHA256()
|
|
201
205
|
const digest = hasher.hash(data) // returns Uint8Array
|
|
@@ -210,8 +214,9 @@ mac.dispose()
|
|
|
210
214
|
|
|
211
215
|
```typescript
|
|
212
216
|
import { init, SHAKE128 } from 'leviathan-crypto'
|
|
217
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
213
218
|
|
|
214
|
-
await init(
|
|
219
|
+
await init({ sha3: sha3Wasm })
|
|
215
220
|
|
|
216
221
|
const xof = new SHAKE128()
|
|
217
222
|
xof.absorb(data)
|
|
@@ -220,12 +225,39 @@ const out2 = xof.squeeze(32) // next 32 bytes — contiguous XOF stream
|
|
|
220
225
|
xof.dispose()
|
|
221
226
|
```
|
|
222
227
|
|
|
228
|
+
### ML-KEM post-quantum key encapsulation
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { init, MlKem768 } from 'leviathan-crypto'
|
|
232
|
+
import { kyberWasm } from 'leviathan-crypto/kyber/embedded'
|
|
233
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
234
|
+
|
|
235
|
+
await init({ kyber: kyberWasm, sha3: sha3Wasm })
|
|
236
|
+
|
|
237
|
+
const kem = new MlKem768()
|
|
238
|
+
const { encapsulationKey, decapsulationKey } = kem.keygen()
|
|
239
|
+
|
|
240
|
+
// Encapsulation (sender — public encapsulationKey only)
|
|
241
|
+
const { ciphertext, sharedSecret: senderSecret } = kem.encapsulate(encapsulationKey)
|
|
242
|
+
|
|
243
|
+
// Decapsulation (recipient — private decapsulationKey)
|
|
244
|
+
const recipientSecret = kem.decapsulate(decapsulationKey, ciphertext)
|
|
245
|
+
|
|
246
|
+
// senderSecret === recipientSecret (32 bytes)
|
|
247
|
+
kem.dispose()
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Kyber classes require **both** `kyber` and `sha3` initialized. ML-KEM produces
|
|
251
|
+
a 32-byte shared secret suitable for use as a symmetric key.
|
|
252
|
+
|
|
223
253
|
### Fortuna CSPRNG
|
|
224
254
|
|
|
225
255
|
```typescript
|
|
226
256
|
import { init, Fortuna } from 'leviathan-crypto'
|
|
257
|
+
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
258
|
+
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
227
259
|
|
|
228
|
-
await init(
|
|
260
|
+
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
229
261
|
|
|
230
262
|
const fortuna = await Fortuna.create() // static factory — not new Fortuna()
|
|
231
263
|
const bytes = fortuna.get(32)
|
|
@@ -244,7 +276,7 @@ cipher.decrypt(key, iv, ciphertext) // correct
|
|
|
244
276
|
```
|
|
245
277
|
|
|
246
278
|
`SerpentCbc` is unauthenticated. Always pair with `HMAC_SHA256`
|
|
247
|
-
(Encrypt-then-MAC) or use `
|
|
279
|
+
(Encrypt-then-MAC) or use `Seal` with `SerpentCipher` instead.
|
|
248
280
|
|
|
249
281
|
---
|
|
250
282
|
|
|
@@ -261,10 +293,11 @@ const safe = constantTimeEqual(a, b) // constant-time equality — never use =
|
|
|
261
293
|
wipe(key) // zero a Uint8Array in place
|
|
262
294
|
```
|
|
263
295
|
|
|
264
|
-
`hasSIMD()` returns `true` if the runtime supports WebAssembly SIMD.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
296
|
+
`hasSIMD()` returns `true` if the runtime supports WebAssembly SIMD.
|
|
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.
|
|
268
301
|
|
|
269
302
|
---
|
|
270
303
|
|
|
@@ -274,12 +307,14 @@ The complete API reference ships in `docs/` alongside this file:
|
|
|
274
307
|
|
|
275
308
|
| File | Contents |
|
|
276
309
|
|------|----------|
|
|
277
|
-
| `docs/serpent.md` | `
|
|
278
|
-
| `docs/chacha20.md` | `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, `
|
|
310
|
+
| `docs/serpent.md` | `SerpentCipher`, `Serpent`, `SerpentCtr`, `SerpentCbc` |
|
|
311
|
+
| `docs/chacha20.md` | `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, `XChaCha20Cipher` |
|
|
279
312
|
| `docs/sha2.md` | `SHA256`, `SHA384`, `SHA512`, `HMAC_SHA256`, `HMAC_SHA384`, `HMAC_SHA512`, `HKDF_SHA256`, `HKDF_SHA512` |
|
|
280
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 |
|
|
281
316
|
| `docs/fortuna.md` | `Fortuna` CSPRNG |
|
|
282
317
|
| `docs/init.md` | `init()` API, loading modes, subpath imports |
|
|
283
318
|
| `docs/utils.md` | Encoding helpers, `constantTimeEqual`, `wipe`, `randomBytes` |
|
|
284
|
-
| `docs/types.md` | `Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD` interfaces |
|
|
319
|
+
| `docs/types.md` | `Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD` interfaces; `CipherSuite`, `DerivedKeys`, `SealStreamOpts`, `PoolOpts`, `WasmSource` |
|
|
285
320
|
| `docs/architecture.md` | Module structure, WASM layer, three-tier design |
|