leviathan-crypto 2.1.0 → 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 (296) hide show
  1. package/CLAUDE.md +86 -443
  2. package/README.md +198 -65
  3. package/dist/aes/aes-cbc.d.ts +40 -0
  4. package/dist/aes/aes-cbc.js +158 -0
  5. package/dist/aes/aes-ctr.d.ts +50 -0
  6. package/dist/aes/aes-ctr.js +141 -0
  7. package/dist/aes/aes-gcm-siv.d.ts +67 -0
  8. package/dist/aes/aes-gcm-siv.js +217 -0
  9. package/dist/aes/aes-gcm.d.ts +61 -0
  10. package/dist/aes/aes-gcm.js +226 -0
  11. package/dist/aes/cipher-suite.d.ts +21 -0
  12. package/dist/aes/cipher-suite.js +179 -0
  13. package/dist/aes/embedded.d.ts +1 -0
  14. package/dist/aes/embedded.js +26 -0
  15. package/dist/aes/generator.d.ts +14 -0
  16. package/dist/aes/generator.js +103 -0
  17. package/dist/aes/index.d.ts +58 -0
  18. package/dist/aes/index.js +125 -0
  19. package/dist/aes/ops.d.ts +60 -0
  20. package/dist/aes/ops.js +164 -0
  21. package/dist/aes/pool-worker.d.ts +1 -0
  22. package/dist/aes/pool-worker.js +92 -0
  23. package/dist/aes/types.d.ts +1 -0
  24. package/dist/aes/types.js +23 -0
  25. package/dist/aes.wasm +0 -0
  26. package/dist/blake3/embedded.d.ts +1 -0
  27. package/dist/blake3/embedded.js +26 -0
  28. package/dist/blake3/index.d.ts +143 -0
  29. package/dist/blake3/index.js +620 -0
  30. package/dist/blake3/types.d.ts +102 -0
  31. package/dist/blake3/types.js +31 -0
  32. package/dist/blake3/validate.d.ts +29 -0
  33. package/dist/blake3/validate.js +80 -0
  34. package/dist/blake3.wasm +0 -0
  35. package/dist/chacha20/cipher-suite.js +47 -25
  36. package/dist/chacha20/generator.d.ts +2 -2
  37. package/dist/chacha20/generator.js +4 -4
  38. package/dist/chacha20/index.d.ts +16 -15
  39. package/dist/chacha20/index.js +52 -46
  40. package/dist/chacha20/ops.d.ts +7 -7
  41. package/dist/chacha20/ops.js +34 -34
  42. package/dist/chacha20/pool-worker.js +5 -3
  43. package/dist/cte-wasm.d.ts +1 -0
  44. package/dist/cte-wasm.js +3 -0
  45. package/dist/curve25519.wasm +0 -0
  46. package/dist/ecdsa/der.d.ts +23 -0
  47. package/dist/ecdsa/der.js +192 -0
  48. package/dist/ecdsa/ecprivatekey-der.d.ts +32 -0
  49. package/dist/ecdsa/ecprivatekey-der.js +230 -0
  50. package/dist/ecdsa/embedded.d.ts +1 -0
  51. package/dist/ecdsa/embedded.js +25 -0
  52. package/dist/ecdsa/index.d.ts +124 -0
  53. package/dist/ecdsa/index.js +366 -0
  54. package/dist/ecdsa/types.d.ts +31 -0
  55. package/dist/ecdsa/types.js +28 -0
  56. package/dist/ecdsa/validate.d.ts +18 -0
  57. package/dist/ecdsa/validate.js +92 -0
  58. package/dist/ed25519/embedded.d.ts +1 -0
  59. package/dist/ed25519/embedded.js +31 -0
  60. package/dist/ed25519/index.d.ts +70 -0
  61. package/dist/ed25519/index.js +308 -0
  62. package/dist/ed25519/types.d.ts +27 -0
  63. package/dist/ed25519/types.js +27 -0
  64. package/dist/ed25519/validate.d.ts +7 -0
  65. package/dist/ed25519/validate.js +77 -0
  66. package/dist/embedded/aes-pool-worker.d.ts +1 -0
  67. package/dist/embedded/aes-pool-worker.js +5 -0
  68. package/dist/embedded/aes.d.ts +1 -0
  69. package/dist/embedded/aes.js +3 -0
  70. package/dist/embedded/blake3.d.ts +1 -0
  71. package/dist/embedded/blake3.js +3 -0
  72. package/dist/embedded/chacha20-pool-worker.d.ts +1 -1
  73. package/dist/embedded/chacha20-pool-worker.js +2 -2
  74. package/dist/embedded/chacha20.d.ts +1 -1
  75. package/dist/embedded/chacha20.js +2 -2
  76. package/dist/embedded/curve25519.d.ts +1 -0
  77. package/dist/embedded/curve25519.js +3 -0
  78. package/dist/embedded/mldsa.d.ts +1 -0
  79. package/dist/embedded/mldsa.js +3 -0
  80. package/dist/embedded/mlkem.d.ts +1 -0
  81. package/dist/embedded/mlkem.js +3 -0
  82. package/dist/embedded/p256.d.ts +1 -0
  83. package/dist/embedded/p256.js +3 -0
  84. package/dist/embedded/serpent-pool-worker.d.ts +1 -1
  85. package/dist/embedded/serpent-pool-worker.js +2 -2
  86. package/dist/embedded/serpent.d.ts +1 -1
  87. package/dist/embedded/serpent.js +2 -2
  88. package/dist/embedded/sha2.d.ts +1 -1
  89. package/dist/embedded/sha2.js +2 -2
  90. package/dist/embedded/sha3.d.ts +1 -1
  91. package/dist/embedded/sha3.js +2 -2
  92. package/dist/embedded/slhdsa.d.ts +1 -0
  93. package/dist/embedded/slhdsa.js +3 -0
  94. package/dist/errors.d.ts +92 -1
  95. package/dist/errors.js +111 -1
  96. package/dist/fortuna.d.ts +5 -5
  97. package/dist/fortuna.js +37 -64
  98. package/dist/index.d.ts +38 -9
  99. package/dist/index.js +63 -19
  100. package/dist/init.d.ts +1 -1
  101. package/dist/init.js +11 -25
  102. package/dist/keccak/embedded.js +1 -1
  103. package/dist/keccak/index.d.ts +2 -0
  104. package/dist/keccak/index.js +4 -2
  105. package/dist/loader.d.ts +1 -24
  106. package/dist/loader.js +13 -16
  107. package/dist/merkle/blake3-tree.d.ts +35 -0
  108. package/dist/merkle/blake3-tree.js +187 -0
  109. package/dist/merkle/checkpoint.d.ts +58 -0
  110. package/dist/merkle/checkpoint.js +217 -0
  111. package/dist/merkle/index.d.ts +19 -0
  112. package/dist/merkle/index.js +37 -0
  113. package/dist/merkle/merkle-log.d.ts +130 -0
  114. package/dist/merkle/merkle-log.js +207 -0
  115. package/dist/merkle/merkle-verifier.d.ts +126 -0
  116. package/dist/merkle/merkle-verifier.js +296 -0
  117. package/dist/merkle/proof.d.ts +70 -0
  118. package/dist/merkle/proof.js +300 -0
  119. package/dist/merkle/sha256-tree.d.ts +33 -0
  120. package/dist/merkle/sha256-tree.js +145 -0
  121. package/dist/merkle/signed-log.d.ts +156 -0
  122. package/dist/merkle/signed-log.js +356 -0
  123. package/dist/merkle/signed-note.d.ts +309 -0
  124. package/dist/merkle/signed-note.js +648 -0
  125. package/dist/merkle/sth.d.ts +31 -0
  126. package/dist/merkle/sth.js +31 -0
  127. package/dist/merkle/storage.d.ts +40 -0
  128. package/dist/merkle/storage.js +71 -0
  129. package/dist/merkle/tree.d.ts +68 -0
  130. package/dist/merkle/tree.js +94 -0
  131. package/dist/mldsa/embedded.d.ts +1 -0
  132. package/dist/{kyber → mldsa}/embedded.js +5 -5
  133. package/dist/mldsa/expand.d.ts +53 -0
  134. package/dist/mldsa/expand.js +188 -0
  135. package/dist/mldsa/format.d.ts +16 -0
  136. package/dist/mldsa/format.js +68 -0
  137. package/dist/mldsa/hashvariant.d.ts +32 -0
  138. package/dist/mldsa/hashvariant.js +248 -0
  139. package/dist/mldsa/index.d.ts +142 -0
  140. package/dist/mldsa/index.js +463 -0
  141. package/dist/mldsa/keygen.d.ts +16 -0
  142. package/dist/mldsa/keygen.js +232 -0
  143. package/dist/mldsa/params.d.ts +21 -0
  144. package/dist/mldsa/params.js +55 -0
  145. package/dist/mldsa/sha3-helpers.d.ts +30 -0
  146. package/dist/mldsa/sha3-helpers.js +124 -0
  147. package/dist/mldsa/sign.d.ts +36 -0
  148. package/dist/mldsa/sign.js +380 -0
  149. package/dist/mldsa/types.d.ts +91 -0
  150. package/dist/mldsa/types.js +25 -0
  151. package/dist/mldsa/validate.d.ts +55 -0
  152. package/dist/mldsa/validate.js +125 -0
  153. package/dist/mldsa/verify.d.ts +29 -0
  154. package/dist/mldsa/verify.js +269 -0
  155. package/dist/mldsa.wasm +0 -0
  156. package/dist/mlkem/embedded.d.ts +1 -0
  157. package/dist/mlkem/embedded.js +27 -0
  158. package/dist/mlkem/indcpa.d.ts +49 -0
  159. package/dist/{kyber → mlkem}/indcpa.js +44 -44
  160. package/dist/mlkem/index.d.ts +37 -0
  161. package/dist/{kyber → mlkem}/index.js +24 -34
  162. package/dist/mlkem/kem.d.ts +21 -0
  163. package/dist/{kyber → mlkem}/kem.js +44 -64
  164. package/dist/{kyber → mlkem}/params.d.ts +4 -4
  165. package/dist/{kyber → mlkem}/params.js +2 -2
  166. package/dist/mlkem/suite.d.ts +12 -0
  167. package/dist/{kyber → mlkem}/suite.js +17 -12
  168. package/dist/{kyber → mlkem}/types.d.ts +3 -3
  169. package/dist/{kyber → mlkem}/types.js +1 -1
  170. package/dist/{kyber → mlkem}/validate.d.ts +7 -7
  171. package/dist/{kyber → mlkem}/validate.js +7 -7
  172. package/dist/{kyber.wasm → mlkem.wasm} +0 -0
  173. package/dist/p256.wasm +0 -0
  174. package/dist/ratchet/index.d.ts +2 -0
  175. package/dist/ratchet/index.js +1 -0
  176. package/dist/ratchet/kdf-chain.js +3 -3
  177. package/dist/ratchet/ratchet-keypair.js +2 -2
  178. package/dist/ratchet/root-kdf.js +7 -7
  179. package/dist/ratchet/skipped-key-store.js +4 -4
  180. package/dist/ratchet/types.d.ts +1 -1
  181. package/dist/serpent/cipher-suite.js +20 -17
  182. package/dist/serpent/generator.d.ts +1 -1
  183. package/dist/serpent/generator.js +2 -2
  184. package/dist/serpent/index.d.ts +8 -7
  185. package/dist/serpent/index.js +18 -27
  186. package/dist/serpent/pool-worker.js +7 -5
  187. package/dist/serpent/serpent-cbc.d.ts +4 -4
  188. package/dist/serpent/serpent-cbc.js +11 -8
  189. package/dist/serpent/shared-ops.d.ts +3 -23
  190. package/dist/serpent/shared-ops.js +50 -85
  191. package/dist/serpent.wasm +0 -0
  192. package/dist/sha2/hkdf.js +5 -5
  193. package/dist/sha2/index.d.ts +21 -1
  194. package/dist/sha2/index.js +65 -10
  195. package/dist/sha2/types.d.ts +41 -2
  196. package/dist/sha2.wasm +0 -0
  197. package/dist/sha3/index.d.ts +72 -3
  198. package/dist/sha3/index.js +240 -14
  199. package/dist/sha3/kmac.d.ts +121 -0
  200. package/dist/sha3/kmac.js +800 -0
  201. package/dist/sha3.wasm +0 -0
  202. package/dist/shared/pkcs7.d.ts +22 -0
  203. package/dist/shared/pkcs7.js +84 -0
  204. package/dist/sign/ctx.d.ts +41 -0
  205. package/dist/sign/ctx.js +102 -0
  206. package/dist/sign/envelope.d.ts +45 -0
  207. package/dist/sign/envelope.js +152 -0
  208. package/dist/sign/hasher.d.ts +9 -0
  209. package/dist/sign/hasher.js +132 -0
  210. package/dist/sign/index.d.ts +11 -0
  211. package/dist/sign/index.js +34 -0
  212. package/dist/sign/sign-stream.d.ts +25 -0
  213. package/dist/sign/sign-stream.js +112 -0
  214. package/dist/sign/suites/ecdsa-p256.d.ts +2 -0
  215. package/dist/sign/suites/ecdsa-p256.js +120 -0
  216. package/dist/sign/suites/ed25519.d.ts +3 -0
  217. package/dist/sign/suites/ed25519.js +165 -0
  218. package/dist/sign/suites/hybrid-classical.d.ts +23 -0
  219. package/dist/sign/suites/hybrid-classical.js +526 -0
  220. package/dist/sign/suites/hybrid-pq.d.ts +4 -0
  221. package/dist/sign/suites/hybrid-pq.js +234 -0
  222. package/dist/sign/suites/mldsa.d.ts +7 -0
  223. package/dist/sign/suites/mldsa.js +161 -0
  224. package/dist/sign/suites/slhdsa.d.ts +7 -0
  225. package/dist/sign/suites/slhdsa.js +176 -0
  226. package/dist/sign/types.d.ts +106 -0
  227. package/dist/sign/types.js +28 -0
  228. package/dist/sign/verify-stream.d.ts +30 -0
  229. package/dist/sign/verify-stream.js +227 -0
  230. package/dist/slhdsa/embedded.d.ts +1 -0
  231. package/dist/slhdsa/embedded.js +26 -0
  232. package/dist/slhdsa/index.d.ts +149 -0
  233. package/dist/slhdsa/index.js +493 -0
  234. package/dist/slhdsa/params.d.ts +26 -0
  235. package/dist/slhdsa/params.js +70 -0
  236. package/dist/slhdsa/prehash.d.ts +68 -0
  237. package/dist/slhdsa/prehash.js +307 -0
  238. package/dist/slhdsa/sign.d.ts +39 -0
  239. package/dist/slhdsa/sign.js +116 -0
  240. package/dist/slhdsa/types.d.ts +129 -0
  241. package/dist/slhdsa/types.js +27 -0
  242. package/dist/slhdsa/validate.d.ts +60 -0
  243. package/dist/slhdsa/validate.js +127 -0
  244. package/dist/slhdsa/verify.d.ts +32 -0
  245. package/dist/slhdsa/verify.js +107 -0
  246. package/dist/slhdsa.wasm +0 -0
  247. package/dist/stream/header.js +3 -3
  248. package/dist/stream/index.d.ts +1 -0
  249. package/dist/stream/index.js +1 -0
  250. package/dist/stream/open-stream.js +31 -10
  251. package/dist/stream/seal-stream-pool.d.ts +1 -0
  252. package/dist/stream/seal-stream-pool.js +63 -26
  253. package/dist/stream/seal-stream.d.ts +1 -1
  254. package/dist/stream/seal-stream.js +20 -9
  255. package/dist/stream/seal.js +6 -6
  256. package/dist/stream/types.d.ts +3 -1
  257. package/dist/stream/types.js +1 -1
  258. package/dist/types.d.ts +1 -1
  259. package/dist/types.js +1 -1
  260. package/dist/utils.d.ts +3 -3
  261. package/dist/utils.js +46 -54
  262. package/dist/wasm-source.d.ts +7 -7
  263. package/dist/wasm-source.js +1 -1
  264. package/dist/x25519/embedded.d.ts +1 -0
  265. package/dist/x25519/embedded.js +31 -0
  266. package/dist/x25519/index.d.ts +43 -0
  267. package/dist/x25519/index.js +159 -0
  268. package/dist/x25519/types.d.ts +25 -0
  269. package/dist/x25519/types.js +27 -0
  270. package/dist/x25519/validate.d.ts +2 -0
  271. package/dist/x25519/validate.js +39 -0
  272. package/package.json +70 -26
  273. package/SECURITY.md +0 -163
  274. package/dist/ct-wasm.d.ts +0 -1
  275. package/dist/ct-wasm.js +0 -3
  276. package/dist/docs/aead.md +0 -363
  277. package/dist/docs/architecture.md +0 -1011
  278. package/dist/docs/argon2id.md +0 -305
  279. package/dist/docs/chacha20.md +0 -781
  280. package/dist/docs/exports.md +0 -277
  281. package/dist/docs/fortuna.md +0 -530
  282. package/dist/docs/init.md +0 -301
  283. package/dist/docs/loader.md +0 -256
  284. package/dist/docs/serpent.md +0 -617
  285. package/dist/docs/sha2.md +0 -671
  286. package/dist/docs/sha3.md +0 -612
  287. package/dist/docs/types.md +0 -416
  288. package/dist/docs/utils.md +0 -457
  289. package/dist/embedded/kyber.d.ts +0 -1
  290. package/dist/embedded/kyber.js +0 -3
  291. package/dist/kyber/embedded.d.ts +0 -1
  292. package/dist/kyber/indcpa.d.ts +0 -49
  293. package/dist/kyber/index.d.ts +0 -38
  294. package/dist/kyber/kem.d.ts +0 -21
  295. package/dist/kyber/suite.d.ts +0 -12
  296. /package/dist/{ct.wasm → cte.wasm} +0 -0
package/dist/docs/sha3.md DELETED
@@ -1,612 +0,0 @@
1
- <img src="https://github.com/xero/leviathan-crypto/raw/main/docs/logo.svg" alt="logo" width="120" align="left" margin="10">
2
-
3
- ### SHA3 TypeScript API Reference
4
-
5
- Covers the SHA-3 hash functions (SHA3-224 through SHA3-512) and the SHAKE extendable-output functions (SHAKE128, SHAKE256). See [SHA-3 implementation audit](./sha3_audit.md) for algorithm correctness verifications.
6
-
7
- > ### Table of Contents
8
- > - [Overview](#overview)
9
- > - [Security Notes](#security-notes)
10
- > - [Module Init](#module-init)
11
- > - [API Reference](#api-reference)
12
- > - [Incremental XOF API](#incremental-xof-api-absorb--squeeze--reset)
13
- > - [SHA3_256Hash](#sha3_256hash)
14
- > - [Usage Examples](#usage-examples)
15
- > - [Error Conditions](#error-conditions)
16
-
17
- ---
18
-
19
- ## Overview
20
-
21
- The SHA-3 family provides six hash functions standardized in **FIPS 202**: four
22
- fixed-output hash functions (SHA3-224, SHA3-256, SHA3-384, SHA3-512) and two
23
- extendable-output functions, or XOFs (SHAKE128, SHAKE256). All six are built on
24
- the **Keccak sponge construction**, a fundamentally different design from the
25
- Merkle-Damgard structure used by SHA-2.
26
-
27
- SHA-3 is **not** a replacement for SHA-2. Both are considered secure, and both are
28
- standardized by NIST. SHA-3 exists to provide **defense-in-depth**: if a flaw is
29
- ever discovered in SHA-2, SHA-3 is completely unaffected because it uses a different
30
- mathematical foundation. You may never need that insurance, but if you do, you will be
31
- very glad it is there.
32
-
33
- The SHAKE XOFs are particularly flexible. Unlike SHA3-256, which always produces
34
- exactly 32 bytes, SHAKE128 and SHAKE256 can produce variable-length output. You
35
- tell them how many bytes you want, making them useful for key derivation, generating
36
- nonces, or any situation where you need more (or fewer) bytes than a standard hash
37
- provides.
38
-
39
- One key advantage of SHA-3 over SHA-2: **SHA-3 is immune to length extension
40
- attacks.** With SHA-2, if you know `SHA256(secret + message)` but not the secret,
41
- you can compute `SHA256(secret + message + padding + extra)` without knowing the
42
- secret. SHA-3's sponge construction makes this impossible.
43
-
44
- ---
45
-
46
- ## Security Notes
47
-
48
- > [!IMPORTANT]
49
- > Read these before using the API. Misusing hash functions is one of the most
50
- > common sources of security vulnerabilities.
51
-
52
- - **Length extension immunity.** Unlike SHA-2, the SHA-3 sponge construction does
53
- not leak enough internal state for length extension attacks. Computing
54
- `SHA3(secret + message)` does not let an attacker forge `SHA3(secret + message + extra)`.
55
- That said, **HMAC is still the correct way to build a MAC** — do not use raw
56
- `SHA3(key + message)` as a MAC construction, even though it is not vulnerable to
57
- length extension. HMAC provides a formally proven security reduction.
58
-
59
- - **SHAKE output is unbounded.** SHAKE128 and SHAKE256 are full XOFs — output
60
- length is unbounded. Request any number of bytes via `hash()`, or drive the
61
- sponge directly with `absorb()` / `squeeze()`. The only constraint is
62
- `outputLength >= 1`.
63
-
64
- - **Not for password hashing.** SHA-3 is a fast hash, which is the opposite of
65
- what you want for password storage. Passwords must be hashed with a slow,
66
- memory-hardened algorithm like **Argon2id**. See [argon2id.md](./argon2id.md) for
67
- usage patterns including passphrase-based encryption with leviathan primitives.
68
-
69
- - **Call `dispose()` when finished.** Every SHA-3 class wraps a WASM module that
70
- stores Keccak state in linear memory. Calling `dispose()` zeroes all internal
71
- state (the 200-byte lane matrix, input buffer, output buffer, and metadata).
72
- If you skip `dispose()`, key material or intermediate hash state may persist
73
- in memory.
74
-
75
- ---
76
-
77
- ## Module Init
78
-
79
- Each module subpath exports its own init function for consumers who want
80
- tree-shakeable imports.
81
-
82
- ### `sha3Init(source)`
83
-
84
- Initializes only the sha3 WASM binary. Equivalent to calling the
85
- root `init({ sha3: source })` but without pulling the other three
86
- modules into the bundle.
87
-
88
- **Signature:**
89
-
90
- ```typescript
91
- async function sha3Init(source: WasmSource): Promise<void>
92
- ```
93
-
94
- **Usage:**
95
-
96
- ```typescript
97
- import { sha3Init, SHA3_256 } from 'leviathan-crypto/sha3'
98
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
99
-
100
- await sha3Init(sha3Wasm)
101
- const sha3 = new SHA3_256()
102
- ```
103
-
104
- ### keccakInit() Alias
105
-
106
- `'keccak'` is an alias for `'sha3'`. Same WASM binary, same instance slot.
107
- `keccakInit()` and `sha3Init()` are interchangeable.
108
-
109
- ```typescript
110
- import { keccakInit, SHAKE256, SHA3_256 } from 'leviathan-crypto/keccak'
111
- import { keccakWasm } from 'leviathan-crypto/keccak/embedded'
112
-
113
- await keccakInit(keccakWasm)
114
- // isInitialized('sha3') === true — same slot
115
- ```
116
-
117
- Use the `keccak` subpath when the consuming context (such as ML-KEM) makes the
118
- Keccak primitive name semantically clearer. See [init.md](./init.md#keccak-alias-for-ml-kem)
119
- for full details.
120
-
121
- ---
122
-
123
- ## API Reference
124
-
125
- All SHA-3 classes require initialization before use. Either the root `init()`:
126
-
127
- ```typescript
128
- import { init } from 'leviathan-crypto'
129
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
130
-
131
- await init({ sha3: sha3Wasm })
132
- ```
133
-
134
- Or the subpath `sha3Init()`:
135
-
136
- ```typescript
137
- import { sha3Init } from 'leviathan-crypto/sha3'
138
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
139
-
140
- await sha3Init(sha3Wasm)
141
- ```
142
-
143
- If you use SHA-3 classes without calling `init()` first, the constructor
144
- will throw an error.
145
-
146
- ---
147
-
148
- ### SHA3_224
149
-
150
- Fixed-output hash function. Produces a **28-byte** (224-bit) digest.
151
-
152
- ```typescript
153
- class SHA3_224 {
154
- constructor()
155
- hash(msg: Uint8Array): Uint8Array // returns 28 bytes
156
- dispose(): void
157
- }
158
- ```
159
-
160
- ---
161
-
162
- ### SHA3_256
163
-
164
- Fixed-output hash function. Produces a **32-byte** (256-bit) digest. This is the
165
- most commonly used SHA-3 variant; 256-bit security is suitable for most
166
- applications.
167
-
168
- ```typescript
169
- class SHA3_256 {
170
- constructor()
171
- hash(msg: Uint8Array): Uint8Array // returns 32 bytes
172
- dispose(): void
173
- }
174
- ```
175
-
176
- ---
177
-
178
- ### SHA3_384
179
-
180
- Fixed-output hash function. Produces a **48-byte** (384-bit) digest.
181
-
182
- ```typescript
183
- class SHA3_384 {
184
- constructor()
185
- hash(msg: Uint8Array): Uint8Array // returns 48 bytes
186
- dispose(): void
187
- }
188
- ```
189
-
190
- ---
191
-
192
- ### SHA3_512
193
-
194
- Fixed-output hash function. Produces a **64-byte** (512-bit) digest. Use this when
195
- you need the highest security margin.
196
-
197
- ```typescript
198
- class SHA3_512 {
199
- constructor()
200
- hash(msg: Uint8Array): Uint8Array // returns 64 bytes
201
- dispose(): void
202
- }
203
- ```
204
-
205
- ---
206
-
207
- ### SHAKE128
208
-
209
- Extendable-output function (XOF). Produces **variable-length** output — any
210
- number of bytes you request. 128-bit security level.
211
-
212
- > [!CAUTION]
213
- > `SHAKE128` is stateful and holds exclusive access to the `sha3` WASM module
214
- > for its entire lifetime. Constructing a second SHAKE128/SHAKE256 or any
215
- > other sha3 class (`SHA3_256`, etc.) while this instance is live throws.
216
- > Call `dispose()` when done. Pool workers are unaffected.
217
-
218
- ```typescript
219
- class SHAKE128 {
220
- constructor()
221
- hash(msg: Uint8Array, outputLength: number): Uint8Array
222
- absorb(msg: Uint8Array): this
223
- squeeze(n: number): Uint8Array
224
- reset(): this
225
- dispose(): void
226
- }
227
- ```
228
-
229
- | Method | Description |
230
- |--------|-------------|
231
- | `hash(msg, outputLength)` | One-shot: reset, absorb, squeeze. Safe on a dirty instance. |
232
- | `absorb(msg)` | Feed data into the sponge. Chainable. Throws if called after `squeeze()`. |
233
- | `squeeze(n)` | Pull `n` bytes of XOF output. Output is contiguous — `squeeze(a)` followed by `squeeze(b)` yields bytes `[0, a)` and `[a, a+b)` of the XOF stream. |
234
- | `reset()` | Return to a fresh, zeroed state. Chainable. Safe at any point. Does not release the sha3 exclusivity token. |
235
- | `dispose()` | Zero all WASM state and the TS-side block buffer, release the sha3 exclusivity token. Idempotent. |
236
-
237
- **`outputLength`** / **`n`** must be `>= 1`. Values below 1 throw a `RangeError`.
238
-
239
- After `dispose()`, all instance methods (`reset`, `absorb`, `squeeze`, `hash`)
240
- throw `Error: SHAKE128: instance has been disposed`. Disposal is permanent;
241
- construct a new instance if you need to continue.
242
-
243
- ---
244
-
245
- ### SHAKE256
246
-
247
- Extendable-output function (XOF). Produces **variable-length** output — any
248
- number of bytes you request. 256-bit security level.
249
-
250
- > [!CAUTION]
251
- > `SHAKE256` is stateful and holds exclusive access to the `sha3` WASM module
252
- > for its entire lifetime. Constructing a second SHAKE128/SHAKE256 or any
253
- > other sha3 class while this instance is live throws. Call `dispose()` when
254
- > done.
255
-
256
- ```typescript
257
- class SHAKE256 {
258
- constructor()
259
- hash(msg: Uint8Array, outputLength: number): Uint8Array
260
- absorb(msg: Uint8Array): this
261
- squeeze(n: number): Uint8Array
262
- reset(): this
263
- dispose(): void
264
- }
265
- ```
266
-
267
- | Method | Description |
268
- |--------|-------------|
269
- | `hash(msg, outputLength)` | One-shot: reset, absorb, squeeze. Safe on a dirty instance. |
270
- | `absorb(msg)` | Feed data into the sponge. Chainable. Throws if called after `squeeze()`. |
271
- | `squeeze(n)` | Pull `n` bytes of XOF output. Output is contiguous — `squeeze(a)` followed by `squeeze(b)` yields bytes `[0, a)` and `[a, a+b)` of the XOF stream. |
272
- | `reset()` | Return to a fresh, zeroed state. Chainable. Safe at any point. Does not release the sha3 exclusivity token. |
273
- | `dispose()` | Zero all WASM state and the TS-side block buffer, release the sha3 exclusivity token. Idempotent. |
274
-
275
- **`outputLength`** / **`n`** must be `>= 1`. Values below 1 throw a `RangeError`.
276
-
277
- After `dispose()`, all instance methods (`reset`, `absorb`, `squeeze`, `hash`)
278
- throw `Error: SHAKE256: instance has been disposed`. Disposal is permanent;
279
- construct a new instance if you need to continue.
280
-
281
- ---
282
-
283
- ## Incremental XOF API (`absorb` / `squeeze` / `reset`)
284
-
285
- For use cases where you need to pull output in multiple steps — key derivation,
286
- mask generation, protocol-specific domain separation — the SHAKE classes expose
287
- a streaming interface alongside the one-shot `hash()`.
288
-
289
- ### State machine
290
-
291
- | State | Valid calls |
292
- |-------------|---------------------------------|
293
- | fresh | `absorb()`, `hash()`, `reset()` |
294
- | absorbing | `absorb()`, `squeeze()`, `hash()`, `reset()` |
295
- | squeezing | `squeeze()`, `hash()`, `reset()` |
296
-
297
- Calling `absorb()` while squeezing throws:
298
- `"SHAKE128: cannot absorb after squeeze — call reset() first"`
299
-
300
- `hash()` always resets before running — safe to call on a dirty instance.
301
-
302
- ### Example
303
-
304
- ```typescript
305
- import { init, SHAKE256 } from 'leviathan-crypto'
306
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
307
-
308
- await init({ sha3: sha3Wasm })
309
-
310
- const xof = new SHAKE256()
311
- xof.absorb(ikm) // input key material
312
- xof.absorb(salt) // additional context
313
-
314
- const encKey = xof.squeeze(32) // 256-bit encryption key
315
- const macKey = xof.squeeze(32) // 256-bit MAC key
316
- const nonce = xof.squeeze(12) // 96-bit nonce
317
-
318
- xof.dispose()
319
- ```
320
-
321
- ---
322
-
323
- ## SHA3_256Hash
324
-
325
- Stateless SHA3-256 `HashFn` for Fortuna's accumulator and reseed slots. Plain
326
- `const` object — no instantiation, no `dispose()`.
327
-
328
- Requires `init({ sha3: sha3Wasm })` (or the `keccak` alias). See
329
- [fortuna.md](./fortuna.md) for full usage with `Fortuna.create()`.
330
-
331
- | Property | Value |
332
- |----------|-------|
333
- | `outputSize` | `32` |
334
- | `wasmModules` | `['sha3']` |
335
-
336
- ### `SHA3_256Hash.digest(msg): Uint8Array`
337
-
338
- Hashes `msg` and returns a 32-byte SHA3-256 digest. Wipes WASM input/output/sponge
339
- state scratch before returning.
340
-
341
- | Parameter | Type | Description |
342
- |-----------|------|-------------|
343
- | `msg` | `Uint8Array` | Message to hash (any length) |
344
-
345
- **Returns** a new `Uint8Array` of 32 bytes.
346
-
347
- **Throws** `Error` if another stateful instance currently owns the `sha3` WASM module.
348
-
349
- ### Usage with `Fortuna`
350
-
351
- ```typescript
352
- import { init, Fortuna } from 'leviathan-crypto'
353
- import { SHA3_256Hash } from 'leviathan-crypto/sha3'
354
- import { ChaCha20Generator } from 'leviathan-crypto/chacha20'
355
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
356
- import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
357
-
358
- await init({ sha3: sha3Wasm, chacha20: chacha20Wasm })
359
- const rng = await Fortuna.create({ generator: ChaCha20Generator, hash: SHA3_256Hash })
360
- const bytes = rng.get(32)
361
- rng.stop()
362
- ```
363
-
364
- ---
365
-
366
- ## Usage Examples
367
-
368
- ### Example 1: Hash a string with SHA3-256
369
-
370
- The most common use case: hash some data and get a hex digest.
371
-
372
- ```typescript
373
- import { init, SHA3_256, bytesToHex, utf8ToBytes } from 'leviathan-crypto'
374
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
375
-
376
- // Initialize the SHA-3 WASM module (once, at startup)
377
- await init({ sha3: sha3Wasm })
378
-
379
- // Create a hasher
380
- const sha3 = new SHA3_256()
381
-
382
- // Hash a UTF-8 string
383
- const message = utf8ToBytes('Hello, world!')
384
- const digest = sha3.hash(message)
385
-
386
- console.log(bytesToHex(digest))
387
- // 32 bytes (64 hex characters) of SHA3-256 output
388
-
389
- // Clean up -- zeroes all WASM state
390
- sha3.dispose()
391
- ```
392
-
393
- ---
394
-
395
- ### Example 2: Hash binary data with SHA3-512
396
-
397
- ```typescript
398
- import { init, SHA3_512, bytesToHex } from 'leviathan-crypto'
399
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
400
-
401
- await init({ sha3: sha3Wasm })
402
-
403
- const sha3 = new SHA3_512()
404
-
405
- // Hash raw bytes (e.g., a file, a key, a nonce)
406
- const data = new Uint8Array([0x01, 0x02, 0x03, 0x04])
407
- const digest = sha3.hash(data)
408
-
409
- console.log(bytesToHex(digest))
410
- // 64 bytes (128 hex characters) of SHA3-512 output
411
-
412
- sha3.dispose()
413
- ```
414
-
415
- ---
416
-
417
- ### Example 3: Hash multiple messages
418
-
419
- Each call to `hash()` is independent; the internal state resets automatically.
420
- You can reuse the same class instance for multiple hashes.
421
-
422
- ```typescript
423
- import { init, SHA3_256, bytesToHex, utf8ToBytes } from 'leviathan-crypto'
424
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
425
-
426
- await init({ sha3: sha3Wasm })
427
-
428
- const sha3 = new SHA3_256()
429
-
430
- const hash1 = sha3.hash(utf8ToBytes('first message'))
431
- const hash2 = sha3.hash(utf8ToBytes('second message'))
432
- const hash3 = sha3.hash(utf8ToBytes('first message'))
433
-
434
- // hash1 and hash3 are identical -- same input, same output
435
- console.log(bytesToHex(hash1) === bytesToHex(hash3)) // true
436
-
437
- // hash2 is different -- different input
438
- console.log(bytesToHex(hash1) === bytesToHex(hash2)) // false
439
-
440
- sha3.dispose()
441
- ```
442
-
443
- ---
444
-
445
- ### Example 4: SHAKE128 variable-length output
446
-
447
- SHAKE lets you choose exactly how many bytes of output you need. This is useful
448
- for key derivation or generating fixed-size tokens.
449
-
450
- ```typescript
451
- import { init, SHAKE128, bytesToHex, utf8ToBytes } from 'leviathan-crypto'
452
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
453
-
454
- await init({ sha3: sha3Wasm })
455
-
456
- const shake = new SHAKE128()
457
-
458
- const seed = utf8ToBytes('my-application-seed')
459
-
460
- // Derive a 16-byte key (128 bits)
461
- const key128 = shake.hash(seed, 16)
462
- console.log('16-byte key:', bytesToHex(key128))
463
-
464
- // Derive a 32-byte key (256 bits) from the same seed
465
- const key256 = shake.hash(seed, 32)
466
- console.log('32-byte key:', bytesToHex(key256))
467
-
468
- // The 16-byte output is NOT a prefix of the 32-byte output --
469
- // each call resets state, re-absorbs, and squeezes independently.
470
- // However, for SHAKE, the first 16 bytes of the 32-byte output
471
- // ARE identical to the 16-byte output (this is how XOFs work).
472
-
473
- shake.dispose()
474
- ```
475
-
476
- ---
477
-
478
- ### Example 5: SHAKE256 for key derivation
479
-
480
- ```typescript
481
- import { init, SHAKE256, bytesToHex } from 'leviathan-crypto'
482
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
483
-
484
- await init({ sha3: sha3Wasm })
485
-
486
- const shake = new SHAKE256()
487
-
488
- // Derive a 48-byte key from raw entropy
489
- const entropy = crypto.getRandomValues(new Uint8Array(32))
490
- const derivedKey = shake.hash(entropy, 48)
491
-
492
- console.log('Derived key:', bytesToHex(derivedKey))
493
- // 48 bytes (96 hex characters) of SHAKE256 output
494
-
495
- shake.dispose()
496
- ```
497
-
498
- ---
499
-
500
- ### Example 6: SHA-256 vs SHA3-256
501
-
502
- SHA-256 (from the SHA-2 family) and SHA3-256 are completely different algorithms.
503
- They produce different output for the same input. Both are secure; SHA3-256 adds defense-in-depth.
504
-
505
- ```typescript
506
- import { init, SHA256, SHA3_256, bytesToHex, utf8ToBytes } from 'leviathan-crypto'
507
- import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
508
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
509
-
510
- // Initialize both modules
511
- await init({ sha2: sha2Wasm, sha3: sha3Wasm })
512
-
513
- const sha2 = new SHA256()
514
- const sha3 = new SHA3_256()
515
-
516
- const message = utf8ToBytes('abc')
517
-
518
- const sha2Digest = sha2.hash(message)
519
- const sha3Digest = sha3.hash(message)
520
-
521
- console.log('SHA-256: ', bytesToHex(sha2Digest))
522
- console.log('SHA3-256: ', bytesToHex(sha3Digest))
523
- // These are completely different values -- different algorithms
524
-
525
- sha2.dispose()
526
- sha3.dispose()
527
- ```
528
-
529
- ---
530
-
531
- ### Example 7: Hashing empty input
532
-
533
- All hash functions accept empty input. This is well-defined and produces a
534
- deterministic output.
535
-
536
- ```typescript
537
- import { init, SHA3_256, bytesToHex } from 'leviathan-crypto'
538
- import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
539
-
540
- await init({ sha3: sha3Wasm })
541
-
542
- const sha3 = new SHA3_256()
543
- const digest = sha3.hash(new Uint8Array(0))
544
-
545
- console.log(bytesToHex(digest))
546
- // The SHA3-256 hash of empty input -- a fixed, known value
547
-
548
- sha3.dispose()
549
- ```
550
-
551
- ---
552
-
553
- ## Error Conditions
554
-
555
- ### SHA-3 module not initialized
556
-
557
- If you construct a SHA-3 class before initializing the module, the constructor
558
- throws immediately:
559
-
560
- ```
561
- Error: leviathan-crypto: call init({ sha3: ... }) before using this class
562
- ```
563
-
564
- **Fix:** Call `await init({ sha3: sha3Wasm })` once at application startup, before creating
565
- any SHA-3 class instances.
566
-
567
- ---
568
-
569
- ### SHAKE output length out of range
570
-
571
- SHAKE128 and SHAKE256 require `outputLength >= 1`. Passing 0 or a negative number
572
- throws a `RangeError`:
573
-
574
- ```
575
- RangeError: outputLength must be >= 1 (got 0)
576
- ```
577
-
578
- **Fix:** Request at least 1 byte.
579
-
580
- ---
581
-
582
- ### SHAKE absorb after squeeze
583
-
584
- Calling `absorb()` after `squeeze()` has been called throws an `Error`. The sponge
585
- has been padded and finalized — further absorption is not meaningful.
586
-
587
- ```
588
- Error: SHAKE128: cannot absorb after squeeze — call reset() first
589
- ```
590
-
591
- **Fix:** Call `reset()` to return the instance to a fresh state before absorbing
592
- new data.
593
-
594
- ---
595
-
596
- ### Empty input
597
-
598
- Passing an empty `Uint8Array` (length 0) is **not** an error. All SHA-3 and SHAKE
599
- functions produce valid, deterministic output for empty input. The sponge simply
600
- absorbs zero bytes and then squeezes.
601
-
602
- ---
603
-
604
-
605
- ## Cross-References
606
-
607
- | Document | Description |
608
- | -------- | ----------- |
609
- | [index](./README.md) | Project Documentation index |
610
- | [architecture](./architecture.md) | architecture overview, module relationships, buffer layouts, and build pipeline |
611
- | [sha3_audit.md](./sha3_audit.md) | SHA-3 / Keccak implementation audit |
612
-