leviathan-crypto 1.3.1 → 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 -76
- package/README.md +166 -221
- package/SECURITY.md +89 -37
- 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 -7
- package/dist/chacha20/index.js +41 -14
- 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 +218 -150
- package/dist/docs/exports.md +241 -0
- package/dist/docs/fortuna.md +65 -74
- package/dist/docs/init.md +172 -178
- package/dist/docs/loader.md +87 -132
- package/dist/docs/serpent.md +134 -565
- 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 +114 -41
- package/dist/embedded/chacha20.d.ts +1 -1
- package/dist/embedded/chacha20.js +2 -1
- 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 +2 -1
- package/dist/embedded/sha2.d.ts +1 -1
- package/dist/embedded/sha2.js +2 -1
- package/dist/embedded/sha3.d.ts +1 -1
- package/dist/embedded/sha3.js +2 -1
- package/dist/errors.d.ts +10 -0
- package/dist/{serpent/seal.js → errors.js} +14 -46
- package/dist/fortuna.d.ts +2 -8
- package/dist/fortuna.js +11 -9
- 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 +19 -4
- package/dist/loader.js +91 -25
- 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 +12 -7
- package/dist/utils.js +75 -19
- 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 -188
- package/dist/chacha20/pool.worker.js +0 -37
- 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/stream-pool.d.ts +0 -48
- package/dist/serpent/stream-pool.js +0 -285
- package/dist/serpent/stream-sealer.d.ts +0 -50
- package/dist/serpent/stream-sealer.js +0 -341
- 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
|
@@ -1,22 +1,34 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Architecture
|
|
2
2
|
|
|
3
3
|
> [!NOTE]
|
|
4
|
-
> -
|
|
5
|
-
|
|
6
|
-
>
|
|
7
|
-
> -
|
|
8
|
-
>
|
|
4
|
+
> `leviathan-crypto` v2.0 packages five WASM modules (Serpent, ChaCha20, SHA-2, SHA-3, Kyber), generic streaming AEAD via CipherSuite, and worker pool parallelism. It supersedes `leviathan` (TypeScript reference) and `leviathan-wasm` (WASM primitives), both of which remain unchanged as development references.
|
|
5
|
+
|
|
6
|
+
> ### Table of Contents
|
|
7
|
+
> - [Vision](#vision)
|
|
8
|
+
> - [Scope](#scope)
|
|
9
|
+
> - [Repository Structure](#repository-structure)
|
|
10
|
+
> - [Architecture: TypeScript over WASM](#architecture-typescript-over-wasm)
|
|
11
|
+
> - [Five Independent WASM Modules](#five-independent-wasm-modules)
|
|
12
|
+
> - [init() API](#init-api)
|
|
13
|
+
> - [Public API Classes](#public-api-classes)
|
|
14
|
+
> - [Build Pipeline](#build-pipeline)
|
|
15
|
+
> - [Module Relationship Diagrams](#module-relationship-diagrams)
|
|
16
|
+
> - [npm Package](#npm-package)
|
|
17
|
+
> - [Buffer Layouts](#buffer-layouts)
|
|
18
|
+
> - [Test Suite](#test-suite)
|
|
19
|
+
> - [Correctness Contract](#correctness-contract)
|
|
20
|
+
> - [Known Limitations](#known-limitations)
|
|
21
|
+
|
|
22
|
+
---
|
|
9
23
|
|
|
10
24
|
## Vision
|
|
11
25
|
|
|
12
26
|
`leviathan-crypto` is a strictly-typed, audited WebAssembly cryptography library for
|
|
13
27
|
the web. It combines two previously separate efforts:
|
|
14
28
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
running outside the JavaScript JIT for predictable execution and practical
|
|
19
|
-
constant-time guarantees
|
|
29
|
+
**leviathan.** Developer-friendly TypeScript API, strict types, audited against specs and known-answer test vectors.
|
|
30
|
+
|
|
31
|
+
**leviathan-wasm.** AssemblyScript WASM implementation of the same primitives, running outside the JavaScript JIT for predictable execution and practical constant-time guarantees.
|
|
20
32
|
|
|
21
33
|
The unified library exposes the TypeScript API from leviathan, backed by the WASM
|
|
22
34
|
execution engine from leviathan-wasm. Developers get ergonomic, well-typed classes.
|
|
@@ -29,17 +41,19 @@ layer handles API ergonomics; the WASM layer handles all cryptographic computati
|
|
|
29
41
|
|
|
30
42
|
---
|
|
31
43
|
|
|
32
|
-
## Scope
|
|
44
|
+
## Scope
|
|
33
45
|
|
|
34
46
|
### In scope
|
|
35
47
|
|
|
36
|
-
| Module
|
|
37
|
-
|
|
38
|
-
| `serpent`
|
|
39
|
-
| `serpent` + `sha2` | `
|
|
40
|
-
| `chacha20`
|
|
41
|
-
| `sha2`
|
|
42
|
-
| `sha3` | SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 (XOFs, multi-squeeze) |
|
|
48
|
+
| Module | Primitives |
|
|
49
|
+
| ------------------ | ----------------------------------------------------------------------------------------------------------------------- |
|
|
50
|
+
| `serpent` | Serpent-256 block cipher: ECB, CTR mode, CBC mode |
|
|
51
|
+
| `serpent` + `sha2` | `SerpentCipher` (CipherSuite for STREAM construction: CBC+HMAC-SHA256) |
|
|
52
|
+
| `chacha20` | ChaCha20, Poly1305, ChaCha20-Poly1305 AEAD, XChaCha20-Poly1305 AEAD, `XChaCha20Cipher` (CipherSuite for streaming AEAD) |
|
|
53
|
+
| `sha2` | SHA-256, SHA-384, SHA-512, HMAC-SHA256, HMAC-SHA384, HMAC-SHA512, HKDF-SHA256, HKDF-SHA512 |
|
|
54
|
+
| `sha3` / `keccak` | SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 (XOFs, multi-squeeze). `'keccak'` is an alias for `'sha3'`; same binary, same instance slot. |
|
|
55
|
+
| `kyber` | `MlKem512`, `MlKem768`, `MlKem1024`. Requires `sha3` for Keccak sponge operations. |
|
|
56
|
+
| `stream` | `SealStream`, `OpenStream` (cipher-agnostic STREAM construction), `SealStreamPool` (worker-based parallelism) |
|
|
43
57
|
|
|
44
58
|
Pure TypeScript utilities (encoding helpers, random generation, format converters)
|
|
45
59
|
ship alongside the WASM-backed primitives with no `init()` dependency.
|
|
@@ -47,27 +61,31 @@ ship alongside the WASM-backed primitives with no `init()` dependency.
|
|
|
47
61
|
### Auxiliary tier (not part of `Module` union)
|
|
48
62
|
|
|
49
63
|
- **`Fortuna`:** CSPRNG requiring two core modules (`serpent` + `sha2`).
|
|
50
|
-
Initialized via the standard `init()` gate.
|
|
51
64
|
|
|
52
65
|
---
|
|
53
66
|
|
|
54
67
|
## Repository Structure
|
|
55
68
|
|
|
56
|
-
|
|
57
|
-
```
|
|
69
|
+
```text
|
|
58
70
|
leviathan-crypto/
|
|
71
|
+
├── .github/
|
|
72
|
+
│ └── workflows/ ← CI: build, test-suite, e2e, publish, release, wiki
|
|
59
73
|
├── src/
|
|
60
74
|
│ ├── asm/ ← AssemblyScript (compiles to .wasm)
|
|
61
75
|
│ │ ├── serpent/
|
|
62
76
|
│ │ │ ├── index.ts ← asc entry point → serpent.wasm
|
|
63
77
|
│ │ │ ├── serpent.ts ← block function + key schedule
|
|
64
78
|
│ │ │ ├── serpent_unrolled.ts ← unrolled S-boxes and round functions
|
|
79
|
+
│ │ │ ├── serpent_simd.ts ← SIMD bitsliced block operations
|
|
65
80
|
│ │ │ ├── cbc.ts ← CBC mode
|
|
81
|
+
│ │ │ ├── cbc_simd.ts ← SIMD CBC decrypt
|
|
66
82
|
│ │ │ ├── ctr.ts ← CTR mode
|
|
83
|
+
│ │ │ ├── ctr_simd.ts ← SIMD CTR 4-wide inter-block
|
|
67
84
|
│ │ │ └── buffers.ts ← static buffer layout + offset getters
|
|
68
85
|
│ │ ├── chacha20/
|
|
69
86
|
│ │ │ ├── index.ts ← asc entry point → chacha20.wasm
|
|
70
87
|
│ │ │ ├── chacha20.ts
|
|
88
|
+
│ │ │ ├── chacha20_simd_4x.ts ← SIMD 4-wide inter-block ChaCha20
|
|
71
89
|
│ │ │ ├── poly1305.ts
|
|
72
90
|
│ │ │ ├── wipe.ts
|
|
73
91
|
│ │ │ └── buffers.ts
|
|
@@ -78,40 +96,78 @@ leviathan-crypto/
|
|
|
78
96
|
│ │ │ ├── hmac.ts
|
|
79
97
|
│ │ │ ├── hmac512.ts
|
|
80
98
|
│ │ │ └── buffers.ts
|
|
81
|
-
│ │
|
|
99
|
+
│ │ ├── sha3/
|
|
82
100
|
│ │ ├── index.ts ← asc entry point → sha3.wasm
|
|
83
101
|
│ │ ├── keccak.ts
|
|
84
102
|
│ │ └── buffers.ts
|
|
103
|
+
│ │ ├── ct/
|
|
104
|
+
│ │ │ └── index.ts ← asc entry point → ct.wasm (SIMD constant-time compare)
|
|
105
|
+
│ │ └── kyber/
|
|
106
|
+
│ │ ├── index.ts ← asc entry point → kyber.wasm
|
|
107
|
+
│ │ ├── ntt.ts ← NTT/invNTT (scalar reference + zetas table)
|
|
108
|
+
│ │ ├── ntt_simd.ts ← SIMD NTT/invNTT (v128 butterflies, fqmul_8x, barrett_reduce_8x)
|
|
109
|
+
│ │ ├── reduce.ts ← Montgomery/Barrett reduction, fqmul
|
|
110
|
+
│ │ ├── poly.ts ← polynomial serialization, compression, arithmetic, basemul
|
|
111
|
+
│ │ ├── poly_simd.ts ← SIMD poly add/sub/reduce/ntt wrappers
|
|
112
|
+
│ │ ├── polyvec.ts ← k-wide polyvec operations
|
|
113
|
+
│ │ ├── cbd.ts ← centered binomial distribution (η=2, η=3)
|
|
114
|
+
│ │ ├── sampling.ts ← uniform rejection sampling
|
|
115
|
+
│ │ ├── verify.ts ← constant-time compare and conditional move
|
|
116
|
+
│ │ ├── params.ts ← Q, QINV, MONT, Barrett/compression constants
|
|
117
|
+
│ │ └── buffers.ts ← static buffer layout + offset getters
|
|
85
118
|
│ └── ts/ ← TypeScript (public API)
|
|
86
119
|
│ ├── init.ts ← initModule() : WASM loading and module cache
|
|
87
|
-
│ ├── loader.ts ←
|
|
120
|
+
│ ├── loader.ts ← loadWasm() / compileWasm() : polymorphic WasmSource dispatch
|
|
121
|
+
│ ├── wasm-source.ts ← WasmSource union type
|
|
122
|
+
│ ├── errors.ts ← AuthenticationError
|
|
88
123
|
│ ├── types.ts ← Hash, KeyedHash, Blockcipher, Streamcipher, AEAD
|
|
89
124
|
│ ├── utils.ts ← encoding, wipe, xor, concat, randomBytes
|
|
90
125
|
│ ├── fortuna.ts ← Fortuna CSPRNG (requires serpent + sha2)
|
|
91
|
-
│ ├── embedded/ ← generated base64
|
|
126
|
+
│ ├── embedded/ ← generated gzip+base64 blobs (build artifact, gitignored)
|
|
92
127
|
│ │ ├── serpent.ts
|
|
93
128
|
│ │ ├── chacha20.ts
|
|
94
129
|
│ │ ├── sha2.ts
|
|
95
130
|
│ │ └── sha3.ts
|
|
96
131
|
│ ├── serpent/
|
|
97
132
|
│ │ ├── index.ts ← serpentInit() + Serpent, SerpentCtr, SerpentCbc
|
|
98
|
-
│ │ ├──
|
|
99
|
-
│ │ ├──
|
|
100
|
-
│ │ ├──
|
|
101
|
-
│ │ ├── stream-sealer.ts ← SerpentStreamSealer / SerpentStreamOpener (incremental AEAD)
|
|
102
|
-
│ │ ├── stream.worker.ts ← Web Worker entry point for SerpentStreamPool
|
|
133
|
+
│ │ ├── cipher-suite.ts ← SerpentCipher (CipherSuite for STREAM construction)
|
|
134
|
+
│ │ ├── pool-worker.ts ← Web Worker for SealStreamPool with SerpentCipher
|
|
135
|
+
│ │ ├── embedded.ts ← re-exports gzip+base64 blob as named export
|
|
103
136
|
│ │ └── types.ts
|
|
104
137
|
│ ├── chacha20/
|
|
105
|
-
│ │ ├── index.ts ← chacha20Init() + ChaCha20, Poly1305, ChaCha20Poly1305, XChaCha20Poly1305
|
|
106
|
-
│ │ ├──
|
|
107
|
-
│ │ ├──
|
|
138
|
+
│ │ ├── index.ts ← chacha20Init() + ChaCha20, Poly1305, ChaCha20Poly1305, XChaCha20Poly1305, XChaCha20Cipher
|
|
139
|
+
│ │ ├── ops.ts ← raw AEAD functions shared by classes and pool worker
|
|
140
|
+
│ │ ├── cipher-suite.ts ← XChaCha20Cipher (CipherSuite for STREAM construction)
|
|
141
|
+
│ │ ├── pool-worker.ts ← Web Worker for SealStreamPool with XChaCha20Cipher
|
|
142
|
+
│ │ ├── embedded.ts ← re-exports gzip+base64 blob as named export
|
|
108
143
|
│ │ └── types.ts
|
|
109
144
|
│ ├── sha2/
|
|
110
|
-
│ │ ├── index.ts ← sha2Init() + SHA256, SHA512, SHA384,
|
|
145
|
+
│ │ ├── index.ts ← sha2Init() + SHA256, SHA512, SHA384, HMAC, HKDF
|
|
146
|
+
│ │ ├── hkdf.ts ← HKDF_SHA256, HKDF_SHA512 (pure TS over HMAC)
|
|
147
|
+
│ │ ├── embedded.ts ← re-exports gzip+base64 blob as named export
|
|
111
148
|
│ │ └── types.ts
|
|
112
149
|
│ ├── sha3/
|
|
113
|
-
│ │ ├── index.ts ← sha3Init() + SHA3_224,
|
|
150
|
+
│ │ ├── index.ts ← sha3Init() + SHA3_224–512, SHAKE128, SHAKE256
|
|
151
|
+
│ │ ├── embedded.ts ← re-exports gzip+base64 blob as named export
|
|
114
152
|
│ │ └── types.ts
|
|
153
|
+
│ ├── kyber/
|
|
154
|
+
│ │ ├── index.ts ← kyberInit() + MlKem512, MlKem768, MlKem1024, KyberSuite
|
|
155
|
+
│ │ ├── kem.ts ← Fujisaki-Okamoto transform (keygen, encaps, decaps)
|
|
156
|
+
│ │ ├── suite.ts ← KyberSuite factory (hybrid KEM+AEAD CipherSuite)
|
|
157
|
+
│ │ ├── indcpa.ts ← IND-CPA encrypt/decrypt + matrix generation
|
|
158
|
+
│ │ ├── validate.ts ← key validation (FIPS 203 §7.2, §7.3)
|
|
159
|
+
│ │ ├── params.ts ← parameter sets (MLKEM512, MLKEM768, MLKEM1024)
|
|
160
|
+
│ │ ├── types.ts ← KyberExports, Sha3Exports, KEM API types
|
|
161
|
+
│ │ └── embedded.ts ← re-exports gzip+base64 blob as kyberWasm
|
|
162
|
+
│ ├── stream/
|
|
163
|
+
│ │ ├── index.ts ← barrel: Seal, SealStream, OpenStream, SealStreamPool, constants
|
|
164
|
+
│ │ ├── seal.ts ← Seal (static one-shot AEAD)
|
|
165
|
+
│ │ ├── seal-stream.ts ← SealStream (cipher-agnostic streaming encryption)
|
|
166
|
+
│ │ ├── open-stream.ts ← OpenStream (cipher-agnostic streaming decryption)
|
|
167
|
+
│ │ ├── seal-stream-pool.ts ← SealStreamPool (worker-based parallel batch)
|
|
168
|
+
│ │ ├── header.ts ← wire format header encode/decode, counter nonce
|
|
169
|
+
│ │ ├── constants.ts ← HEADER_SIZE, CHUNK_MIN/MAX, TAG_DATA/FINAL, FLAG_FRAMED
|
|
170
|
+
│ │ └── types.ts ← CipherSuite, DerivedKeys, SealStreamOpts
|
|
115
171
|
│ └── index.ts ← root barrel : dispatching init() + re-exports everything
|
|
116
172
|
├── test/
|
|
117
173
|
│ ├── unit/ ← Vitest (JS target, fast iteration)
|
|
@@ -119,42 +175,44 @@ leviathan-crypto/
|
|
|
119
175
|
│ │ ├── chacha20/
|
|
120
176
|
│ │ ├── sha2/
|
|
121
177
|
│ │ ├── sha3/
|
|
122
|
-
│ │
|
|
178
|
+
│ │ ├── stream/ ← SealStream, OpenStream, SealStreamPool tests
|
|
179
|
+
│ │ ├── loader/ ← WasmSource loading tests
|
|
180
|
+
│ │ ├── init.test.ts
|
|
181
|
+
│ │ ├── errors.test.ts
|
|
182
|
+
│ │ ├── fortuna.test.ts
|
|
183
|
+
│ │ └── utils.test.ts
|
|
123
184
|
│ ├── e2e/ ← Playwright (WASM target, cross-browser)
|
|
124
185
|
│ └── vectors/ ← test vector files (read-only reference data)
|
|
125
|
-
├── build/ ← WASM build output (gitignored)
|
|
126
|
-
├── dist/ ← npm publish output (gitignored)
|
|
127
|
-
├── docs/ ← project documentation
|
|
128
186
|
├── scripts/
|
|
129
|
-
│ ├── embed-wasm.ts ← reads build/*.wasm, generates src/ts/embedded/*.ts
|
|
130
187
|
│ ├── build-asm.js ← orchestrates AssemblyScript compilation
|
|
131
|
-
│ ├──
|
|
132
|
-
│
|
|
188
|
+
│ ├── embed-wasm.ts ← reads build/*.wasm, generates src/ts/embedded/*.ts
|
|
189
|
+
│ ├── gen-seal-vectors.ts ← generates KAT vectors for Seal
|
|
190
|
+
│ ├── gen-sealstream-vectors.ts ← generates KAT vectors for SealStream
|
|
191
|
+
│ ├── generate_simd.ts ← generates SIMD assembly variants
|
|
192
|
+
│ ├── gen-changelog.ts ← changelog generation
|
|
193
|
+
│ ├── copy-docs.ts ← copies docs subset to dist/
|
|
194
|
+
│ └── pin-actions.ts ← pins GitHub Actions to SHA hashes
|
|
195
|
+
├── docs/ ← project documentation + wiki source
|
|
133
196
|
├── package.json
|
|
134
197
|
├── asconfig.json ← four AssemblyScript entry points
|
|
135
198
|
├── tsconfig.json
|
|
136
199
|
├── vitest.config.ts
|
|
137
|
-
|
|
200
|
+
├── playwright.config.ts
|
|
201
|
+
├── AGENTS.md ← ai agent contract
|
|
202
|
+
└── SECURITY.md
|
|
138
203
|
```
|
|
139
204
|
|
|
140
205
|
---
|
|
141
206
|
|
|
142
207
|
## Architecture: TypeScript over WASM
|
|
143
208
|
|
|
209
|
+
The TypeScript layer never implements cryptographic algorithms. It manages the boundary between JavaScript and WebAssembly by writing inputs into WASM linear memory, calling exported functions, and reading back outputs. All algorithm logic resides within AssemblyScript.
|
|
144
210
|
|
|
145
|
-
|
|
146
|
-
> The TypeScript layer never implements cryptographic algorithms. It handles the
|
|
147
|
-
> JS/WASM boundary: writing inputs into WASM linear memory, calling exported
|
|
148
|
-
> functions, reading outputs back. All algorithm logic lives in AssemblyScript.
|
|
149
|
-
>
|
|
150
|
-
> The exception is the Tier 2 composition layer: `SerpentSeal`, `SerpentStream`,
|
|
151
|
-
> `SerpentStreamPool`, `SerpentStreamSealer`, `SerpentStreamOpener`, and `HKDF`.
|
|
152
|
-
> These are pure TypeScript, they compose the WASM-backed Tier 1 primitives
|
|
153
|
-
> (Serpent-CBC, HMAC-SHA256, HKDF-SHA256) without adding new algorithm logic.
|
|
211
|
+
Higher-level classes like `Seal`, `SealStream`, and `SealStreamPool` are pure TypeScript, but they compose WASM-backed primitives (Serpent-CBC, HMAC-SHA256, ChaCha20-Poly1305, and HKDF-SHA256) rather than implementing new cryptographic logic. TypeScript orchestrates, while WASM computes. Pool workers instantiate their own WASM modules and directly call primitives, bypassing the main-thread module cache.
|
|
154
212
|
|
|
155
213
|
---
|
|
156
214
|
|
|
157
|
-
##
|
|
215
|
+
## Five Independent WASM Modules
|
|
158
216
|
|
|
159
217
|
Each primitive family compiles to its own `.wasm` binary. Modules are fully
|
|
160
218
|
independent, separate linear memories, separate buffer layouts, no shared state.
|
|
@@ -165,11 +223,11 @@ independent, separate linear memories, separate buffer layouts, no shared state.
|
|
|
165
223
|
| `chacha20` | `chacha20.wasm` | ChaCha20, Poly1305, ChaCha20-Poly1305 AEAD, XChaCha20-Poly1305 AEAD |
|
|
166
224
|
| `sha2` | `sha2.wasm` | SHA-256, SHA-384, SHA-512, HMAC-SHA256, HMAC-SHA384, HMAC-SHA512 |
|
|
167
225
|
| `sha3` | `sha3.wasm` | SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 |
|
|
226
|
+
| `kyber` | `kyber.wasm` | ML-KEM polynomial arithmetic: SIMD NTT/invNTT (v128 butterflies with scalar tail), basemul, Montgomery/Barrett, CBD, compress, CT verify/cmov |
|
|
227
|
+
|
|
228
|
+
**Size.** Consumers who only use Serpent don't load the SHA-3 binary.
|
|
168
229
|
|
|
169
|
-
**
|
|
170
|
-
1. **Size:** consumers who only use Serpent don't load the SHA-3 binary
|
|
171
|
-
2. **Isolation:** key material in `serpent.wasm` memory cannot bleed into
|
|
172
|
-
`sha3.wasm` memory even in theory
|
|
230
|
+
**Isolation.** Key material in `serpent.wasm` memory cannot bleed into `sha3.wasm` memory even in theory.
|
|
173
231
|
|
|
174
232
|
Each module's buffer layout starts at offset 0 and is defined in its own
|
|
175
233
|
`buffers.ts`. Buffer layouts are fully independent across modules.
|
|
@@ -178,26 +236,23 @@ Each module's buffer layout starts at offset 0 and is defined in its own
|
|
|
178
236
|
|
|
179
237
|
**`serpent.wasm`**
|
|
180
238
|
Serpent-256 block cipher. Key schedule, block encrypt, block decrypt. CTR mode
|
|
181
|
-
chunked streaming encrypt/decrypt. CBC mode chunked encrypt/decrypt.
|
|
239
|
+
chunked streaming encrypt/decrypt. CBC mode chunked encrypt/decrypt. SIMD
|
|
240
|
+
variants for CTR 4-wide inter-block and CBC decrypt parallelism.
|
|
182
241
|
Source: `src/asm/serpent/`
|
|
183
242
|
|
|
184
|
-
The serpent TypeScript module
|
|
185
|
-
|
|
186
|
-
`
|
|
187
|
-
parallel AEAD), and `SerpentStreamSealer` / `SerpentStreamOpener` (incremental
|
|
188
|
-
streaming AEAD). All Tier 2 classes use HKDF-SHA256 for per-chunk key derivation
|
|
189
|
-
and require both `serpent` and `sha2` to be initialized.
|
|
243
|
+
The serpent TypeScript module includes `SerpentCipher` (CipherSuite implementation
|
|
244
|
+
for the STREAM construction: Serpent-CBC + HMAC-SHA256 with HKDF key derivation).
|
|
245
|
+
Requires `serpent` and `sha2` to be initialized.
|
|
190
246
|
|
|
191
247
|
**`chacha20.wasm`**
|
|
192
248
|
ChaCha20 stream cipher (RFC 8439). Poly1305 MAC (RFC 8439 §2.5). ChaCha20-Poly1305
|
|
193
249
|
AEAD (RFC 8439 §2.8). XChaCha20-Poly1305 AEAD (draft-irtf-cfrg-xchacha).
|
|
194
|
-
HChaCha20 subkey derivation.
|
|
250
|
+
HChaCha20 subkey derivation. SIMD 4-wide inter-block parallelism.
|
|
195
251
|
Source: `src/asm/chacha20/`
|
|
196
252
|
|
|
197
|
-
The chacha20 TypeScript module
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
is an internal file loaded by the pool at runtime, not a public named subpath.
|
|
253
|
+
The chacha20 TypeScript module includes `XChaCha20Cipher` (CipherSuite implementation
|
|
254
|
+
for the STREAM construction: XChaCha20-Poly1305 with HKDF key derivation).
|
|
255
|
+
Pool workers are internal, loaded by `SealStreamPool` at runtime, not registered in the package exports map.
|
|
201
256
|
|
|
202
257
|
**`sha2.wasm`**
|
|
203
258
|
SHA-256 and SHA-512 (FIPS 180-4). SHA-384 (SHA-512 with different IVs, truncated
|
|
@@ -213,90 +268,88 @@ All six variants share one permutation, differing only in rate, domain
|
|
|
213
268
|
separation byte, and output length.
|
|
214
269
|
Source: `src/asm/sha3/`
|
|
215
270
|
|
|
271
|
+
**`kyber.wasm`**
|
|
272
|
+
ML-KEM (FIPS 203) polynomial arithmetic. Montgomery and Barrett reduction,
|
|
273
|
+
7-layer NTT and inverse NTT, basemul in Z_q[X]/(X²-ζ), centered binomial
|
|
274
|
+
distribution sampling (η=2, η=3), division-free compression/decompression
|
|
275
|
+
(all 5 bit-width paths: 4, 5, 10, 11, 1-bit), rejection sampling for matrix
|
|
276
|
+
generation, constant-time byte comparison and conditional move. Requires
|
|
277
|
+
WebAssembly SIMD (`v128` instructions) for NTT and polynomial arithmetic.
|
|
278
|
+
3 pages (192 KB) linear memory with 10 poly slots, 8 polyvec slots, and
|
|
279
|
+
dedicated byte buffers for keys/ciphertexts.
|
|
280
|
+
Source: `src/asm/kyber/`
|
|
281
|
+
|
|
282
|
+
The kyber TypeScript module includes `MlKem512`, `MlKem768`, `MlKem1024`
|
|
283
|
+
(KEM classes implementing the Fujisaki-Okamoto transform). All require both
|
|
284
|
+
`kyber` and `sha3` to be initialized; the sha3 module provides the Keccak sponge (SHAKE128 for matrix gen, SHAKE256 for noise/J function, SHA3-256 for H, SHA3-512 for G).
|
|
285
|
+
|
|
216
286
|
---
|
|
217
287
|
|
|
218
288
|
## `init()` API
|
|
219
289
|
|
|
220
|
-
WASM instantiation is async. `init()` is the
|
|
221
|
-
it must be called once before any cryptographic class is used. This is honest
|
|
222
|
-
about the initialization cost and gives the developer control over when it is paid.
|
|
290
|
+
WASM instantiation is async. `init()` is the initialization gate, call it once before using any cryptographic class. The cost is explicit and the developer controls when it is paid.
|
|
223
291
|
|
|
224
292
|
### Signature
|
|
225
293
|
|
|
226
294
|
```typescript
|
|
227
|
-
type Module = 'serpent' | 'chacha20' | 'sha2' | 'sha3'
|
|
228
|
-
type Mode = 'embedded' | 'streaming' | 'manual'
|
|
295
|
+
type Module = 'serpent' | 'chacha20' | 'sha2' | 'sha3' | 'keccak' | 'kyber'
|
|
229
296
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
297
|
+
type WasmSource =
|
|
298
|
+
| string // gzip+base64 embedded blob
|
|
299
|
+
| URL // fetch + compileStreaming
|
|
300
|
+
| ArrayBuffer // compile from raw bytes
|
|
301
|
+
| Uint8Array // compile from raw bytes
|
|
302
|
+
| WebAssembly.Module // pre-compiled (edge runtimes)
|
|
303
|
+
| Response // instantiateStreaming
|
|
304
|
+
| Promise<Response> // deferred fetch
|
|
234
305
|
|
|
235
306
|
async function init(
|
|
236
|
-
|
|
237
|
-
mode?: Mode,
|
|
238
|
-
opts?: InitOpts
|
|
307
|
+
sources: Partial<Record<Module, WasmSource>>,
|
|
239
308
|
): Promise<void>
|
|
240
309
|
```
|
|
241
310
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
is decoded and passed to `WebAssembly.instantiate()`. Works everywhere with no
|
|
248
|
-
bundler configuration. ~33% size overhead from base64 encoding. Cannot use
|
|
249
|
-
streaming compilation.
|
|
311
|
+
The loading strategy is inferred from the source type, so there is no need
|
|
312
|
+
for a mode string. Each module also exports its own init function, such as
|
|
313
|
+
`serpentInit(source)`, `chacha20Init(source)`, `sha2Init(source)`,
|
|
314
|
+
`sha3Init(source)`, `keccakInit(source)`, and `kyberInit(source)`,
|
|
315
|
+
enabling tree-shakeable imports.
|
|
250
316
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
```
|
|
317
|
+
> [!NOTE]
|
|
318
|
+
> **`'keccak'` is an alias for `'sha3'`.** Both names are accepted by `init()`, `initModule()`, `getInstance()`, and `isInitialized()`. They share the same WASM binary and the same instance slot. The alias exists so Kyber/ML-KEM consumers can write `init({ keccak: keccakWasm })` using the semantically correct name for the underlying sponge primitive.
|
|
254
319
|
|
|
255
|
-
|
|
256
|
-
Uses `WebAssembly.instantiateStreaming()` for maximum load performance. The
|
|
257
|
-
browser compiles the WASM binary while still downloading it. `wasmUrl` is a
|
|
258
|
-
base URL, the loader appends the filename (`serpent.wasm`, `chacha20.wasm`, etc.).
|
|
259
|
-
Requires the `.wasm` files to be served with `Content-Type: application/wasm`.
|
|
320
|
+
### Embedded subpath exports
|
|
260
321
|
|
|
322
|
+
Each module provides a `/embedded` subpath that exports the gzip+base64
|
|
323
|
+
blob as a ready-to-use `WasmSource`:
|
|
261
324
|
```typescript
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
325
|
+
import { init } from 'leviathan-crypto'
|
|
326
|
+
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
327
|
+
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
265
328
|
|
|
266
|
-
|
|
267
|
-
Caller provides the compiled binary directly as a `Uint8Array` or `ArrayBuffer`.
|
|
268
|
-
For environments with custom loading requirements (CDN, service worker cache,
|
|
269
|
-
non-standard fetch).
|
|
270
|
-
|
|
271
|
-
```typescript
|
|
272
|
-
await init(['chacha20'], 'manual', {
|
|
273
|
-
wasmBinary: { chacha20: myBuffer }
|
|
274
|
-
})
|
|
329
|
+
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
275
330
|
```
|
|
276
331
|
|
|
277
332
|
### Behavioral contracts
|
|
278
333
|
|
|
279
|
-
**Idempotent.** Calling `init()`
|
|
280
|
-
no-op.
|
|
334
|
+
**Idempotent initialization.** Calling `init()` on an already initialized
|
|
335
|
+
module is a no-op. It is safe to call `init()` from multiple locations
|
|
336
|
+
within the codebase.
|
|
281
337
|
|
|
282
|
-
**Module-scope cache.**
|
|
283
|
-
|
|
284
|
-
|
|
338
|
+
**Module-scope cache.** Each `WebAssembly.Instance` is cached at module
|
|
339
|
+
scope after initial instantiation. All subsequent class constructions use
|
|
340
|
+
the cached instance with no recompilation.
|
|
285
341
|
|
|
286
|
-
**Error before
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
```
|
|
342
|
+
**Error before initialization.** Invoking any cryptographic class before
|
|
343
|
+
calling `init()` throws a clear error prompting the developer to call
|
|
344
|
+
`init({ <module>: ... })` first.
|
|
290
345
|
|
|
291
|
-
**No
|
|
292
|
-
|
|
346
|
+
**No implicit initialization.** Classes never call `init()` automatically
|
|
347
|
+
on first use. Explicit initialization is preferable to hidden costs.
|
|
293
348
|
|
|
294
|
-
**Thread safety.**
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
`XChaCha20Poly1305Pool` (AEAD). Each pool worker owns its own WASM instances with
|
|
299
|
-
isolated linear memory. For other primitives: create one instance per Worker if
|
|
349
|
+
**Thread safety.** The main thread uses a single WASM instance per module.
|
|
350
|
+
`SealStreamPool` provides worker-based parallelism. Each pool worker owns
|
|
351
|
+
its own WASM instances with isolated linear memory, bypassing the main-thread
|
|
352
|
+
cache entirely. For other primitives, create one instance per Worker if
|
|
300
353
|
Workers are used.
|
|
301
354
|
|
|
302
355
|
---
|
|
@@ -307,33 +360,36 @@ Names match conventional cryptographic notation.
|
|
|
307
360
|
|
|
308
361
|
| Module | Classes |
|
|
309
362
|
|--------|---------|
|
|
310
|
-
| `serpent` + `sha2` | `
|
|
363
|
+
| `serpent` + `sha2` | `SerpentCipher` |
|
|
311
364
|
| `serpent` | `Serpent`, `SerpentCtr`, `SerpentCbc` |
|
|
312
|
-
| `chacha20` | `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, `
|
|
365
|
+
| `chacha20` | `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, `XChaCha20Cipher` |
|
|
313
366
|
| `sha2` | `SHA256`, `SHA384`, `SHA512`, `HMAC_SHA256`, `HMAC_SHA384`, `HMAC_SHA512`, `HKDF_SHA256`, `HKDF_SHA512` |
|
|
314
367
|
| `sha3` | `SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512`, `SHAKE128`, `SHAKE256` |
|
|
368
|
+
| `kyber` + `sha3` | `MlKem512`, `MlKem768`, `MlKem1024` |
|
|
369
|
+
| `kyber` + `sha3` + inner cipher | `KyberSuite` (hybrid KEM+AEAD factory) |
|
|
370
|
+
| `stream` | `Seal`, `SealStream`, `OpenStream`, `SealStreamPool` |
|
|
315
371
|
| `serpent` + `sha2` | `Fortuna` |
|
|
316
372
|
|
|
317
373
|
HMAC names use underscore separator (`HMAC_SHA256`) matching RFC convention.
|
|
318
374
|
SHA-3 names use underscore separator (`SHA3_256`) for readability.
|
|
375
|
+
`SealStream`, `OpenStream`, and `SealStreamPool` are cipher-agnostic; you select the cipher by passing `XChaCha20Cipher` or `SerpentCipher` at construction.
|
|
319
376
|
|
|
320
377
|
**`Fortuna`** requires `await Fortuna.create()` rather than `new Fortuna()` due
|
|
321
|
-
to the async `init()` dependency on two modules.
|
|
322
|
-
`sha2` to be initialized. In Node.js, Fortuna collects additional entropy from
|
|
323
|
-
`process.hrtime`, `process.cpuUsage`, `process.memoryUsage`, `os.loadavg`,
|
|
324
|
-
and `os.freemem` in addition to `crypto.randomBytes`.
|
|
378
|
+
to the async `init()` dependency on two modules.
|
|
325
379
|
|
|
326
380
|
### Usage pattern
|
|
327
381
|
|
|
328
382
|
All WASM-backed classes follow the same pattern:
|
|
329
|
-
|
|
330
383
|
```typescript
|
|
331
|
-
import { init,
|
|
384
|
+
import { init, Seal, SerpentCipher, SHA3_256 } from 'leviathan-crypto'
|
|
385
|
+
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
386
|
+
import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
|
|
387
|
+
import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
|
|
332
388
|
|
|
333
|
-
await init(
|
|
389
|
+
await init({ serpent: serpentWasm, sha2: sha2Wasm, sha3: sha3Wasm })
|
|
334
390
|
|
|
335
|
-
const
|
|
336
|
-
const
|
|
391
|
+
const key = SerpentCipher.keygen()
|
|
392
|
+
const blob = Seal.encrypt(SerpentCipher, key, plaintext)
|
|
337
393
|
|
|
338
394
|
const hasher = new SHA3_256()
|
|
339
395
|
const digest = hasher.hash(message)
|
|
@@ -354,35 +410,33 @@ Pure TypeScript utilities ship alongside the WASM-backed primitives:
|
|
|
354
410
|
|
|
355
411
|
## Build Pipeline
|
|
356
412
|
|
|
413
|
+
1. `npm run build:asm`: AssemblyScript compiler reads `src/asm/*/index.ts`, emits `build/*.wasm`
|
|
414
|
+
2. `npm run build:embed`: `scripts/embed-wasm.ts` reads each `.wasm`, gzip compresses, base64 encodes, writes to `src/ts/embedded/*.ts` and per-module `src/ts/*/embedded.ts`
|
|
415
|
+
3. `npm run build:ts`: TypeScript compiler emits `dist/`
|
|
416
|
+
4. `cp build/*.wasm dist/`: WASM binaries copied for URL-based consumers
|
|
417
|
+
5. At runtime (subpath): `serpentInit(serpentWasm)` → `initModule()` → `loadWasm(source)` → decode gzip+base64 → `WebAssembly.instantiate` → cache in `init.ts`
|
|
418
|
+
6. At runtime (root): `init({ serpent: serpentWasm, sha2: sha2Wasm })` → dispatches to each module's init function via `Promise.all` → same path as step 5 per module
|
|
357
419
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
1. `npm run build:asm` — AssemblyScript compiler reads `src/asm/*/index.ts`, emits `build/*.wasm`
|
|
361
|
-
2. `npm run build:embed` — `scripts/embed-wasm.ts` reads each `.wasm`, writes base64 to `src/ts/embedded/*.ts`
|
|
362
|
-
3. `npm run build:ts` — TypeScript compiler emits `dist/`
|
|
363
|
-
4. `cp build/*.wasm dist/` — WASM binaries copied for streaming mode consumers
|
|
364
|
-
5. At runtime (subpath): `serpent/index.ts:serpentInit()` → `initModule()` → `loadEmbedded(thunk)` → `thunk()` → dynamic-import `embedded/serpent.ts` → decode base64 → `WebAssembly.instantiate` → cache in `init.ts`
|
|
365
|
-
6. At runtime (root): `index.ts:init(['serpent', 'sha3'])` → dispatches to each module's init function (`serpentInit`, `sha3Init`) via `Promise.all` → same path as step 5 per module
|
|
366
|
-
|
|
367
|
-
`src/ts/embedded/` is gitignored, these files are a build artifacts derived from the WASM
|
|
368
|
-
binaries. There is one source of truth for each binary: the AssemblyScript source.
|
|
420
|
+
`src/ts/embedded/` is gitignored; these files are build artifacts derived from the WASM binaries. There is one source of truth for each binary: the AssemblyScript source.
|
|
369
421
|
|
|
370
422
|
---
|
|
371
423
|
|
|
372
424
|
## Module Relationship Diagrams
|
|
373
425
|
|
|
374
|
-
### ASM layer
|
|
426
|
+
### ASM layer: internal import graph
|
|
375
427
|
|
|
376
428
|
Each WASM module is fully independent. No cross-module imports exist.
|
|
377
429
|
|
|
378
430
|
**Serpent (`src/asm/serpent/`)**
|
|
379
|
-
|
|
380
431
|
```
|
|
381
432
|
buffers.ts
|
|
382
433
|
<- serpent.ts (offsets for key, block, subkey, work, CBC IV)
|
|
383
434
|
<- serpent_unrolled.ts (block offsets, subkey, work)
|
|
435
|
+
<- serpent_simd.ts (SIMD bitsliced block operations)
|
|
384
436
|
<- cbc.ts (IV, block, chunk offsets)
|
|
437
|
+
<- cbc_simd.ts (SIMD CBC decrypt)
|
|
385
438
|
<- ctr.ts (nonce, counter, block, chunk offsets)
|
|
439
|
+
<- ctr_simd.ts (SIMD CTR 4-wide inter-block)
|
|
386
440
|
|
|
387
441
|
serpent.ts
|
|
388
442
|
<- serpent_unrolled.ts (S-boxes sb0-sb7, si0-si7, lk, kl, keyXor)
|
|
@@ -391,20 +445,24 @@ serpent_unrolled.ts
|
|
|
391
445
|
<- cbc.ts (encryptBlock_unrolled, decryptBlock_unrolled)
|
|
392
446
|
<- ctr.ts (encryptBlock_unrolled)
|
|
393
447
|
|
|
448
|
+
serpent_simd.ts
|
|
449
|
+
<- cbc_simd.ts (SIMD block operations)
|
|
450
|
+
<- ctr_simd.ts (SIMD block operations)
|
|
451
|
+
|
|
394
452
|
index.ts
|
|
395
|
-
re-exports: buffers + serpent + serpent_unrolled + cbc + ctr
|
|
453
|
+
re-exports: buffers + serpent + serpent_unrolled + serpent_simd + cbc + cbc_simd + ctr + ctr_simd
|
|
396
454
|
```
|
|
397
455
|
|
|
398
456
|
**ChaCha (`src/asm/chacha20/`)**
|
|
399
|
-
|
|
400
457
|
```
|
|
401
458
|
buffers.ts
|
|
402
459
|
<- chacha20.ts (key, nonce, counter, block, state, poly key, xchacha offsets)
|
|
460
|
+
<- chacha20_simd_4x.ts (SIMD work buffer, chunk offsets)
|
|
403
461
|
<- poly1305.ts (poly key, msg, buf, tag, h, r, rs, s offsets)
|
|
404
462
|
<- wipe.ts (all buffer offsets, zeroes everything)
|
|
405
463
|
|
|
406
464
|
index.ts
|
|
407
|
-
re-exports: buffers + chacha20 + poly1305 + wipe
|
|
465
|
+
re-exports: buffers + chacha20 + chacha20_simd_4x + poly1305 + wipe
|
|
408
466
|
```
|
|
409
467
|
|
|
410
468
|
**SHA-2 (`src/asm/sha2/`)**
|
|
@@ -437,99 +495,111 @@ index.ts
|
|
|
437
495
|
re-exports: buffers + keccak
|
|
438
496
|
```
|
|
439
497
|
|
|
440
|
-
|
|
498
|
+
**Kyber (`src/asm/kyber/`)**
|
|
499
|
+
|
|
500
|
+
```
|
|
501
|
+
params.ts
|
|
502
|
+
<- reduce.ts (Q, QINV, BARRETT_V, BARRETT_SHIFT)
|
|
503
|
+
<- poly.ts (Q, POLY_BYTES, HALF_Q, compression constants)
|
|
504
|
+
<- polyvec.ts (Q, POLY_BYTES, compression constants)
|
|
505
|
+
<- sampling.ts (Q)
|
|
506
|
+
|
|
507
|
+
buffers.ts
|
|
508
|
+
<- polyvec.ts (POLY_ACC_OFFSET)
|
|
509
|
+
|
|
510
|
+
reduce.ts
|
|
511
|
+
<- ntt.ts (fqmul, barrett_reduce)
|
|
512
|
+
<- ntt_simd.ts (fqmul, barrett_reduce — scalar tail)
|
|
513
|
+
<- poly.ts (montgomery_reduce, barrett_reduce, fqmul)
|
|
514
|
+
|
|
515
|
+
ntt.ts
|
|
516
|
+
<- ntt_simd.ts (getZetasOffset — zetas table pointer)
|
|
517
|
+
<- poly.ts (ntt, invntt, basemul, getZeta)
|
|
518
|
+
|
|
519
|
+
ntt_simd.ts
|
|
520
|
+
<- poly_simd.ts (ntt_simd, invntt_simd, barrett_reduce_8x)
|
|
521
|
+
|
|
522
|
+
poly.ts
|
|
523
|
+
<- polyvec.ts (poly_tobytes, poly_frombytes, poly_basemul_montgomery)
|
|
524
|
+
|
|
525
|
+
poly_simd.ts
|
|
526
|
+
<- polyvec.ts (poly_add_simd, poly_reduce_simd, poly_ntt_simd, poly_invntt_simd)
|
|
527
|
+
|
|
528
|
+
cbd.ts
|
|
529
|
+
<- poly.ts (cbd2, cbd3)
|
|
530
|
+
|
|
531
|
+
index.ts
|
|
532
|
+
re-exports: buffers + ntt (scalar aliases) + ntt_simd (as ntt/invntt) +
|
|
533
|
+
reduce + poly (scalar serialization/compression/basemul) +
|
|
534
|
+
poly_simd (as poly_add/sub/reduce/ntt/invntt) +
|
|
535
|
+
polyvec + sampling + verify
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
### TS layer: internal import graph
|
|
441
541
|
|
|
442
542
|
```
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
serpent.ts chacha20.ts sha2.ts sha3.ts
|
|
468
|
-
(each module owns its own embedded thunk, no cross-module imports)
|
|
543
|
+
+---------------------+
|
|
544
|
+
| index.ts | <- barrel: dispatching init()
|
|
545
|
+
| (public API root) | + re-exports everything
|
|
546
|
+
+--+--+--+--+--+--+--+
|
|
547
|
+
| | | | | |
|
|
548
|
+
+-------------------------+ | | | | +----------------------+
|
|
549
|
+
| +----------------+ | | +----------+ |
|
|
550
|
+
v v v v v v
|
|
551
|
+
serpent/ chacha20/ sha2/ sha3/ fortuna.ts stream/
|
|
552
|
+
index.ts index.ts index.ts index.ts index.ts
|
|
553
|
+
| | | | | | |
|
|
554
|
+
| | +-> ops.ts | | +-> init.ts |
|
|
555
|
+
| | | | +-> serpent/ |
|
|
556
|
+
| +-> cipher- | | +-> sha2/ +-> seal-stream.ts
|
|
557
|
+
| suite.ts | | +-> utils.ts +-> open-stream.ts
|
|
558
|
+
+-> cipher- | | | +-> seal-stream-pool.ts
|
|
559
|
+
suite.ts +-> pool- +-> hkdf.ts +-> header.ts
|
|
560
|
+
| worker.ts +-> constants.ts
|
|
561
|
+
+-> pool- | +-> types.ts
|
|
562
|
+
worker.ts |
|
|
563
|
+
|
|
|
564
|
+
All module index.ts files ──────────────────────────> init.ts <── getInstance()
|
|
565
|
+
initModule()
|
|
566
|
+
All */embedded.ts files ──────────────────────────> embedded/*.ts (gzip+base64 blobs)
|
|
469
567
|
```
|
|
470
568
|
|
|
471
569
|
Each module's init function (`serpentInit`, `chacha20Init`, `sha2Init`,
|
|
472
|
-
`sha3Init`) calls `initModule()` from `init.ts`, passing
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
| `loader.ts` | `init.ts` | `Module` (type) |
|
|
482
|
-
| `types.ts` | *(none)* | — |
|
|
483
|
-
| `utils.ts` | *(none)* | — |
|
|
484
|
-
| `serpent/types.ts` | *(none)* | — |
|
|
485
|
-
| `chacha20/types.ts` | *(none)* | — |
|
|
486
|
-
| `sha2/types.ts` | *(none)* | — |
|
|
487
|
-
| `sha3/types.ts` | *(none)* | — |
|
|
488
|
-
| `serpent/index.ts` | `init.ts`, `embedded/serpent.ts` | `getInstance`, `initModule`, `Mode`, `InitOpts`, `WASM_BASE64` |
|
|
489
|
-
| `serpent/seal.ts` | `serpent/index.ts`, `sha2/index.ts`, `utils.ts` | `SerpentCbc`, `HMAC_SHA256`, `concat`, `constantTimeEqual`, `wipe` |
|
|
490
|
-
| `serpent/stream.ts` | `serpent/index.ts`, `sha2/index.ts`, `utils.ts` | `SerpentCtr`, `HMAC_SHA256`, `HKDF_SHA256`, `constantTimeEqual`, `concat` |
|
|
491
|
-
| `serpent/stream-pool.ts` | `serpent/stream.ts` | `sealChunk`, `openChunk`, `chunkInfo` |
|
|
492
|
-
| `serpent/stream-sealer.ts` | `serpent/index.ts`, `sha2/index.ts`, `utils.ts` | `SerpentCbc`, `HMAC_SHA256`, `HKDF_SHA256`, `concat`, `constantTimeEqual`, `wipe` |
|
|
493
|
-
| `chacha20/index.ts` | `init.ts`, `utils.ts`, `chacha20/types.ts`, `embedded/chacha20.ts` | `getInstance`, `initModule`, `Mode`, `InitOpts`, `constantTimeEqual`, `ChaChaExports`, `WASM_BASE64` |
|
|
494
|
-
| `sha2/index.ts` | `init.ts`, `embedded/sha2.ts` | `getInstance`, `initModule`, `Mode`, `InitOpts`, `WASM_BASE64` |
|
|
495
|
-
| `sha3/index.ts` | `init.ts`, `embedded/sha3.ts` | `getInstance`, `initModule`, `Mode`, `InitOpts`, `WASM_BASE64` |
|
|
496
|
-
| `fortuna.ts` | `init.ts`, `serpent/index.ts`, `sha2/index.ts`, `utils.ts` | `isInitialized`, `Serpent`, `SHA256`, `wipe`/`concat`/`utf8ToBytes` |
|
|
497
|
-
| `index.ts` | `serpent/`, `chacha20/`, `sha2/`, `sha3/`, `init.ts`, `fortuna.ts`, `types.ts`, `utils.ts` | `serpentInit`, `chacha20Init`, `sha2Init`, `sha3Init` (from each module), *(all public exports)* |
|
|
570
|
+
`sha3Init`, `kyberInit`) calls `initModule()` from `init.ts`, passing a `WasmSource`.
|
|
571
|
+
`initModule()` delegates to `loadWasm(source)` in `loader.ts`. The loader
|
|
572
|
+
infers the loading strategy from the source type, with no mode string and no knowledge of module names or embedded file paths.
|
|
573
|
+
|
|
574
|
+
Pool workers (`serpent/pool-worker.ts`, `chacha20/pool-worker.ts`) instantiate
|
|
575
|
+
their own WASM modules from pre-compiled `WebAssembly.Module` objects passed
|
|
576
|
+
via `postMessage`. They do not use `initModule()` or the main-thread cache.
|
|
577
|
+
|
|
578
|
+
---
|
|
498
579
|
|
|
499
580
|
### TS-to-WASM mapping
|
|
500
581
|
|
|
501
582
|
Each TS wrapper class maps to one WASM module and specific exported functions.
|
|
502
|
-
Tier 2 composition classes
|
|
503
|
-
TypeScript, they call Tier 1 classes rather than WASM functions directly.
|
|
583
|
+
Tier 2 composition classes are pure TypeScript; they call Tier 1 classes rather than WASM functions directly.
|
|
504
584
|
|
|
505
585
|
**serpent/index.ts → asm/serpent/ (Tier 1: direct WASM callers)**
|
|
506
586
|
|
|
507
587
|
| TS Class | WASM functions called |
|
|
508
588
|
|----------|---------------------|
|
|
509
589
|
| `Serpent` | `loadKey`, `encryptBlock`, `decryptBlock`, `wipeBuffers` + buffer getters |
|
|
510
|
-
| `SerpentCtr` | `loadKey`, `resetCounter`, `setCounter`, `encryptChunk`, `
|
|
511
|
-
| `SerpentCbc` | `loadKey`, `cbcEncryptChunk`, `cbcDecryptChunk`, `wipeBuffers` + buffer getters |
|
|
590
|
+
| `SerpentCtr` | `loadKey`, `resetCounter`, `setCounter`, `encryptChunk`, `encryptChunk_simd`, `wipeBuffers` + buffer getters |
|
|
591
|
+
| `SerpentCbc` | `loadKey`, `cbcEncryptChunk`, `cbcDecryptChunk`, `cbcDecryptChunk_simd`, `wipeBuffers` + buffer getters |
|
|
512
592
|
|
|
513
|
-
**
|
|
514
|
-
|
|
515
|
-
| TS Class | Composes |
|
|
516
|
-
|----------|---------|
|
|
517
|
-
| `SerpentSeal` | `SerpentCbc` + `HMAC_SHA256` |
|
|
518
|
-
| `SerpentStream` | `SerpentCtr` + `HMAC_SHA256` + `HKDF_SHA256` |
|
|
519
|
-
| `SerpentStreamPool` | `SerpentStream` (via worker) |
|
|
520
|
-
| `SerpentStreamSealer` | `SerpentCbc` + `HMAC_SHA256` + `HKDF_SHA256` |
|
|
521
|
-
| `SerpentStreamOpener` | `SerpentCbc` + `HMAC_SHA256` + `HKDF_SHA256` |
|
|
522
|
-
|
|
523
|
-
**chacha20/index.ts → asm/chacha20/**
|
|
593
|
+
**chacha20/index.ts → asm/chacha20/ (Tier 1: direct WASM callers)**
|
|
524
594
|
|
|
525
595
|
| TS Class | WASM functions called |
|
|
526
596
|
|----------|---------------------|
|
|
527
|
-
| `ChaCha20` | `chachaLoadKey`, `chachaSetCounter`, `
|
|
597
|
+
| `ChaCha20` | `chachaLoadKey`, `chachaSetCounter`, `chachaEncryptChunk`, `chachaEncryptChunk_simd`, `wipeBuffers` + buffer getters |
|
|
528
598
|
| `Poly1305` | `polyInit`, `polyUpdate`, `polyFinal`, `wipeBuffers` + buffer getters |
|
|
529
|
-
| `ChaCha20Poly1305` | `chachaLoadKey`, `
|
|
530
|
-
| `XChaCha20Poly1305` | All of `ChaCha20Poly1305` + `hchacha20` + xchacha buffer getters |
|
|
599
|
+
| `ChaCha20Poly1305` | `chachaLoadKey`, `chachaSetCounter`, `chachaGenPolyKey`, `chachaEncryptChunk`, `polyInit`, `polyUpdate`, `polyFinal`, `wipeBuffers` + buffer getters (via `ops.ts`) |
|
|
600
|
+
| `XChaCha20Poly1305` | All of `ChaCha20Poly1305` + `hchacha20` + xchacha buffer getters (via `ops.ts`) |
|
|
531
601
|
|
|
532
|
-
**sha2/index.ts → asm/sha2
|
|
602
|
+
**sha2/index.ts → asm/sha2/ (Tier 1: direct WASM callers)**
|
|
533
603
|
|
|
534
604
|
| TS Class | WASM functions called |
|
|
535
605
|
|----------|---------------------|
|
|
@@ -539,10 +609,8 @@ TypeScript, they call Tier 1 classes rather than WASM functions directly.
|
|
|
539
609
|
| `HMAC_SHA256` | `hmac256Init`, `hmac256Update`, `hmac256Final`, `sha256Init`, `sha256Update`, `sha256Final`, `wipeBuffers` + buffer getters |
|
|
540
610
|
| `HMAC_SHA512` | `hmac512Init`, `hmac512Update`, `hmac512Final`, `sha512Init`, `sha512Update`, `sha512Final`, `wipeBuffers` + buffer getters |
|
|
541
611
|
| `HMAC_SHA384` | `hmac384Init`, `hmac384Update`, `hmac384Final`, `sha384Init`, `sha512Update`, `sha384Final`, `wipeBuffers` + buffer getters |
|
|
542
|
-
| `HKDF_SHA256` | Pure TS composition over `HMAC_SHA256` (extract + expand per RFC 5869) |
|
|
543
|
-
| `HKDF_SHA512` | Pure TS composition over `HMAC_SHA512` (extract + expand per RFC 5869) |
|
|
544
612
|
|
|
545
|
-
**sha3/index.ts → asm/sha3
|
|
613
|
+
**sha3/index.ts → asm/sha3/ (Tier 1: direct WASM callers)**
|
|
546
614
|
|
|
547
615
|
| TS Class | WASM functions called |
|
|
548
616
|
|----------|---------------------|
|
|
@@ -553,77 +621,117 @@ TypeScript, they call Tier 1 classes rather than WASM functions directly.
|
|
|
553
621
|
| `SHAKE128` | `shake128Init`, `keccakAbsorb`, `shakePad`, `shakeSqueezeBlock`, `wipeBuffers` + buffer getters |
|
|
554
622
|
| `SHAKE256` | `shake256Init`, `keccakAbsorb`, `shakePad`, `shakeSqueezeBlock`, `wipeBuffers` + buffer getters |
|
|
555
623
|
|
|
624
|
+
**kyber/index.ts + kyber/kem.ts + kyber/indcpa.ts → asm/kyber/ (Tier 1)**
|
|
625
|
+
|
|
626
|
+
| TS Class | WASM functions called |
|
|
627
|
+
|----------|---------------------|
|
|
628
|
+
| `MlKem512`, `MlKem768`, `MlKem1024` | `polyvec_ntt`, `polyvec_invntt`, `polyvec_basemul_acc_montgomery`, `polyvec_add`, `polyvec_reduce`, `polyvec_tobytes`, `polyvec_frombytes`, `polyvec_compress`, `polyvec_decompress`, `poly_ntt`, `poly_invntt`, `poly_tomont`, `poly_add`, `poly_sub`, `poly_reduce`, `poly_basemul_montgomery`, `poly_frommsg`, `poly_tomsg`, `poly_compress`, `poly_decompress`, `poly_getnoise`, `rej_uniform`, `ct_verify`, `ct_cmov`, `wipeBuffers` + buffer getters |
|
|
629
|
+
|
|
630
|
+
All MlKem classes also call sha3 WASM via `indcpa.ts`: `sha3_256Init`, `sha3_512Init`, `shake128Init`, `shake256Init`, `keccakAbsorb`, `sha3_256Final`, `sha3_512Final`, `shakeFinal`, `shakePad`, `shakeSqueezeBlock`.
|
|
631
|
+
|
|
632
|
+
**Tier 2: pure TS composition**
|
|
633
|
+
|
|
634
|
+
| TS Class / Object | Composes |
|
|
635
|
+
|--------------------|----------|
|
|
636
|
+
| `SerpentCipher` | `SerpentCbc` + `HMAC_SHA256` + `HKDF_SHA256` |
|
|
637
|
+
| `XChaCha20Cipher` | `ChaCha20Poly1305` (via `ops.ts`) + `HKDF_SHA256` |
|
|
638
|
+
| `Seal` | `SealStream` + `OpenStream` (degenerate single-chunk case) |
|
|
639
|
+
| `SealStream` | `CipherSuite` (generic — caller provides cipher) |
|
|
640
|
+
| `OpenStream` | `CipherSuite` (generic — caller provides cipher) |
|
|
641
|
+
| `SealStreamPool` | `CipherSuite` + `compileWasm()` + Web Workers |
|
|
642
|
+
| `HKDF_SHA256` | `HMAC_SHA256` (extract + expand per RFC 5869) |
|
|
643
|
+
| `HKDF_SHA512` | `HMAC_SHA512` (extract + expand per RFC 5869) |
|
|
644
|
+
| `Fortuna` | `Serpent` + `SHA256` |
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
556
648
|
### Cross-module dependencies
|
|
557
649
|
|
|
558
650
|
| Relationship | Notes |
|
|
559
651
|
|-------------|-------|
|
|
560
|
-
| `
|
|
561
|
-
| `
|
|
562
|
-
| `
|
|
563
|
-
| `
|
|
652
|
+
| `SerpentCipher` → `serpent` + `sha2` | Tier 2 composition: Serpent-CBC + HMAC-SHA256 + HKDF-SHA256. |
|
|
653
|
+
| `XChaCha20Cipher` → `chacha20` + `sha2` | HKDF-SHA256 for key derivation + HChaCha20 + ChaCha20-Poly1305 for per-chunk AEAD. |
|
|
654
|
+
| `KyberSuite` → `kyber` + `sha3` + inner cipher | KEM encaps/decaps + HKDF with kemCt binding + inner CipherSuite. |
|
|
655
|
+
| `SealStream`, `OpenStream` → depends on cipher | Cipher-agnostic. Module requirements are determined by the `CipherSuite` passed at construction. |
|
|
656
|
+
| `SealStreamPool` → depends on cipher | Same module requirements as the cipher, plus `WasmSource` in pool opts for worker compilation. |
|
|
657
|
+
| `Fortuna` → `serpent` + `sha2` | Uses `Fortuna.create()` static factory instead of `new`. |
|
|
658
|
+
| `MlKem512`, `MlKem768`, `MlKem1024` → `kyber` + `sha3` | Kyber module handles polynomial arithmetic; sha3 provides SHAKE128/256, SHA3-256/512 for G/H/J/matrix gen. |
|
|
659
|
+
| `HKDF_SHA256`, `HKDF_SHA512` → `sha2` | Pure TS composition — extract and expand steps per RFC 5869. |
|
|
564
660
|
| All other classes | Each depends on exactly **one** WASM module. |
|
|
565
661
|
|
|
662
|
+
---
|
|
663
|
+
|
|
566
664
|
### Public API barrel (`src/ts/index.ts`)
|
|
567
665
|
|
|
568
666
|
The root barrel defines and exports the dispatching `init()` function.
|
|
569
667
|
It is the only file that imports all four module-scoped init functions.
|
|
570
668
|
|
|
571
669
|
| Source | Exports |
|
|
572
|
-
|
|
670
|
+
|--------|------------|
|
|
573
671
|
| *(barrel itself)* | `init` (dispatching function — calls per-module init functions via `Promise.all`) |
|
|
574
|
-
| `init.ts` | `Module`, `
|
|
575
|
-
| `
|
|
576
|
-
| `
|
|
577
|
-
| `chacha20/
|
|
672
|
+
| `init.ts` | `Module`, `WasmSource`, `isInitialized`, `_resetForTesting` |
|
|
673
|
+
| `errors.ts` | `AuthenticationError` |
|
|
674
|
+
| `serpent/index.ts` | `Serpent`, `SerpentCtr`, `SerpentCbc`, `SerpentCipher`, `_serpentReady` |
|
|
675
|
+
| `chacha20/index.ts` | `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, `XChaCha20Cipher`, `_chachaReady` |
|
|
578
676
|
| `sha2/index.ts` | `SHA256`, `SHA512`, `SHA384`, `HMAC_SHA256`, `HMAC_SHA512`, `HMAC_SHA384`, `HKDF_SHA256`, `HKDF_SHA512`, `_sha2Ready` |
|
|
579
677
|
| `sha3/index.ts` | `SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512`, `SHAKE128`, `SHAKE256`, `_sha3Ready` |
|
|
678
|
+
| `keccak/index.ts` | `keccakInit` + re-exports all sha3 classes (alias subpath) |
|
|
679
|
+
| `kyber/index.ts` | `kyberInit`, `KyberSuite`, `MlKem512`, `MlKem768`, `MlKem1024`, `KyberKeyPair`, `KyberEncapsulation`, `KyberParams`, `MLKEM512`, `MLKEM768`, `MLKEM1024` |
|
|
680
|
+
| `stream/index.ts` | `Seal`, `SealStream`, `OpenStream`, `SealStreamPool`, `CipherSuite`, `DerivedKeys`, `SealStreamOpts`, `PoolOpts`, `FLAG_FRAMED`, `TAG_DATA`, `TAG_FINAL`, `HEADER_SIZE`, `CHUNK_MIN`, `CHUNK_MAX` |
|
|
580
681
|
| `fortuna.ts` | `Fortuna` |
|
|
581
682
|
| `types.ts` | `Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD` |
|
|
582
683
|
| `utils.ts` | `hexToBytes`, `bytesToHex`, `utf8ToBytes`, `bytesToUtf8`, `base64ToBytes`, `bytesToBase64`, `constantTimeEqual`, `wipe`, `xor`, `concat`, `randomBytes` |
|
|
583
684
|
|
|
584
685
|
Each subpath export also exports its own module-specific init function for
|
|
585
|
-
tree-shakeable loading: `serpentInit(
|
|
586
|
-
`sha2Init(
|
|
686
|
+
tree-shakeable loading: `serpentInit(source)`, `chacha20Init(source)`,
|
|
687
|
+
`sha2Init(source)`, `sha3Init(source)`, `keccakInit(source)`.
|
|
587
688
|
|
|
588
689
|
---
|
|
589
690
|
|
|
590
691
|
## npm Package
|
|
591
692
|
|
|
592
693
|
**Subpath exports:**
|
|
593
|
-
|
|
594
694
|
```json
|
|
595
695
|
{
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
696
|
+
"exports": {
|
|
697
|
+
".": "./dist/index.js",
|
|
698
|
+
"./stream": "./dist/stream/index.js",
|
|
699
|
+
"./serpent": "./dist/serpent/index.js",
|
|
700
|
+
"./serpent/embedded": "./dist/serpent/embedded.js",
|
|
701
|
+
"./chacha20": "./dist/chacha20/index.js",
|
|
702
|
+
"./chacha20/embedded": "./dist/chacha20/embedded.js",
|
|
703
|
+
"./sha2": "./dist/sha2/index.js",
|
|
704
|
+
"./sha2/embedded": "./dist/sha2/embedded.js",
|
|
705
|
+
"./sha3": "./dist/sha3/index.js",
|
|
706
|
+
"./sha3/embedded": "./dist/sha3/embedded.js",
|
|
707
|
+
"./keccak": "./dist/keccak/index.js",
|
|
708
|
+
"./keccak/embedded": "./dist/keccak/embedded.js",
|
|
709
|
+
"./kyber": "./dist/kyber/index.js",
|
|
710
|
+
"./kyber/embedded": "./dist/kyber/embedded.js"
|
|
711
|
+
}
|
|
604
712
|
}
|
|
605
713
|
```
|
|
606
714
|
|
|
607
715
|
> [!NOTE]
|
|
608
|
-
> `dist/chacha20/pool
|
|
609
|
-
> `exports` map.
|
|
610
|
-
>
|
|
716
|
+
> Pool worker files (`dist/serpent/pool-worker.js`, `dist/chacha20/pool-worker.js`)
|
|
717
|
+
> ship in the package but are not in the `exports` map. They are internal Web
|
|
718
|
+
> Worker entry points loaded by `SealStreamPool` at runtime via
|
|
719
|
+
> `new URL('./pool-worker.js', import.meta.url)`. Do not import them as named
|
|
720
|
+
> subpaths.
|
|
721
|
+
|
|
722
|
+
The root `.` export re-exports everything. Subpath exports allow bundlers to tree-shake at the module level; a consumer importing only `./sha3` does not include the Serpent wrapper classes or their embedded WASM binaries in their bundle.
|
|
611
723
|
|
|
612
|
-
The
|
|
613
|
-
tree-shake at the module level, a consumer importing only `./sha3` does not
|
|
614
|
-
include the Serpent wrapper classes or their embedded WASM binaries in their
|
|
615
|
-
bundle.
|
|
724
|
+
The `/embedded` subpaths provide gzip+base64 WASM blobs for zero-config usage. Consumers using URL-based or pre-compiled loading can skip the `/embedded` imports entirely, keeping them out of the bundle.
|
|
616
725
|
|
|
617
|
-
**Tree-shaking:** `"sideEffects": false` is set in `package.json`.
|
|
618
|
-
module's `index.ts` owns its own embedded import thunk. Bundlers that support
|
|
619
|
-
tree-shaking (webpack, Rollup, esbuild) can eliminate unused modules and
|
|
620
|
-
their embedded WASM binaries from the final bundle.
|
|
726
|
+
**Tree-shaking:** `"sideEffects": false` is set in `package.json`. Bundlers that support tree-shaking (webpack, Rollup, esbuild) can eliminate unused modules and their embedded WASM binaries from the final bundle.
|
|
621
727
|
|
|
622
|
-
**Published
|
|
623
|
-
and WASM binaries as assets for streaming mode. The embedded base64 is compiled
|
|
624
|
-
into the JS, not a separate file.
|
|
728
|
+
**Published.** The npm package includes:
|
|
625
729
|
|
|
626
|
-
|
|
730
|
+
- `dist/`: compiled JS, TypeScript declarations, WASM binaries, pool worker scripts, and a subset of consumer-facing API docs for offline use.
|
|
731
|
+
- `CLAUDE.md`: agent-facing project context.
|
|
732
|
+
- `SECURITY.md`: vulnerability disclosure policy.
|
|
733
|
+
|
|
734
|
+
**Not published.** `src/`, `test/`, `build/`, `scripts/`, `docs/`, `.github/`, editor configs.
|
|
627
735
|
|
|
628
736
|
---
|
|
629
737
|
|
|
@@ -632,7 +740,7 @@ into the JS, not a separate file.
|
|
|
632
740
|
All offsets start at 0 per module. Independent linear memory. No offsets are
|
|
633
741
|
shared or coordinated across modules.
|
|
634
742
|
|
|
635
|
-
### Serpent module
|
|
743
|
+
### Serpent module (3 pages, 192 KB)
|
|
636
744
|
|
|
637
745
|
Source: `src/asm/serpent/buffers.ts`
|
|
638
746
|
|
|
@@ -652,7 +760,7 @@ Source: `src/asm/serpent/buffers.ts`
|
|
|
652
760
|
|
|
653
761
|
`wipeBuffers()` zeroes all 10 buffers (key, block pt/ct, nonce, counter, subkeys, work, chunk pt/ct, CBC IV).
|
|
654
762
|
|
|
655
|
-
### ChaCha20 module
|
|
763
|
+
### ChaCha20 module (3 pages, 192 KB)
|
|
656
764
|
|
|
657
765
|
Source: `src/asm/chacha20/buffers.ts`
|
|
658
766
|
|
|
@@ -682,7 +790,7 @@ Source: `src/asm/chacha20/buffers.ts`
|
|
|
682
790
|
|
|
683
791
|
`wipeBuffers()` zeroes all 15 buffer regions (key, chacha nonce/ctr/block/state, chunk pt/ct, poly key/msg/buf/tag/h/r/rs/s, xchacha nonce/subkey, SIMD work).
|
|
684
792
|
|
|
685
|
-
### SHA-2 module
|
|
793
|
+
### SHA-2 module (3 pages, 192 KB)
|
|
686
794
|
|
|
687
795
|
Source: `src/asm/sha2/buffers.ts`
|
|
688
796
|
|
|
@@ -712,7 +820,7 @@ Source: `src/asm/sha2/buffers.ts`
|
|
|
712
820
|
|
|
713
821
|
`wipeBuffers()` zeroes all 20 buffer regions (SHA-256 state/block/W/out/input/partial/total, HMAC-256 ipad/opad/inner, SHA-512 state/block/W/out/input/partial/total, HMAC-512 ipad/opad/inner).
|
|
714
822
|
|
|
715
|
-
### SHA-3 module
|
|
823
|
+
### SHA-3 module (3 pages, 192 KB)
|
|
716
824
|
|
|
717
825
|
Source: `src/asm/sha3/buffers.ts`
|
|
718
826
|
|
|
@@ -728,6 +836,28 @@ Source: `src/asm/sha3/buffers.ts`
|
|
|
728
836
|
|
|
729
837
|
`wipeBuffers()` zeroes all 6 buffer regions (state, rate, absorbed, dsbyte, input, output).
|
|
730
838
|
|
|
839
|
+
### Kyber module (3 pages, 192 KB)
|
|
840
|
+
|
|
841
|
+
Source: `src/asm/kyber/`
|
|
842
|
+
|
|
843
|
+
| Region | Offset | Size | Purpose |
|
|
844
|
+
|--------|--------|------|---------|
|
|
845
|
+
| AS data segment | 0 | 4096 | Zetas table (128 × i16, bit-reversed Montgomery domain) |
|
|
846
|
+
| Poly slots | 4096 | 5120 | 10 × 512B scratch polynomials (256 × i16 each) |
|
|
847
|
+
| Polyvec slots | 9216 | 16384 | 8 × 2048B scratch polyvecs (k=4 max: 4 × 512B) |
|
|
848
|
+
| SEED buffer | 25600 | 32 | Seed ρ/σ |
|
|
849
|
+
| MSG buffer | 25632 | 32 | Message / shared secret |
|
|
850
|
+
| PK buffer | 25664 | 1568 | Encapsulation key (max k=4) |
|
|
851
|
+
| SK buffer | 27232 | 1536 | IND-CPA secret key (max k=4) |
|
|
852
|
+
| CT buffer | 28768 | 1568 | Ciphertext (max k=4) |
|
|
853
|
+
| CT_PRIME buffer | 30336 | 1568 | Decaps re-encrypt comparison (max k=4) |
|
|
854
|
+
| XOF/PRF buffer | 31904 | 1024 | SHAKE squeeze output for rej_uniform / CBD |
|
|
855
|
+
| Poly accumulator | 32928 | 512 | Internal scratch for polyvec_basemul_acc |
|
|
856
|
+
|
|
857
|
+
Total mutable: 29344 bytes (4096–33440). End = 33440 < 192 KB.
|
|
858
|
+
|
|
859
|
+
`wipeBuffers()` zeroes all mutable regions (poly slots, polyvec slots, SEED, MSG, PK, SK, CT, CT_PRIME, XOF/PRF, accumulator). The zetas data segment is read-only and is not wiped.
|
|
860
|
+
|
|
731
861
|
---
|
|
732
862
|
|
|
733
863
|
## Test Suite
|
|
@@ -739,16 +869,14 @@ For the full testing methodology and vector corpus, see: [test-suite.md](./test-
|
|
|
739
869
|
|
|
740
870
|
### Gate discipline
|
|
741
871
|
|
|
742
|
-
Each primitive family has a gate test
|
|
743
|
-
that primitive. The gate must pass before any other tests in that family are
|
|
744
|
-
written or run. Gate tests are annotated with a `// GATE` comment.
|
|
872
|
+
Each primitive family has a gate test: the simplest authoritative vector for that primitive. The gate must pass before any other tests in that family are written or run. Gate tests are annotated with a `// GATE` comment.
|
|
745
873
|
|
|
746
874
|
### `init.test.ts` contracts
|
|
747
875
|
|
|
748
|
-
- `init()` with each
|
|
876
|
+
- `init()` with each `WasmSource` type loads and caches the module correctly
|
|
749
877
|
- Idempotency: second `init()` call for same module is a no-op
|
|
750
878
|
- Error before init: clear error thrown for each class before its module is loaded
|
|
751
|
-
- Partial init: loading `
|
|
879
|
+
- Partial init: loading `{ serpent: ... }` does not make `sha3` classes available
|
|
752
880
|
|
|
753
881
|
---
|
|
754
882
|
|
|
@@ -765,32 +893,38 @@ They are the immutable truth, and must never be modified to make tests pass.
|
|
|
765
893
|
|
|
766
894
|
---
|
|
767
895
|
|
|
768
|
-
## Known Limitations
|
|
896
|
+
## Known Limitations
|
|
769
897
|
|
|
770
|
-
- **`SerpentCbc` is unauthenticated**: use `
|
|
771
|
-
Serpent encryption, or pair `SerpentCbc` with `HMAC_SHA256`
|
|
772
|
-
if direct CBC access is required.
|
|
898
|
+
- **`SerpentCbc` is unauthenticated**: use `Seal` with `SerpentCipher` for
|
|
899
|
+
authenticated Serpent encryption, or pair `SerpentCbc` with `HMAC_SHA256`
|
|
900
|
+
(Encrypt-then-MAC) if direct CBC access is required.
|
|
773
901
|
- **Single-threaded WASM per instance**: one WASM instance per binary per thread.
|
|
774
|
-
`
|
|
775
|
-
|
|
902
|
+
`SealStreamPool` provides Worker-based parallelism for both cipher families;
|
|
903
|
+
other primitives remain single-threaded.
|
|
776
904
|
- **Max input per WASM call**: chunk-based APIs (CTR, CBC) accept at most 64KB
|
|
777
905
|
per call. Wrappers handle splitting automatically for larger inputs.
|
|
778
|
-
- **
|
|
779
|
-
|
|
906
|
+
- **WASM side-channel posture**: WebAssembly implementations offer the best
|
|
907
|
+
available side-channel resistance (branchless, table-free), but lack
|
|
908
|
+
hardware-level constant-time guarantees. For applications where timing
|
|
909
|
+
side channels are a primary threat, a native cryptographic library with
|
|
910
|
+
verified constant-time guarantees will be more appropriate than any
|
|
911
|
+
WASM-based implementation.
|
|
780
912
|
|
|
781
913
|
---
|
|
782
914
|
|
|
783
915
|
> ## Cross-References
|
|
784
916
|
>
|
|
785
917
|
> - [index](./README.md) — Project Documentation index
|
|
918
|
+
> - [lexicon](./lexicon.md) — Glossary of cryptographic terms
|
|
786
919
|
> - [test-suite](./test-suite.md) — testing methodology, vector corpus, and gate discipline
|
|
787
|
-
> - [init](./init.md) — `init()` API,
|
|
788
|
-
> - [loader](./loader.md) — internal WASM binary loading strategies
|
|
920
|
+
> - [init](./init.md) — `init()` API, `WasmSource`, and idempotent behavior
|
|
921
|
+
> - [loader](./loader.md) — internal WASM binary loading strategies
|
|
789
922
|
> - [wasm](./wasm.md) — WebAssembly primer: modules, instances, memory, and the init gate
|
|
790
|
-
> - [types](./types.md) — public TypeScript interfaces
|
|
923
|
+
> - [types](./types.md) — public TypeScript interfaces and `CipherSuite`
|
|
791
924
|
> - [utils](./utils.md) — encoding helpers, `constantTimeEqual`, `wipe`, `randomBytes`
|
|
792
|
-
> - [
|
|
793
|
-
> - [
|
|
925
|
+
> - [authenticated encryption](./aead.md) — SealStream, OpenStream, SealStreamPool, wire format
|
|
926
|
+
> - [serpent](./serpent.md) — Serpent-256 TypeScript API, SerpentCipher
|
|
927
|
+
> - [chacha20](./chacha20.md) — ChaCha20/Poly1305 TypeScript API, XChaCha20Cipher
|
|
794
928
|
> - [sha2](./sha2.md) — SHA-2 hashes, HMAC, and HKDF TypeScript API
|
|
795
929
|
> - [sha3](./sha3.md) — SHA-3 hashes and SHAKE XOFs TypeScript API
|
|
796
930
|
> - [fortuna](./fortuna.md) — Fortuna CSPRNG with forward secrecy and entropy pooling
|