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
package/CLAUDE.md CHANGED
@@ -1,320 +1,127 @@
1
- # leviathan-crypto AI Assistant Guide
1
+ # leviathan-crypto: AI Assistant Guide
2
2
 
3
3
  > [!NOTE]
4
- > This file ships with the package to help AI assistants use this library correctly. Full API documentation is in the `docs/` directory alongside this file.
4
+ > Ships with the npm package. Inside the repo? Read `AGENTS.md` instead.
5
5
 
6
- > ### Table of Contents
7
- > - [What This Library Is](#what-this-library-is)
8
- > - [Critical: `init()` is required](#critical-init-is-required)
9
- > - [Critical: call `dispose()` after use](#critical-call-dispose-after-use)
10
- > - [Critical: `decrypt()` throws on authentication failure](#critical-decrypt-throws-on-authentication-failure--never-returns-null)
11
- > - [Critical: subpath init function names](#critical-subpath-init-function-names)
12
- > - [Which module does each class require?](#which-module-does-each-class-require)
13
- > - [Recommended patterns](#recommended-patterns)
14
- > - [`SerpentCbc` arg order](#serpentcbc-arg-order)
15
- > - [Utilities (no `init()` required)](#utilities-no-init-required)
16
- > - [Full documentation](#full-documentation)
6
+ ## What this is
17
7
 
18
- ---
8
+ Zero-dependency WASM crypto for TS/JS. All compute in WASM (outside JS JIT); TS layer = input validation + ergonomics.
19
9
 
20
- ## What This Library Is
10
+ | Family | Primitives |
11
+ |---|---|
12
+ | Symmetric AEAD | Serpent-256, XChaCha20-Poly1305, AES-256-GCM-SIV |
13
+ | Post-quantum sig | ML-DSA, SLH-DSA, PQ-only hybrid composites |
14
+ | Classical sig | Ed25519, ECDSA-P256, classical+PQ hybrid composites |
15
+ | Key agreement | ML-KEM, X25519 |
16
+ | Transparency log | Merkle log (C2SP-conformant) |
17
+ | Forward-secret ratchet | Signal SPQR KDF (rule 8) |
21
18
 
22
- `leviathan-crypto` is a zero-dependency WebAssembly cryptography library for
23
- TypeScript and JavaScript. All cryptographic computation runs in WASM, outside
24
- the JavaScript JIT. The TypeScript layer provides the public API: input
25
- validation, type safety, and ergonomics. It never implements cryptographic
26
- algorithms itself.
19
+ ## API shape
27
20
 
28
- ---
21
+ Two hierarchies, one suite extension point. Tier = data shape. Suite = crypto choice.
29
22
 
30
- ## Critical: `init()` is required
23
+ | Tier | AEAD | Signatures |
24
+ |---|---|---|
25
+ | One-shot | Seal | Sign |
26
+ | Streaming | SealStream / OpenStream | SignStream / VerifyStream |
27
+ | Parallel | SealStreamPool (Web Workers) | n/a |
28
+ | Suite arg | CipherSuite | SignatureSuite |
31
29
 
32
- **No class works before `init()` is called.** Calling any class before its
33
- module is loaded throws immediately with a clear error. Call `init()` once at
34
- startup, before any cryptographic operations.
30
+ `Seal` blob = single-chunk `SealStream` output (interchangeable). Symmetric: `SerpentCipher`, `XChaCha20Cipher`, `AESGCMSIVCipher`. `MlKemSuite(MlKem*, inner)` wraps any of them for PQ hybrid (same `CipherSuite` interface).
35
31
 
36
- ```typescript
37
- import { init, Serpent } from 'leviathan-crypto'
38
- import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
39
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
40
-
41
- await init({ serpent: serpentWasm, sha2: sha2Wasm })
42
- ```
43
-
44
- `init()` accepts a `Partial<Record<Module, WasmSource>>`. Each value is a
45
- `WasmSource`: a gzip+base64 string, `URL`, `ArrayBuffer`, `Uint8Array`,
46
- pre-compiled `WebAssembly.Module`, `Response`, or `Promise<Response>`.
47
-
48
- The `/embedded` subpath exports are the simplest WasmSource: they are the
49
- gzip+base64 blobs for each module, bundled with the package.
50
-
51
- ---
52
-
53
- ## Critical: call `dispose()` after use
54
-
55
- Every class holds WASM memory containing key material. Call `dispose()` when
56
- done; it zeroes that memory. Not calling `dispose()` leaks key material.
57
-
58
- ```typescript
59
- const cipher = new XChaCha20Poly1305()
60
- try {
61
- return cipher.encrypt(key, nonce, plaintext)
62
- } finally {
63
- cipher.dispose()
64
- }
65
- ```
66
-
67
- ---
68
-
69
- ## Critical: `decrypt()` throws on authentication failure — never returns null
70
-
71
- All AEAD `decrypt()` methods throw if authentication fails. Do not check for a
72
- null return; catch the exception.
73
-
74
- ```typescript
75
- try {
76
- const plaintext = seal.decrypt(key, ciphertext)
77
- } catch {
78
- // wrong key or tampered data
79
- }
80
- ```
81
-
82
- ---
83
-
84
- ## Critical: subpath init function names
85
-
86
- Each subpath export has its own module-specific init function, not `init()`.
87
- These are only needed for tree-shakeable imports. The root barrel `init()` is
88
- the normal path.
89
-
90
- Each init function takes a single `WasmSource` argument. Use the module's
91
- `/embedded` subpath to get the bundled blob as a ready-to-use WasmSource.
92
-
93
- | Subpath | Init function | Embedded blob |
94
- |---------|---------------|---------------|
95
- | `leviathan-crypto/serpent` | `serpentInit(source)` | `leviathan-crypto/serpent/embedded` → `serpentWasm` |
96
- | `leviathan-crypto/chacha20` | `chacha20Init(source)` | `leviathan-crypto/chacha20/embedded` → `chacha20Wasm` |
97
- | `leviathan-crypto/sha2` | `sha2Init(source)` | `leviathan-crypto/sha2/embedded` → `sha2Wasm` |
98
- | `leviathan-crypto/sha3` | `sha3Init(source)` | `leviathan-crypto/sha3/embedded` → `sha3Wasm` |
99
- | `leviathan-crypto/keccak` | `keccakInit(source)` | `leviathan-crypto/keccak/embedded` → `keccakWasm` |
100
- | `leviathan-crypto/kyber` | `kyberInit(source)` | `leviathan-crypto/kyber/embedded` → `kyberWasm` |
101
-
102
- ```typescript
103
- // Tree-shakeable — loads only serpent WASM
104
- import { serpentInit, Serpent } from 'leviathan-crypto/serpent'
105
- import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
106
- await serpentInit(serpentWasm)
107
- ```
108
-
109
- ---
110
-
111
- ## Which module does each class require?
112
-
113
- | Classes | Required modules |
114
- |---------|-----------------|
115
- | `Serpent`, `SerpentCtr`, `SerpentCbc`, `SerpentCipher` | `init({ serpent: serpentWasm, sha2: sha2Wasm })` |
116
- | `SealStream`, `OpenStream`, `SerpentCipher` (when using SerpentCipher) | `init({ serpent: serpentWasm, sha2: sha2Wasm })` |
117
- | `SealStream`, `OpenStream`, `XChaCha20Cipher` (when using XChaCha20Cipher) | `init({ chacha20: chacha20Wasm, sha2: sha2Wasm })` |
118
- | `SealStreamPool` | depends on cipher: same modules as the cipher suite + `sha2` |
119
- | `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305` | `init({ chacha20: chacha20Wasm })` |
120
- | `SHA256`, `SHA384`, `SHA512`, `HMAC_SHA256`, `HMAC_SHA384`, `HMAC_SHA512`, `HKDF_SHA256`, `HKDF_SHA512` | `init({ sha2: sha2Wasm })` |
121
- | `SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512`, `SHAKE128`, `SHAKE256` | `init({ sha3: sha3Wasm })` or `init({ keccak: keccakWasm })` — `'keccak'` is an alias for `'sha3'` |
122
- | `MlKem512`, `MlKem768`, `MlKem1024` | `init({ kyber: kyberWasm, sha3: sha3Wasm })` — both modules required |
123
- | `Fortuna` | `init({ serpent: serpentWasm, sha2: sha2Wasm })` |
124
-
125
- ---
126
-
127
- ## Recommended patterns
128
-
129
- ### Authenticated encryption (recommended default)
130
-
131
- ```typescript
132
- import { init, Seal, SerpentCipher, randomBytes } from 'leviathan-crypto'
133
- import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
134
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
32
+ **Prefer the high-level surface (Seal / Sign / Fortuna).** Handles KDF, nonce management, auth, key wipes, counter binding. Rejects tampered/reordered/spliced inputs before plaintext release. Low-level primitives (raw `ChaCha20`, `SerpentCbc`, etc.) require reading their wiki page first.
135
33
 
136
- await init({ serpent: serpentWasm, sha2: sha2Wasm })
137
-
138
- const key = SerpentCipher.keygen()
139
- const blob = Seal.encrypt(SerpentCipher, key, plaintext)
140
- const decrypted = Seal.decrypt(SerpentCipher, key, blob)
141
- ```
142
-
143
- ### Incremental streaming AEAD
144
-
145
- Use when you cannot buffer the full message before encrypting.
146
-
147
- ```typescript
148
- import { init, SealStream, OpenStream, SerpentCipher, randomBytes } from 'leviathan-crypto'
149
- import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
150
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
151
-
152
- await init({ serpent: serpentWasm, sha2: sha2Wasm })
153
-
154
- const key = randomBytes(32)
155
- const sealer = new SealStream(SerpentCipher, key)
156
- const preamble = sealer.preamble // 20 bytes — send first
157
- const ct0 = sealer.push(chunk0)
158
- const ct1 = sealer.push(chunk1)
159
- const ctLast = sealer.finalize(lastChunk)
160
-
161
- const opener = new OpenStream(SerpentCipher, key, preamble)
162
- const pt0 = opener.pull(ct0)
163
- const pt1 = opener.pull(ct1)
164
- const ptLast = opener.finalize(ctLast)
165
- ```
166
-
167
- ### Length-prefixed streaming (for files and buffered transports)
168
-
169
- Pass `{ framed: true }` to `SealStream` for self-delimiting `u32be` length-prefixed
170
- framing. Use when chunks will be concatenated into a flat byte stream. Omit when the
171
- transport frames messages itself (WebSocket, IPC).
172
-
173
- ```typescript
174
- const sealer = new SealStream(SerpentCipher, key, { framed: true })
175
- ```
176
-
177
- ### XChaCha20-Poly1305
178
-
179
- ```typescript
180
- import { init, XChaCha20Poly1305, randomBytes } from 'leviathan-crypto'
181
- import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
182
-
183
- await init({ chacha20: chacha20Wasm })
184
-
185
- const aead = new XChaCha20Poly1305()
186
- const key = randomBytes(32)
187
- const nonce = randomBytes(24)
188
- const sealed = aead.encrypt(key, nonce, plaintext, aad?) // ciphertext || tag
189
- const plaintext = aead.decrypt(key, nonce, sealed, aad?) // throws on tamper
190
- aead.dispose()
191
- ```
34
+ ## Rules (cross-cutting foot-guns)
192
35
 
193
- Note: `encrypt()` returns ciphertext with the 16-byte Poly1305 tag appended.
194
- `decrypt()` expects the same concatenated format, not separate ciphertext and tag.
36
+ 1. **`init()` required.** Nothing works before `init()`. Throws on missing module. Idempotent. Use `/embedded` subpath for bundled gzip+base64 blob.
195
37
 
196
- ### Hashing
38
+ 2. **`dispose()` stateful in `finally`.** Stateful classes hold key material in WASM until `dispose()` zeros it. Wrap in `try { ... } finally { x.dispose() }`. Atomic one-shots (`Seal.encrypt`, `Sign.sign`, hashes, MACs) self-wipe.
197
39
 
198
- ```typescript
199
- import { init, SHA256, HMAC_SHA256 } from 'leviathan-crypto'
200
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
40
+ 3. **Stateful = exclusive module access.** A stateful class (`SHAKE128`, `ChaCha20`, `SerpentCtr/Cbc`, `SealStream`, `MlKem*`, etc.) owns its WASM module for its lifetime. Second stateful instance on same module throws. Atomic methods on same module throw while a stateful holder is alive. Pool workers isolated.
201
41
 
202
- await init({ sha2: sha2Wasm })
42
+ 4. **AEAD `decrypt()` throws on auth failure.** `Seal.decrypt`, AEAD `decrypt()`, `OpenStream.pull` never return null or corrupted plaintext. Wrong key, tampered blob, corrupted bytes all surface as exceptions.
203
43
 
204
- const hasher = new SHA256()
205
- const digest = hasher.hash(data) // returns Uint8Array
206
- hasher.dispose()
44
+ 5. **Raw `verify()` returns bool. `Sign.verify` throws.** Raw primitives (`MlDsa*.verify`, `SlhDsa*.verify`, hybrid `verifyPrehashed`) return `false` on bad sig; only contract violations throw. `Sign.verify` envelope throws on bad sig (parity with `Seal.decrypt`).
207
45
 
208
- const mac = new HMAC_SHA256()
209
- const tag = mac.hash(key, data)
210
- mac.dispose()
211
- ```
46
+ 6. **Pure-mode and prehash sigs NOT interchangeable.** `dsa.sign` vs `dsa.verifyHash` bind different M' domain bytes (0x00 vs 0x01, FIPS 204 §3.6.4 / FIPS 205 §10.2.2). Sigs don't cross even with identical messages. SignatureSuite enforces at the type level.
212
47
 
213
- ### SHAKE (XOF variable-length output)
48
+ 7. **v3 sign envelope: `ctx` required.** `Sign.sign` / `Sign.verify` / `SignStream` / `VerifyStream` all require `ctx`. Pass `new Uint8Array()` for empty. Each suite prepends `ctxDomain` (blocks cross-suite verify). Per-call `ctx` ≤ 255 bytes (FIPS 204 §3.6.1); longer throws `SigningError('sig-ctx-too-long')`. Per-call ceiling = `253 - len(ctxDomain)` (221-234 bytes across catalog).
214
49
 
215
- ```typescript
216
- import { init, SHAKE128 } from 'leviathan-crypto'
217
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
50
+ 8. **Ratchet = KDF primitives, not a session.** Forward secrecy + post-compromise security primitives only. State machine, message counters, header format, epoch orchestration, transport = app concerns. NOT a drop-in Signal client.
218
51
 
219
- await init({ sha3: sha3Wasm })
52
+ ## Subpath imports
220
53
 
221
- const xof = new SHAKE128()
222
- xof.absorb(data)
223
- const out1 = xof.squeeze(32) // first 32 bytes of output stream
224
- const out2 = xof.squeeze(32) // next 32 bytes — contiguous XOF stream
225
- xof.dispose()
226
- ```
54
+ Pattern: `leviathan-crypto/<mod>` exports `<mod>Init(source)`; `leviathan-crypto/<mod>/embedded` exports `<mod>Wasm`. Twelve modules: `serpent`, `chacha20`, `aes`, `sha2`, `sha3`, `keccak`, `mlkem`, `mldsa`, `slhdsa`, `blake3`, `curve25519`, `p256`.
227
55
 
228
- ### ML-KEM post-quantum key encapsulation
56
+ Aliases share binary + instance slot:
229
57
 
230
- ```typescript
231
- import { init, MlKem768 } from 'leviathan-crypto'
232
- import { kyberWasm } from 'leviathan-crypto/kyber/embedded'
233
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
58
+ | Alias | Backed by |
59
+ |---|---|
60
+ | keccak | sha3 |
61
+ | ed25519 | curve25519 |
62
+ | x25519 | curve25519 |
63
+ | ecdsa | p256 |
234
64
 
235
- await init({ kyber: kyberWasm, sha3: sha3Wasm })
65
+ No `/embedded`: `leviathan-crypto/ratchet`, `leviathan-crypto/stream`, `leviathan-crypto/sign`, `leviathan-crypto/merkle`.
236
66
 
237
- const kem = new MlKem768()
238
- const { encapsulationKey, decapsulationKey } = kem.keygen()
67
+ ## Class init modules + wiki
239
68
 
240
- // Encapsulation (sender public encapsulationKey only)
241
- const { ciphertext, sharedSecret: senderSecret } = kem.encapsulate(encapsulationKey)
69
+ | Class | init modules | wiki |
70
+ |---|---|---|
71
+ | Seal / SealStream / OpenStream / SealStreamPool | varies by suite | https://github.com/xero/leviathan-crypto/wiki/aead |
72
+ | SerpentCipher | serpent, sha2 | https://github.com/xero/leviathan-crypto/wiki/serpent |
73
+ | XChaCha20Cipher | chacha20, sha2 | https://github.com/xero/leviathan-crypto/wiki/chacha20 |
74
+ | AESGCMSIVCipher | aes, sha2 | https://github.com/xero/leviathan-crypto/wiki/aes |
75
+ | MlKemSuite(MlKem*, inner) | mlkem, sha3 + inner | https://github.com/xero/leviathan-crypto/wiki/mlkem |
76
+ | Sign / SignStream / VerifyStream | varies by suite | https://github.com/xero/leviathan-crypto/wiki/signing |
77
+ | MlDsa{44,65,87}Suite (pure, prehash) | mldsa, sha3 (+sha2 for SHA-2 prehash) | https://github.com/xero/leviathan-crypto/wiki/mldsa |
78
+ | SlhDsa{128f,192f,256f}Suite | slhdsa, sha3 (+sha2 for SHA-2 prehash) | https://github.com/xero/leviathan-crypto/wiki/slhdsa |
79
+ | Ed25519Suite / Ed25519PreHashSuite | curve25519 (+sha2 for PreHash) | https://github.com/xero/leviathan-crypto/wiki/ed25519 |
80
+ | EcdsaP256Suite (hedged, low-S) | p256, sha2 | https://github.com/xero/leviathan-crypto/wiki/ecdsa-p256 |
81
+ | MlDsa{44,65}Ed25519Suite (0x20, 0x21) | mldsa, sha3, curve25519, sha2 | https://github.com/xero/leviathan-crypto/wiki/signaturesuite |
82
+ | MlDsa{44,65}EcdsaP256Suite (0x22, 0x23) | mldsa, sha3, p256, sha2 | https://github.com/xero/leviathan-crypto/wiki/signaturesuite |
83
+ | MlDsa{44,65,87}SlhDsa{128f,192f,256f}Suite (0x30-0x32) | mldsa, sha3, slhdsa | https://github.com/xero/leviathan-crypto/wiki/signaturesuite |
84
+ | X25519 | curve25519 | https://github.com/xero/leviathan-crypto/wiki/x25519 |
85
+ | MerkleVerifier / MerkleLog | sha2 + suite (+blake3 if `hashing: 'blake3'`) | https://github.com/xero/leviathan-crypto/wiki/merkle |
86
+ | Sparse PQ Ratchet (KDF, rule 8) | sha2, mlkem, sha3 | https://github.com/xero/leviathan-crypto/wiki/ratchet |
87
+ | Fortuna | one cipher + one hash | https://github.com/xero/leviathan-crypto/wiki/fortuna |
88
+ | SHA-2 / HMAC / HKDF | sha2 | https://github.com/xero/leviathan-crypto/wiki/sha2 |
89
+ | SHA-3 / SHAKE | sha3 | https://github.com/xero/leviathan-crypto/wiki/sha3 |
90
+ | CSHAKE / KMAC / KMACXOF | sha3 | https://github.com/xero/leviathan-crypto/wiki/kmac |
91
+ | BLAKE3 family | blake3 | https://github.com/xero/leviathan-crypto/wiki/blake3 |
242
92
 
243
- // Decapsulation (recipient — private decapsulationKey)
244
- const recipientSecret = kem.decapsulate(decapsulationKey, ciphertext)
93
+ Other refs:
245
94
 
246
- // senderSecret === recipientSecret (32 bytes)
247
- kem.dispose()
248
- ```
95
+ | Topic | wiki |
96
+ |---|---|
97
+ | init() / WasmSource | https://github.com/xero/leviathan-crypto/wiki/init |
98
+ | Loading strategies | https://github.com/xero/leviathan-crypto/wiki/loader |
99
+ | CDN usage | https://github.com/xero/leviathan-crypto/wiki/cdn |
100
+ | Content-Security-Policy | https://github.com/xero/leviathan-crypto/wiki/csp |
101
+ | Worked examples | https://github.com/xero/leviathan-crypto/wiki/examples |
102
+ | Utilities | https://github.com/xero/leviathan-crypto/wiki/utils |
103
+ | Argon2id integration | https://github.com/xero/leviathan-crypto/wiki/argon2id |
104
+ | CipherSuite interface | https://github.com/xero/leviathan-crypto/wiki/ciphersuite |
105
+ | SignatureSuite catalog | https://github.com/xero/leviathan-crypto/wiki/signaturesuite |
249
106
 
250
- Kyber classes require **both** `kyber` and `sha3` initialized. ML-KEM produces
251
- a 32-byte shared secret suitable for use as a symmetric key.
107
+ ## Canonical example
252
108
 
253
- ### Fortuna CSPRNG
109
+ `Seal` + `SerpentCipher` round-trip:
254
110
 
255
111
  ```typescript
256
- import { init, Fortuna } from 'leviathan-crypto'
112
+ import { init, Seal, SerpentCipher } from 'leviathan-crypto'
257
113
  import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
258
114
  import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
259
115
 
260
116
  await init({ serpent: serpentWasm, sha2: sha2Wasm })
261
117
 
262
- const fortuna = await Fortuna.create() // static factory — not new Fortuna()
263
- const bytes = fortuna.get(32)
264
- fortuna.stop()
265
- ```
266
-
267
- ---
268
-
269
- ## `SerpentCbc` arg order
270
-
271
- IV is the **second** argument, not the third:
272
-
273
- ```typescript
274
- cipher.encrypt(key, iv, plaintext) // correct
275
- cipher.decrypt(key, iv, ciphertext) // correct
276
- ```
277
-
278
- `SerpentCbc` is unauthenticated. Always pair with `HMAC_SHA256`
279
- (Encrypt-then-MAC) or use `Seal` with `SerpentCipher` instead.
280
-
281
- ---
282
-
283
- ## Utilities (no `init()` required)
284
-
285
- ```typescript
286
- import { hexToBytes, bytesToHex, randomBytes, constantTimeEqual, wipe, hasSIMD } from 'leviathan-crypto'
287
-
288
- // available immediately — no await init() needed
289
- const key = randomBytes(32)
290
- const hex = bytesToHex(key)
291
- const back = hexToBytes(hex)
292
- const safe = constantTimeEqual(a, b) // constant-time equality — never use ===
293
- wipe(key) // zero a Uint8Array in place
118
+ const key = SerpentCipher.keygen()
119
+ const blob = Seal.encrypt(SerpentCipher, key, plaintext)
120
+ try {
121
+ const pt = Seal.decrypt(SerpentCipher, key, blob)
122
+ } catch {
123
+ // wrong key, tampered blob, or corrupted bytes
124
+ }
294
125
  ```
295
126
 
296
- `hasSIMD()` returns `true` if the runtime supports WebAssembly SIMD.
297
- Serpent, ChaCha20, and Kyber modules all require SIMD; `init()` throws
298
- a clear error on runtimes without support. SIMD has been a baseline
299
- feature of all major browsers and runtimes since 2021. SHA-2 and SHA-3
300
- modules run on any WASM-capable runtime.
301
-
302
- ---
303
-
304
- ## Full documentation
305
-
306
- The complete API reference ships in `docs/` alongside this file:
307
-
308
- | File | Contents |
309
- |------|----------|
310
- | `docs/serpent.md` | `SerpentCipher`, `Serpent`, `SerpentCtr`, `SerpentCbc` |
311
- | `docs/chacha20.md` | `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, `XChaCha20Cipher` |
312
- | `docs/sha2.md` | `SHA256`, `SHA384`, `SHA512`, `HMAC_SHA256`, `HMAC_SHA384`, `HMAC_SHA512`, `HKDF_SHA256`, `HKDF_SHA512` |
313
- | `docs/sha3.md` | `SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512`, `SHAKE128`, `SHAKE256` |
314
- | `docs/aead.md` | `Seal`, `SealStream`, `OpenStream`, `SealStreamPool`, `CipherSuite` |
315
- | `docs/kyber.md` | `MlKem512`, `MlKem768`, `MlKem1024`, `KyberSuite` — ML-KEM (FIPS 203) API reference |
316
- | `docs/fortuna.md` | `Fortuna` CSPRNG |
317
- | `docs/init.md` | `init()` API, loading modes, subpath imports |
318
- | `docs/utils.md` | Encoding helpers, `constantTimeEqual`, `wipe`, `randomBytes` |
319
- | `docs/types.md` | `Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD` interfaces; `CipherSuite`, `DerivedKeys`, `SealStreamOpts`, `PoolOpts`, `WasmSource` |
320
- | `docs/architecture.md` | Module structure, WASM layer, three-tier design |
127
+ Streaming: `Seal` `SealStream` + `OpenStream`. PQ hybrid: `SerpentCipher` → `MlKemSuite(new MlKem768(), SerpentCipher)`. Same call site, wire format, catch semantics.
package/LICENSE CHANGED
@@ -2,6 +2,10 @@ MIT License
2
2
 
3
3
  Copyright (c) 2026 Leviathan Crypto Library
4
4
 
5
+ https://leviathan.3xi.club
6
+ https://github.com/xero/leviathan-crypto
7
+ https://npmjs.com/package/leviathan-crypto
8
+
5
9
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
10
  of this software and associated documentation files (the "Software"), to deal
7
11
  in the Software without restriction, including without limitation the rights