leviathan-crypto 1.4.0 → 2.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 +129 -94
- package/README.md +166 -223
- package/SECURITY.md +85 -45
- package/dist/chacha20/cipher-suite.d.ts +4 -0
- package/dist/chacha20/cipher-suite.js +78 -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 +320 -0
- package/dist/docs/architecture.md +419 -285
- 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 +93 -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/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 +93 -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 +121 -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 +202 -0
- package/dist/serpent/serpent-cbc.d.ts +30 -0
- package/dist/serpent/serpent-cbc.js +136 -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 +391 -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 +24 -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/dist/docs/sha3.md
CHANGED
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
# SHA3 TypeScript API Reference
|
|
2
2
|
|
|
3
3
|
> [!NOTE]
|
|
4
|
-
> SHA-3 hash functions and SHAKE
|
|
5
|
-
|
|
6
|
-
>
|
|
4
|
+
> Covers the SHA-3 hash functions (SHA3-224 through SHA3-512) and the SHAKE extendable-output functions (SHAKE128, SHAKE256). See [SHA-3 implementation audit](./sha3_audit.md) for algorithm correctness verifications.
|
|
5
|
+
|
|
6
|
+
> ### Table of Contents
|
|
7
|
+
> - [Overview](#overview)
|
|
8
|
+
> - [Security Notes](#security-notes)
|
|
9
|
+
> - [Module Init](#module-init)
|
|
10
|
+
> - [API Reference](#api-reference)
|
|
11
|
+
> - [Incremental XOF API](#incremental-xof-api-absorb--squeeze--reset)
|
|
12
|
+
> - [Usage Examples](#usage-examples)
|
|
13
|
+
> - [Error Conditions](#error-conditions)
|
|
14
|
+
|
|
15
|
+
---
|
|
7
16
|
|
|
8
17
|
## Overview
|
|
9
18
|
|
|
10
19
|
The SHA-3 family provides six hash functions standardized in **FIPS 202**: four
|
|
11
20
|
fixed-output hash functions (SHA3-224, SHA3-256, SHA3-384, SHA3-512) and two
|
|
12
21
|
extendable-output functions, or XOFs (SHAKE128, SHAKE256). All six are built on
|
|
13
|
-
the **Keccak sponge construction
|
|
22
|
+
the **Keccak sponge construction**, a fundamentally different design from the
|
|
14
23
|
Merkle-Damgard structure used by SHA-2.
|
|
15
24
|
|
|
16
25
|
SHA-3 is **not** a replacement for SHA-2. Both are considered secure, and both are
|
|
17
26
|
standardized by NIST. SHA-3 exists to provide **defense-in-depth**: if a flaw is
|
|
18
27
|
ever discovered in SHA-2, SHA-3 is completely unaffected because it uses a different
|
|
19
|
-
mathematical foundation.
|
|
20
|
-
|
|
28
|
+
mathematical foundation. You may never need that insurance, but if you do, you will be
|
|
29
|
+
very glad it is there.
|
|
21
30
|
|
|
22
31
|
The SHAKE XOFs are particularly flexible. Unlike SHA3-256, which always produces
|
|
23
|
-
exactly 32 bytes, SHAKE128 and SHAKE256 can produce variable-length output
|
|
24
|
-
tell them how many bytes you want
|
|
32
|
+
exactly 32 bytes, SHAKE128 and SHAKE256 can produce variable-length output. You
|
|
33
|
+
tell them how many bytes you want, making them useful for key derivation, generating
|
|
25
34
|
nonces, or any situation where you need more (or fewer) bytes than a standard hash
|
|
26
35
|
provides.
|
|
27
36
|
|
|
@@ -41,7 +50,7 @@ secret. SHA-3's sponge construction makes this impossible.
|
|
|
41
50
|
- **Length extension immunity.** Unlike SHA-2, the SHA-3 sponge construction does
|
|
42
51
|
not leak enough internal state for length extension attacks. Computing
|
|
43
52
|
`SHA3(secret + message)` does not let an attacker forge `SHA3(secret + message + extra)`.
|
|
44
|
-
That said, **HMAC is still the correct way to build a MAC**
|
|
53
|
+
That said, **HMAC is still the correct way to build a MAC** — do not use raw
|
|
45
54
|
`SHA3(key + message)` as a MAC construction, even though it is not vulnerable to
|
|
46
55
|
length extension. HMAC provides a formally proven security reduction.
|
|
47
56
|
|
|
@@ -50,7 +59,7 @@ secret. SHA-3's sponge construction makes this impossible.
|
|
|
50
59
|
sponge directly with `absorb()` / `squeeze()`. The only constraint is
|
|
51
60
|
`outputLength >= 1`.
|
|
52
61
|
|
|
53
|
-
- **Not for password hashing.** SHA-3 is a fast hash
|
|
62
|
+
- **Not for password hashing.** SHA-3 is a fast hash, which is the opposite of
|
|
54
63
|
what you want for password storage. Passwords must be hashed with a slow,
|
|
55
64
|
memory-hardened algorithm like **Argon2id**. See [argon2id.md](./argon2id.md) for
|
|
56
65
|
usage patterns including passphrase-based encryption with leviathan primitives.
|
|
@@ -68,27 +77,45 @@ secret. SHA-3's sponge construction makes this impossible.
|
|
|
68
77
|
Each module subpath exports its own init function for consumers who want
|
|
69
78
|
tree-shakeable imports.
|
|
70
79
|
|
|
71
|
-
### `sha3Init(
|
|
80
|
+
### `sha3Init(source)`
|
|
72
81
|
|
|
73
82
|
Initializes only the sha3 WASM binary. Equivalent to calling the
|
|
74
|
-
root `init(
|
|
83
|
+
root `init({ sha3: source })` but without pulling the other three
|
|
75
84
|
modules into the bundle.
|
|
76
85
|
|
|
77
86
|
**Signature:**
|
|
78
87
|
|
|
79
88
|
```typescript
|
|
80
|
-
async function sha3Init(
|
|
89
|
+
async function sha3Init(source: WasmSource): Promise<void>
|
|
81
90
|
```
|
|
82
91
|
|
|
83
92
|
**Usage:**
|
|
84
93
|
|
|
85
94
|
```typescript
|
|
86
95
|
import { sha3Init, SHA3_256 } from 'leviathan-crypto/sha3'
|
|
96
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
87
97
|
|
|
88
|
-
await sha3Init()
|
|
98
|
+
await sha3Init(sha3Wasm)
|
|
89
99
|
const sha3 = new SHA3_256()
|
|
90
100
|
```
|
|
91
101
|
|
|
102
|
+
### keccakInit() Alias
|
|
103
|
+
|
|
104
|
+
`'keccak'` is an alias for `'sha3'`. Same WASM binary, same instance slot.
|
|
105
|
+
`keccakInit()` and `sha3Init()` are interchangeable.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { keccakInit, SHAKE256, SHA3_256 } from 'leviathan-crypto/keccak'
|
|
109
|
+
import { keccakWasm } from 'leviathan-crypto/keccak/embedded'
|
|
110
|
+
|
|
111
|
+
await keccakInit(keccakWasm)
|
|
112
|
+
// isInitialized('sha3') === true — same slot
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Use the `keccak` subpath when the consuming context (such as ML-KEM) makes the
|
|
116
|
+
Keccak primitive name semantically clearer. See [init.md](./init.md#keccak-alias-for-ml-kem)
|
|
117
|
+
for full details.
|
|
118
|
+
|
|
92
119
|
---
|
|
93
120
|
|
|
94
121
|
## API Reference
|
|
@@ -97,19 +124,18 @@ All SHA-3 classes require initialization before use. Either the root `init()`:
|
|
|
97
124
|
|
|
98
125
|
```typescript
|
|
99
126
|
import { init } from 'leviathan-crypto'
|
|
127
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
100
128
|
|
|
101
|
-
await init(
|
|
129
|
+
await init({ sha3: sha3Wasm })
|
|
102
130
|
```
|
|
103
131
|
|
|
104
|
-
Both `init('sha3')` and `init(['sha3'])` are valid — the root `init()` accepts
|
|
105
|
-
a single `Module` string or an array.
|
|
106
|
-
|
|
107
132
|
Or the subpath `sha3Init()`:
|
|
108
133
|
|
|
109
134
|
```typescript
|
|
110
135
|
import { sha3Init } from 'leviathan-crypto/sha3'
|
|
136
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
111
137
|
|
|
112
|
-
await sha3Init()
|
|
138
|
+
await sha3Init(sha3Wasm)
|
|
113
139
|
```
|
|
114
140
|
|
|
115
141
|
If you use SHA-3 classes without calling `init()` first, the constructor
|
|
@@ -134,7 +160,7 @@ class SHA3_224 {
|
|
|
134
160
|
### SHA3_256
|
|
135
161
|
|
|
136
162
|
Fixed-output hash function. Produces a **32-byte** (256-bit) digest. This is the
|
|
137
|
-
most commonly used SHA-3 variant
|
|
163
|
+
most commonly used SHA-3 variant; 256-bit security is suitable for most
|
|
138
164
|
applications.
|
|
139
165
|
|
|
140
166
|
```typescript
|
|
@@ -255,8 +281,9 @@ Calling `absorb()` while squeezing throws:
|
|
|
255
281
|
|
|
256
282
|
```typescript
|
|
257
283
|
import { init, SHAKE256 } from 'leviathan-crypto'
|
|
284
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
258
285
|
|
|
259
|
-
await init(
|
|
286
|
+
await init({ sha3: sha3Wasm })
|
|
260
287
|
|
|
261
288
|
const xof = new SHAKE256()
|
|
262
289
|
xof.absorb(ikm) // input key material
|
|
@@ -275,13 +302,14 @@ xof.dispose()
|
|
|
275
302
|
|
|
276
303
|
### Example 1: Hash a string with SHA3-256
|
|
277
304
|
|
|
278
|
-
The most common use case
|
|
305
|
+
The most common use case: hash some data and get a hex digest.
|
|
279
306
|
|
|
280
307
|
```typescript
|
|
281
308
|
import { init, SHA3_256, bytesToHex, utf8ToBytes } from 'leviathan-crypto'
|
|
309
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
282
310
|
|
|
283
311
|
// Initialize the SHA-3 WASM module (once, at startup)
|
|
284
|
-
await init(
|
|
312
|
+
await init({ sha3: sha3Wasm })
|
|
285
313
|
|
|
286
314
|
// Create a hasher
|
|
287
315
|
const sha3 = new SHA3_256()
|
|
@@ -303,8 +331,9 @@ sha3.dispose()
|
|
|
303
331
|
|
|
304
332
|
```typescript
|
|
305
333
|
import { init, SHA3_512, bytesToHex } from 'leviathan-crypto'
|
|
334
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
306
335
|
|
|
307
|
-
await init(
|
|
336
|
+
await init({ sha3: sha3Wasm })
|
|
308
337
|
|
|
309
338
|
const sha3 = new SHA3_512()
|
|
310
339
|
|
|
@@ -322,13 +351,14 @@ sha3.dispose()
|
|
|
322
351
|
|
|
323
352
|
### Example 3: Hash multiple messages
|
|
324
353
|
|
|
325
|
-
Each call to `hash()` is independent
|
|
354
|
+
Each call to `hash()` is independent; the internal state resets automatically.
|
|
326
355
|
You can reuse the same class instance for multiple hashes.
|
|
327
356
|
|
|
328
357
|
```typescript
|
|
329
358
|
import { init, SHA3_256, bytesToHex, utf8ToBytes } from 'leviathan-crypto'
|
|
359
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
330
360
|
|
|
331
|
-
await init(
|
|
361
|
+
await init({ sha3: sha3Wasm })
|
|
332
362
|
|
|
333
363
|
const sha3 = new SHA3_256()
|
|
334
364
|
|
|
@@ -354,8 +384,9 @@ for key derivation or generating fixed-size tokens.
|
|
|
354
384
|
|
|
355
385
|
```typescript
|
|
356
386
|
import { init, SHAKE128, bytesToHex, utf8ToBytes } from 'leviathan-crypto'
|
|
387
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
357
388
|
|
|
358
|
-
await init(
|
|
389
|
+
await init({ sha3: sha3Wasm })
|
|
359
390
|
|
|
360
391
|
const shake = new SHAKE128()
|
|
361
392
|
|
|
@@ -383,8 +414,9 @@ shake.dispose()
|
|
|
383
414
|
|
|
384
415
|
```typescript
|
|
385
416
|
import { init, SHAKE256, bytesToHex } from 'leviathan-crypto'
|
|
417
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
386
418
|
|
|
387
|
-
await init(
|
|
419
|
+
await init({ sha3: sha3Wasm })
|
|
388
420
|
|
|
389
421
|
const shake = new SHAKE256()
|
|
390
422
|
|
|
@@ -400,17 +432,18 @@ shake.dispose()
|
|
|
400
432
|
|
|
401
433
|
---
|
|
402
434
|
|
|
403
|
-
### Example 6: SHA-256 vs SHA3-256
|
|
435
|
+
### Example 6: SHA-256 vs SHA3-256
|
|
404
436
|
|
|
405
437
|
SHA-256 (from the SHA-2 family) and SHA3-256 are completely different algorithms.
|
|
406
|
-
They produce different output for the same input.
|
|
407
|
-
are secure. SHA3-256 adds defense-in-depth.
|
|
438
|
+
They produce different output for the same input. Both are secure; SHA3-256 adds defense-in-depth.
|
|
408
439
|
|
|
409
440
|
```typescript
|
|
410
441
|
import { init, SHA256, SHA3_256, bytesToHex, utf8ToBytes } from 'leviathan-crypto'
|
|
442
|
+
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
443
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
411
444
|
|
|
412
445
|
// Initialize both modules
|
|
413
|
-
await init(
|
|
446
|
+
await init({ sha2: sha2Wasm, sha3: sha3Wasm })
|
|
414
447
|
|
|
415
448
|
const sha2 = new SHA256()
|
|
416
449
|
const sha3 = new SHA3_256()
|
|
@@ -437,8 +470,9 @@ deterministic output.
|
|
|
437
470
|
|
|
438
471
|
```typescript
|
|
439
472
|
import { init, SHA3_256, bytesToHex } from 'leviathan-crypto'
|
|
473
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
440
474
|
|
|
441
|
-
await init(
|
|
475
|
+
await init({ sha3: sha3Wasm })
|
|
442
476
|
|
|
443
477
|
const sha3 = new SHA3_256()
|
|
444
478
|
const digest = sha3.hash(new Uint8Array(0))
|
|
@@ -453,16 +487,16 @@ sha3.dispose()
|
|
|
453
487
|
|
|
454
488
|
## Error Conditions
|
|
455
489
|
|
|
456
|
-
###
|
|
490
|
+
### SHA-3 module not initialized
|
|
457
491
|
|
|
458
492
|
If you construct a SHA-3 class before initializing the module, the constructor
|
|
459
493
|
throws immediately:
|
|
460
494
|
|
|
461
495
|
```
|
|
462
|
-
Error: leviathan-crypto: call init(
|
|
496
|
+
Error: leviathan-crypto: call init({ sha3: ... }) before using this class
|
|
463
497
|
```
|
|
464
498
|
|
|
465
|
-
**Fix:** Call `await init(
|
|
499
|
+
**Fix:** Call `await init({ sha3: sha3Wasm })` once at application startup, before creating
|
|
466
500
|
any SHA-3 class instances.
|
|
467
501
|
|
|
468
502
|
---
|
package/dist/docs/types.md
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
#
|
|
1
|
+
# TypeScript Interfaces
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> [!NOTE]
|
|
4
|
+
> Defines the abstract interfaces all leviathan-crypto cryptographic classes implement. These are type-only exports; they contain no runtime code and generate no JavaScript output.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
This module contains type definitions only. There are no security-sensitive operations.
|
|
6
|
+
> ### Table of Contents
|
|
7
|
+
> - [API Reference](#api-reference)
|
|
8
|
+
> - [Usage Examples](#usage-examples)
|
|
9
|
+
> - [WasmSource](#wasmsource)
|
|
10
|
+
> - [CipherSuite](#ciphersuite)
|
|
11
|
+
> - [DerivedKeys](#derivedkeys)
|
|
12
|
+
> - [SealStreamOpts](#sealstreamopts)
|
|
13
|
+
> - [PoolOpts](#poolopts)
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
## API Reference
|
|
18
18
|
|
|
19
|
+
Use these interfaces when you need generic code that works with any hash function, any cipher, or any AEAD scheme without depending on a specific implementation. They are available immediately on import with no `init()` call required.
|
|
20
|
+
|
|
19
21
|
### Hash
|
|
20
22
|
|
|
21
23
|
```typescript
|
|
@@ -45,7 +47,7 @@ interface KeyedHash {
|
|
|
45
47
|
|
|
46
48
|
Interface for keyed hash functions / MACs (e.g., HMAC-SHA256, HMAC-SHA512).
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
`KeyedHash` does **not** extend `Hash`. Its `hash` method takes a `key` parameter in addition to the message.
|
|
49
51
|
|
|
50
52
|
| Method | Description |
|
|
51
53
|
|---|---|
|
|
@@ -109,7 +111,7 @@ Interface for authenticated encryption with associated data (e.g., XChaCha20-Pol
|
|
|
109
111
|
| Method | Description |
|
|
110
112
|
|---|---|
|
|
111
113
|
| `encrypt(msg, aad?)` | Encrypts `msg` and authenticates both `msg` and optional `aad`. Returns ciphertext with appended authentication tag. |
|
|
112
|
-
| `decrypt(ciphertext, aad?)` | Decrypts and verifies the authentication tag. Returns plaintext on success. Throws `Error` on authentication failure
|
|
114
|
+
| `decrypt(ciphertext, aad?)` | Decrypts and verifies the authentication tag. Returns plaintext on success. Throws `Error` on authentication failure. Never returns null. |
|
|
113
115
|
| `dispose()` | Releases WASM resources and wipes internal buffers. |
|
|
114
116
|
|
|
115
117
|
---
|
|
@@ -128,7 +130,7 @@ function digestAndLog(hasher: Hash, data: Uint8Array): Uint8Array {
|
|
|
128
130
|
}
|
|
129
131
|
```
|
|
130
132
|
|
|
131
|
-
This function accepts any `Hash` implementation
|
|
133
|
+
This function accepts any `Hash` implementation (`SHA256`, `SHA512`, `SHA3_256`, etc.) without importing any of them directly.
|
|
132
134
|
|
|
133
135
|
---
|
|
134
136
|
|
|
@@ -142,7 +144,7 @@ function sealMessage(aead: AEAD, plaintext: Uint8Array, metadata: Uint8Array): U
|
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
function openMessage(aead: AEAD, ciphertext: Uint8Array, metadata: Uint8Array): Uint8Array {
|
|
145
|
-
// decrypt() throws on auth failure
|
|
147
|
+
// decrypt() throws on auth failure, no null check needed
|
|
146
148
|
return aead.decrypt(ciphertext, metadata)
|
|
147
149
|
}
|
|
148
150
|
```
|
|
@@ -186,13 +188,88 @@ function cleanup(ctx: EncryptionContext): void {
|
|
|
186
188
|
|
|
187
189
|
---
|
|
188
190
|
|
|
191
|
+
## WasmSource
|
|
192
|
+
|
|
193
|
+
Union type for WASM module sources. Accepted by `init()`, `serpentInit()`, etc.
|
|
194
|
+
|
|
195
|
+
`string | URL | ArrayBuffer | Uint8Array | WebAssembly.Module | Response | Promise<Response>`
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## CipherSuite
|
|
200
|
+
|
|
201
|
+
Cipher-specific logic injected into `SealStream` and `OpenStream`.
|
|
202
|
+
|
|
203
|
+
| Field | Type | Description |
|
|
204
|
+
|-------|------|-------------|
|
|
205
|
+
| `formatEnum` | `number` | Wire format ID encoded in header byte 0 bits 0-5 (max 0x3f): bits 0-3 = cipher nibble (0x1=xchacha20, 0x2=serpent), bits 4-5 = KEM selector (0x00=none, 0x10=ML-KEM-512, 0x20=ML-KEM-768, 0x30=ML-KEM-1024), bit 6 reserved |
|
|
206
|
+
| `formatName` | `string` | Human-readable label, e.g. `'xchacha20'`, `'serpent'`, `'mlkem768+xchacha20'` |
|
|
207
|
+
| `hkdfInfo` | `string` | HKDF info string for key derivation |
|
|
208
|
+
| `keySize` | `number` | Seal/encrypt key size in bytes (encapsulation key bytes for KEM suites) |
|
|
209
|
+
| `decKeySize` | `number \| undefined` | Open/decrypt key size in bytes (decapsulation key bytes for KEM suites). Absent → same as `keySize` (symmetric case) |
|
|
210
|
+
| `kemCtSize` | `number` | KEM ciphertext byte length appended to the header in the preamble. `0` for symmetric suites |
|
|
211
|
+
| `tagSize` | `number` | Authentication tag size in bytes |
|
|
212
|
+
| `padded` | `boolean` | Whether ciphertext includes padding (PKCS7 for CBC) |
|
|
213
|
+
| `wasmModules` | `readonly string[]` | Cipher-specific WASM modules used by pool workers and per-chunk operations (not transitive dependencies such as HKDF-SHA-256 used by `deriveKeys()`) |
|
|
214
|
+
|
|
215
|
+
| Method | Signature | Description |
|
|
216
|
+
|--------|-----------|-------------|
|
|
217
|
+
| `deriveKeys` | `(masterKey, nonce) → DerivedKeys` | HKDF key derivation |
|
|
218
|
+
| `sealChunk` | `(keys, counterNonce, chunk, aad?) → Uint8Array` | Encrypt one chunk |
|
|
219
|
+
| `openChunk` | `(keys, counterNonce, chunk, aad?) → Uint8Array` | Decrypt one chunk |
|
|
220
|
+
| `wipeKeys` | `(keys) → void` | Zero derived key material |
|
|
221
|
+
| `createPoolWorker` | `() → Worker` | Create a Web Worker for pool use |
|
|
222
|
+
|
|
223
|
+
Implementations: `XChaCha20Cipher`, `SerpentCipher` (plain `const` objects, not classes), and `KyberSuite` (factory function returning a `CipherSuite`). See [ciphersuite.md](./ciphersuite.md).
|
|
224
|
+
|
|
225
|
+
> [!IMPORTANT]
|
|
226
|
+
> All CipherSuite implementations use HKDF-SHA-256 in `deriveKeys()`. The stream layer requires
|
|
227
|
+
> `sha2` to be initialized regardless of which cipher is selected.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## DerivedKeys
|
|
232
|
+
|
|
233
|
+
Opaque key material returned by `CipherSuite.deriveKeys()`.
|
|
234
|
+
|
|
235
|
+
| Field | Type | Description |
|
|
236
|
+
|-------|------|-------------|
|
|
237
|
+
| `bytes` | `readonly Uint8Array` | Raw derived key bytes (opaque to the stream layer) |
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## SealStreamOpts
|
|
242
|
+
|
|
243
|
+
Options for `SealStream` constructor.
|
|
244
|
+
|
|
245
|
+
| Field | Type | Default | Description |
|
|
246
|
+
|-------|------|---------|-------------|
|
|
247
|
+
| `chunkSize` | `number` | `65536` | Chunk size in bytes. Range: [1024, 16777215]. |
|
|
248
|
+
| `framed` | `boolean` | `false` | Enable u32be length-prefixed framing. |
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## PoolOpts
|
|
253
|
+
|
|
254
|
+
Options for `SealStreamPool.create()`.
|
|
255
|
+
|
|
256
|
+
| Field | Type | Default | Description |
|
|
257
|
+
|-------|------|---------|-------------|
|
|
258
|
+
| `wasm` | `WasmSource \| Record<string, WasmSource>` | | WASM module source(s). Single source for single-module ciphers, Record for multi-module. |
|
|
259
|
+
| `workers` | `number` | `navigator.hardwareConcurrency ?? 4` | Number of Web Workers. |
|
|
260
|
+
| `chunkSize` | `number` | `65536` | Chunk size in bytes. |
|
|
261
|
+
| `framed` | `boolean` | `false` | Enable framed mode. |
|
|
262
|
+
| `jobTimeout` | `number` | `30000` | Per-job timeout in milliseconds. |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
189
266
|
> ## Cross-References
|
|
190
267
|
>
|
|
191
268
|
> - [index](./README.md) — Project Documentation index
|
|
192
269
|
> - [architecture](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
193
270
|
> - [utils](./utils.md) — encoding utilities and `constantTimeEqual` for verifying MACs from `KeyedHash`
|
|
194
271
|
> - [serpent](./serpent.md) — Serpent classes implement `Blockcipher`, `Streamcipher`, and `AEAD`
|
|
195
|
-
> - [chacha20](./chacha20.md) — `
|
|
272
|
+
> - [chacha20](./chacha20.md) — `XChaCha20Cipher` is a `CipherSuite` for `SealStream`/`OpenStream`/`Seal`; `Seal` provides one-shot AEAD over any `CipherSuite`; `ChaCha20`/`ChaCha20Poly1305`/`XChaCha20Poly1305` are stateless primitives
|
|
196
273
|
> - [sha2](./sha2.md) — SHA-2 classes implement `Hash`; HMAC classes implement `KeyedHash`
|
|
197
274
|
> - [sha3](./sha3.md) — SHA-3 classes implement `Hash`; SHAKE classes extend with XOF API
|
|
198
275
|
> - [test-suite](./test-suite.md) — test suite structure and vector corpus
|
package/dist/docs/utils.md
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Utilities
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> [!NOTE]
|
|
4
|
+
> Pure TypeScript utilities that ship alongside the WASM-backed primitives. No `init()` call required; all functions work immediately on import.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
- **Security** -- constant-time comparison and secure memory wiping
|
|
11
|
-
- **Byte manipulation** -- XOR and concatenation of byte arrays
|
|
12
|
-
- **Random** -- cryptographically secure random byte generation
|
|
6
|
+
> ### Table of Contents
|
|
7
|
+
> - [Security Notes](#security-notes)
|
|
8
|
+
> - [API Reference](#api-reference)
|
|
9
|
+
> - [Usage Examples](#usage-examples)
|
|
10
|
+
> - [Error Conditions](#error-conditions)
|
|
13
11
|
|
|
14
12
|
---
|
|
15
13
|
|
|
14
|
+
The module covers encoding (hex, UTF-8, and base64 conversions between strings and `Uint8Array`), security (constant-time comparison and secure memory wiping), byte manipulation (XOR and concatenation), and random byte generation.
|
|
15
|
+
|
|
16
16
|
## Security Notes
|
|
17
17
|
|
|
18
|
-
**`constantTimeEqual`** uses an XOR-accumulate
|
|
18
|
+
**`constantTimeEqual`** uses a WASM SIMD module when available to remove the JS JIT compiler from the timing picture, falling back to an XOR-accumulate loop on older runtimes. Use this function whenever you compare MACs, hashes, authentication tags, or any secret-derived values. Never use `===`, `Buffer.equals`, or a manual loop-with-break for security comparisons. Those leak timing information that attackers can exploit to recover secrets. Inputs are limited to [`CT_MAX_BYTES`](#ct_max_bytes) (32768 bytes) per side.
|
|
19
19
|
|
|
20
|
-
The length check in `constantTimeEqual` is
|
|
20
|
+
The length check in `constantTimeEqual` is not constant-time, because array length is non-secret in all standard protocols. If your use case treats length as secret, pad to equal length before comparing.
|
|
21
21
|
|
|
22
22
|
**`wipe`** zeroes a typed array in-place. Call it on keys, plaintext buffers, and any other sensitive data as soon as you are done with them. JavaScript's garbage collector does not guarantee timely or complete erasure of memory.
|
|
23
23
|
|
|
@@ -75,7 +75,7 @@ Decodes UTF-8 bytes to a JavaScript string using the platform `TextDecoder`.
|
|
|
75
75
|
base64ToBytes(b64: string): Uint8Array | undefined
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
Decodes a base64 or base64url string to a `Uint8Array`. Handles padded, unpadded, and legacy `%3d` padding. Unpadded base64url input is accepted (RFC 4648 §5). Returns `undefined` if the input is not valid base64 (
|
|
78
|
+
Decodes a base64 or base64url string to a `Uint8Array`. Handles padded, unpadded, and legacy `%3d` padding. Unpadded base64url input is accepted (RFC 4648 §5). Returns `undefined` if the input is not valid base64 (illegal characters or `rem=1` length).
|
|
79
79
|
|
|
80
80
|
---
|
|
81
81
|
|
|
@@ -85,7 +85,7 @@ Decodes a base64 or base64url string to a `Uint8Array`. Handles padded, unpadded
|
|
|
85
85
|
bytesToBase64(bytes: Uint8Array, url?: boolean): string
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
Encodes a `Uint8Array` to a base64 string. Pass `url = true` for base64url (RFC 4648 §5
|
|
88
|
+
Encodes a `Uint8Array` to a base64 string. Pass `url = true` for base64url (RFC 4648 §5), which uses `-` and `_` instead of `+` and `/` with no padding characters. Defaults to standard base64.
|
|
89
89
|
|
|
90
90
|
---
|
|
91
91
|
|
|
@@ -95,7 +95,40 @@ Encodes a `Uint8Array` to a base64 string. Pass `url = true` for base64url (RFC
|
|
|
95
95
|
constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
Returns `true` if `a` and `b` contain identical bytes.
|
|
98
|
+
Returns `true` if `a` and `b` contain identical bytes. Returns `false` immediately if the arrays differ in length (length is non-secret in all standard protocols).
|
|
99
|
+
|
|
100
|
+
When WebAssembly SIMD is available the comparison runs inside a WASM module, removing the JS JIT compiler from the timing picture. Speculative optimisation and branch prediction inside the engine cannot short-circuit the loop. On runtimes without SIMD support the function falls back to an XOR-accumulate loop in JavaScript, which is best-effort but not a hardware-level guarantee. The overall posture is best-available constant-time, not a cryptographic proof of timing safety.
|
|
101
|
+
|
|
102
|
+
Maximum input size is [`CT_MAX_BYTES`](#ct_max_bytes) (32768 bytes) per side. Throws `RangeError` if either array exceeds this limit.
|
|
103
|
+
|
|
104
|
+
Use this function when working with lower-level unauthenticated primitives or building custom authenticated protocols on top of the hashing and KDF APIs. Three common cases:
|
|
105
|
+
|
|
106
|
+
**Encrypt-then-MAC with `SerpentCbc` or `SerpentCtr`.** If you use the `dangerUnauthenticated` primitive directly and compute your own HMAC-SHA256 tag, compare that tag with `constantTimeEqual`. See the [example below](#encrypt-then-mac-with-serpentcbc).
|
|
107
|
+
|
|
108
|
+
**Argon2id key verification.** When re-deriving an Argon2id hash to verify a passphrase, the final comparison must be constant-time. See [argon2id.md](./argon2id.md#password-hashing-and-verification) for the full example.
|
|
109
|
+
|
|
110
|
+
**Custom HMAC protocols.** Any protocol where you derive a MAC with `HMAC_SHA256` or `HMAC_SHA512` and compare it against a received value. See [examples.md](./examples.md#hmac-sha256-message-authentication) for a complete example.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### CT_MAX_BYTES
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const CT_MAX_BYTES: 32768
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Maximum input size accepted by [`constantTimeEqual`](#constanttimeequal) per side, in bytes. Reflects the physical layout of the WASM comparison module: one 64 KiB page of linear memory split equally between the two input buffers (32 KiB each).
|
|
121
|
+
|
|
122
|
+
In practice the largest comparison performed anywhere in this library is a 32-byte HMAC-SHA-256 tag. This limit only matters for custom protocols that compare unusually large values. Use this constant to guard your own inputs rather than hardcoding the magic number:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { constantTimeEqual, CT_MAX_BYTES } from 'leviathan-crypto'
|
|
126
|
+
|
|
127
|
+
if (a.length > CT_MAX_BYTES || b.length > CT_MAX_BYTES) {
|
|
128
|
+
throw new RangeError(`comparison input exceeds CT_MAX_BYTES (${CT_MAX_BYTES})`)
|
|
129
|
+
}
|
|
130
|
+
const match = constantTimeEqual(a, b)
|
|
131
|
+
```
|
|
99
132
|
|
|
100
133
|
---
|
|
101
134
|
|
|
@@ -115,7 +148,7 @@ Zeroes a typed array in-place by calling `fill(0)`. Use this to clear keys, plai
|
|
|
115
148
|
xor(a: Uint8Array, b: Uint8Array): Uint8Array
|
|
116
149
|
```
|
|
117
150
|
|
|
118
|
-
Returns a new `Uint8Array` where each byte is `a[i] ^ b[i]`. Both arrays must have the same length
|
|
151
|
+
Returns a new `Uint8Array` where each byte is `a[i] ^ b[i]`. Both arrays must have the same length. Throws `RangeError` if they differ.
|
|
119
152
|
|
|
120
153
|
---
|
|
121
154
|
|
|
@@ -125,7 +158,7 @@ Returns a new `Uint8Array` where each byte is `a[i] ^ b[i]`. Both arrays must ha
|
|
|
125
158
|
concat(...arrays: Uint8Array[]): Uint8Array
|
|
126
159
|
```
|
|
127
160
|
|
|
128
|
-
|
|
161
|
+
Concatenates one or more `Uint8Array`s into a new array.
|
|
129
162
|
|
|
130
163
|
---
|
|
131
164
|
|
|
@@ -149,10 +182,10 @@ Returns `true` if the current runtime supports WebAssembly SIMD (the `v128`
|
|
|
149
182
|
type and associated operations). The result is computed once on first call by
|
|
150
183
|
validating a minimal v128 WASM module, then cached for subsequent calls.
|
|
151
184
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
185
|
+
`SerpentCtr.encryptChunk`, `SerpentCbc.decrypt`, and `ChaCha20.encryptChunk`
|
|
186
|
+
call this internally to select the fast SIMD path at runtime. It is exported
|
|
187
|
+
for informational purposes. You do not need to call it yourself. SIMD dispatch
|
|
188
|
+
is fully automatic.
|
|
156
189
|
|
|
157
190
|
Supported in all modern browsers and Node.js 16+. Returns `false` in older
|
|
158
191
|
environments, which fall back silently to the scalar path.
|
|
@@ -201,21 +234,62 @@ if (decoded) console.log(bytesToUtf8(decoded)) // "leviathan-crypto"
|
|
|
201
234
|
|
|
202
235
|
---
|
|
203
236
|
|
|
204
|
-
###
|
|
237
|
+
### Encrypt-then-MAC with SerpentCbc
|
|
238
|
+
|
|
239
|
+
If you use `SerpentCbc` or `SerpentCtr` directly with `{ dangerUnauthenticated: true }`, you are responsible for authentication. The correct pattern is Encrypt-then-MAC: encrypt first, then compute HMAC-SHA256 over the ciphertext, and use `constantTimeEqual` to verify on decrypt.
|
|
205
240
|
|
|
206
241
|
```typescript
|
|
207
|
-
import {
|
|
242
|
+
import {
|
|
243
|
+
init, SerpentCbc, HMAC_SHA256,
|
|
244
|
+
constantTimeEqual, randomBytes, wipe, concat,
|
|
245
|
+
} from 'leviathan-crypto'
|
|
246
|
+
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
247
|
+
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
248
|
+
|
|
249
|
+
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
250
|
+
|
|
251
|
+
const encKey = randomBytes(32)
|
|
252
|
+
const macKey = randomBytes(32)
|
|
253
|
+
const iv = randomBytes(16)
|
|
208
254
|
|
|
209
|
-
//
|
|
210
|
-
// NEVER use === or .every() for this -- timing leaks enable forgery attacks.
|
|
211
|
-
const computedMac: Uint8Array = hmac.hash(key, message)
|
|
212
|
-
const receivedMac: Uint8Array = getTagFromNetwork()
|
|
255
|
+
// ── Encrypt ──────────────────────────────────────────────────────────────────
|
|
213
256
|
|
|
214
|
-
|
|
215
|
-
|
|
257
|
+
const cbc = new SerpentCbc({ dangerUnauthenticated: true })
|
|
258
|
+
const ct = cbc.encrypt(encKey, iv, plaintext)
|
|
259
|
+
cbc.dispose()
|
|
260
|
+
|
|
261
|
+
// MAC covers iv || ct so the IV is authenticated too
|
|
262
|
+
const hmac = new HMAC_SHA256()
|
|
263
|
+
const tag = hmac.hash(macKey, concat(iv, ct))
|
|
264
|
+
hmac.dispose()
|
|
265
|
+
|
|
266
|
+
const envelope = concat(iv, ct, tag) // store or transmit this
|
|
267
|
+
|
|
268
|
+
// ── Decrypt ──────────────────────────────────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
const receivedIv = envelope.subarray(0, 16)
|
|
271
|
+
const receivedCt = envelope.subarray(16, envelope.length - 32)
|
|
272
|
+
const receivedTag = envelope.subarray(envelope.length - 32)
|
|
273
|
+
|
|
274
|
+
const hmac2 = new HMAC_SHA256()
|
|
275
|
+
const expectedTag = hmac2.hash(macKey, concat(receivedIv, receivedCt))
|
|
276
|
+
hmac2.dispose()
|
|
277
|
+
|
|
278
|
+
// Always verify before decrypting — never decrypt unauthenticated ciphertext
|
|
279
|
+
if (!constantTimeEqual(expectedTag, receivedTag)) {
|
|
280
|
+
wipe(expectedTag)
|
|
281
|
+
throw new Error('Authentication failed')
|
|
216
282
|
}
|
|
283
|
+
|
|
284
|
+
const cbc2 = new SerpentCbc({ dangerUnauthenticated: true })
|
|
285
|
+
const pt = cbc2.decrypt(encKey, receivedIv, receivedCt)
|
|
286
|
+
cbc2.dispose()
|
|
287
|
+
wipe(expectedTag)
|
|
217
288
|
```
|
|
218
289
|
|
|
290
|
+
> [!NOTE]
|
|
291
|
+
> `Seal` with `SerpentCipher` does all of this for you — key derivation, IV handling, Encrypt-then-MAC, and constant-time verification — with no manual steps. The pattern above is only relevant if you need direct access to the raw `SerpentCbc` primitive.
|
|
292
|
+
|
|
219
293
|
---
|
|
220
294
|
|
|
221
295
|
### Generating random keys and nonces
|
|
@@ -223,9 +297,9 @@ if (!constantTimeEqual(computedMac, receivedMac)) {
|
|
|
223
297
|
```typescript
|
|
224
298
|
import { randomBytes } from 'leviathan-crypto'
|
|
225
299
|
|
|
226
|
-
const key
|
|
227
|
-
const nonce = randomBytes(24)
|
|
228
|
-
const iv
|
|
300
|
+
const key = randomBytes(32) // 256-bit symmetric key
|
|
301
|
+
const nonce = randomBytes(24) // 192-bit nonce for XChaCha20
|
|
302
|
+
const iv = randomBytes(16) // 128-bit IV for Serpent-CBC
|
|
229
303
|
```
|
|
230
304
|
|
|
231
305
|
---
|
|
@@ -272,6 +346,7 @@ console.log(combined.length) // 32
|
|
|
272
346
|
| `hexToBytes` | Invalid hex characters | Bytes decode as `NaN` -> `0` |
|
|
273
347
|
| `base64ToBytes` | Invalid length or characters | Returns `undefined` |
|
|
274
348
|
| `constantTimeEqual` | Arrays differ in length | Returns `false` immediately |
|
|
349
|
+
| `constantTimeEqual` | Either array exceeds `CT_MAX_BYTES` | Throws `RangeError` |
|
|
275
350
|
| `xor` | Arrays differ in length | Throws `RangeError` |
|
|
276
351
|
| `randomBytes` | `crypto` not available | Throws (runtime-dependent) |
|
|
277
352
|
| `hasSIMD` | `WebAssembly` not available | Returns `false` |
|
|
@@ -286,5 +361,7 @@ console.log(combined.length) // 32
|
|
|
286
361
|
> - [chacha20](./chacha20.md) — ChaCha20/Poly1305 classes use `randomBytes` for nonce generation
|
|
287
362
|
> - [sha2](./sha2.md) — SHA-2 and HMAC classes; output often converted with `bytesToHex`
|
|
288
363
|
> - [sha3](./sha3.md) — SHA-3 and SHAKE classes; output often converted with `bytesToHex`
|
|
364
|
+
> - [argon2id](./argon2id.md) — passphrase-based encryption; uses `constantTimeEqual` for hash verification
|
|
365
|
+
> - [examples](./examples.md) — full HMAC-SHA256 custom protocol example using `constantTimeEqual`
|
|
289
366
|
> - [types](./types.md) — public interfaces whose implementations rely on these utilities
|
|
290
367
|
> - [test-suite](./test-suite.md) — test suite structure and vector corpus
|