leviathan-crypto 2.0.1 → 2.1.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 +171 -7
- package/LICENSE +4 -0
- package/README.md +109 -54
- package/SECURITY.md +125 -238
- package/dist/chacha20/cipher-suite.d.ts +10 -0
- package/dist/chacha20/cipher-suite.js +65 -2
- package/dist/chacha20/generator.d.ts +12 -0
- package/dist/chacha20/generator.js +91 -0
- package/dist/chacha20/index.d.ts +97 -1
- package/dist/chacha20/index.js +139 -11
- package/dist/chacha20/ops.d.ts +57 -6
- package/dist/chacha20/ops.js +93 -13
- package/dist/chacha20/pool-worker.js +12 -0
- package/dist/chacha20/types.d.ts +1 -32
- package/dist/ct-wasm.js +1 -1
- package/dist/ct.wasm +0 -0
- package/dist/docs/aead.md +66 -26
- package/dist/docs/architecture.md +600 -521
- package/dist/docs/argon2id.md +17 -14
- package/dist/docs/chacha20.md +146 -39
- package/dist/docs/exports.md +46 -10
- package/dist/docs/fortuna.md +339 -122
- package/dist/docs/init.md +24 -25
- package/dist/docs/loader.md +142 -47
- package/dist/docs/serpent.md +139 -41
- package/dist/docs/sha2.md +77 -19
- package/dist/docs/sha3.md +81 -15
- package/dist/docs/types.md +155 -15
- package/dist/docs/utils.md +171 -81
- package/dist/embedded/chacha20-pool-worker.d.ts +1 -0
- package/dist/embedded/chacha20-pool-worker.js +5 -0
- package/dist/embedded/kyber.d.ts +1 -1
- package/dist/embedded/kyber.js +1 -1
- package/dist/embedded/serpent-pool-worker.d.ts +1 -0
- package/dist/embedded/serpent-pool-worker.js +5 -0
- package/dist/fortuna.d.ts +14 -8
- package/dist/fortuna.js +144 -50
- package/dist/index.d.ts +8 -6
- package/dist/index.js +6 -5
- package/dist/init.d.ts +0 -2
- package/dist/init.js +83 -3
- package/dist/kyber/indcpa.js +4 -4
- package/dist/kyber/index.js +25 -5
- package/dist/kyber/kem.js +56 -1
- package/dist/kyber/suite.d.ts +1 -2
- package/dist/kyber/types.d.ts +1 -0
- package/dist/kyber/validate.d.ts +8 -4
- package/dist/kyber/validate.js +18 -14
- package/dist/kyber.wasm +0 -0
- package/dist/loader.d.ts +7 -2
- package/dist/loader.js +25 -28
- package/dist/ratchet/index.d.ts +6 -0
- package/dist/ratchet/index.js +37 -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 +135 -50
- package/dist/serpent/generator.d.ts +12 -0
- package/dist/serpent/generator.js +97 -0
- package/dist/serpent/index.d.ts +61 -1
- package/dist/serpent/index.js +92 -7
- package/dist/serpent/pool-worker.js +25 -101
- package/dist/serpent/serpent-cbc.d.ts +14 -4
- package/dist/serpent/serpent-cbc.js +50 -32
- package/dist/serpent/shared-ops.d.ts +83 -0
- package/dist/serpent/shared-ops.js +213 -0
- package/dist/serpent/types.d.ts +1 -5
- package/dist/sha2/hash.d.ts +2 -0
- package/dist/sha2/hash.js +53 -0
- package/dist/sha2/index.d.ts +1 -0
- package/dist/sha2/index.js +15 -1
- package/dist/sha3/hash.d.ts +2 -0
- package/dist/sha3/hash.js +53 -0
- package/dist/sha3/index.d.ts +17 -2
- package/dist/sha3/index.js +79 -7
- package/dist/stream/header.js +5 -5
- package/dist/stream/open-stream.js +36 -14
- package/dist/stream/seal-stream-pool.d.ts +1 -0
- package/dist/stream/seal-stream-pool.js +38 -8
- package/dist/stream/seal-stream.js +29 -11
- package/dist/types.d.ts +21 -0
- package/dist/utils.d.ts +7 -8
- package/dist/utils.js +73 -40
- package/dist/wasm-source.d.ts +9 -8
- package/package.json +79 -64
package/dist/docs/argon2id.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<img src="https://github.com/xero/leviathan-crypto/raw/main/docs/logo.svg" alt="logo" width="120" align="left" margin="10">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
> how to pair it with leviathan primitives for passphrase-based encryption.
|
|
3
|
+
### Argon2id: Memory-Hardened Password Hashing and Key Derivation
|
|
4
|
+
|
|
5
|
+
leviathan-crypto does not wrap Argon2id. This document covers how to use the [`argon2id`](https://www.npmjs.com/package/argon2id) npm package directly and how to pair it with leviathan primitives for passphrase-based encryption.
|
|
7
6
|
|
|
8
7
|
> ### Table of Contents
|
|
9
8
|
> - [Why Argon2id](#why-argon2id)
|
|
@@ -291,12 +290,16 @@ xc2.dispose();
|
|
|
291
290
|
|
|
292
291
|
---
|
|
293
292
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
293
|
+
|
|
294
|
+
## Cross-References
|
|
295
|
+
|
|
296
|
+
| Document | Description |
|
|
297
|
+
| -------- | ----------- |
|
|
298
|
+
| [index](./README.md) | Project Documentation index |
|
|
299
|
+
| [sha2](./sha2.md) | HKDF-SHA256 for key expansion from Argon2id root keys |
|
|
300
|
+
| [serpent](./serpent.md) | `SerpentCipher`: Serpent-256 cipher suite (use with `Seal` and Argon2id-derived keys) |
|
|
301
|
+
| [authenticated encryption](./aead.md) | `Seal`, `SealStream`, `OpenStream`: cipher-agnostic AEAD APIs using a `CipherSuite` such as `SerpentCipher` or `XChaCha20Cipher` |
|
|
302
|
+
| [chacha20](./chacha20.md) | XChaCha20Poly1305: ChaCha20 authenticated encryption (pairs with Argon2id-derived keys) |
|
|
303
|
+
| [utils](./utils.md) | `randomBytes` for generating salts, `constantTimeEqual` for hash verification |
|
|
304
|
+
| [architecture](./architecture.md) | architecture overview, module relationships, buffer layouts, and build pipeline |
|
|
305
|
+
|
package/dist/docs/chacha20.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<img src="https://github.com/xero/leviathan-crypto/raw/main/docs/logo.svg" alt="logo" width="120" align="left" margin="10">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
### ChaCha20 TypeScript API
|
|
4
|
+
|
|
5
|
+
API reference for `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, and `XChaCha20Cipher`. Covers initialization, all class methods, usage examples, and error conditions.
|
|
5
6
|
|
|
6
7
|
> ### Table of Contents
|
|
7
8
|
> - [Overview](#overview)
|
|
@@ -12,6 +13,7 @@
|
|
|
12
13
|
> - [`Poly1305`](#poly1305)
|
|
13
14
|
> - [`ChaCha20Poly1305`](#chacha20poly1305)
|
|
14
15
|
> - [`XChaCha20Poly1305`](#xchacha20poly1305)
|
|
16
|
+
> - [`ChaCha20Generator`](#chacha20generator)
|
|
15
17
|
> - [XChaCha20Cipher](#xchacha20cipher)
|
|
16
18
|
> - [Usage Examples](#usage-examples)
|
|
17
19
|
> - [Error Conditions](#error-conditions)
|
|
@@ -20,11 +22,13 @@
|
|
|
20
22
|
|
|
21
23
|
## Overview
|
|
22
24
|
|
|
23
|
-
**ChaCha20** is a modern stream cipher designed by Daniel J. Bernstein. It is
|
|
24
|
-
on all platforms (including those without hardware AES), resistant to
|
|
25
|
-
by design, and widely deployed in TLS, SSH, and WireGuard.
|
|
26
|
-
by generating a pseudorandom keystream from a 256-bit
|
|
27
|
-
it with the plaintext. It does **not** provide
|
|
25
|
+
**ChaCha20** is a modern stream cipher designed by Daniel J. Bernstein. It is
|
|
26
|
+
fast on all platforms (including those without hardware AES), resistant to
|
|
27
|
+
timing attacks by design, and widely deployed in TLS, SSH, and WireGuard.
|
|
28
|
+
ChaCha20 encrypts data by generating a pseudorandom keystream from a 256-bit
|
|
29
|
+
key and a nonce, then XORing it with the plaintext. It does **not** provide
|
|
30
|
+
authentication on its own. A modified message will decrypt to garbage with no
|
|
31
|
+
warning.
|
|
28
32
|
|
|
29
33
|
**Poly1305** is a one-time message authentication code (MAC). Given a unique 256-bit
|
|
30
34
|
key and a message, it produces a 16-byte tag that proves the message has not been
|
|
@@ -41,10 +45,10 @@ you get an error instead of corrupted data. The nonce is 96 bits (12 bytes).
|
|
|
41
45
|
**XChaCha20-Poly1305** extends the nonce to 192 bits (24 bytes) using the HChaCha20
|
|
42
46
|
subkey derivation step. This makes random nonce generation completely safe. With a
|
|
43
47
|
24-byte nonce, the probability of a collision is negligible even after billions of
|
|
44
|
-
messages. **For most users, `Seal` with `XChaCha20Cipher`
|
|
45
|
-
produces a self-contained authenticated blob with
|
|
46
|
-
instantiation, and no `dispose()`. For protocol interop
|
|
47
|
-
control, use `XChaCha20Poly1305` directly.
|
|
48
|
+
messages. **For most users, [`Seal`](./aead.md#seal) with [`XChaCha20Cipher`](./ciphersuite.md#xchacha20cipher)
|
|
49
|
+
is the recommended choice.** It produces a self-contained authenticated blob with
|
|
50
|
+
no nonce management, no instantiation, and no `dispose()`. For protocol interop
|
|
51
|
+
requiring explicit nonce control, use `XChaCha20Poly1305` directly.
|
|
48
52
|
|
|
49
53
|
---
|
|
50
54
|
|
|
@@ -54,10 +58,10 @@ control, use `XChaCha20Poly1305` directly.
|
|
|
54
58
|
> Read this section before writing any code. These are not theoretical concerns.
|
|
55
59
|
> They are the mistakes that cause real-world breaches.
|
|
56
60
|
|
|
57
|
-
- **Use `Seal` with `XChaCha20Cipher`
|
|
58
|
-
It is the safest default: authenticated
|
|
59
|
-
If you are unsure which class to pick, pick this
|
|
60
|
-
when protocol interop requires you to manage nonces yourself.
|
|
61
|
+
- **Use [`Seal`](./aead.md#seal) with [`XChaCha20Cipher`](./ciphersuite.md#xchacha20cipher)
|
|
62
|
+
unless you need explicit nonce control.** It is the safest default: authenticated
|
|
63
|
+
encryption in a single static call. If you are unsure which class to pick, pick this
|
|
64
|
+
one. Use `XChaCha20Poly1305` when protocol interop requires you to manage nonces yourself.
|
|
61
65
|
|
|
62
66
|
- **Never reuse a nonce with the same key.** This is the single most important
|
|
63
67
|
rule. If you encrypt two different messages with the same key and the same nonce,
|
|
@@ -138,13 +142,21 @@ Error: leviathan-crypto: call init({ chacha20: ... }) before using this class
|
|
|
138
142
|
Raw ChaCha20 stream cipher. **No authentication.** Use `XChaCha20Poly1305` instead
|
|
139
143
|
unless you are building a custom protocol and understand the risks.
|
|
140
144
|
|
|
145
|
+
> [!CAUTION]
|
|
146
|
+
> `ChaCha20` is stateful and holds exclusive access to the `chacha20` WASM
|
|
147
|
+
> module for its entire lifetime. Constructing a second `ChaCha20`, or any
|
|
148
|
+
> atomic chacha20 class (`Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`,
|
|
149
|
+
> or a `XChaCha20Cipher`-backed `Seal`/`SealStream`), while this instance is
|
|
150
|
+
> live throws. Call `dispose()` when done. Pool workers are unaffected.
|
|
151
|
+
|
|
141
152
|
#### Constructor
|
|
142
153
|
|
|
143
154
|
```typescript
|
|
144
155
|
new ChaCha20()
|
|
145
156
|
```
|
|
146
157
|
|
|
147
|
-
Throws if `init({ chacha20: chacha20Wasm })` has not been called
|
|
158
|
+
Throws if `init({ chacha20: chacha20Wasm })` has not been called, or if
|
|
159
|
+
another stateful chacha20 instance is still live.
|
|
148
160
|
|
|
149
161
|
---
|
|
150
162
|
|
|
@@ -159,6 +171,13 @@ Prepares the cipher for encryption with the given key and nonce.
|
|
|
159
171
|
|
|
160
172
|
**Throws** `RangeError` if `key` is not 32 bytes or `nonce` is not 12 bytes.
|
|
161
173
|
|
|
174
|
+
> [!NOTE]
|
|
175
|
+
> **Block counter convention.** `beginEncrypt()` starts the ChaCha20 keystream
|
|
176
|
+
> at block counter 1, not 0. Block 0 is reserved for Poly1305 one-time key
|
|
177
|
+
> generation per RFC 8439 §2.6. The class is designed for use inside an AEAD
|
|
178
|
+
> construction; if you need to match RFC 8439 §2.4.2 verbatim (keystream
|
|
179
|
+
> starting at counter 0), use the lower-level primitives directly.
|
|
180
|
+
|
|
162
181
|
---
|
|
163
182
|
|
|
164
183
|
#### `encryptChunk(chunk: Uint8Array): Uint8Array`
|
|
@@ -176,7 +195,8 @@ a new `Uint8Array` containing the ciphertext (same length as input).
|
|
|
176
195
|
|
|
177
196
|
#### `beginDecrypt(key: Uint8Array, nonce: Uint8Array): void`
|
|
178
197
|
|
|
179
|
-
Prepares the cipher for decryption. Identical to `beginEncrypt`. ChaCha20 is
|
|
198
|
+
Prepares the cipher for decryption. Identical to `beginEncrypt`. ChaCha20 is
|
|
199
|
+
symmetric; encryption and decryption are the same XOR operation.
|
|
180
200
|
|
|
181
201
|
| Parameter | Type | Description |
|
|
182
202
|
|-----------|------|-------------|
|
|
@@ -205,6 +225,11 @@ plaintext (same length as input).
|
|
|
205
225
|
Wipes all key material and intermediate state from WASM memory. Always call this
|
|
206
226
|
when you are done with the instance.
|
|
207
227
|
|
|
228
|
+
After `dispose()`, all instance methods (`beginEncrypt`, `encryptChunk`,
|
|
229
|
+
`beginDecrypt`, `decryptChunk`) throw `Error: ChaCha20: instance has been
|
|
230
|
+
disposed`. Disposal is permanent; construct a new instance if you need to
|
|
231
|
+
continue.
|
|
232
|
+
|
|
208
233
|
---
|
|
209
234
|
|
|
210
235
|
### `Poly1305`
|
|
@@ -272,6 +297,13 @@ appended.
|
|
|
272
297
|
> Each `ChaCha20Poly1305` instance allows only **one** `encrypt()` call. A second
|
|
273
298
|
> call throws to prevent accidental nonce reuse. Create a new instance for each
|
|
274
299
|
> encryption, or use `Seal` with `XChaCha20Cipher` for automatic nonce management.
|
|
300
|
+
>
|
|
301
|
+
> **Strict single-use on any throw.** Any throw from `encrypt()`, including
|
|
302
|
+
> `RangeError` from wrong-length `key` or `nonce`, exclusivity errors, or any
|
|
303
|
+
> failure inside the WASM call, is *terminal*. The guard is set before
|
|
304
|
+
> argument validation, so a subsequent `encrypt()` on the same instance throws
|
|
305
|
+
> the single-use error rather than retrying. Always allocate a new AEAD
|
|
306
|
+
> instance per message.
|
|
275
307
|
|
|
276
308
|
| Parameter | Type | Default | Description |
|
|
277
309
|
|-----------|------|---------|-------------|
|
|
@@ -283,9 +315,9 @@ appended.
|
|
|
283
315
|
**Returns** `Uint8Array`: ciphertext + 16-byte tag (length = plaintext.length + 16).
|
|
284
316
|
|
|
285
317
|
**Throws:**
|
|
286
|
-
- `RangeError` if `key` is not 32 bytes
|
|
287
|
-
- `RangeError` if `nonce` is not 12 bytes
|
|
288
|
-
- `RangeError` if `plaintext` exceeds the maximum chunk size
|
|
318
|
+
- `RangeError` if `key` is not 32 bytes *(terminal: instance locked)*
|
|
319
|
+
- `RangeError` if `nonce` is not 12 bytes *(terminal: instance locked)*
|
|
320
|
+
- `RangeError` if `plaintext` exceeds the maximum chunk size *(terminal: instance locked)*
|
|
289
321
|
- `Error` if `encrypt()` has already been called on this instance
|
|
290
322
|
|
|
291
323
|
---
|
|
@@ -297,7 +329,8 @@ parameter must include the appended 16-byte tag (i.e., the exact output of
|
|
|
297
329
|
`encrypt()`). If authentication fails, an error is thrown and no plaintext is
|
|
298
330
|
returned.
|
|
299
331
|
|
|
300
|
-
Tag comparison uses a constant-time XOR-accumulate pattern; no timing side
|
|
332
|
+
Tag comparison uses a constant-time XOR-accumulate pattern; no timing side
|
|
333
|
+
channel leaks whether the tag was "close" to correct.
|
|
301
334
|
|
|
302
335
|
| Parameter | Type | Default | Description |
|
|
303
336
|
|-----------|------|---------|-------------|
|
|
@@ -326,8 +359,8 @@ Wipes all key material and intermediate state from WASM memory.
|
|
|
326
359
|
|
|
327
360
|
XChaCha20-Poly1305 AEAD (draft-irtf-cfrg-xchacha). RFC-faithful stateless
|
|
328
361
|
primitive. Key and nonce are passed per-call. Use when protocol interop
|
|
329
|
-
requires explicit nonce control. For most use cases, prefer `Seal`
|
|
330
|
-
`XChaCha20Cipher`
|
|
362
|
+
requires explicit nonce control. For most use cases, prefer [`Seal`](./aead.md#seal)
|
|
363
|
+
with [`XChaCha20Cipher`](./ciphersuite.md#xchacha20cipher)(automatic nonce management, no instantiation).
|
|
331
364
|
|
|
332
365
|
It uses a 24-byte (192-bit) nonce, which is large enough that randomly generated
|
|
333
366
|
nonces will never collide in practice. Internally, it derives a subkey via
|
|
@@ -351,6 +384,19 @@ Throws if `init({ chacha20: chacha20Wasm })` has not been called.
|
|
|
351
384
|
|
|
352
385
|
Encrypts plaintext and returns the ciphertext with the 16-byte tag appended.
|
|
353
386
|
|
|
387
|
+
> [!WARNING]
|
|
388
|
+
> Same single-use contract as `ChaCha20Poly1305.encrypt()`. Each instance
|
|
389
|
+
> allows only **one** `encrypt()` call. A second call throws to prevent
|
|
390
|
+
> accidental nonce reuse. Create a new instance for each encryption, or use
|
|
391
|
+
> `Seal` with `XChaCha20Cipher` for automatic nonce management.
|
|
392
|
+
>
|
|
393
|
+
> **Strict single-use on any throw.** Any throw from `encrypt()` is *terminal*,
|
|
394
|
+
> whether the cause is a `RangeError` from wrong-length `key` or `nonce`, an
|
|
395
|
+
> exclusivity error, or a failure inside the WASM call. The guard is set
|
|
396
|
+
> before argument validation, so a subsequent `encrypt()` on the same instance
|
|
397
|
+
> throws the single-use error rather than retrying with a reused nonce. Always
|
|
398
|
+
> allocate a new AEAD instance per message.
|
|
399
|
+
|
|
354
400
|
| Parameter | Type | Default | Description |
|
|
355
401
|
|-----------|------|---------|-------------|
|
|
356
402
|
| `key` | `Uint8Array` | | 32 bytes (256-bit key) |
|
|
@@ -361,8 +407,10 @@ Encrypts plaintext and returns the ciphertext with the 16-byte tag appended.
|
|
|
361
407
|
**Returns** `Uint8Array`: ciphertext + 16-byte tag (length = plaintext.length + 16).
|
|
362
408
|
|
|
363
409
|
**Throws:**
|
|
364
|
-
- `RangeError` if `key` is not 32 bytes
|
|
365
|
-
- `RangeError` if `nonce` is not 24 bytes
|
|
410
|
+
- `RangeError` if `key` is not 32 bytes *(terminal: instance locked)*
|
|
411
|
+
- `RangeError` if `nonce` is not 24 bytes *(terminal: instance locked)*
|
|
412
|
+
- `RangeError` if `plaintext` exceeds the maximum chunk size *(terminal: instance locked)*
|
|
413
|
+
- `Error` if `encrypt()` has already been called on this instance
|
|
366
414
|
|
|
367
415
|
---
|
|
368
416
|
|
|
@@ -395,6 +443,59 @@ Wipes all key material and intermediate state from WASM memory.
|
|
|
395
443
|
|
|
396
444
|
---
|
|
397
445
|
|
|
446
|
+
### ChaCha20Generator
|
|
447
|
+
|
|
448
|
+
ChaCha20 block-function PRF for Fortuna's generator slot (RFC 8439 §2.3).
|
|
449
|
+
Uses a fixed zero nonce; Fortuna's counter is the only varying input.
|
|
450
|
+
Implements the `Generator` interface. Plain `const` object — no instantiation,
|
|
451
|
+
no `dispose()`.
|
|
452
|
+
|
|
453
|
+
Requires `init({ chacha20: chacha20Wasm })`. See [fortuna.md](./fortuna.md)
|
|
454
|
+
for full usage with `Fortuna.create()`.
|
|
455
|
+
|
|
456
|
+
| Property | Value |
|
|
457
|
+
|----------|-------|
|
|
458
|
+
| `keySize` | `32` |
|
|
459
|
+
| `blockSize` | `64` |
|
|
460
|
+
| `counterSize` | `4` |
|
|
461
|
+
| `wasmModules` | `['chacha20']` |
|
|
462
|
+
|
|
463
|
+
#### `ChaCha20Generator.generate(key, counter, n): Uint8Array`
|
|
464
|
+
|
|
465
|
+
Produces `n` bytes from `(key, counter)`. Neither input is mutated. Wipes WASM
|
|
466
|
+
key/state/keystream scratch before returning.
|
|
467
|
+
|
|
468
|
+
| Parameter | Type | Description |
|
|
469
|
+
|-----------|------|-------------|
|
|
470
|
+
| `key` | `Uint8Array` | 32 bytes |
|
|
471
|
+
| `counter` | `Uint8Array` | 4 bytes, read as a little-endian u32 |
|
|
472
|
+
| `n` | `number` | Output byte count: 0 ≤ n ≤ 2³⁰ |
|
|
473
|
+
|
|
474
|
+
**Returns** a new `Uint8Array` of length `n`.
|
|
475
|
+
|
|
476
|
+
**Throws:**
|
|
477
|
+
- `RangeError('ChaCha20Generator: key must be 32 bytes (got N)')` if key length ≠ 32
|
|
478
|
+
- `RangeError('ChaCha20Generator: counter must be 4 bytes (got N)')` if counter length ≠ 4
|
|
479
|
+
- `RangeError('ChaCha20Generator: n must be a non-negative safe integer <= 2^30 (got N)')` if n is out of range
|
|
480
|
+
- `Error` if another stateful instance currently owns the `chacha20` WASM module
|
|
481
|
+
|
|
482
|
+
#### Usage with `Fortuna`
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
import { init, Fortuna } from 'leviathan-crypto'
|
|
486
|
+
import { ChaCha20Generator } from 'leviathan-crypto/chacha20'
|
|
487
|
+
import { SHA256Hash } from 'leviathan-crypto/sha2'
|
|
488
|
+
import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
|
|
489
|
+
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
490
|
+
|
|
491
|
+
await init({ chacha20: chacha20Wasm, sha2: sha2Wasm })
|
|
492
|
+
const rng = await Fortuna.create({ generator: ChaCha20Generator, hash: SHA256Hash })
|
|
493
|
+
const bytes = rng.get(32)
|
|
494
|
+
rng.stop()
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
398
499
|
## XChaCha20Cipher
|
|
399
500
|
|
|
400
501
|
`CipherSuite` implementation for XChaCha20-Poly1305. Pass to `Seal`,
|
|
@@ -412,7 +513,7 @@ Requires `init({ chacha20: chacha20Wasm, sha2: sha2Wasm })`.
|
|
|
412
513
|
| `keySize` | `32` |
|
|
413
514
|
| `tagSize` | `16` (Poly1305) |
|
|
414
515
|
| `padded` | `false` |
|
|
415
|
-
| `wasmModules` | `['chacha20'
|
|
516
|
+
| `wasmModules` | `['chacha20']` |
|
|
416
517
|
|
|
417
518
|
#### `XChaCha20Cipher.keygen(): Uint8Array`
|
|
418
519
|
|
|
@@ -638,7 +739,7 @@ const pt2 = cipher.decryptChunk(ct2)
|
|
|
638
739
|
|
|
639
740
|
// WARNING: Without authentication, an attacker can flip bits in ciphertext
|
|
640
741
|
// and the corresponding plaintext bits will flip with no error.
|
|
641
|
-
//
|
|
742
|
+
// Use the seal api or XChaCha20Poly1305 instead.
|
|
642
743
|
|
|
643
744
|
cipher.dispose()
|
|
644
745
|
```
|
|
@@ -660,15 +761,21 @@ cipher.dispose()
|
|
|
660
761
|
| Chunk or plaintext exceeds WASM buffer size | `RangeError` | `plaintext exceeds N bytes — split into smaller chunks` / `chunk exceeds maximum size of N bytes — split into smaller chunks` |
|
|
661
762
|
| Authentication tag does not match on decrypt | `Error` | `ChaCha20Poly1305: authentication failed` |
|
|
662
763
|
| Empty plaintext | | Allowed. Encrypting zero bytes produces just a 16-byte tag (AEAD) or zero bytes (raw ChaCha20). |
|
|
764
|
+
| `ChaCha20Generator.generate()` key ≠ 32 bytes | `RangeError` | `ChaCha20Generator: key must be 32 bytes (got N)` |
|
|
765
|
+
| `ChaCha20Generator.generate()` counter ≠ 4 bytes | `RangeError` | `ChaCha20Generator: counter must be 4 bytes (got N)` |
|
|
766
|
+
| `ChaCha20Generator.generate()` n out of range | `RangeError` | `ChaCha20Generator: n must be a non-negative safe integer <= 2^30 (got N)` |
|
|
767
|
+
|
|
768
|
+
## Cross-References
|
|
769
|
+
|
|
770
|
+
| Document | Description |
|
|
771
|
+
| -------- | ----------- |
|
|
772
|
+
| [index](./README.md) | Project Documentation index |
|
|
773
|
+
| [lexicon](./lexicon.md) | Glossary of cryptographic terms |
|
|
774
|
+
| [asm_chacha](./asm_chacha.md) | WASM (AssemblyScript) implementation details for the chacha20 module |
|
|
775
|
+
| [authenticated encryption](./aead.md) | `Seal`, `SealStream`, `OpenStream`: use `XChaCha20Cipher` as the suite argument |
|
|
776
|
+
| [serpent](./serpent.md) | `SerpentCipher`: alternative `CipherSuite` for `Seal` and streaming |
|
|
777
|
+
| [sha2](./sha2.md) | SHA-2 hashes and HMAC. Needed for Encrypt-then-MAC if using raw ChaCha20 |
|
|
778
|
+
| [types](./types.md) | `AEAD` and `Streamcipher` interfaces implemented by ChaCha20 classes |
|
|
779
|
+
| [architecture](./architecture.md) | architecture overview, module relationships, buffer layouts, and build pipeline |
|
|
780
|
+
| [chacha_audit](./chacha_audit.md) | XChaCha20-Poly1305 implementation audit |
|
|
663
781
|
|
|
664
|
-
> ## Cross-References
|
|
665
|
-
>
|
|
666
|
-
> - [index](./README.md) — Project Documentation index
|
|
667
|
-
> - [lexicon](./lexicon.md) — Glossary of cryptographic terms
|
|
668
|
-
> - [asm_chacha](./asm_chacha.md) — WASM (AssemblyScript) implementation details for the chacha20 module
|
|
669
|
-
> - [authenticated encryption](./aead.md) — `Seal`, `SealStream`, `OpenStream`: use `XChaCha20Cipher` as the suite argument
|
|
670
|
-
> - [serpent](./serpent.md) — `SerpentCipher`: alternative `CipherSuite` for `Seal` and streaming
|
|
671
|
-
> - [sha2](./sha2.md) — SHA-2 hashes and HMAC. Needed for Encrypt-then-MAC if using raw ChaCha20
|
|
672
|
-
> - [types](./types.md) — `AEAD` and `Streamcipher` interfaces implemented by ChaCha20 classes
|
|
673
|
-
> - [architecture](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
674
|
-
> - [chacha_audit](./chacha_audit.md) — XChaCha20-Poly1305 implementation audit
|
package/dist/docs/exports.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<img src="https://github.com/xero/leviathan-crypto/raw/main/docs/logo.svg" alt="logo" width="120" align="left" margin="10">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
### All Exports
|
|
4
|
+
|
|
5
|
+
Complete reference for every public export in leviathan-crypto, grouped by module. Follow the module links for deeper documentation on each class.
|
|
5
6
|
|
|
6
7
|
> ### Table of Contents
|
|
7
8
|
> - [Initialization](#initialization)
|
|
@@ -14,6 +15,7 @@
|
|
|
14
15
|
> - [Keccak (alias for SHA-3)](#keccak-alias-for-sha-3)
|
|
15
16
|
> - [ML-KEM (Post-quantum KEM)](#ml-kem-post-quantum-kem)
|
|
16
17
|
> - [Fortuna CSPRNG](#fortuna-csprng)
|
|
18
|
+
> - [Ratchet (Sparse Post-Quantum Ratchet KDF)](#ratchet-sparse-post-quantum-ratchet-kdf)
|
|
17
19
|
> - [Types](#types)
|
|
18
20
|
> - [Utilities](#utilities)
|
|
19
21
|
|
|
@@ -191,11 +193,41 @@ Subpath: `leviathan-crypto/kyber`. See [kyber.md](./kyber.md).
|
|
|
191
193
|
|
|
192
194
|
## Fortuna CSPRNG
|
|
193
195
|
|
|
194
|
-
|
|
196
|
+
Takes a `Generator` and a `HashFn` at create time. Required `init()` modules depend on which pair you pass; valid combinations are listed in [fortuna.md](./fortuna.md).
|
|
197
|
+
|
|
198
|
+
| Export | Kind | Description |
|
|
199
|
+
|--------|------|-------------|
|
|
200
|
+
| `Fortuna` | class | Fortuna CSPRNG (Ferguson & Schneier). `Fortuna.create({ generator, hash })` static factory; `get(n)`, `addEntropy()`, `stop()`. |
|
|
201
|
+
| `SerpentGenerator` | const | `Generator` const for `Fortuna`. Serpent-256 PRF in counter mode. Requires `init({ serpent })`. Re-exported from `'leviathan-crypto/serpent'`. |
|
|
202
|
+
| `ChaCha20Generator` | const | `Generator` const for `Fortuna`. ChaCha20 PRF with fixed zero nonce. Requires `init({ chacha20 })`. Re-exported from `'leviathan-crypto/chacha20'`. |
|
|
203
|
+
| `SHA256Hash` | const | `HashFn` const for `Fortuna`. Stateless SHA-256. Requires `init({ sha2 })`. Re-exported from `'leviathan-crypto/sha2'`. |
|
|
204
|
+
| `SHA3_256Hash` | const | `HashFn` const for `Fortuna`. Stateless SHA3-256. Requires `init({ sha3 })`. Re-exported from `'leviathan-crypto/sha3'`. |
|
|
205
|
+
| `Generator` | type | Interface implemented by `SerpentGenerator` and `ChaCha20Generator`. |
|
|
206
|
+
| `HashFn` | type | Interface implemented by `SHA256Hash` and `SHA3_256Hash`. |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Ratchet (Sparse Post-Quantum Ratchet KDF)
|
|
211
|
+
|
|
212
|
+
`ratchetInit`, `KDFChain`, `ratchetReady` require `init({ sha2: sha2Wasm })`.
|
|
213
|
+
`kemRatchetEncap`, `kemRatchetDecap` additionally require `init({ kyber: kyberWasm, sha3: sha3Wasm })`.
|
|
214
|
+
Subpath: `leviathan-crypto/ratchet`. See [ratchet.md](./ratchet.md).
|
|
195
215
|
|
|
196
216
|
| Export | Kind | Description |
|
|
197
217
|
|--------|------|-------------|
|
|
198
|
-
| `
|
|
218
|
+
| `ratchetInit` | function | `ratchetInit(sk, context?)` — derives initial root key, send chain key, and receive chain key from a 32-byte shared secret (`KDF_SCKA_INIT`). Returns `RatchetInitResult`. |
|
|
219
|
+
| `KDFChain` | class | Stateful symmetric ratchet chain (`KDF_SCKA_CK`). `new KDFChain(ck)`, `step()` → 32-byte message key, `stepWithCounter()` → `{ key, counter }`, `dispose()`. |
|
|
220
|
+
| `SkippedKeyStore` | class | MKSKIPPED cache for a single `KDFChain` (DR spec §3.2/§3.5). `new SkippedKeyStore({ maxCacheSize?, maxSkipPerResolve? })`. `resolve(chain, counter)` → `ResolveHandle` — call `handle.commit()` on successful decrypt, `handle.rollback()` on auth failure. `advanceToBoundary(chain, pn)`, `size`, `wipeAll()`. Requires `sha2`. |
|
|
221
|
+
| `RatchetKeypair` | class | Single-use ek/dk lifecycle for one KEM ratchet step. `new RatchetKeypair(kem)`, `readonly ek`, `decap(kem, rk, kemCt, context?)`, `dispose()`. Requires `sha2`, `kyber`, `sha3`. |
|
|
222
|
+
| `kemRatchetEncap` | function | `kemRatchetEncap(kem, rk, peerEk, context?)` — encapsulation side of a KEM ratchet step (`KDF_SCKA_RK`). Returns `KemEncapResult` including `kemCt` to transmit to peer. |
|
|
223
|
+
| `kemRatchetDecap` | function | `kemRatchetDecap(kem, rk, dk, kemCt, ownEk, context?)` — decapsulation side of a KEM ratchet step. `ownEk` is the local party's encapsulation key, bound into the HKDF info string alongside `peerEk` and `kemCt` as defense-in-depth on top of the KEM FO transform. Returns `KemDecapResult` with chain key slots swapped to match Bob's perspective. |
|
|
224
|
+
| `ratchetReady` | function | `ratchetReady(): boolean` — returns `true` if `sha2` has been initialized. |
|
|
225
|
+
| `RatchetInitResult` | type | `{ nextRootKey, sendChainKey, recvChainKey }` — all 32-byte `Uint8Array` fields. |
|
|
226
|
+
| `KemEncapResult` | type | `{ nextRootKey, sendChainKey, recvChainKey, kemCt }` — three 32-byte keys plus the ML-KEM ciphertext. |
|
|
227
|
+
| `KemDecapResult` | type | `{ nextRootKey, sendChainKey, recvChainKey }` — all 32-byte `Uint8Array` fields. Slots are swapped relative to the encap side. |
|
|
228
|
+
| `RatchetMessageHeader` | interface | `{ epoch, counter, pn?, kemCt? }` — canonical message header shape. `pn` and `kemCt` present only on the first message of a new epoch. |
|
|
229
|
+
| `MlKemLike` | interface | Structural interface satisfied by `MlKem512`, `MlKem768`, `MlKem1024`. Used as the `kem` parameter type for `kemRatchetEncap`/`kemRatchetDecap`/`RatchetKeypair`. |
|
|
230
|
+
| `ResolveHandle` | interface | Return type of `SkippedKeyStore.resolve()`. `readonly key` — 32-byte message key (throws after settlement). `commit()` — wipes key, marks settled (call on successful decrypt). `rollback()` — returns key to store, marks settled (call on auth failure). Double-settle throws. |
|
|
199
231
|
|
|
200
232
|
---
|
|
201
233
|
|
|
@@ -225,7 +257,7 @@ No `init()` required. See [utils.md](./utils.md).
|
|
|
225
257
|
| `bytesToUtf8` | function | `Uint8Array` to UTF-8 string. |
|
|
226
258
|
| `base64ToBytes` | function | Base64/base64url string to `Uint8Array`. Returns `undefined` on invalid input. |
|
|
227
259
|
| `bytesToBase64` | function | `Uint8Array` to base64 string. Pass `url=true` for base64url. |
|
|
228
|
-
| `constantTimeEqual` | function |
|
|
260
|
+
| `constantTimeEqual` | function | Constant-time byte-array equality. Runs entirely inside a dedicated WASM SIMD module (v128 XOR-accumulate with branch-free reduction) to eliminate JIT timing leaks. Throws a branded error on runtimes without WebAssembly SIMD; no JS fallback. Returns `false` immediately on length mismatch. Throws `RangeError` if either input exceeds `CT_MAX_BYTES`. |
|
|
229
261
|
| `CT_MAX_BYTES` | const | Maximum input size for `constantTimeEqual` per side (32768 bytes, one 64 KiB WASM page split between two buffers). |
|
|
230
262
|
| `wipe` | function | Zero a typed array in place. |
|
|
231
263
|
| `xor` | function | XOR two equal-length `Uint8Array`s, returns new array. |
|
|
@@ -235,7 +267,11 @@ No `init()` required. See [utils.md](./utils.md).
|
|
|
235
267
|
|
|
236
268
|
---
|
|
237
269
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
270
|
+
|
|
271
|
+
## Cross-References
|
|
272
|
+
|
|
273
|
+
| Document | Description |
|
|
274
|
+
| -------- | ----------- |
|
|
275
|
+
| [index](./README.md) | Project Documentation index |
|
|
276
|
+
| [architecture](./architecture.md) | architecture overview, module relationships, buffer layouts, and build pipeline |
|
|
277
|
+
|