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,21 +1,73 @@
1
1
  import type { WasmSource } from '../wasm-source.js';
2
2
  import { AuthenticationError } from '../errors.js';
3
3
  export { AuthenticationError };
4
+ /**
5
+ * Load and initialise the ChaCha20 WASM module from `source`.
6
+ * Must be called before constructing any ChaCha20 class.
7
+ * @param source WASM binary, gzip+base64 string, URL, ArrayBuffer, Uint8Array,
8
+ * pre-compiled WebAssembly.Module, Response, or Promise<Response>
9
+ */
4
10
  export declare function chacha20Init(source: WasmSource): Promise<void>;
5
11
  export type { WasmSource };
12
+ export { isInitialized } from '../init.js';
13
+ /**
14
+ * Raw ChaCha20 stream cipher (RFC 8439 §2.4).
15
+ *
16
+ * Holds exclusive access to the `chacha20` WASM module from construction
17
+ * until `dispose()`. Constructing a second ChaCha20 or any other chacha20
18
+ * user while this instance is live throws. Call `dispose()` when done.
19
+ */
6
20
  export declare class ChaCha20 {
7
21
  private readonly x;
22
+ private _tok;
8
23
  constructor();
24
+ /**
25
+ * Load key and nonce into WASM state and set the block counter to 1.
26
+ * Must be called before each message (RFC 8439 §2.4).
27
+ * @param key 32 bytes
28
+ * @param nonce 12 bytes, must be unique per (key, message)
29
+ */
9
30
  beginEncrypt(key: Uint8Array, nonce: Uint8Array): void;
31
+ /**
32
+ * XOR `chunk` with the next keystream block(s). Counter advances automatically.
33
+ * @param chunk Plaintext chunk, must not exceed WASM CHUNK_SIZE
34
+ * @returns Ciphertext of the same length
35
+ */
10
36
  encryptChunk(chunk: Uint8Array): Uint8Array;
37
+ /**
38
+ * Alias for `beginEncrypt`, ChaCha20 is a stream cipher (symmetric).
39
+ * @param key 32 bytes
40
+ * @param nonce 12 bytes, must match the value used to encrypt
41
+ */
11
42
  beginDecrypt(key: Uint8Array, nonce: Uint8Array): void;
43
+ /**
44
+ * Alias for `encryptChunk`, ChaCha20 is a stream cipher (symmetric).
45
+ * @param chunk Ciphertext chunk
46
+ * @returns Plaintext of the same length
47
+ */
12
48
  decryptChunk(chunk: Uint8Array): Uint8Array;
49
+ /** Wipe WASM state and release exclusive module access. Idempotent. */
13
50
  dispose(): void;
14
51
  }
52
+ /**
53
+ * Poly1305 one-time MAC (RFC 8439 §2.5).
54
+ *
55
+ * Atomic (stateless) class: each `mac()` call is independent.
56
+ * The key must never be reused across messages. For most use cases, prefer
57
+ * `ChaCha20Poly1305` or `XChaCha20Poly1305` which manage the one-time key
58
+ * automatically.
59
+ */
15
60
  export declare class Poly1305 {
16
61
  private readonly x;
17
62
  constructor();
63
+ /**
64
+ * Compute a 16-byte Poly1305 MAC for `msg` using `key`.
65
+ * @param key 32-byte one-time key, must not be reused across messages
66
+ * @param msg Message to authenticate
67
+ * @returns 16-byte Poly1305 tag
68
+ */
18
69
  mac(key: Uint8Array, msg: Uint8Array): Uint8Array;
70
+ /** Wipe WASM MAC state. */
19
71
  dispose(): void;
20
72
  }
21
73
  /**
@@ -27,23 +79,45 @@ export declare class Poly1305 {
27
79
  * Single-use encrypt guard: `encrypt()` may only be called once per instance.
28
80
  * Create a new instance for each encryption to prevent nonce reuse.
29
81
  *
30
- * `decrypt()` uses constant-time tag comparison XOR-accumulate pattern,
82
+ * `decrypt()` uses constant-time tag comparison, XOR-accumulate pattern,
31
83
  * no early return on mismatch. Plaintext is never returned on failure.
32
84
  */
33
85
  export declare class ChaCha20Poly1305 {
34
86
  private readonly x;
35
87
  private _used;
36
88
  constructor();
89
+ /**
90
+ * Encrypt and authenticate `plaintext` with ChaCha20-Poly1305 (RFC 8439 §2.8).
91
+ *
92
+ * **Single-use guard:** `encrypt()` may only be called once per instance.
93
+ * Any throw, including validation errors, permanently locks this instance.
94
+ * Always create a new `ChaCha20Poly1305` per message.
95
+ * @param key 32 bytes
96
+ * @param nonce 12 bytes, must be unique per (key, message)
97
+ * @param plaintext Data to encrypt
98
+ * @param aad Additional authenticated data (optional)
99
+ * @returns Ciphertext || 16-byte Poly1305 tag
100
+ */
37
101
  encrypt(key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, aad?: Uint8Array): Uint8Array;
102
+ /**
103
+ * Verify and decrypt a ChaCha20-Poly1305 ciphertext (RFC 8439 §2.8).
104
+ * Throws `AuthenticationError` if the tag does not match.
105
+ * @param key 32 bytes
106
+ * @param nonce 12 bytes, must match the value used to encrypt
107
+ * @param ciphertext Ciphertext || 16-byte tag (combined format from `encrypt`)
108
+ * @param aad Additional authenticated data (optional)
109
+ * @returns Plaintext
110
+ */
38
111
  decrypt(key: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array, // ciphertext || tag(16) combined
39
112
  aad?: Uint8Array): Uint8Array;
113
+ /** Wipe WASM cipher and MAC state. */
40
114
  dispose(): void;
41
115
  }
42
116
  /**
43
117
  * XChaCha20-Poly1305 AEAD (IETF draft-irtf-cfrg-xchacha).
44
118
  *
45
119
  * Recommended authenticated encryption primitive for most use cases.
46
- * Uses a 24-byte nonce safe for random generation via crypto.getRandomValues.
120
+ * Uses a 24-byte nonce, safe for random generation via crypto.getRandomValues.
47
121
  *
48
122
  * Single-use encrypt guard: `encrypt()` may only be called once per instance.
49
123
  * Create a new instance for each encryption to prevent nonce reuse.
@@ -54,9 +128,32 @@ export declare class XChaCha20Poly1305 {
54
128
  private readonly x;
55
129
  private _used;
56
130
  constructor();
131
+ /**
132
+ * Encrypt and authenticate `plaintext` with XChaCha20-Poly1305
133
+ * (draft-irtf-cfrg-xchacha). Recommended for general-purpose AEAD.
134
+ *
135
+ * **Single-use guard:** `encrypt()` may only be called once per instance.
136
+ * Any throw, including validation errors, permanently locks this instance.
137
+ * Always create a new `XChaCha20Poly1305` per message to prevent nonce reuse.
138
+ * @param key 32 bytes
139
+ * @param nonce 24 bytes, safe to generate randomly via `randomBytes(24)`
140
+ * @param plaintext Data to encrypt
141
+ * @param aad Additional authenticated data (optional)
142
+ * @returns Ciphertext || 16-byte Poly1305 tag
143
+ */
57
144
  encrypt(key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, aad?: Uint8Array): Uint8Array;
145
+ /**
146
+ * Verify and decrypt an XChaCha20-Poly1305 ciphertext.
147
+ * Throws `AuthenticationError` if the tag does not match.
148
+ * @param key 32 bytes
149
+ * @param nonce 24 bytes, must match the value used to encrypt
150
+ * @param ciphertext Ciphertext || 16-byte tag (combined format from `encrypt`)
151
+ * @param aad Additional authenticated data (optional)
152
+ * @returns Plaintext
153
+ */
58
154
  decrypt(key: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array, aad?: Uint8Array): Uint8Array;
155
+ /** Wipe WASM cipher and MAC state. */
59
156
  dispose(): void;
60
157
  }
61
158
  export { XChaCha20Cipher } from './cipher-suite.js';
62
- export declare function _chachaReady(): boolean;
159
+ export { ChaCha20Generator } from './generator.js';
@@ -22,24 +22,49 @@
22
22
  // src/ts/chacha20/index.ts
23
23
  //
24
24
  // Public API classes for the ChaCha20 WASM module.
25
- // Uses the init() module cache call chacha20Init(source) before constructing.
26
- import { getInstance, initModule } from '../init.js';
25
+ // Uses the init() module cache, call chacha20Init(source) before constructing.
26
+ import { getInstance, initModule, _acquireModule, _releaseModule, _assertNotOwned } from '../init.js';
27
27
  import { aeadEncrypt, aeadDecrypt, xcEncrypt, xcDecrypt } from './ops.js';
28
28
  import { AuthenticationError } from '../errors.js';
29
29
  export { AuthenticationError };
30
+ /**
31
+ * Load and initialise the ChaCha20 WASM module from `source`.
32
+ * Must be called before constructing any ChaCha20 class.
33
+ * @param source WASM binary, gzip+base64 string, URL, ArrayBuffer, Uint8Array,
34
+ * pre-compiled WebAssembly.Module, Response, or Promise<Response>
35
+ */
30
36
  export async function chacha20Init(source) {
31
37
  return initModule('chacha20', source);
32
38
  }
39
+ export { isInitialized } from '../init.js';
40
+ /** Returns the raw chacha20 WASM export object. @internal */
33
41
  function getExports() {
34
42
  return getInstance('chacha20').exports;
35
43
  }
36
- // ── ChaCha20 ──────────────────────────────────────────────────────────────────
44
+ // ── ChaCha20 ────────────────────────────────────────────────────────────────
45
+ /**
46
+ * Raw ChaCha20 stream cipher (RFC 8439 §2.4).
47
+ *
48
+ * Holds exclusive access to the `chacha20` WASM module from construction
49
+ * until `dispose()`. Constructing a second ChaCha20 or any other chacha20
50
+ * user while this instance is live throws. Call `dispose()` when done.
51
+ */
37
52
  export class ChaCha20 {
38
53
  x;
54
+ _tok;
39
55
  constructor() {
40
56
  this.x = getExports();
57
+ this._tok = _acquireModule('chacha20');
41
58
  }
59
+ /**
60
+ * Load key and nonce into WASM state and set the block counter to 1.
61
+ * Must be called before each message (RFC 8439 §2.4).
62
+ * @param key 32 bytes
63
+ * @param nonce 12 bytes, must be unique per (key, message)
64
+ */
42
65
  beginEncrypt(key, nonce) {
66
+ if (this._tok === undefined)
67
+ throw new Error('ChaCha20: instance has been disposed');
43
68
  if (key.length !== 32)
44
69
  throw new RangeError(`ChaCha20 key must be 32 bytes (got ${key.length})`);
45
70
  if (nonce.length !== 12)
@@ -50,10 +75,17 @@ export class ChaCha20 {
50
75
  this.x.chachaSetCounter(1);
51
76
  this.x.chachaLoadKey();
52
77
  }
78
+ /**
79
+ * XOR `chunk` with the next keystream block(s). Counter advances automatically.
80
+ * @param chunk Plaintext chunk, must not exceed WASM CHUNK_SIZE
81
+ * @returns Ciphertext of the same length
82
+ */
53
83
  encryptChunk(chunk) {
84
+ if (this._tok === undefined)
85
+ throw new Error('ChaCha20: instance has been disposed');
54
86
  const maxChunk = this.x.getChunkSize();
55
87
  if (chunk.length > maxChunk)
56
- throw new RangeError(`chunk exceeds maximum size of ${maxChunk} bytes split into smaller chunks`);
88
+ throw new RangeError(`chunk exceeds maximum size of ${maxChunk} bytes, split into smaller chunks`);
57
89
  const mem = new Uint8Array(this.x.memory.buffer);
58
90
  const ptOff = this.x.getChunkPtOffset();
59
91
  const ctOff = this.x.getChunkCtOffset();
@@ -61,23 +93,57 @@ export class ChaCha20 {
61
93
  this.x.chachaEncryptChunk_simd(chunk.length);
62
94
  return mem.slice(ctOff, ctOff + chunk.length);
63
95
  }
96
+ /**
97
+ * Alias for `beginEncrypt`, ChaCha20 is a stream cipher (symmetric).
98
+ * @param key 32 bytes
99
+ * @param nonce 12 bytes, must match the value used to encrypt
100
+ */
64
101
  beginDecrypt(key, nonce) {
65
102
  this.beginEncrypt(key, nonce);
66
103
  }
104
+ /**
105
+ * Alias for `encryptChunk`, ChaCha20 is a stream cipher (symmetric).
106
+ * @param chunk Ciphertext chunk
107
+ * @returns Plaintext of the same length
108
+ */
67
109
  decryptChunk(chunk) {
68
110
  return this.encryptChunk(chunk);
69
111
  }
112
+ /** Wipe WASM state and release exclusive module access. Idempotent. */
70
113
  dispose() {
71
- this.x.wipeBuffers();
114
+ if (this._tok === undefined)
115
+ return;
116
+ try {
117
+ this.x.wipeBuffers();
118
+ }
119
+ finally {
120
+ _releaseModule('chacha20', this._tok);
121
+ this._tok = undefined;
122
+ }
72
123
  }
73
124
  }
74
- // ── Poly1305 ──────────────────────────────────────────────────────────────────
125
+ // ── Poly1305 ────────────────────────────────────────────────────────────────
126
+ /**
127
+ * Poly1305 one-time MAC (RFC 8439 §2.5).
128
+ *
129
+ * Atomic (stateless) class: each `mac()` call is independent.
130
+ * The key must never be reused across messages. For most use cases, prefer
131
+ * `ChaCha20Poly1305` or `XChaCha20Poly1305` which manage the one-time key
132
+ * automatically.
133
+ */
75
134
  export class Poly1305 {
76
135
  x;
77
136
  constructor() {
78
137
  this.x = getExports();
79
138
  }
139
+ /**
140
+ * Compute a 16-byte Poly1305 MAC for `msg` using `key`.
141
+ * @param key 32-byte one-time key, must not be reused across messages
142
+ * @param msg Message to authenticate
143
+ * @returns 16-byte Poly1305 tag
144
+ */
80
145
  mac(key, msg) {
146
+ _assertNotOwned('chacha20');
81
147
  if (key.length !== 32)
82
148
  throw new RangeError(`Poly1305 key must be 32 bytes (got ${key.length})`);
83
149
  const mem = new Uint8Array(this.x.memory.buffer);
@@ -96,11 +162,13 @@ export class Poly1305 {
96
162
  this.x.polyFinal();
97
163
  return new Uint8Array(this.x.memory.buffer).slice(tagOff, tagOff + 16);
98
164
  }
165
+ /** Wipe WASM MAC state. */
99
166
  dispose() {
167
+ _assertNotOwned('chacha20');
100
168
  this.x.wipeBuffers();
101
169
  }
102
170
  }
103
- // ── ChaCha20Poly1305 ─────────────────────────────────────────────────────────
171
+ // ── ChaCha20Poly1305 ────────────────────────────────────────────────────────
104
172
  /**
105
173
  * ChaCha20-Poly1305 AEAD (RFC 8439 §2.8).
106
174
  *
@@ -110,7 +178,7 @@ export class Poly1305 {
110
178
  * Single-use encrypt guard: `encrypt()` may only be called once per instance.
111
179
  * Create a new instance for each encryption to prevent nonce reuse.
112
180
  *
113
- * `decrypt()` uses constant-time tag comparison XOR-accumulate pattern,
181
+ * `decrypt()` uses constant-time tag comparison, XOR-accumulate pattern,
114
182
  * no early return on mismatch. Plaintext is never returned on failure.
115
183
  */
116
184
  export class ChaCha20Poly1305 {
@@ -119,43 +187,80 @@ export class ChaCha20Poly1305 {
119
187
  constructor() {
120
188
  this.x = getExports();
121
189
  }
190
+ /**
191
+ * Encrypt and authenticate `plaintext` with ChaCha20-Poly1305 (RFC 8439 §2.8).
192
+ *
193
+ * **Single-use guard:** `encrypt()` may only be called once per instance.
194
+ * Any throw, including validation errors, permanently locks this instance.
195
+ * Always create a new `ChaCha20Poly1305` per message.
196
+ * @param key 32 bytes
197
+ * @param nonce 12 bytes, must be unique per (key, message)
198
+ * @param plaintext Data to encrypt
199
+ * @param aad Additional authenticated data (optional)
200
+ * @returns Ciphertext || 16-byte Poly1305 tag
201
+ */
122
202
  encrypt(key, nonce, plaintext, aad = new Uint8Array(0)) {
123
203
  if (this._used)
124
204
  throw new Error('leviathan-crypto: encrypt() already called on this instance. '
125
205
  + 'Create a new instance for each encryption to prevent nonce reuse.');
206
+ // Strict single-use: lock FIRST, before anything else. Any subsequent
207
+ // throw, including validation errors, terminates the instance.
208
+ this._used = true;
209
+ _assertNotOwned('chacha20');
126
210
  if (key.length !== 32)
127
211
  throw new RangeError(`key must be 32 bytes (got ${key.length})`);
128
212
  if (nonce.length !== 12)
129
213
  throw new RangeError(`nonce must be 12 bytes (got ${nonce.length})`);
130
- const { ciphertext, tag } = aeadEncrypt(this.x, key, nonce, plaintext, aad);
131
- this._used = true;
132
- const out = new Uint8Array(ciphertext.length + 16);
133
- out.set(ciphertext);
134
- out.set(tag, ciphertext.length);
135
- return out;
214
+ try {
215
+ const { ciphertext, tag } = aeadEncrypt(this.x, key, nonce, plaintext, aad);
216
+ const out = new Uint8Array(ciphertext.length + 16);
217
+ out.set(ciphertext);
218
+ out.set(tag, ciphertext.length);
219
+ return out;
220
+ }
221
+ finally {
222
+ this.x.wipeBuffers();
223
+ }
136
224
  }
225
+ /**
226
+ * Verify and decrypt a ChaCha20-Poly1305 ciphertext (RFC 8439 §2.8).
227
+ * Throws `AuthenticationError` if the tag does not match.
228
+ * @param key 32 bytes
229
+ * @param nonce 12 bytes, must match the value used to encrypt
230
+ * @param ciphertext Ciphertext || 16-byte tag (combined format from `encrypt`)
231
+ * @param aad Additional authenticated data (optional)
232
+ * @returns Plaintext
233
+ */
137
234
  decrypt(key, nonce, ciphertext, // ciphertext || tag(16) combined
138
235
  aad = new Uint8Array(0)) {
236
+ _assertNotOwned('chacha20');
139
237
  if (key.length !== 32)
140
238
  throw new RangeError(`key must be 32 bytes (got ${key.length})`);
141
239
  if (nonce.length !== 12)
142
240
  throw new RangeError(`nonce must be 12 bytes (got ${nonce.length})`);
143
241
  if (ciphertext.length < 16)
144
- throw new RangeError(`ciphertext too short must include 16-byte tag (got ${ciphertext.length})`);
145
- const ct = ciphertext.subarray(0, ciphertext.length - 16);
146
- const tag = ciphertext.subarray(ciphertext.length - 16);
147
- return aeadDecrypt(this.x, key, nonce, ct, tag, aad);
242
+ throw new RangeError(`ciphertext too short, must include 16-byte tag (got ${ciphertext.length})`);
243
+ try {
244
+ const ct = ciphertext.subarray(0, ciphertext.length - 16);
245
+ const tag = ciphertext.subarray(ciphertext.length - 16);
246
+ return aeadDecrypt(this.x, key, nonce, ct, tag, aad);
247
+ }
248
+ finally {
249
+ this.x.wipeBuffers();
250
+ }
148
251
  }
252
+ /** Wipe WASM cipher and MAC state. */
149
253
  dispose() {
254
+ _assertNotOwned('chacha20');
150
255
  this.x.wipeBuffers();
151
256
  }
152
257
  }
153
- // ── XChaCha20Poly1305 ────────────────────────────────────────────────────────
258
+ // ── XChaCha20Poly1305 ───────────────────────────────────────────────────────
154
259
  /**
155
260
  * XChaCha20-Poly1305 AEAD (IETF draft-irtf-cfrg-xchacha).
156
261
  *
157
262
  * Recommended authenticated encryption primitive for most use cases.
158
- * Uses a 24-byte nonce safe for random generation via crypto.getRandomValues.
263
+ * Uses a 24-byte nonce, safe for random generation via crypto.getRandomValues.
159
264
  *
160
265
  * Single-use encrypt guard: `encrypt()` may only be called once per instance.
161
266
  * Create a new instance for each encryption to prevent nonce reuse.
@@ -168,39 +273,68 @@ export class XChaCha20Poly1305 {
168
273
  constructor() {
169
274
  this.x = getExports();
170
275
  }
276
+ /**
277
+ * Encrypt and authenticate `plaintext` with XChaCha20-Poly1305
278
+ * (draft-irtf-cfrg-xchacha). Recommended for general-purpose AEAD.
279
+ *
280
+ * **Single-use guard:** `encrypt()` may only be called once per instance.
281
+ * Any throw, including validation errors, permanently locks this instance.
282
+ * Always create a new `XChaCha20Poly1305` per message to prevent nonce reuse.
283
+ * @param key 32 bytes
284
+ * @param nonce 24 bytes, safe to generate randomly via `randomBytes(24)`
285
+ * @param plaintext Data to encrypt
286
+ * @param aad Additional authenticated data (optional)
287
+ * @returns Ciphertext || 16-byte Poly1305 tag
288
+ */
171
289
  encrypt(key, nonce, plaintext, aad = new Uint8Array(0)) {
172
290
  if (this._used)
173
291
  throw new Error('leviathan-crypto: encrypt() already called on this instance. '
174
292
  + 'Create a new instance for each encryption to prevent nonce reuse.');
293
+ // Strict single-use: lock FIRST, before anything else. Any subsequent
294
+ // throw, including validation errors, terminates the instance.
295
+ this._used = true;
296
+ _assertNotOwned('chacha20');
175
297
  if (key.length !== 32)
176
298
  throw new RangeError(`key must be 32 bytes (got ${key.length})`);
177
299
  if (nonce.length !== 24)
178
300
  throw new RangeError(`XChaCha20 nonce must be 24 bytes (got ${nonce.length})`);
179
- const result = xcEncrypt(this.x, key, nonce, plaintext, aad);
180
- this._used = true;
181
- return result;
301
+ try {
302
+ return xcEncrypt(this.x, key, nonce, plaintext, aad);
303
+ }
304
+ finally {
305
+ this.x.wipeBuffers();
306
+ }
182
307
  }
308
+ /**
309
+ * Verify and decrypt an XChaCha20-Poly1305 ciphertext.
310
+ * Throws `AuthenticationError` if the tag does not match.
311
+ * @param key 32 bytes
312
+ * @param nonce 24 bytes, must match the value used to encrypt
313
+ * @param ciphertext Ciphertext || 16-byte tag (combined format from `encrypt`)
314
+ * @param aad Additional authenticated data (optional)
315
+ * @returns Plaintext
316
+ */
183
317
  decrypt(key, nonce, ciphertext, aad = new Uint8Array(0)) {
318
+ _assertNotOwned('chacha20');
184
319
  if (key.length !== 32)
185
320
  throw new RangeError(`key must be 32 bytes (got ${key.length})`);
186
321
  if (nonce.length !== 24)
187
322
  throw new RangeError(`XChaCha20 nonce must be 24 bytes (got ${nonce.length})`);
188
323
  if (ciphertext.length < 16)
189
- throw new RangeError(`ciphertext too short must include 16-byte tag (got ${ciphertext.length})`);
190
- return xcDecrypt(this.x, key, nonce, ciphertext, aad);
324
+ throw new RangeError(`ciphertext too short, must include 16-byte tag (got ${ciphertext.length})`);
325
+ try {
326
+ return xcDecrypt(this.x, key, nonce, ciphertext, aad);
327
+ }
328
+ finally {
329
+ this.x.wipeBuffers();
330
+ }
191
331
  }
332
+ /** Wipe WASM cipher and MAC state. */
192
333
  dispose() {
334
+ _assertNotOwned('chacha20');
193
335
  this.x.wipeBuffers();
194
336
  }
195
337
  }
196
338
  export { XChaCha20Cipher } from './cipher-suite.js';
197
- // ── Ready check ──────────────────────────────────────────────────────────────
198
- export function _chachaReady() {
199
- try {
200
- getInstance('chacha20');
201
- return true;
202
- }
203
- catch {
204
- return false;
205
- }
206
- }
339
+ // ── ChaCha20Generator ───────────────────────────────────────────────────────
340
+ export { ChaCha20Generator } from './generator.js';
@@ -1,16 +1,67 @@
1
1
  import type { ChaChaExports } from './types.js';
2
- /** ChaCha20-Poly1305 AEAD encrypt (RFC 8439 §2.8). */
2
+ /**
3
+ * ChaCha20-Poly1305 AEAD encrypt (RFC 8439 §2.8).
4
+ * @param x ChaCha20 WASM exports
5
+ * @param key 32-byte key
6
+ * @param nonce 12-byte nonce, must be unique per (key, message)
7
+ * @param plaintext Data to encrypt (must be ≤ WASM CHUNK_SIZE)
8
+ * @param aad Additional authenticated data
9
+ * @returns `{ ciphertext, tag }`, tag is 16 bytes
10
+ */
3
11
  export declare function aeadEncrypt(x: ChaChaExports, key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, aad: Uint8Array): {
4
12
  ciphertext: Uint8Array;
5
13
  tag: Uint8Array;
6
14
  };
7
- /** ChaCha20-Poly1305 AEAD decrypt (RFC 8439 §2.8). Constant-time tag comparison. */
15
+ /**
16
+ * ChaCha20-Poly1305 AEAD decrypt with constant-time tag comparison (RFC 8439 §2.8).
17
+ * Throws `AuthenticationError` on tag mismatch; never returns plaintext on failure.
18
+ * @param x ChaCha20 WASM exports
19
+ * @param key 32-byte key
20
+ * @param nonce 12-byte nonce, must match the value used to encrypt
21
+ * @param ciphertext Ciphertext bytes (must be ≤ WASM CHUNK_SIZE)
22
+ * @param tag 16-byte Poly1305 tag
23
+ * @param aad Additional authenticated data
24
+ * @param cipherName Error label for `AuthenticationError` (default 'chacha20-poly1305')
25
+ * @returns Plaintext
26
+ */
8
27
  export declare function aeadDecrypt(x: ChaChaExports, key: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array, tag: Uint8Array, aad: Uint8Array, cipherName?: string): Uint8Array;
9
- /** HChaCha20 subkey derivation — first 16 bytes of nonce. */
28
+ /**
29
+ * Derive a 32-byte HChaCha20 subkey from `key` and the first 16 bytes of `nonce`.
30
+ * Used as the inner key for XChaCha20-Poly1305 (draft-irtf-cfrg-xchacha §2.3).
31
+ * @param x ChaCha20 WASM exports
32
+ * @param key 32-byte master key
33
+ * @param nonce 24-byte XChaCha20 nonce (only bytes 0-15 are used)
34
+ * @returns 32-byte HChaCha20 subkey
35
+ */
10
36
  export declare function deriveSubkey(x: ChaChaExports, key: Uint8Array, nonce: Uint8Array): Uint8Array;
11
- /** Build inner 12-byte nonce from bytes 16–23 of XChaCha nonce. */
37
+ /**
38
+ * Build the inner 12-byte ChaCha20 nonce for XChaCha20 from bytes 16-23 of the
39
+ * 24-byte XChaCha nonce (draft-irtf-cfrg-xchacha §2.3).
40
+ * @param nonce 24-byte XChaCha20 nonce
41
+ * @returns 12-byte inner nonce (bytes 0-3 are zero, bytes 4-11 are nonce[16:24])
42
+ */
12
43
  export declare function innerNonce(nonce: Uint8Array): Uint8Array;
13
- /** XChaCha20-Poly1305 encrypt → ciphertext || tag. */
44
+ /**
45
+ * XChaCha20-Poly1305 encrypt (draft-irtf-cfrg-xchacha).
46
+ * Derives HChaCha20 subkey from `key` + nonce[0:16], then runs
47
+ * ChaCha20-Poly1305 with a 12-byte inner nonce (nonce[16:24]).
48
+ * @param x ChaCha20 WASM exports
49
+ * @param key 32-byte key
50
+ * @param nonce 24-byte nonce
51
+ * @param plaintext Data to encrypt
52
+ * @param aad Additional authenticated data
53
+ * @returns Ciphertext || 16-byte Poly1305 tag
54
+ */
14
55
  export declare function xcEncrypt(x: ChaChaExports, key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, aad: Uint8Array): Uint8Array;
15
- /** XChaCha20-Poly1305 decrypt → plaintext (throws on auth failure). */
56
+ /**
57
+ * XChaCha20-Poly1305 decrypt (draft-irtf-cfrg-xchacha).
58
+ * Derives HChaCha20 subkey, verifies the Poly1305 tag, then decrypts.
59
+ * Throws `AuthenticationError` on tag mismatch.
60
+ * @param x ChaCha20 WASM exports
61
+ * @param key 32-byte key
62
+ * @param nonce 24-byte nonce, must match the value used to encrypt
63
+ * @param ciphertext Ciphertext || 16-byte tag (combined format from `xcEncrypt`)
64
+ * @param aad Additional authenticated data
65
+ * @returns Plaintext
66
+ */
16
67
  export declare function xcDecrypt(x: ChaChaExports, key: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array, aad: Uint8Array): Uint8Array;