leviathan-crypto 2.0.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) hide show
  1. package/CLAUDE.md +88 -281
  2. package/LICENSE +4 -0
  3. package/README.md +275 -87
  4. package/dist/aes/aes-cbc.d.ts +40 -0
  5. package/dist/aes/aes-cbc.js +158 -0
  6. package/dist/aes/aes-ctr.d.ts +50 -0
  7. package/dist/aes/aes-ctr.js +141 -0
  8. package/dist/aes/aes-gcm-siv.d.ts +67 -0
  9. package/dist/aes/aes-gcm-siv.js +217 -0
  10. package/dist/aes/aes-gcm.d.ts +61 -0
  11. package/dist/aes/aes-gcm.js +226 -0
  12. package/dist/aes/cipher-suite.d.ts +21 -0
  13. package/dist/aes/cipher-suite.js +179 -0
  14. package/dist/aes/embedded.d.ts +1 -0
  15. package/dist/aes/embedded.js +26 -0
  16. package/dist/aes/generator.d.ts +14 -0
  17. package/dist/aes/generator.js +103 -0
  18. package/dist/aes/index.d.ts +58 -0
  19. package/dist/aes/index.js +125 -0
  20. package/dist/aes/ops.d.ts +60 -0
  21. package/dist/aes/ops.js +164 -0
  22. package/dist/aes/pool-worker.d.ts +1 -0
  23. package/dist/aes/pool-worker.js +92 -0
  24. package/dist/aes/types.d.ts +1 -0
  25. package/dist/aes/types.js +23 -0
  26. package/dist/aes.wasm +0 -0
  27. package/dist/blake3/embedded.d.ts +1 -0
  28. package/dist/blake3/embedded.js +26 -0
  29. package/dist/blake3/index.d.ts +143 -0
  30. package/dist/blake3/index.js +620 -0
  31. package/dist/blake3/types.d.ts +102 -0
  32. package/dist/blake3/types.js +31 -0
  33. package/dist/blake3/validate.d.ts +29 -0
  34. package/dist/blake3/validate.js +80 -0
  35. package/dist/blake3.wasm +0 -0
  36. package/dist/chacha20/cipher-suite.d.ts +10 -0
  37. package/dist/chacha20/cipher-suite.js +98 -13
  38. package/dist/chacha20/generator.d.ts +12 -0
  39. package/dist/chacha20/generator.js +91 -0
  40. package/dist/chacha20/index.d.ts +100 -3
  41. package/dist/chacha20/index.js +169 -35
  42. package/dist/chacha20/ops.d.ts +57 -6
  43. package/dist/chacha20/ops.js +107 -27
  44. package/dist/chacha20/pool-worker.js +14 -0
  45. package/dist/chacha20/types.d.ts +1 -32
  46. package/dist/cte-wasm.d.ts +1 -0
  47. package/dist/cte-wasm.js +3 -0
  48. package/dist/cte.wasm +0 -0
  49. package/dist/curve25519.wasm +0 -0
  50. package/dist/ecdsa/der.d.ts +23 -0
  51. package/dist/ecdsa/der.js +192 -0
  52. package/dist/ecdsa/ecprivatekey-der.d.ts +32 -0
  53. package/dist/ecdsa/ecprivatekey-der.js +230 -0
  54. package/dist/ecdsa/embedded.d.ts +1 -0
  55. package/dist/ecdsa/embedded.js +25 -0
  56. package/dist/ecdsa/index.d.ts +124 -0
  57. package/dist/ecdsa/index.js +366 -0
  58. package/dist/ecdsa/types.d.ts +31 -0
  59. package/dist/ecdsa/types.js +28 -0
  60. package/dist/ecdsa/validate.d.ts +18 -0
  61. package/dist/ecdsa/validate.js +92 -0
  62. package/dist/ed25519/embedded.d.ts +1 -0
  63. package/dist/ed25519/embedded.js +31 -0
  64. package/dist/ed25519/index.d.ts +70 -0
  65. package/dist/ed25519/index.js +308 -0
  66. package/dist/ed25519/types.d.ts +27 -0
  67. package/dist/ed25519/types.js +27 -0
  68. package/dist/ed25519/validate.d.ts +7 -0
  69. package/dist/ed25519/validate.js +77 -0
  70. package/dist/embedded/aes-pool-worker.d.ts +1 -0
  71. package/dist/embedded/aes-pool-worker.js +5 -0
  72. package/dist/embedded/aes.d.ts +1 -0
  73. package/dist/embedded/aes.js +3 -0
  74. package/dist/embedded/blake3.d.ts +1 -0
  75. package/dist/embedded/blake3.js +3 -0
  76. package/dist/embedded/chacha20-pool-worker.d.ts +1 -0
  77. package/dist/embedded/chacha20-pool-worker.js +5 -0
  78. package/dist/embedded/chacha20.d.ts +1 -1
  79. package/dist/embedded/chacha20.js +2 -2
  80. package/dist/embedded/curve25519.d.ts +1 -0
  81. package/dist/embedded/curve25519.js +3 -0
  82. package/dist/embedded/mldsa.d.ts +1 -0
  83. package/dist/embedded/mldsa.js +3 -0
  84. package/dist/embedded/mlkem.d.ts +1 -0
  85. package/dist/embedded/mlkem.js +3 -0
  86. package/dist/embedded/p256.d.ts +1 -0
  87. package/dist/embedded/p256.js +3 -0
  88. package/dist/embedded/serpent-pool-worker.d.ts +1 -0
  89. package/dist/embedded/serpent-pool-worker.js +5 -0
  90. package/dist/embedded/serpent.d.ts +1 -1
  91. package/dist/embedded/serpent.js +2 -2
  92. package/dist/embedded/sha2.d.ts +1 -1
  93. package/dist/embedded/sha2.js +2 -2
  94. package/dist/embedded/sha3.d.ts +1 -1
  95. package/dist/embedded/sha3.js +2 -2
  96. package/dist/embedded/slhdsa.d.ts +1 -0
  97. package/dist/embedded/slhdsa.js +3 -0
  98. package/dist/errors.d.ts +92 -1
  99. package/dist/errors.js +111 -1
  100. package/dist/fortuna.d.ts +18 -12
  101. package/dist/fortuna.js +166 -99
  102. package/dist/index.d.ts +42 -11
  103. package/dist/index.js +65 -20
  104. package/dist/init.d.ts +1 -3
  105. package/dist/init.js +73 -7
  106. package/dist/keccak/embedded.js +1 -1
  107. package/dist/keccak/index.d.ts +2 -0
  108. package/dist/keccak/index.js +4 -2
  109. package/dist/loader.d.ts +1 -19
  110. package/dist/loader.js +26 -32
  111. package/dist/merkle/blake3-tree.d.ts +35 -0
  112. package/dist/merkle/blake3-tree.js +187 -0
  113. package/dist/merkle/checkpoint.d.ts +58 -0
  114. package/dist/merkle/checkpoint.js +217 -0
  115. package/dist/merkle/index.d.ts +19 -0
  116. package/dist/merkle/index.js +37 -0
  117. package/dist/merkle/merkle-log.d.ts +130 -0
  118. package/dist/merkle/merkle-log.js +207 -0
  119. package/dist/merkle/merkle-verifier.d.ts +126 -0
  120. package/dist/merkle/merkle-verifier.js +296 -0
  121. package/dist/merkle/proof.d.ts +70 -0
  122. package/dist/merkle/proof.js +300 -0
  123. package/dist/merkle/sha256-tree.d.ts +33 -0
  124. package/dist/merkle/sha256-tree.js +145 -0
  125. package/dist/merkle/signed-log.d.ts +156 -0
  126. package/dist/merkle/signed-log.js +356 -0
  127. package/dist/merkle/signed-note.d.ts +309 -0
  128. package/dist/merkle/signed-note.js +648 -0
  129. package/dist/merkle/sth.d.ts +31 -0
  130. package/dist/merkle/sth.js +31 -0
  131. package/dist/merkle/storage.d.ts +40 -0
  132. package/dist/merkle/storage.js +71 -0
  133. package/dist/merkle/tree.d.ts +68 -0
  134. package/dist/merkle/tree.js +94 -0
  135. package/dist/mldsa/embedded.d.ts +1 -0
  136. package/dist/{kyber → mldsa}/embedded.js +5 -5
  137. package/dist/mldsa/expand.d.ts +53 -0
  138. package/dist/mldsa/expand.js +188 -0
  139. package/dist/mldsa/format.d.ts +16 -0
  140. package/dist/mldsa/format.js +68 -0
  141. package/dist/mldsa/hashvariant.d.ts +32 -0
  142. package/dist/mldsa/hashvariant.js +248 -0
  143. package/dist/mldsa/index.d.ts +142 -0
  144. package/dist/mldsa/index.js +463 -0
  145. package/dist/mldsa/keygen.d.ts +16 -0
  146. package/dist/mldsa/keygen.js +232 -0
  147. package/dist/mldsa/params.d.ts +21 -0
  148. package/dist/mldsa/params.js +55 -0
  149. package/dist/mldsa/sha3-helpers.d.ts +30 -0
  150. package/dist/mldsa/sha3-helpers.js +124 -0
  151. package/dist/mldsa/sign.d.ts +36 -0
  152. package/dist/mldsa/sign.js +380 -0
  153. package/dist/mldsa/types.d.ts +91 -0
  154. package/dist/mldsa/types.js +25 -0
  155. package/dist/mldsa/validate.d.ts +55 -0
  156. package/dist/mldsa/validate.js +125 -0
  157. package/dist/mldsa/verify.d.ts +29 -0
  158. package/dist/mldsa/verify.js +269 -0
  159. package/dist/mldsa.wasm +0 -0
  160. package/dist/mlkem/embedded.d.ts +1 -0
  161. package/dist/mlkem/embedded.js +27 -0
  162. package/dist/mlkem/indcpa.d.ts +49 -0
  163. package/dist/{kyber → mlkem}/indcpa.js +48 -48
  164. package/dist/mlkem/index.d.ts +37 -0
  165. package/dist/{kyber → mlkem}/index.js +41 -31
  166. package/dist/mlkem/kem.d.ts +21 -0
  167. package/dist/{kyber → mlkem}/kem.js +48 -13
  168. package/dist/{kyber → mlkem}/params.d.ts +4 -4
  169. package/dist/{kyber → mlkem}/params.js +2 -2
  170. package/dist/mlkem/suite.d.ts +12 -0
  171. package/dist/{kyber → mlkem}/suite.js +17 -12
  172. package/dist/{kyber → mlkem}/types.d.ts +4 -3
  173. package/dist/{kyber → mlkem}/types.js +1 -1
  174. package/dist/mlkem/validate.d.ts +23 -0
  175. package/dist/{kyber → mlkem}/validate.js +24 -20
  176. package/dist/{kyber.wasm → mlkem.wasm} +0 -0
  177. package/dist/p256.wasm +0 -0
  178. package/dist/ratchet/index.d.ts +8 -0
  179. package/dist/ratchet/index.js +38 -0
  180. package/dist/ratchet/kdf-chain.d.ts +13 -0
  181. package/dist/ratchet/kdf-chain.js +85 -0
  182. package/dist/ratchet/ratchet-keypair.d.ts +9 -0
  183. package/dist/ratchet/ratchet-keypair.js +61 -0
  184. package/dist/ratchet/root-kdf.d.ts +4 -0
  185. package/dist/ratchet/root-kdf.js +124 -0
  186. package/dist/ratchet/skipped-key-store.d.ts +14 -0
  187. package/dist/ratchet/skipped-key-store.js +154 -0
  188. package/dist/ratchet/types.d.ts +36 -0
  189. package/dist/ratchet/types.js +26 -0
  190. package/dist/serpent/cipher-suite.d.ts +10 -0
  191. package/dist/serpent/cipher-suite.js +144 -56
  192. package/dist/serpent/generator.d.ts +12 -0
  193. package/dist/serpent/generator.js +97 -0
  194. package/dist/serpent/index.d.ts +62 -1
  195. package/dist/serpent/index.js +97 -21
  196. package/dist/serpent/pool-worker.js +28 -102
  197. package/dist/serpent/serpent-cbc.d.ts +16 -6
  198. package/dist/serpent/serpent-cbc.js +58 -37
  199. package/dist/serpent/shared-ops.d.ts +63 -0
  200. package/dist/serpent/shared-ops.js +178 -0
  201. package/dist/serpent/types.d.ts +1 -5
  202. package/dist/serpent.wasm +0 -0
  203. package/dist/sha2/hash.d.ts +2 -0
  204. package/dist/sha2/hash.js +53 -0
  205. package/dist/sha2/hkdf.js +5 -5
  206. package/dist/sha2/index.d.ts +22 -1
  207. package/dist/sha2/index.js +80 -11
  208. package/dist/sha2/types.d.ts +41 -2
  209. package/dist/sha2.wasm +0 -0
  210. package/dist/sha3/hash.d.ts +2 -0
  211. package/dist/sha3/hash.js +53 -0
  212. package/dist/sha3/index.d.ts +87 -3
  213. package/dist/sha3/index.js +317 -19
  214. package/dist/sha3/kmac.d.ts +121 -0
  215. package/dist/sha3/kmac.js +800 -0
  216. package/dist/sha3.wasm +0 -0
  217. package/dist/shared/pkcs7.d.ts +22 -0
  218. package/dist/shared/pkcs7.js +84 -0
  219. package/dist/sign/ctx.d.ts +41 -0
  220. package/dist/sign/ctx.js +102 -0
  221. package/dist/sign/envelope.d.ts +45 -0
  222. package/dist/sign/envelope.js +152 -0
  223. package/dist/sign/hasher.d.ts +9 -0
  224. package/dist/sign/hasher.js +132 -0
  225. package/dist/sign/index.d.ts +11 -0
  226. package/dist/sign/index.js +34 -0
  227. package/dist/sign/sign-stream.d.ts +25 -0
  228. package/dist/sign/sign-stream.js +112 -0
  229. package/dist/sign/suites/ecdsa-p256.d.ts +2 -0
  230. package/dist/sign/suites/ecdsa-p256.js +120 -0
  231. package/dist/sign/suites/ed25519.d.ts +3 -0
  232. package/dist/sign/suites/ed25519.js +165 -0
  233. package/dist/sign/suites/hybrid-classical.d.ts +23 -0
  234. package/dist/sign/suites/hybrid-classical.js +526 -0
  235. package/dist/sign/suites/hybrid-pq.d.ts +4 -0
  236. package/dist/sign/suites/hybrid-pq.js +234 -0
  237. package/dist/sign/suites/mldsa.d.ts +7 -0
  238. package/dist/sign/suites/mldsa.js +161 -0
  239. package/dist/sign/suites/slhdsa.d.ts +7 -0
  240. package/dist/sign/suites/slhdsa.js +176 -0
  241. package/dist/sign/types.d.ts +106 -0
  242. package/dist/sign/types.js +28 -0
  243. package/dist/sign/verify-stream.d.ts +30 -0
  244. package/dist/sign/verify-stream.js +227 -0
  245. package/dist/slhdsa/embedded.d.ts +1 -0
  246. package/dist/slhdsa/embedded.js +26 -0
  247. package/dist/slhdsa/index.d.ts +149 -0
  248. package/dist/slhdsa/index.js +493 -0
  249. package/dist/slhdsa/params.d.ts +26 -0
  250. package/dist/slhdsa/params.js +70 -0
  251. package/dist/slhdsa/prehash.d.ts +68 -0
  252. package/dist/slhdsa/prehash.js +307 -0
  253. package/dist/slhdsa/sign.d.ts +39 -0
  254. package/dist/slhdsa/sign.js +116 -0
  255. package/dist/slhdsa/types.d.ts +129 -0
  256. package/dist/slhdsa/types.js +27 -0
  257. package/dist/slhdsa/validate.d.ts +60 -0
  258. package/dist/slhdsa/validate.js +127 -0
  259. package/dist/slhdsa/verify.d.ts +32 -0
  260. package/dist/slhdsa/verify.js +107 -0
  261. package/dist/slhdsa.wasm +0 -0
  262. package/dist/stream/header.js +8 -8
  263. package/dist/stream/index.d.ts +1 -0
  264. package/dist/stream/index.js +1 -0
  265. package/dist/stream/open-stream.js +65 -22
  266. package/dist/stream/seal-stream-pool.d.ts +2 -0
  267. package/dist/stream/seal-stream-pool.js +100 -33
  268. package/dist/stream/seal-stream.d.ts +1 -1
  269. package/dist/stream/seal-stream.js +48 -19
  270. package/dist/stream/seal.js +6 -6
  271. package/dist/stream/types.d.ts +3 -1
  272. package/dist/stream/types.js +1 -1
  273. package/dist/types.d.ts +22 -1
  274. package/dist/types.js +1 -1
  275. package/dist/utils.d.ts +9 -10
  276. package/dist/utils.js +84 -59
  277. package/dist/wasm-source.d.ts +9 -8
  278. package/dist/wasm-source.js +1 -1
  279. package/dist/x25519/embedded.d.ts +1 -0
  280. package/dist/x25519/embedded.js +31 -0
  281. package/dist/x25519/index.d.ts +43 -0
  282. package/dist/x25519/index.js +159 -0
  283. package/dist/x25519/types.d.ts +25 -0
  284. package/dist/x25519/types.js +27 -0
  285. package/dist/x25519/validate.d.ts +2 -0
  286. package/dist/x25519/validate.js +39 -0
  287. package/package.json +123 -64
  288. package/SECURITY.md +0 -276
  289. package/dist/ct-wasm.d.ts +0 -1
  290. package/dist/ct-wasm.js +0 -3
  291. package/dist/ct.wasm +0 -0
  292. package/dist/docs/aead.md +0 -323
  293. package/dist/docs/architecture.md +0 -932
  294. package/dist/docs/argon2id.md +0 -302
  295. package/dist/docs/chacha20.md +0 -674
  296. package/dist/docs/exports.md +0 -241
  297. package/dist/docs/fortuna.md +0 -313
  298. package/dist/docs/init.md +0 -302
  299. package/dist/docs/loader.md +0 -161
  300. package/dist/docs/serpent.md +0 -519
  301. package/dist/docs/sha2.md +0 -613
  302. package/dist/docs/sha3.md +0 -546
  303. package/dist/docs/types.md +0 -276
  304. package/dist/docs/utils.md +0 -367
  305. package/dist/embedded/kyber.d.ts +0 -1
  306. package/dist/embedded/kyber.js +0 -3
  307. package/dist/kyber/embedded.d.ts +0 -1
  308. package/dist/kyber/indcpa.d.ts +0 -49
  309. package/dist/kyber/index.d.ts +0 -38
  310. package/dist/kyber/kem.d.ts +0 -21
  311. package/dist/kyber/suite.d.ts +0 -13
  312. package/dist/kyber/validate.d.ts +0 -19
@@ -1,932 +0,0 @@
1
- # Architecture
2
-
3
- > [!NOTE]
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
- ---
23
-
24
- ## Vision
25
-
26
- `leviathan-crypto` is a strictly-typed, audited WebAssembly cryptography library for
27
- the web. It combines two previously separate efforts:
28
-
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.
32
-
33
- The unified library exposes the TypeScript API from leviathan, backed by the WASM
34
- execution engine from leviathan-wasm. Developers get ergonomic, well-typed classes.
35
- The runtime gets deterministic cryptographic computation outside the JIT.
36
-
37
- **The fundamental insight:** JavaScript engines provide no formal constant-time
38
- guarantees for arbitrary code. WASM execution is deterministic and not subject to
39
- JIT speculation. For a cryptography library, this distinction matters. The TypeScript
40
- layer handles API ergonomics; the WASM layer handles all cryptographic computation.
41
-
42
- ---
43
-
44
- ## Scope
45
-
46
- ### In scope
47
-
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) |
57
-
58
- Pure TypeScript utilities (encoding helpers, random generation, format converters)
59
- ship alongside the WASM-backed primitives with no `init()` dependency.
60
-
61
- ### Auxiliary tier (not part of `Module` union)
62
-
63
- - **`Fortuna`:** CSPRNG requiring two core modules (`serpent` + `sha2`).
64
-
65
- ---
66
-
67
- ## Repository Structure
68
-
69
- ```text
70
- leviathan-crypto/
71
- ├── .github/
72
- │ └── workflows/ ← CI: build, test-suite, e2e, publish, release, wiki
73
- ├── src/
74
- │ ├── asm/ ← AssemblyScript (compiles to .wasm)
75
- │ │ ├── serpent/
76
- │ │ │ ├── index.ts ← asc entry point → serpent.wasm
77
- │ │ │ ├── serpent.ts ← block function + key schedule
78
- │ │ │ ├── serpent_unrolled.ts ← unrolled S-boxes and round functions
79
- │ │ │ ├── serpent_simd.ts ← SIMD bitsliced block operations
80
- │ │ │ ├── cbc.ts ← CBC mode
81
- │ │ │ ├── cbc_simd.ts ← SIMD CBC decrypt
82
- │ │ │ ├── ctr.ts ← CTR mode
83
- │ │ │ ├── ctr_simd.ts ← SIMD CTR 4-wide inter-block
84
- │ │ │ └── buffers.ts ← static buffer layout + offset getters
85
- │ │ ├── chacha20/
86
- │ │ │ ├── index.ts ← asc entry point → chacha20.wasm
87
- │ │ │ ├── chacha20.ts
88
- │ │ │ ├── chacha20_simd_4x.ts ← SIMD 4-wide inter-block ChaCha20
89
- │ │ │ ├── poly1305.ts
90
- │ │ │ ├── wipe.ts
91
- │ │ │ └── buffers.ts
92
- │ │ ├── sha2/
93
- │ │ │ ├── index.ts ← asc entry point → sha2.wasm
94
- │ │ │ ├── sha256.ts
95
- │ │ │ ├── sha512.ts
96
- │ │ │ ├── hmac.ts
97
- │ │ │ ├── hmac512.ts
98
- │ │ │ └── buffers.ts
99
- │ │ ├── sha3/
100
- │ │ ├── index.ts ← asc entry point → sha3.wasm
101
- │ │ ├── keccak.ts
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
118
- │ └── ts/ ← TypeScript (public API)
119
- │ ├── init.ts ← initModule() : WASM loading and module cache
120
- │ ├── loader.ts ← loadWasm() / compileWasm() : polymorphic WasmSource dispatch
121
- │ ├── wasm-source.ts ← WasmSource union type
122
- │ ├── errors.ts ← AuthenticationError
123
- │ ├── types.ts ← Hash, KeyedHash, Blockcipher, Streamcipher, AEAD
124
- │ ├── utils.ts ← encoding, wipe, xor, concat, randomBytes
125
- │ ├── fortuna.ts ← Fortuna CSPRNG (requires serpent + sha2)
126
- │ ├── embedded/ ← generated gzip+base64 blobs (build artifact, gitignored)
127
- │ │ ├── serpent.ts
128
- │ │ ├── chacha20.ts
129
- │ │ ├── sha2.ts
130
- │ │ └── sha3.ts
131
- │ ├── serpent/
132
- │ │ ├── index.ts ← serpentInit() + Serpent, SerpentCtr, SerpentCbc
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
136
- │ │ └── types.ts
137
- │ ├── chacha20/
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
143
- │ │ └── types.ts
144
- │ ├── sha2/
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
148
- │ │ └── types.ts
149
- │ ├── sha3/
150
- │ │ ├── index.ts ← sha3Init() + SHA3_224–512, SHAKE128, SHAKE256
151
- │ │ ├── embedded.ts ← re-exports gzip+base64 blob as named export
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
171
- │ └── index.ts ← root barrel : dispatching init() + re-exports everything
172
- ├── test/
173
- │ ├── unit/ ← Vitest (JS target, fast iteration)
174
- │ │ ├── serpent/
175
- │ │ ├── chacha20/
176
- │ │ ├── sha2/
177
- │ │ ├── sha3/
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
184
- │ ├── e2e/ ← Playwright (WASM target, cross-browser)
185
- │ └── vectors/ ← test vector files (read-only reference data)
186
- ├── scripts/
187
- │ ├── build-asm.js ← orchestrates AssemblyScript compilation
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
196
- ├── package.json
197
- ├── asconfig.json ← four AssemblyScript entry points
198
- ├── tsconfig.json
199
- ├── vitest.config.ts
200
- ├── playwright.config.ts
201
- ├── AGENTS.md ← ai agent contract
202
- └── SECURITY.md
203
- ```
204
-
205
- ---
206
-
207
- ## Architecture: TypeScript over WASM
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.
210
-
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.
212
-
213
- ---
214
-
215
- ## Five Independent WASM Modules
216
-
217
- Each primitive family compiles to its own `.wasm` binary. Modules are fully
218
- independent, separate linear memories, separate buffer layouts, no shared state.
219
-
220
- | Module | Binary | Primitives |
221
- |--------|--------|------------|
222
- | `serpent` | `serpent.wasm` | Serpent-256 block cipher: ECB, CTR mode, CBC mode |
223
- | `chacha20` | `chacha20.wasm` | ChaCha20, Poly1305, ChaCha20-Poly1305 AEAD, XChaCha20-Poly1305 AEAD |
224
- | `sha2` | `sha2.wasm` | SHA-256, SHA-384, SHA-512, HMAC-SHA256, HMAC-SHA384, HMAC-SHA512 |
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.
229
-
230
- **Isolation.** Key material in `serpent.wasm` memory cannot bleed into `sha3.wasm` memory even in theory.
231
-
232
- Each module's buffer layout starts at offset 0 and is defined in its own
233
- `buffers.ts`. Buffer layouts are fully independent across modules.
234
-
235
- ### Module contents
236
-
237
- **`serpent.wasm`**
238
- Serpent-256 block cipher. Key schedule, block encrypt, block decrypt. CTR mode
239
- chunked streaming encrypt/decrypt. CBC mode chunked encrypt/decrypt. SIMD
240
- variants for CTR 4-wide inter-block and CBC decrypt parallelism.
241
- Source: `src/asm/serpent/`
242
-
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.
246
-
247
- **`chacha20.wasm`**
248
- ChaCha20 stream cipher (RFC 8439). Poly1305 MAC (RFC 8439 §2.5). ChaCha20-Poly1305
249
- AEAD (RFC 8439 §2.8). XChaCha20-Poly1305 AEAD (draft-irtf-cfrg-xchacha).
250
- HChaCha20 subkey derivation. SIMD 4-wide inter-block parallelism.
251
- Source: `src/asm/chacha20/`
252
-
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.
256
-
257
- **`sha2.wasm`**
258
- SHA-256 and SHA-512 (FIPS 180-4). SHA-384 (SHA-512 with different IVs, truncated
259
- output, shares all SHA-512 buffers and compress function). HMAC-SHA256,
260
- HMAC-SHA512, HMAC-SHA384 (RFC 2104). HKDF-SHA256 and HKDF-SHA512 (RFC 5869)
261
- are pure TypeScript compositions over HMAC, with no new WASM logic.
262
- Source: `src/asm/sha2/`
263
-
264
- **`sha3.wasm`**
265
- Keccak-f[1600] permutation (FIPS 202). SHA3-224, SHA3-256, SHA3-384, SHA3-512.
266
- SHAKE128, SHAKE256 (XOFs, multi-squeeze capable, unbounded output length).
267
- All six variants share one permutation, differing only in rate, domain
268
- separation byte, and output length.
269
- Source: `src/asm/sha3/`
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
-
286
- ---
287
-
288
- ## `init()` API
289
-
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.
291
-
292
- ### Signature
293
-
294
- ```typescript
295
- type Module = 'serpent' | 'chacha20' | 'sha2' | 'sha3' | 'keccak' | 'kyber'
296
-
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
305
-
306
- async function init(
307
- sources: Partial<Record<Module, WasmSource>>,
308
- ): Promise<void>
309
- ```
310
-
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.
316
-
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.
319
-
320
- ### Embedded subpath exports
321
-
322
- Each module provides a `/embedded` subpath that exports the gzip+base64
323
- blob as a ready-to-use `WasmSource`:
324
- ```typescript
325
- import { init } from 'leviathan-crypto'
326
- import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
327
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
328
-
329
- await init({ serpent: serpentWasm, sha2: sha2Wasm })
330
- ```
331
-
332
- ### Behavioral contracts
333
-
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.
337
-
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.
341
-
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.
345
-
346
- **No implicit initialization.** Classes never call `init()` automatically
347
- on first use. Explicit initialization is preferable to hidden costs.
348
-
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
353
- Workers are used.
354
-
355
- ---
356
-
357
- ## Public API Classes
358
-
359
- Names match conventional cryptographic notation.
360
-
361
- | Module | Classes |
362
- |--------|---------|
363
- | `serpent` + `sha2` | `SerpentCipher` |
364
- | `serpent` | `Serpent`, `SerpentCtr`, `SerpentCbc` |
365
- | `chacha20` | `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, `XChaCha20Cipher` |
366
- | `sha2` | `SHA256`, `SHA384`, `SHA512`, `HMAC_SHA256`, `HMAC_SHA384`, `HMAC_SHA512`, `HKDF_SHA256`, `HKDF_SHA512` |
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` |
371
- | `serpent` + `sha2` | `Fortuna` |
372
-
373
- HMAC names use underscore separator (`HMAC_SHA256`) matching RFC convention.
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.
376
-
377
- **`Fortuna`** requires `await Fortuna.create()` rather than `new Fortuna()` due
378
- to the async `init()` dependency on two modules.
379
-
380
- ### Usage pattern
381
-
382
- All WASM-backed classes follow the same pattern:
383
- ```typescript
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'
388
-
389
- await init({ serpent: serpentWasm, sha2: sha2Wasm, sha3: sha3Wasm })
390
-
391
- const key = SerpentCipher.keygen()
392
- const blob = Seal.encrypt(SerpentCipher, key, plaintext)
393
-
394
- const hasher = new SHA3_256()
395
- const digest = hasher.hash(message)
396
- ```
397
-
398
- ### Utility exports (no `init()` required)
399
-
400
- Pure TypeScript utilities ship alongside the WASM-backed primitives:
401
-
402
- | Category | Exports |
403
- |----------|---------|
404
- | Encoding | `hexToBytes`, `bytesToHex`, `utf8ToBytes`, `bytesToUtf8`, `base64ToBytes`, `bytesToBase64` |
405
- | Security | `constantTimeEqual`, `wipe`, `xor` |
406
- | Helpers | `concat`, `randomBytes` |
407
- | Types | `Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD` |
408
-
409
- ---
410
-
411
- ## Build Pipeline
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
419
-
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.
421
-
422
- ---
423
-
424
- ## Module Relationship Diagrams
425
-
426
- ### ASM layer: internal import graph
427
-
428
- Each WASM module is fully independent. No cross-module imports exist.
429
-
430
- **Serpent (`src/asm/serpent/`)**
431
- ```
432
- buffers.ts
433
- <- serpent.ts (offsets for key, block, subkey, work, CBC IV)
434
- <- serpent_unrolled.ts (block offsets, subkey, work)
435
- <- serpent_simd.ts (SIMD bitsliced block operations)
436
- <- cbc.ts (IV, block, chunk offsets)
437
- <- cbc_simd.ts (SIMD CBC decrypt)
438
- <- ctr.ts (nonce, counter, block, chunk offsets)
439
- <- ctr_simd.ts (SIMD CTR 4-wide inter-block)
440
-
441
- serpent.ts
442
- <- serpent_unrolled.ts (S-boxes sb0-sb7, si0-si7, lk, kl, keyXor)
443
-
444
- serpent_unrolled.ts
445
- <- cbc.ts (encryptBlock_unrolled, decryptBlock_unrolled)
446
- <- ctr.ts (encryptBlock_unrolled)
447
-
448
- serpent_simd.ts
449
- <- cbc_simd.ts (SIMD block operations)
450
- <- ctr_simd.ts (SIMD block operations)
451
-
452
- index.ts
453
- re-exports: buffers + serpent + serpent_unrolled + serpent_simd + cbc + cbc_simd + ctr + ctr_simd
454
- ```
455
-
456
- **ChaCha (`src/asm/chacha20/`)**
457
- ```
458
- buffers.ts
459
- <- chacha20.ts (key, nonce, counter, block, state, poly key, xchacha offsets)
460
- <- chacha20_simd_4x.ts (SIMD work buffer, chunk offsets)
461
- <- poly1305.ts (poly key, msg, buf, tag, h, r, rs, s offsets)
462
- <- wipe.ts (all buffer offsets, zeroes everything)
463
-
464
- index.ts
465
- re-exports: buffers + chacha20 + chacha20_simd_4x + poly1305 + wipe
466
- ```
467
-
468
- **SHA-2 (`src/asm/sha2/`)**
469
-
470
- ```
471
- buffers.ts
472
- <- sha256.ts (H, block, W, out, input, partial, total offsets)
473
- <- sha512.ts (H, block, W, out, input, partial, total offsets)
474
- <- hmac.ts (SHA-256 input, out, ipad, opad, inner offsets)
475
- <- hmac512.ts (SHA-512 input, out, ipad, opad, inner offsets)
476
-
477
- sha256.ts
478
- <- hmac.ts (sha256Init, sha256Update, sha256Final)
479
-
480
- sha512.ts
481
- <- hmac512.ts (sha512Init, sha384Init, sha512Update, sha512Final, sha384Final)
482
-
483
- index.ts
484
- re-exports: buffers + sha256 + sha512 + hmac + hmac512
485
- defines: wipeBuffers() inline
486
- ```
487
-
488
- **SHA-3 (`src/asm/sha3/`)**
489
-
490
- ```
491
- buffers.ts
492
- <- keccak.ts (state, rate, absorbed, dsbyte, input, out offsets)
493
-
494
- index.ts
495
- re-exports: buffers + keccak
496
- ```
497
-
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
541
-
542
- ```
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)
567
- ```
568
-
569
- Each module's init function (`serpentInit`, `chacha20Init`, `sha2Init`,
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
- ---
579
-
580
- ### TS-to-WASM mapping
581
-
582
- Each TS wrapper class maps to one WASM module and specific exported functions.
583
- Tier 2 composition classes are pure TypeScript; they call Tier 1 classes rather than WASM functions directly.
584
-
585
- **serpent/index.ts → asm/serpent/ (Tier 1: direct WASM callers)**
586
-
587
- | TS Class | WASM functions called |
588
- |----------|---------------------|
589
- | `Serpent` | `loadKey`, `encryptBlock`, `decryptBlock`, `wipeBuffers` + buffer getters |
590
- | `SerpentCtr` | `loadKey`, `resetCounter`, `setCounter`, `encryptChunk`, `encryptChunk_simd`, `wipeBuffers` + buffer getters |
591
- | `SerpentCbc` | `loadKey`, `cbcEncryptChunk`, `cbcDecryptChunk`, `cbcDecryptChunk_simd`, `wipeBuffers` + buffer getters |
592
-
593
- **chacha20/index.ts → asm/chacha20/ (Tier 1: direct WASM callers)**
594
-
595
- | TS Class | WASM functions called |
596
- |----------|---------------------|
597
- | `ChaCha20` | `chachaLoadKey`, `chachaSetCounter`, `chachaEncryptChunk`, `chachaEncryptChunk_simd`, `wipeBuffers` + buffer getters |
598
- | `Poly1305` | `polyInit`, `polyUpdate`, `polyFinal`, `wipeBuffers` + 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`) |
601
-
602
- **sha2/index.ts → asm/sha2/ (Tier 1: direct WASM callers)**
603
-
604
- | TS Class | WASM functions called |
605
- |----------|---------------------|
606
- | `SHA256` | `sha256Init`, `sha256Update`, `sha256Final`, `wipeBuffers` + buffer getters |
607
- | `SHA512` | `sha512Init`, `sha512Update`, `sha512Final`, `wipeBuffers` + buffer getters |
608
- | `SHA384` | `sha384Init`, `sha512Update`, `sha384Final`, `wipeBuffers` + buffer getters |
609
- | `HMAC_SHA256` | `hmac256Init`, `hmac256Update`, `hmac256Final`, `sha256Init`, `sha256Update`, `sha256Final`, `wipeBuffers` + buffer getters |
610
- | `HMAC_SHA512` | `hmac512Init`, `hmac512Update`, `hmac512Final`, `sha512Init`, `sha512Update`, `sha512Final`, `wipeBuffers` + buffer getters |
611
- | `HMAC_SHA384` | `hmac384Init`, `hmac384Update`, `hmac384Final`, `sha384Init`, `sha512Update`, `sha384Final`, `wipeBuffers` + buffer getters |
612
-
613
- **sha3/index.ts → asm/sha3/ (Tier 1: direct WASM callers)**
614
-
615
- | TS Class | WASM functions called |
616
- |----------|---------------------|
617
- | `SHA3_224` | `sha3_224Init`, `keccakAbsorb`, `sha3_224Final`, `wipeBuffers` + buffer getters |
618
- | `SHA3_256` | `sha3_256Init`, `keccakAbsorb`, `sha3_256Final`, `wipeBuffers` + buffer getters |
619
- | `SHA3_384` | `sha3_384Init`, `keccakAbsorb`, `sha3_384Final`, `wipeBuffers` + buffer getters |
620
- | `SHA3_512` | `sha3_512Init`, `keccakAbsorb`, `sha3_512Final`, `wipeBuffers` + buffer getters |
621
- | `SHAKE128` | `shake128Init`, `keccakAbsorb`, `shakePad`, `shakeSqueezeBlock`, `wipeBuffers` + buffer getters |
622
- | `SHAKE256` | `shake256Init`, `keccakAbsorb`, `shakePad`, `shakeSqueezeBlock`, `wipeBuffers` + buffer getters |
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
-
648
- ### Cross-module dependencies
649
-
650
- | Relationship | Notes |
651
- |-------------|-------|
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. |
660
- | All other classes | Each depends on exactly **one** WASM module. |
661
-
662
- ---
663
-
664
- ### Public API barrel (`src/ts/index.ts`)
665
-
666
- The root barrel defines and exports the dispatching `init()` function.
667
- It is the only file that imports all four module-scoped init functions.
668
-
669
- | Source | Exports |
670
- |--------|------------|
671
- | *(barrel itself)* | `init` (dispatching function — calls per-module init functions via `Promise.all`) |
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` |
676
- | `sha2/index.ts` | `SHA256`, `SHA512`, `SHA384`, `HMAC_SHA256`, `HMAC_SHA512`, `HMAC_SHA384`, `HKDF_SHA256`, `HKDF_SHA512`, `_sha2Ready` |
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` |
681
- | `fortuna.ts` | `Fortuna` |
682
- | `types.ts` | `Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD` |
683
- | `utils.ts` | `hexToBytes`, `bytesToHex`, `utf8ToBytes`, `bytesToUtf8`, `base64ToBytes`, `bytesToBase64`, `constantTimeEqual`, `wipe`, `xor`, `concat`, `randomBytes` |
684
-
685
- Each subpath export also exports its own module-specific init function for
686
- tree-shakeable loading: `serpentInit(source)`, `chacha20Init(source)`,
687
- `sha2Init(source)`, `sha3Init(source)`, `keccakInit(source)`.
688
-
689
- ---
690
-
691
- ## npm Package
692
-
693
- **Subpath exports:**
694
- ```json
695
- {
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
- }
712
- }
713
- ```
714
-
715
- > [!NOTE]
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.
723
-
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.
725
-
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.
727
-
728
- **Published.** The npm package includes:
729
-
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.
735
-
736
- ---
737
-
738
- ## Buffer Layouts
739
-
740
- All offsets start at 0 per module. Independent linear memory. No offsets are
741
- shared or coordinated across modules.
742
-
743
- ### Serpent module (3 pages, 192 KB)
744
-
745
- Source: `src/asm/serpent/buffers.ts`
746
-
747
- | Offset | Size | Name |
748
- |--------|------|------|
749
- | 0 | 32 | `KEY_BUFFER` — key input (padded to 32 bytes for all key sizes) |
750
- | 32 | 16 | `BLOCK_PT_BUFFER` — single block plaintext |
751
- | 48 | 16 | `BLOCK_CT_BUFFER` — single block ciphertext |
752
- | 64 | 16 | `NONCE_BUFFER` — CTR mode nonce |
753
- | 80 | 16 | `COUNTER_BUFFER` — 128-bit little-endian counter |
754
- | 96 | 528 | `SUBKEY_BUFFER` — key schedule output (33 rounds × 4 × 4 bytes) |
755
- | 624 | 65552 | `CHUNK_PT_BUFFER` — streaming plaintext (CTR/CBC); +16 from 65536 to fit PKCS7 max overhead |
756
- | 66176 | 65552 | `CHUNK_CT_BUFFER` — streaming ciphertext (CTR/CBC) |
757
- | 131728 | 20 | `WORK_BUFFER` — 5 × i32 scratch registers (key schedule + S-box/LT rounds) |
758
- | 131748 | 16 | `CBC_IV_BUFFER` — CBC initialization vector / chaining value |
759
- | 131856 | — | END |
760
-
761
- `wipeBuffers()` zeroes all 10 buffers (key, block pt/ct, nonce, counter, subkeys, work, chunk pt/ct, CBC IV).
762
-
763
- ### ChaCha20 module (3 pages, 192 KB)
764
-
765
- Source: `src/asm/chacha20/buffers.ts`
766
-
767
- | Offset | Size | Name |
768
- |--------|------|------|
769
- | 0 | 32 | `KEY_BUFFER` — ChaCha20 256-bit key |
770
- | 32 | 12 | `CHACHA_NONCE_BUFFER` — 96-bit nonce (3 × u32, LE) |
771
- | 44 | 4 | `CHACHA_CTR_BUFFER` — u32 block counter |
772
- | 48 | 64 | `CHACHA_BLOCK_BUFFER` — 64-byte keystream block output |
773
- | 112 | 64 | `CHACHA_STATE_BUFFER` — 16 × u32 initial state |
774
- | 176 | 65536 | `CHUNK_PT_BUFFER` — streaming plaintext |
775
- | 65712 | 65536 | `CHUNK_CT_BUFFER` — streaming ciphertext |
776
- | 131248 | 32 | `POLY_KEY_BUFFER` — one-time key r‖s |
777
- | 131280 | 64 | `POLY_MSG_BUFFER` — message staging (≤ 64 bytes per polyUpdate) |
778
- | 131344 | 16 | `POLY_BUF_BUFFER` — partial block accumulator |
779
- | 131360 | 4 | `POLY_BUF_LEN_BUFFER` — u32 bytes in partial block |
780
- | 131364 | 16 | `POLY_TAG_BUFFER` — 16-byte output MAC tag |
781
- | 131380 | 40 | `POLY_H_BUFFER` — accumulator h: 5 × u64 |
782
- | 131420 | 40 | `POLY_R_BUFFER` — clamped r: 5 × u64 |
783
- | 131460 | 32 | `POLY_RS_BUFFER` — precomputed 5×r[1..4]: 4 × u64 |
784
- | 131492 | 16 | `POLY_S_BUFFER` — s pad: 4 × u32 |
785
- | 131508 | 24 | `XCHACHA_NONCE_BUFFER` — full 24-byte XChaCha20 nonce |
786
- | 131532 | 32 | `XCHACHA_SUBKEY_BUFFER` — HChaCha20 output (key material) |
787
- | 131564 | 4 | *(padding for 16-byte SIMD alignment)* |
788
- | 131568 | 256 | `CHACHA_SIMD_WORK_BUFFER` — 4-wide inter-block keystream (4 × 64 bytes) |
789
- | 131824 | — | END |
790
-
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).
792
-
793
- ### SHA-2 module (3 pages, 192 KB)
794
-
795
- Source: `src/asm/sha2/buffers.ts`
796
-
797
- | Offset | Size | Name |
798
- |--------|------|------|
799
- | 0 | 32 | `SHA256_H` — SHA-256 hash state H0..H7 (8 × u32) |
800
- | 32 | 64 | `SHA256_BLOCK` — SHA-256 block accumulator |
801
- | 96 | 256 | `SHA256_W` — SHA-256 message schedule W[0..63] (64 × u32) |
802
- | 352 | 32 | `SHA256_OUT` — SHA-256 digest output |
803
- | 384 | 64 | `SHA256_INPUT` — SHA-256 user input staging (one block) |
804
- | 448 | 4 | `SHA256_PARTIAL` — u32 partial block length |
805
- | 452 | 8 | `SHA256_TOTAL` — u64 total bytes hashed |
806
- | 460 | 64 | `HMAC256_IPAD` — HMAC-SHA256 K' XOR ipad |
807
- | 524 | 64 | `HMAC256_OPAD` — HMAC-SHA256 K' XOR opad |
808
- | 588 | 32 | `HMAC256_INNER` — HMAC-SHA256 inner hash |
809
- | 620 | 64 | `SHA512_H` — SHA-512 hash state H0..H7 (8 × u64) |
810
- | 684 | 128 | `SHA512_BLOCK` — SHA-512 block accumulator |
811
- | 812 | 640 | `SHA512_W` — SHA-512 message schedule W[0..79] (80 × u64) |
812
- | 1452 | 64 | `SHA512_OUT` — SHA-512 digest output (SHA-384 uses first 48 bytes) |
813
- | 1516 | 128 | `SHA512_INPUT` — SHA-512 user input staging (one block) |
814
- | 1644 | 4 | `SHA512_PARTIAL` — u32 partial block length |
815
- | 1648 | 8 | `SHA512_TOTAL` — u64 total bytes hashed |
816
- | 1656 | 128 | `HMAC512_IPAD` — HMAC-SHA512 K' XOR ipad (128-byte block size) |
817
- | 1784 | 128 | `HMAC512_OPAD` — HMAC-SHA512 K' XOR opad |
818
- | 1912 | 64 | `HMAC512_INNER` — HMAC-SHA512 inner hash |
819
- | 1976 | — | END |
820
-
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).
822
-
823
- ### SHA-3 module (3 pages, 192 KB)
824
-
825
- Source: `src/asm/sha3/buffers.ts`
826
-
827
- | Offset | Size | Name |
828
- |--------|------|------|
829
- | 0 | 200 | `KECCAK_STATE` — 25 × u64 Keccak-f[1600] lane matrix (5×5, row-major x+5y) |
830
- | 200 | 4 | `KECCAK_RATE` — u32 rate in bytes (variant-specific: 72–168) |
831
- | 204 | 4 | `KECCAK_ABSORBED` — u32 bytes absorbed into current block |
832
- | 208 | 1 | `KECCAK_DSBYTE` — u8 domain separation byte (0x06 for SHA-3, 0x1f for SHAKE) |
833
- | 209 | 168 | `KECCAK_INPUT` — input staging buffer (max rate = SHAKE128 at 168 bytes) |
834
- | 377 | 168 | `KECCAK_OUT` — output buffer (one SHAKE128 squeeze block) |
835
- | 545 | — | END |
836
-
837
- `wipeBuffers()` zeroes all 6 buffer regions (state, rate, absorbed, dsbyte, input, output).
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
-
861
- ---
862
-
863
- ## Test Suite
864
-
865
- ### Structure
866
-
867
-
868
- For the full testing methodology and vector corpus, see: [test-suite.md](./test-suite.md)
869
-
870
- ### Gate discipline
871
-
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.
873
-
874
- ### `init.test.ts` contracts
875
-
876
- - `init()` with each `WasmSource` type loads and caches the module correctly
877
- - Idempotency: second `init()` call for same module is a no-op
878
- - Error before init: clear error thrown for each class before its module is loaded
879
- - Partial init: loading `{ serpent: ... }` does not make `sha3` classes available
880
-
881
- ---
882
-
883
- ## Correctness Contract
884
-
885
- leviathan-crypto must produce byte-identical output to the authoritative
886
- specification for every known test vector. Cross-checks against the leviathan
887
- TypeScript reference and external tools (OpenSSL, Python hashlib, Node.js crypto)
888
- provide additional verification layers.
889
-
890
- The test vector corpus in `test/vectors/` is read-only. Integrity is verified via
891
- `SHA256SUMS`, expected values are sourced directly from authoritative references.
892
- They are the immutable truth, and must never be modified to make tests pass.
893
-
894
- ---
895
-
896
- ## Known Limitations
897
-
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.
901
- - **Single-threaded WASM per instance**: one WASM instance per binary per thread.
902
- `SealStreamPool` provides Worker-based parallelism for both cipher families;
903
- other primitives remain single-threaded.
904
- - **Max input per WASM call**: CTR accepts at most 65536 bytes per call; CBC
905
- accepts at most 65552 bytes (65536 + 16 bytes PKCS7 maximum overhead).
906
- Wrappers handle splitting automatically for larger inputs.
907
- - **WASM side-channel posture**: WebAssembly implementations offer the best
908
- available side-channel resistance (branchless, table-free), but lack
909
- hardware-level constant-time guarantees. For applications where timing
910
- side channels are a primary threat, a native cryptographic library with
911
- verified constant-time guarantees will be more appropriate than any
912
- WASM-based implementation.
913
-
914
- ---
915
-
916
- > ## Cross-References
917
- >
918
- > - [index](./README.md) — Project Documentation index
919
- > - [lexicon](./lexicon.md) — Glossary of cryptographic terms
920
- > - [test-suite](./test-suite.md) — testing methodology, vector corpus, and gate discipline
921
- > - [init](./init.md) — `init()` API, `WasmSource`, and idempotent behavior
922
- > - [loader](./loader.md) — internal WASM binary loading strategies
923
- > - [wasm](./wasm.md) — WebAssembly primer: modules, instances, memory, and the init gate
924
- > - [types](./types.md) — public TypeScript interfaces and `CipherSuite`
925
- > - [utils](./utils.md) — encoding helpers, `constantTimeEqual`, `wipe`, `randomBytes`
926
- > - [authenticated encryption](./aead.md) — SealStream, OpenStream, SealStreamPool, wire format
927
- > - [serpent](./serpent.md) — Serpent-256 TypeScript API, SerpentCipher
928
- > - [chacha20](./chacha20.md) — ChaCha20/Poly1305 TypeScript API, XChaCha20Cipher
929
- > - [sha2](./sha2.md) — SHA-2 hashes, HMAC, and HKDF TypeScript API
930
- > - [sha3](./sha3.md) — SHA-3 hashes and SHAKE XOFs TypeScript API
931
- > - [fortuna](./fortuna.md) — Fortuna CSPRNG with forward secrecy and entropy pooling
932
- > - [argon2id](./argon2id.md) — Argon2id password hashing and key derivation