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,674 +0,0 @@
1
- # ChaCha20 TypeScript API
2
-
3
- > [!NOTE]
4
- > API reference for `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, and `XChaCha20Cipher`. Covers initialization, all class methods, usage examples, and error conditions.
5
-
6
- > ### Table of Contents
7
- > - [Overview](#overview)
8
- > - [Security Notes](#security-notes)
9
- > - [Module Init](#module-init)
10
- > - [API Reference](#api-reference)
11
- > - [`ChaCha20`](#chacha20)
12
- > - [`Poly1305`](#poly1305)
13
- > - [`ChaCha20Poly1305`](#chacha20poly1305)
14
- > - [`XChaCha20Poly1305`](#xchacha20poly1305)
15
- > - [XChaCha20Cipher](#xchacha20cipher)
16
- > - [Usage Examples](#usage-examples)
17
- > - [Error Conditions](#error-conditions)
18
-
19
- ---
20
-
21
- ## Overview
22
-
23
- **ChaCha20** is a modern stream cipher designed by Daniel J. Bernstein. It is fast
24
- on all platforms (including those without hardware AES), resistant to timing attacks
25
- by design, and widely deployed in TLS, SSH, and WireGuard. ChaCha20 encrypts data
26
- by generating a pseudorandom keystream from a 256-bit key and a nonce, then XORing
27
- it with the plaintext. It does **not** provide authentication on its own. A modified message will decrypt to garbage with no warning.
28
-
29
- **Poly1305** is a one-time message authentication code (MAC). Given a unique 256-bit
30
- key and a message, it produces a 16-byte tag that proves the message has not been
31
- tampered with. The critical requirement is that each Poly1305 key is used **exactly
32
- once**. Reusing a key completely breaks its security. You almost never need to use
33
- Poly1305 directly; the AEAD constructions below handle key derivation for you.
34
-
35
- **ChaCha20-Poly1305** (RFC 8439) combines both primitives into an AEAD
36
- (Authenticated Encryption with Associated Data). It encrypts your data and
37
- produces an authentication tag in a single operation. On decryption, it verifies
38
- the tag before returning any plaintext. If someone tampered with the ciphertext,
39
- you get an error instead of corrupted data. The nonce is 96 bits (12 bytes).
40
-
41
- **XChaCha20-Poly1305** extends the nonce to 192 bits (24 bytes) using the HChaCha20
42
- subkey derivation step. This makes random nonce generation completely safe. With a
43
- 24-byte nonce, the probability of a collision is negligible even after billions of
44
- messages. **For most users, `Seal` with `XChaCha20Cipher` is the recommended choice.** It
45
- produces a self-contained authenticated blob with no nonce management, no
46
- instantiation, and no `dispose()`. For protocol interop requiring explicit nonce
47
- control, use `XChaCha20Poly1305` directly.
48
-
49
- ---
50
-
51
- ## Security Notes
52
-
53
- > [!IMPORTANT]
54
- > Read this section before writing any code. These are not theoretical concerns.
55
- > They are the mistakes that cause real-world breaches.
56
-
57
- - **Use `Seal` with `XChaCha20Cipher` unless you need explicit nonce control.**
58
- It is the safest default: authenticated encryption in a single static call.
59
- If you are unsure which class to pick, pick this one. Use `XChaCha20Poly1305`
60
- when protocol interop requires you to manage nonces yourself.
61
-
62
- - **Never reuse a nonce with the same key.** This is the single most important
63
- rule. If you encrypt two different messages with the same key and the same nonce,
64
- an attacker can XOR the two ciphertexts together and recover both plaintexts.
65
- With `ChaCha20Poly1305` (12-byte nonce), random generation has a meaningful
66
- collision risk after roughly 2^32 messages under one key. With
67
- `XChaCha20Poly1305` (24-byte nonce), random generation is safe for any practical
68
- message count. Just call `randomBytes(24)` for each message.
69
-
70
- - **Poly1305 keys are single-use.** Each Poly1305 key must be used to authenticate
71
- exactly one message. The AEAD classes (`ChaCha20Poly1305` and
72
- `XChaCha20Poly1305`) handle this automatically by deriving a fresh Poly1305 key
73
- from the ChaCha20 keystream for each encryption. If you use the standalone
74
- `Poly1305` class directly, it is your responsibility to never reuse a key.
75
-
76
- - **AEAD protects both confidentiality and authenticity.** If authentication fails
77
- during decryption, the plaintext is never returned. You get an error. This is
78
- intentional. Do not try to work around it. If decryption fails, the ciphertext was corrupted or tampered with.
79
-
80
- - **Associated data (AAD) is authenticated but not encrypted.** Use AAD for data
81
- that must travel in the clear (headers, routing metadata, user IDs) but must be
82
- verified as unmodified. If someone changes the AAD, decryption will fail even
83
- if the ciphertext itself is untouched.
84
-
85
- - **Always call `dispose()` when you are done.** This wipes key material and
86
- intermediate state from WASM memory. Failing to call `dispose()` leaves
87
- sensitive data in memory longer than necessary.
88
-
89
- - **`ChaCha20` alone has no authentication.** If you use the raw `ChaCha20` class
90
- without pairing it with a MAC, an attacker can flip bits in the ciphertext and
91
- the corresponding bits in the plaintext will flip silently. Unless you are
92
- building your own authenticated construction (and you probably should not be),
93
- use one of the AEAD classes instead.
94
-
95
- ---
96
-
97
- ## Module Init
98
-
99
- Each module subpath exports its own init function for consumers who want
100
- tree-shakeable imports.
101
-
102
- ### `chacha20Init(source)`
103
-
104
- Initializes only the chacha20 WASM binary. Equivalent to calling the
105
- root `init({ chacha20: chacha20Wasm })` but without pulling the other three
106
- modules into the bundle.
107
-
108
- **Signature:**
109
-
110
- ```typescript
111
- async function chacha20Init(source: WasmSource): Promise<void>
112
- ```
113
-
114
- **Usage:**
115
-
116
- ```typescript
117
- import { chacha20Init, XChaCha20Poly1305 } from 'leviathan-crypto/chacha20'
118
- import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
119
-
120
- await chacha20Init(chacha20Wasm)
121
- const aead = new XChaCha20Poly1305()
122
- ```
123
-
124
- ---
125
-
126
- ## API Reference
127
-
128
- All classes require calling `await init({ chacha20: chacha20Wasm })` or the subpath `chacha20Init()`
129
- before construction. If you construct a class before initialization, it throws:
130
- ```
131
- Error: leviathan-crypto: call init({ chacha20: ... }) before using this class
132
- ```
133
-
134
- ---
135
-
136
- ### `ChaCha20`
137
-
138
- Raw ChaCha20 stream cipher. **No authentication.** Use `XChaCha20Poly1305` instead
139
- unless you are building a custom protocol and understand the risks.
140
-
141
- #### Constructor
142
-
143
- ```typescript
144
- new ChaCha20()
145
- ```
146
-
147
- Throws if `init({ chacha20: chacha20Wasm })` has not been called.
148
-
149
- ---
150
-
151
- #### `beginEncrypt(key: Uint8Array, nonce: Uint8Array): void`
152
-
153
- Prepares the cipher for encryption with the given key and nonce.
154
-
155
- | Parameter | Type | Description |
156
- |-----------|------|-------------|
157
- | `key` | `Uint8Array` | 32 bytes (256 bits) |
158
- | `nonce` | `Uint8Array` | 12 bytes (96 bits) |
159
-
160
- **Throws** `RangeError` if `key` is not 32 bytes or `nonce` is not 12 bytes.
161
-
162
- ---
163
-
164
- #### `encryptChunk(chunk: Uint8Array): Uint8Array`
165
-
166
- Encrypts a chunk of plaintext. Call repeatedly for streaming encryption. Returns
167
- a new `Uint8Array` containing the ciphertext (same length as input).
168
-
169
- | Parameter | Type | Description |
170
- |-----------|------|-------------|
171
- | `chunk` | `Uint8Array` | Plaintext bytes (up to the module's chunk size limit) |
172
-
173
- **Throws** `RangeError` if the chunk exceeds the maximum chunk size.
174
-
175
- ---
176
-
177
- #### `beginDecrypt(key: Uint8Array, nonce: Uint8Array): void`
178
-
179
- Prepares the cipher for decryption. Identical to `beginEncrypt`. ChaCha20 is symmetric; encryption and decryption are the same XOR operation.
180
-
181
- | Parameter | Type | Description |
182
- |-----------|------|-------------|
183
- | `key` | `Uint8Array` | 32 bytes (256 bits) |
184
- | `nonce` | `Uint8Array` | 12 bytes (96 bits) |
185
-
186
- **Throws** `RangeError` if `key` is not 32 bytes or `nonce` is not 12 bytes.
187
-
188
- ---
189
-
190
- #### `decryptChunk(chunk: Uint8Array): Uint8Array`
191
-
192
- Decrypts a chunk of ciphertext. Returns a new `Uint8Array` containing the
193
- plaintext (same length as input).
194
-
195
- | Parameter | Type | Description |
196
- |-----------|------|-------------|
197
- | `chunk` | `Uint8Array` | Ciphertext bytes |
198
-
199
- **Throws** `RangeError` if the chunk exceeds the maximum chunk size.
200
-
201
- ---
202
-
203
- #### `dispose(): void`
204
-
205
- Wipes all key material and intermediate state from WASM memory. Always call this
206
- when you are done with the instance.
207
-
208
- ---
209
-
210
- ### `Poly1305`
211
-
212
- Standalone Poly1305 one-time MAC. **Each key must be used exactly once.** You
213
- almost certainly want `ChaCha20Poly1305` or `XChaCha20Poly1305` instead. They
214
- handle Poly1305 key derivation automatically.
215
-
216
- #### Constructor
217
-
218
- ```typescript
219
- new Poly1305()
220
- ```
221
-
222
- Throws if `init({ chacha20: chacha20Wasm })` has not been called.
223
-
224
- ---
225
-
226
- #### `mac(key: Uint8Array, msg: Uint8Array): Uint8Array`
227
-
228
- Computes a 16-byte Poly1305 authentication tag over the given message.
229
-
230
- | Parameter | Type | Description |
231
- |-----------|------|-------------|
232
- | `key` | `Uint8Array` | 32 bytes. Must be unique per message. |
233
- | `msg` | `Uint8Array` | The message to authenticate (any length) |
234
-
235
- **Returns** `Uint8Array`: a 16-byte authentication tag.
236
-
237
- **Throws** `RangeError` if `key` is not 32 bytes.
238
-
239
- ---
240
-
241
- #### `dispose(): void`
242
-
243
- Wipes all key material and intermediate state from WASM memory.
244
-
245
- ---
246
-
247
- ### `ChaCha20Poly1305`
248
-
249
- ChaCha20-Poly1305 AEAD as specified in RFC 8439. Provides authenticated encryption
250
- with a 12-byte (96-bit) nonce. The Poly1305 one-time key is derived automatically
251
- from the ChaCha20 keystream (counter 0).
252
-
253
- If you are generating nonces randomly, prefer `XChaCha20Poly1305` (24-byte nonce)
254
- to avoid collision risk.
255
-
256
- #### Constructor
257
-
258
- ```typescript
259
- new ChaCha20Poly1305()
260
- ```
261
-
262
- Throws if `init({ chacha20: chacha20Wasm })` has not been called.
263
-
264
- ---
265
-
266
- #### `encrypt(key, nonce, plaintext, aad?): Uint8Array`
267
-
268
- Encrypts plaintext and returns the ciphertext with the 16-byte Poly1305 tag
269
- appended.
270
-
271
- > [!WARNING]
272
- > Each `ChaCha20Poly1305` instance allows only **one** `encrypt()` call. A second
273
- > call throws to prevent accidental nonce reuse. Create a new instance for each
274
- > encryption, or use `Seal` with `XChaCha20Cipher` for automatic nonce management.
275
-
276
- | Parameter | Type | Default | Description |
277
- |-----------|------|---------|-------------|
278
- | `key` | `Uint8Array` | | 32 bytes (256-bit key) |
279
- | `nonce` | `Uint8Array` | | 12 bytes (96-bit nonce) |
280
- | `plaintext` | `Uint8Array` | | Data to encrypt (up to the module's chunk size limit) |
281
- | `aad` | `Uint8Array` | `new Uint8Array(0)` | Associated data. Authenticated but not encrypted. |
282
-
283
- **Returns** `Uint8Array`: ciphertext + 16-byte tag (length = plaintext.length + 16).
284
-
285
- **Throws:**
286
- - `RangeError` if `key` is not 32 bytes
287
- - `RangeError` if `nonce` is not 12 bytes
288
- - `RangeError` if `plaintext` exceeds the maximum chunk size
289
- - `Error` if `encrypt()` has already been called on this instance
290
-
291
- ---
292
-
293
- #### `decrypt(key, nonce, ciphertext, aad?): Uint8Array`
294
-
295
- Verifies the authentication tag and decrypts the ciphertext. The `ciphertext`
296
- parameter must include the appended 16-byte tag (i.e., the exact output of
297
- `encrypt()`). If authentication fails, an error is thrown and no plaintext is
298
- returned.
299
-
300
- Tag comparison uses a constant-time XOR-accumulate pattern; no timing side channel leaks whether the tag was "close" to correct.
301
-
302
- | Parameter | Type | Default | Description |
303
- |-----------|------|---------|-------------|
304
- | `key` | `Uint8Array` | | 32 bytes (same key used for encryption) |
305
- | `nonce` | `Uint8Array` | | 12 bytes (same nonce used for encryption) |
306
- | `ciphertext` | `Uint8Array` | | Encrypted data with appended tag (output of `encrypt()`) |
307
- | `aad` | `Uint8Array` | `new Uint8Array(0)` | Associated data (must match what was passed to `encrypt()`) |
308
-
309
- **Returns** `Uint8Array`: the decrypted plaintext.
310
-
311
- **Throws:**
312
- - `RangeError` if `key` is not 32 bytes
313
- - `RangeError` if `nonce` is not 12 bytes
314
- - `RangeError` if `ciphertext` is shorter than 16 bytes (no room for a tag)
315
- - `Error('ChaCha20Poly1305: authentication failed')` if the tag does not match
316
-
317
- ---
318
-
319
- #### `dispose(): void`
320
-
321
- Wipes all key material and intermediate state from WASM memory.
322
-
323
- ---
324
-
325
- ### `XChaCha20Poly1305`
326
-
327
- XChaCha20-Poly1305 AEAD (draft-irtf-cfrg-xchacha). RFC-faithful stateless
328
- primitive. Key and nonce are passed per-call. Use when protocol interop
329
- requires explicit nonce control. For most use cases, prefer `Seal` with
330
- `XChaCha20Cipher` (automatic nonce management, no instantiation).
331
-
332
- It uses a 24-byte (192-bit) nonce, which is large enough that randomly generated
333
- nonces will never collide in practice. Internally, it derives a subkey via
334
- HChaCha20 and delegates to `ChaCha20Poly1305`.
335
-
336
- Like `ChaCha20Poly1305`, the `encrypt()` method returns a single `Uint8Array`
337
- with the tag appended to the ciphertext. The `decrypt()` method expects this
338
- combined format and splits it internally.
339
-
340
- #### Constructor
341
-
342
- ```typescript
343
- new XChaCha20Poly1305()
344
- ```
345
-
346
- Throws if `init({ chacha20: chacha20Wasm })` has not been called.
347
-
348
- ---
349
-
350
- #### `encrypt(key, nonce, plaintext, aad?): Uint8Array`
351
-
352
- Encrypts plaintext and returns the ciphertext with the 16-byte tag appended.
353
-
354
- | Parameter | Type | Default | Description |
355
- |-----------|------|---------|-------------|
356
- | `key` | `Uint8Array` | | 32 bytes (256-bit key) |
357
- | `nonce` | `Uint8Array` | | 24 bytes (192-bit nonce) |
358
- | `plaintext` | `Uint8Array` | | Data to encrypt |
359
- | `aad` | `Uint8Array` | `new Uint8Array(0)` | Associated data. Authenticated but not encrypted. |
360
-
361
- **Returns** `Uint8Array`: ciphertext + 16-byte tag (length = plaintext.length + 16).
362
-
363
- **Throws:**
364
- - `RangeError` if `key` is not 32 bytes
365
- - `RangeError` if `nonce` is not 24 bytes
366
-
367
- ---
368
-
369
- #### `decrypt(key, nonce, ciphertext, aad?): Uint8Array`
370
-
371
- Verifies the authentication tag and decrypts the ciphertext. The `ciphertext`
372
- parameter must include the appended 16-byte tag (i.e., the exact output of
373
- `encrypt()`).
374
-
375
- | Parameter | Type | Default | Description |
376
- |-----------|------|---------|-------------|
377
- | `key` | `Uint8Array` | | 32 bytes (same key used for encryption) |
378
- | `nonce` | `Uint8Array` | | 24 bytes (same nonce used for encryption) |
379
- | `ciphertext` | `Uint8Array` | | Encrypted data with appended tag (output of `encrypt()`) |
380
- | `aad` | `Uint8Array` | `new Uint8Array(0)` | Associated data (must match what was passed to `encrypt()`) |
381
-
382
- **Returns** `Uint8Array`: the decrypted plaintext.
383
-
384
- **Throws:**
385
- - `RangeError` if `key` is not 32 bytes
386
- - `RangeError` if `nonce` is not 24 bytes
387
- - `RangeError` if `ciphertext` is shorter than 16 bytes (no room for a tag)
388
- - `Error('ChaCha20Poly1305: authentication failed')` if the tag does not match
389
-
390
- ---
391
-
392
- #### `dispose(): void`
393
-
394
- Wipes all key material and intermediate state from WASM memory.
395
-
396
- ---
397
-
398
- ## XChaCha20Cipher
399
-
400
- `CipherSuite` implementation for XChaCha20-Poly1305. Pass to `Seal`,
401
- `SealStream`, or `OpenStream`. Never instantiated directly.
402
-
403
- Requires `init({ chacha20: chacha20Wasm, sha2: sha2Wasm })`.
404
-
405
- > [!NOTE]
406
- > `sha2` is required by the stream layer for HKDF key derivation, not by
407
- > `XChaCha20Poly1305` itself.
408
-
409
- | Property | Value |
410
- |----------|-------|
411
- | `formatEnum` | `0x01` |
412
- | `keySize` | `32` |
413
- | `tagSize` | `16` (Poly1305) |
414
- | `padded` | `false` |
415
- | `wasmModules` | `['chacha20', 'sha2']` |
416
-
417
- #### `XChaCha20Cipher.keygen(): Uint8Array`
418
-
419
- Returns `randomBytes(32)`. Convenience method. Not on the `CipherSuite` interface.
420
-
421
- #### Usage with `Seal`
422
-
423
- ```typescript
424
- import { init, Seal, XChaCha20Cipher } from 'leviathan-crypto'
425
- import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
426
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
427
-
428
- await init({ chacha20: chacha20Wasm, sha2: sha2Wasm })
429
-
430
- const key = XChaCha20Cipher.keygen()
431
- const blob = Seal.encrypt(XChaCha20Cipher, key, plaintext)
432
- const pt = Seal.decrypt(XChaCha20Cipher, key, blob) // throws on tamper
433
- ```
434
-
435
- #### Usage with `SealStream` / `OpenStream`
436
-
437
- ```typescript
438
- import { SealStream, OpenStream } from 'leviathan-crypto/stream'
439
- import { XChaCha20Cipher } from 'leviathan-crypto/chacha20'
440
-
441
- const sealer = new SealStream(XChaCha20Cipher, key)
442
- const preamble = sealer.preamble // 20 bytes, send before first chunk
443
- const ct0 = sealer.push(chunk0)
444
- const ctLast = sealer.finalize(lastChunk)
445
-
446
- const opener = new OpenStream(XChaCha20Cipher, key, preamble)
447
- const pt0 = opener.pull(ct0)
448
- const ptLast = opener.finalize(ctLast)
449
- ```
450
-
451
- See [aead.md](./aead.md) for the full `Seal`, `SealStream`, and `OpenStream` API.
452
-
453
- ---
454
-
455
- ## Usage Examples
456
-
457
- ### Example 1: Seal with XChaCha20Cipher (recommended)
458
-
459
- One-shot AEAD. No instantiation, no `dispose()`. The blob format is
460
- `preamble(20) || ciphertext || tag(16)`.
461
-
462
- ```typescript
463
- import { init, Seal, XChaCha20Cipher, utf8ToBytes, bytesToUtf8 } from 'leviathan-crypto'
464
- import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
465
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
466
-
467
- await init({ chacha20: chacha20Wasm, sha2: sha2Wasm })
468
-
469
- const key = XChaCha20Cipher.keygen()
470
- const blob = Seal.encrypt(XChaCha20Cipher, key, utf8ToBytes('Hello, world!'))
471
- const pt = Seal.decrypt(XChaCha20Cipher, key, blob) // throws on tamper
472
-
473
- console.log(bytesToUtf8(pt)) // "Hello, world!"
474
-
475
- // Optional: bind metadata without encrypting it (AAD)
476
- const aad = utf8ToBytes('document-v2')
477
- const blob2 = Seal.encrypt(XChaCha20Cipher, key, utf8ToBytes('Hello, world!'), { aad })
478
- const pt2 = Seal.decrypt(XChaCha20Cipher, key, blob2, { aad })
479
- ```
480
-
481
- > For explicit nonce control, use `XChaCha20Poly1305` directly. Same
482
- > API shape, 24-byte nonce passed per call. See Example 2.
483
-
484
- ### Example 2: ChaCha20Poly1305
485
-
486
- Same idea as above, but with a 12-byte nonce. Use this if you are implementing
487
- a protocol that specifies RFC 8439 ChaCha20-Poly1305 explicitly.
488
-
489
- Both `ChaCha20Poly1305` and `XChaCha20Poly1305` return a single `Uint8Array`
490
- with the tag appended, and `decrypt()` expects the same combined format.
491
- The only difference is the nonce size (12 vs 24 bytes).
492
-
493
- > [!NOTE]
494
- > Each `ChaCha20Poly1305` instance allows only one `encrypt()` call. A second
495
- > call throws to prevent accidental nonce reuse. Create a new instance for each
496
- > encryption.
497
-
498
- ```typescript
499
- import { init, ChaCha20Poly1305, randomBytes, utf8ToBytes, bytesToUtf8 } from 'leviathan-crypto'
500
- import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
501
-
502
- await init({ chacha20: chacha20Wasm })
503
-
504
- const key = randomBytes(32)
505
- const aead = new ChaCha20Poly1305()
506
-
507
- // Encrypt
508
- const nonce = randomBytes(12) // 12 bytes, use XChaCha20Poly1305 for high-volume random generation
509
- const plaintext = utf8ToBytes('Sensitive data')
510
- const sealed = aead.encrypt(key, nonce, plaintext)
511
- // sealed = ciphertext || tag(16), store/transmit nonce and sealed together
512
-
513
- // Decrypt (new instance, encrypt is single-use)
514
- const aead2 = new ChaCha20Poly1305()
515
- const decrypted = aead2.decrypt(key, nonce, sealed)
516
- console.log(bytesToUtf8(decrypted)) // "Sensitive data"
517
-
518
- aead.dispose()
519
- aead2.dispose()
520
- ```
521
-
522
- ### Example 3: Detecting Tampered Ciphertext
523
-
524
- AEAD decryption fails loudly if anyone has modified the ciphertext or
525
- the associated data. This is a feature. It prevents you from processing
526
- corrupted or maliciously altered data.
527
-
528
- ```typescript
529
- import { init, Seal, XChaCha20Cipher, randomBytes, utf8ToBytes } from 'leviathan-crypto'
530
- import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
531
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
532
-
533
- await init({ chacha20: chacha20Wasm, sha2: sha2Wasm })
534
-
535
- const key = XChaCha20Cipher.keygen()
536
- const sealed = Seal.encrypt(XChaCha20Cipher, key, utf8ToBytes('Original message'))
537
-
538
- // Simulate tampering: flip one bit in the ciphertext
539
- const tampered = new Uint8Array(sealed)
540
- tampered[20] ^= 0x01 // byte 20 is the first ciphertext byte (after the 20-byte preamble)
541
-
542
- try {
543
- const plaintext = Seal.decrypt(XChaCha20Cipher, key, tampered)
544
- // This line is never reached
545
- console.log(plaintext)
546
- } catch (err) {
547
- console.error(err.message)
548
- // "ChaCha20Poly1305: authentication failed"
549
- // The plaintext is never returned. Decryption stops immediately on failure.
550
- }
551
- ```
552
-
553
- ### Example 4: Using Associated Data (AAD)
554
-
555
- Associated data is metadata that you want to authenticate (prove unmodified) but
556
- not encrypt. Common uses: user IDs, message sequence numbers, protocol version
557
- headers, routing information.
558
-
559
- ```typescript
560
- import { init, Seal, XChaCha20Cipher, randomBytes, utf8ToBytes, bytesToUtf8 } from 'leviathan-crypto'
561
- import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
562
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
563
-
564
- await init({ chacha20: chacha20Wasm, sha2: sha2Wasm })
565
-
566
- const key = XChaCha20Cipher.keygen()
567
-
568
- // The user ID travels in the clear, but decryption will fail if anyone changes it
569
- const userId = utf8ToBytes('user-12345')
570
- const message = utf8ToBytes('Your account balance is $1,000,000')
571
-
572
- const sealed = Seal.encrypt(XChaCha20Cipher, key, message, { aad: userId })
573
-
574
- // Decrypt, pass the same AAD
575
- const decrypted = Seal.decrypt(XChaCha20Cipher, key, sealed, { aad: userId })
576
- console.log(bytesToUtf8(decrypted))
577
- // "Your account balance is $1,000,000"
578
-
579
- // If someone changes the AAD, decryption fails
580
- const wrongUserId = utf8ToBytes('user-99999')
581
- try {
582
- Seal.decrypt(XChaCha20Cipher, key, sealed, { aad: wrongUserId })
583
- } catch (err) {
584
- console.error(err.message)
585
- // "ChaCha20Poly1305: authentication failed"
586
- // Even though the ciphertext was not modified, the AAD mismatch is detected.
587
- }
588
- ```
589
-
590
- ### Example 5: Encrypting and Decrypting Binary Data
591
-
592
- The API works with raw bytes, not just text. Here is an example encrypting
593
- arbitrary binary content.
594
-
595
- ```typescript
596
- import { init, Seal, XChaCha20Cipher, randomBytes } from 'leviathan-crypto'
597
- import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
598
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
599
-
600
- await init({ chacha20: chacha20Wasm, sha2: sha2Wasm })
601
-
602
- const key = XChaCha20Cipher.keygen()
603
-
604
- // Encrypt binary data (e.g., an image thumbnail, a protobuf, a file chunk)
605
- const binaryData = new Uint8Array([0x89, 0x50, 0x4e, 0x47, /* ...more bytes... */])
606
- const sealed = Seal.encrypt(XChaCha20Cipher, key, binaryData)
607
-
608
- // Decrypt
609
- const recovered = Seal.decrypt(XChaCha20Cipher, key, sealed)
610
- // `recovered` is byte-identical to `binaryData`
611
- ```
612
-
613
- ### Example 6: Raw ChaCha20 Stream Cipher (Advanced)
614
-
615
- Use this only if you are building a custom protocol and will add your own
616
- authentication layer. For almost all use cases, use `Seal` with `XChaCha20Cipher` instead.
617
-
618
- ```typescript
619
- import { init, ChaCha20, randomBytes } from 'leviathan-crypto'
620
- import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
621
-
622
- await init({ chacha20: chacha20Wasm })
623
-
624
- const key = randomBytes(32)
625
- const nonce = randomBytes(12)
626
- const cipher = new ChaCha20()
627
-
628
- // Encrypt
629
- cipher.beginEncrypt(key, nonce)
630
- const ct1 = cipher.encryptChunk(new Uint8Array([1, 2, 3, 4]))
631
- const ct2 = cipher.encryptChunk(new Uint8Array([5, 6, 7, 8]))
632
-
633
- // Decrypt, uses the same key and nonce
634
- cipher.beginDecrypt(key, nonce)
635
- const pt1 = cipher.decryptChunk(ct1)
636
- const pt2 = cipher.decryptChunk(ct2)
637
- // pt1 = [1, 2, 3, 4], pt2 = [5, 6, 7, 8]
638
-
639
- // WARNING: Without authentication, an attacker can flip bits in ciphertext
640
- // and the corresponding plaintext bits will flip with no error.
641
- // Pair with HMAC (Encrypt-then-MAC) or use XChaCha20Poly1305 instead.
642
-
643
- cipher.dispose()
644
- ```
645
-
646
- ---
647
-
648
- ## Error Conditions
649
-
650
- | Condition | Error Type | Message |
651
- |-----------|-----------|---------|
652
- | `init({ chacha20: ... })` not called before constructing a class | `Error` | `leviathan-crypto: call init({ chacha20: ... }) before using this class` |
653
- | Key is not 32 bytes | `RangeError` | `ChaCha20 key must be 32 bytes (got N)` / `key must be 32 bytes (got N)` / `Poly1305 key must be 32 bytes (got N)` |
654
- | `ChaCha20` nonce is not 12 bytes | `RangeError` | `ChaCha20 nonce must be 12 bytes (got N)` |
655
- | `ChaCha20Poly1305` nonce is not 12 bytes | `RangeError` | `nonce must be 12 bytes (got N)` |
656
- | `XChaCha20Poly1305` nonce is not 24 bytes | `RangeError` | `XChaCha20 nonce must be 24 bytes (got N)` |
657
- | `ChaCha20Poly1305` ciphertext shorter than 16 bytes | `RangeError` | `ciphertext too short — must include 16-byte tag (got N)` |
658
- | `XChaCha20Poly1305` ciphertext shorter than 16 bytes | `RangeError` | `ciphertext too short — must include 16-byte tag (got N)` |
659
- | `ChaCha20Poly1305.encrypt()` called a second time | `Error` | Single-use encrypt guard. Create a new instance for each encryption. |
660
- | Chunk or plaintext exceeds WASM buffer size | `RangeError` | `plaintext exceeds N bytes — split into smaller chunks` / `chunk exceeds maximum size of N bytes — split into smaller chunks` |
661
- | Authentication tag does not match on decrypt | `Error` | `ChaCha20Poly1305: authentication failed` |
662
- | Empty plaintext | | Allowed. Encrypting zero bytes produces just a 16-byte tag (AEAD) or zero bytes (raw ChaCha20). |
663
-
664
- > ## Cross-References
665
- >
666
- > - [index](./README.md) — Project Documentation index
667
- > - [lexicon](./lexicon.md) — Glossary of cryptographic terms
668
- > - [asm_chacha](./asm_chacha.md) — WASM (AssemblyScript) implementation details for the chacha20 module
669
- > - [authenticated encryption](./aead.md) — `Seal`, `SealStream`, `OpenStream`: use `XChaCha20Cipher` as the suite argument
670
- > - [serpent](./serpent.md) — `SerpentCipher`: alternative `CipherSuite` for `Seal` and streaming
671
- > - [sha2](./sha2.md) — SHA-2 hashes and HMAC. Needed for Encrypt-then-MAC if using raw ChaCha20
672
- > - [types](./types.md) — `AEAD` and `Streamcipher` interfaces implemented by ChaCha20 classes
673
- > - [architecture](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
674
- > - [chacha_audit](./chacha_audit.md) — XChaCha20-Poly1305 implementation audit