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/fortuna.js CHANGED
@@ -21,7 +21,7 @@
21
21
  //
22
22
  // src/ts/fortuna.ts
23
23
  //
24
- // Fortuna CSPRNG Ferguson & Schneier, Practical Cryptography (2003), Chapter 9.
24
+ // Fortuna CSPRNG, Ferguson & Schneier, Practical Cryptography (2003), Chapter 9.
25
25
  // Backed by a pluggable Generator (cipher PRF) and HashFn (accumulator hash).
26
26
  // Requires init() for the modules used by the chosen generator and hash pair.
27
27
  import { isInitialized, getInstance } from './init.js';
@@ -29,17 +29,17 @@ import { wipe, utf8ToBytes, concat } from './utils.js';
29
29
  const isBrowser = typeof window !== 'undefined';
30
30
  const isNode = typeof process !== 'undefined' && typeof process.pid === 'number';
31
31
  /**
32
- * Fortuna CSPRNG spec §9.3–§9.5
32
+ * Fortuna CSPRNG, spec §9.39.5
33
33
  *
34
34
  * Use `Fortuna.create({ generator, hash })` to instantiate. Direct construction is not allowed.
35
35
  */
36
36
  export class Fortuna {
37
37
  // ── Constants ──────────────────────────────────────────────────────────
38
38
  static NUM_POOLS = 32;
39
- static RESEED_LIMIT = 64; // bits pool 0 threshold (spec §9.5)
40
- static MS_PER_RESEED = 100; // ms minimum reseed interval (spec §9.5)
41
- static NODE_STATS_INTERVAL = 1000; // ms OS stats collector interval
42
- static CRYPTO_INTERVAL = 3000; // ms crypto.randomBytes interval
39
+ static RESEED_LIMIT = 64; // bits, pool 0 threshold (spec §9.5)
40
+ static MS_PER_RESEED = 100; // ms, minimum reseed interval (spec §9.5)
41
+ static NODE_STATS_INTERVAL = 1000; // ms, OS stats collector interval
42
+ static CRYPTO_INTERVAL = 3000; // ms, crypto.randomBytes interval
43
43
  // ── State ─────────────────────────────────────────────────────────────
44
44
  gen;
45
45
  hash;
@@ -74,7 +74,7 @@ export class Fortuna {
74
74
  }
75
75
  const f = new Fortuna(opts.generator, opts.hash, opts.msPerReseed ?? Fortuna.MS_PER_RESEED);
76
76
  f.initialize(opts.entropy);
77
- // Force the first reseed pool[0] is saturated by initialize(),
77
+ // Force the first reseed, pool[0] is saturated by initialize(),
78
78
  // so this call triggers an immediate reseed and guarantees get() never
79
79
  // returns undefined. The byte is discarded.
80
80
  f.get(1);
@@ -101,14 +101,14 @@ export class Fortuna {
101
101
  }
102
102
  }
103
103
  // ── Public API ────────────────────────────────────────────────────────
104
- /** Get n random bytes. Always returns Uint8Array instance is guaranteed seeded after create(). */
104
+ /** Get n random bytes. Always returns Uint8Array, instance is guaranteed seeded after create(). */
105
105
  get(length) {
106
106
  if (this.disposed)
107
107
  throw new Error('Fortuna instance has been disposed');
108
- // Capture hrtime jitter at call time (Node.js) spec §9.5
108
+ // Capture hrtime jitter at call time (Node.js), spec §9.5
109
109
  if (isNode)
110
110
  this.captureHrtime();
111
- // Check reseed trigger spec §9.5
111
+ // Check reseed trigger, spec §9.5
112
112
  if (this.poolEntropy[0] >= Fortuna.RESEED_LIMIT &&
113
113
  Date.now() >= this.lastReseed + this.msPerReseed) {
114
114
  this.reseedCnt = (this.reseedCnt + 1) >>> 0; // u32 wrap
@@ -121,7 +121,7 @@ export class Fortuna {
121
121
  // Pool digest = current chain hash
122
122
  seed = concat(seed, this.poolHash[i]);
123
123
  strength += this.poolEntropy[i];
124
- // Reset pool wipe old chain hash before dropping the reference.
124
+ // Reset pool, wipe old chain hash before dropping the reference.
125
125
  const old = this.poolHash[i];
126
126
  this.poolHash[i] = new Uint8Array(this.hash.outputSize);
127
127
  wipe(old);
@@ -152,21 +152,17 @@ export class Fortuna {
152
152
  stop() {
153
153
  if (this.disposed)
154
154
  throw new Error('Fortuna instance has been disposed');
155
- // Mark disposed FIRST. WASM wipeBuffers can throw if a stateful instance
156
- // holds the module; we must not allow get()/addEntropy()/getEntropy() to
157
- // run on a partially-disposed instance.
155
+ // Mark disposed first so partially-disposed reentry throws cleanly.
158
156
  this.disposed = true;
159
157
  this.stopCollectors();
160
158
  wipe(this.genKey);
161
159
  wipe(this.genCnt);
162
- // Wipe all 32 pool-hash chain values so residual entropy-bearing
160
+ // Wipe the 32 pool-hash chain values so residual entropy-bearing
163
161
  // bytes do not outlive the instance.
164
162
  for (const p of this.poolHash)
165
163
  wipe(p);
166
164
  this.reseedCnt = 0;
167
- // Best-effort wipe of WASM scratch buffers for every module the chosen
168
- // generator and hash touched. Surface the first error so the caller
169
- // knows the WASM scratch leak occurred.
165
+ // Best-effort wipe of WASM scratch; surface the first error.
170
166
  const required = new Set([...this.gen.wasmModules, ...this.hash.wasmModules]);
171
167
  let err;
172
168
  for (const mod of required) {
@@ -181,24 +177,24 @@ export class Fortuna {
181
177
  throw err;
182
178
  }
183
179
  // ── Test-only accessors ───────────────────────────────────────────────
184
- /** @internal exposed for testing key replacement */
180
+ /** @internal, exposed for testing key replacement */
185
181
  _getGenKey() {
186
182
  return this.genKey;
187
183
  }
188
- /** @internal exposed for testing pool state */
184
+ /** @internal, exposed for testing pool state */
189
185
  _getPoolEntropy() {
190
186
  return this.poolEntropy;
191
187
  }
192
- /** @internal exposed for testing reseed count */
188
+ /** @internal, exposed for testing reseed count */
193
189
  _getReseedCnt() {
194
190
  return this.reseedCnt;
195
191
  }
196
- /** @internal exposed for testing pool-hash backing arrays */
192
+ /** @internal, exposed for testing pool-hash backing arrays */
197
193
  _getPoolHash() {
198
194
  return this.poolHash;
199
195
  }
200
196
  /**
201
- * @internal test-only deterministic factory. Seeds pool[0] with the provided
197
+ * @internal, test-only deterministic factory. Seeds pool[0] with the provided
202
198
  * entropy and triggers one reseed directly, bypassing all OS entropy collection
203
199
  * and the hrtime jitter capture in get(). This makes KAT vectors reproducible
204
200
  * across runs. Not suitable for production use.
@@ -219,20 +215,20 @@ export class Fortuna {
219
215
  const f = new Fortuna(opts.generator, opts.hash, 0);
220
216
  // Seed pool[0] with the provided entropy, no OS collection.
221
217
  f.addRandomEvent(opts.entropy, 0, opts.entropy.length * 8);
222
- // Manually trigger reseed #1 without calling get() get() calls captureHrtime()
218
+ // Manually trigger reseed #1 without calling get(), get() calls captureHrtime()
223
219
  // in Node.js which adds non-deterministic data before the reseed fires.
224
220
  f.reseedFromPool0();
225
221
  return f;
226
222
  }
227
223
  // ── Generator (spec §9.4) ─────────────────────────────────────────────
228
- /** Get length pseudo-random bytes. spec §9.4 */
224
+ /** Get length pseudo-random bytes., spec §9.4 */
229
225
  pseudoRandomData(length) {
230
226
  const blocks = Math.ceil(length / this.gen.blockSize);
231
227
  const out = this.gen.generate(this.genKey, this.genCnt, length);
232
- // External counter advance generator is stateless and does not mutate caller's counter
228
+ // External counter advance, generator is stateless and does not mutate caller's counter
233
229
  for (let i = 0; i < blocks; i++)
234
230
  this.incrementCounter();
235
- // Key replacement mandatory forward secrecy (spec §9.4).
231
+ // Key replacement, mandatory forward secrecy (spec §9.4).
236
232
  // Wipe the prior key BEFORE dropping its reference so no key bytes are
237
233
  // reachable after key replacement; anyone holding a Uint8Array view to
238
234
  // the old key now observes zero.
@@ -243,7 +239,7 @@ export class Fortuna {
243
239
  this.genKey = newKey;
244
240
  return out;
245
241
  }
246
- /** Reseed the generator spec §9.4 */
242
+ /** Reseed the generator, spec §9.4 */
247
243
  reseed(seed) {
248
244
  // genKey = hash(genKey ‖ seed). Wipe both the hash input and the
249
245
  // prior key before dropping references.
@@ -252,7 +248,7 @@ export class Fortuna {
252
248
  wipe(combined);
253
249
  wipe(this.genKey);
254
250
  this.genKey = newKey;
255
- // Increment counter makes it nonzero on first reseed, marking generator as seeded
251
+ // Increment counter, makes it nonzero on first reseed, marking generator as seeded
256
252
  this.incrementCounter();
257
253
  this.lastReseed = Date.now();
258
254
  }
@@ -271,7 +267,7 @@ export class Fortuna {
271
267
  this.reseed(seed);
272
268
  wipe(seed);
273
269
  }
274
- /** Increment little-endian counter. spec §9.4 */
270
+ /** Increment little-endian counter., spec §9.4 */
275
271
  incrementCounter() {
276
272
  for (let i = 0; i < this.genCnt.length; i++) {
277
273
  if (++this.genCnt[i] !== 0)
@@ -300,7 +296,7 @@ export class Fortuna {
300
296
  }
301
297
  // ── Initialization ────────────────────────────────────────────────────
302
298
  initialize(entropy) {
303
- // Initial seeding crypto random per pool (spec §9.5)
299
+ // Initial seeding, crypto random per pool (spec §9.5)
304
300
  for (let i = 0; i < Fortuna.NUM_POOLS * 4; i++) {
305
301
  this.collectorCryptoRandom();
306
302
  }
@@ -319,7 +315,7 @@ export class Fortuna {
319
315
  // runtimes). This post-init check covers all silent-failure paths uniformly.
320
316
  if (this.poolEntropy[0] < Fortuna.RESEED_LIMIT)
321
317
  throw new Error('leviathan-crypto: Fortuna initialization could not gather sufficient entropy. '
322
- + 'No working crypto.getRandomValues or node:crypto in this environment.');
318
+ + 'No working crypto.getRandomValues in this environment.');
323
319
  this.startCollectors();
324
320
  }
325
321
  // ── Collectors ────────────────────────────────────────────────────────
@@ -349,7 +345,7 @@ export class Fortuna {
349
345
  // OS stats timer
350
346
  this.timers.push(setInterval(() => this.collectNodeStats(), Fortuna.NODE_STATS_INTERVAL));
351
347
  }
352
- // Crypto timer both environments
348
+ // Crypto timer, both environments
353
349
  this.timers.push(setInterval(() => this.collectorCryptoRandom(), Fortuna.CRYPTO_INTERVAL));
354
350
  this.active = true;
355
351
  }
@@ -458,19 +454,12 @@ export class Fortuna {
458
454
  }
459
455
  collectorCryptoRandom() {
460
456
  try {
457
+ // Web Crypto is the only secure source. No node:crypto fallback: an absent
458
+ // source must fail loud via the init invariant below, never be polyfilled.
459
+ if (typeof globalThis.crypto === 'undefined' || typeof globalThis.crypto.getRandomValues !== 'function')
460
+ return;
461
461
  const rnd = new Uint8Array(128);
462
- if (typeof globalThis.crypto !== 'undefined' && typeof globalThis.crypto.getRandomValues === 'function') {
463
- globalThis.crypto.getRandomValues(rnd);
464
- }
465
- else if (isNode) {
466
- // eslint-disable-next-line @typescript-eslint/no-require-imports
467
- const nodeCrypto = require('node:crypto');
468
- const buf = nodeCrypto.randomBytes(128);
469
- rnd.set(new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
470
- }
471
- else {
472
- return; // no crypto source available
473
- }
462
+ globalThis.crypto.getRandomValues(rnd);
474
463
  this.addRandomEvent(rnd, this.robin.rnd, 1024);
475
464
  this.robin.rnd = (this.robin.rnd + 1) % Fortuna.NUM_POOLS;
476
465
  }
@@ -489,14 +478,14 @@ export class Fortuna {
489
478
  }
490
479
  collectNodeStats() {
491
480
  try {
492
- // hrtime nanosecond scheduling jitter
481
+ // hrtime, nanosecond scheduling jitter
493
482
  const hr = process.hrtime.bigint();
494
483
  const hrBytes = new Uint8Array(8);
495
484
  for (let i = 0; i < 8; i++)
496
485
  hrBytes[i] = Number((hr >> BigInt(i * 8)) & 0xffn);
497
486
  this.addRandomEvent(hrBytes, this.robin.time, 8);
498
487
  this.robin.time = (this.robin.time + 1) % Fortuna.NUM_POOLS;
499
- // cpuUsage user + system CPU microseconds
488
+ // cpuUsage, user + system CPU microseconds
500
489
  const cpu = process.cpuUsage();
501
490
  const cpuBytes = new Uint8Array(8);
502
491
  cpuBytes[0] = cpu.user & 0xff;
@@ -509,7 +498,7 @@ export class Fortuna {
509
498
  cpuBytes[7] = (cpu.system >>> 24) & 0xff;
510
499
  this.addRandomEvent(cpuBytes, this.robin.rnd, 2);
511
500
  this.robin.rnd = (this.robin.rnd + 1) % Fortuna.NUM_POOLS;
512
- // memoryUsage heapUsed changes constantly
501
+ // memoryUsage, heapUsed changes constantly
513
502
  const mem = process.memoryUsage();
514
503
  const memVal = mem.heapUsed;
515
504
  const memBytes = new Uint8Array(4);
@@ -519,22 +508,6 @@ export class Fortuna {
519
508
  memBytes[3] = (memVal >>> 24) & 0xff;
520
509
  this.addRandomEvent(memBytes, this.robin.rnd, 1);
521
510
  this.robin.rnd = (this.robin.rnd + 1) % Fortuna.NUM_POOLS;
522
- // loadavg — slow-changing but real system state
523
- // eslint-disable-next-line @typescript-eslint/no-require-imports
524
- const os = require('node:os');
525
- const la = os.loadavg();
526
- const laStr = la.map((n) => Math.round(n * 1000).toString()).join('');
527
- this.addRandomEvent(utf8ToBytes(laStr), this.robin.time, 1);
528
- this.robin.time = (this.robin.time + 1) % Fortuna.NUM_POOLS;
529
- // freemem — changes with allocation activity
530
- const fm = os.freemem();
531
- const fmBytes = new Uint8Array(4);
532
- fmBytes[0] = fm & 0xff;
533
- fmBytes[1] = (fm >>> 8) & 0xff;
534
- fmBytes[2] = (fm >>> 16) & 0xff;
535
- fmBytes[3] = (fm >>> 24) & 0xff;
536
- this.addRandomEvent(fmBytes, this.robin.rnd, 1);
537
- this.robin.rnd = (this.robin.rnd + 1) % Fortuna.NUM_POOLS;
538
511
  }
539
512
  catch { /* Node APIs may not be available */ }
540
513
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  import type { Module } from './init.js';
2
2
  import type { WasmSource } from './wasm-source.js';
3
+ /**
4
+ * Top-level init() input. Accepts the canonical module keys plus the
5
+ * `ed25519` and `x25519` aliases; both aliases resolve to the underlying
6
+ * `curve25519` WASM module and are de-duped if given identical sources.
7
+ */
8
+ export type InitInput = Partial<Record<Module | 'ed25519' | 'x25519', WasmSource>>;
3
9
  /**
4
10
  * Load one or more WASM modules. Each key is a module name; the value is the
5
11
  * WasmSource to load it from (embedded blob, URL, ArrayBuffer, etc.).
@@ -10,22 +16,45 @@ import type { WasmSource } from './wasm-source.js';
10
16
  * import { sha2Wasm } from 'leviathan-crypto/sha2/embedded';
11
17
  * await init({ serpent: serpentWasm, sha2: sha2Wasm });
12
18
  * ```
19
+ *
20
+ * `ed25519` and `x25519` are aliases for the underlying `curve25519`
21
+ * module. `init({ ed25519: src })` and `init({ x25519: src })` both work,
22
+ * and `init({ ed25519: src, x25519: src })` is accepted (single underlying
23
+ * init). Two different sources for the same underlying module is rejected.
13
24
  */
14
- export declare function init(sources: Partial<Record<Module, WasmSource>>): Promise<void>;
25
+ export declare function init(sources: InitInput): Promise<void>;
15
26
  export type { Module, WasmSource };
16
27
  export { isInitialized } from './init.js';
17
- export { AuthenticationError } from './errors.js';
18
- export { serpentInit, Serpent, SerpentCtr, SerpentCbc, SerpentCipher, SerpentGenerator, _serpentReady } from './serpent/index.js';
19
- export { chacha20Init, ChaCha20, Poly1305, ChaCha20Poly1305, XChaCha20Poly1305, XChaCha20Cipher, ChaCha20Generator, _chachaReady } from './chacha20/index.js';
20
- export { sha2Init, SHA256, SHA512, SHA384, HMAC_SHA256, HMAC_SHA512, HMAC_SHA384, HKDF_SHA256, HKDF_SHA512, SHA256Hash, _sha2Ready } from './sha2/index.js';
21
- export { sha3Init, SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, SHAKE256, SHA3_256Hash, _sha3Ready } from './sha3/index.js';
28
+ export { AuthenticationError, SigningError, KeyAgreementError, MerkleCodecError, MerkleLogError } from './errors.js';
29
+ export { serpentInit, Serpent, SerpentCtr, SerpentCbc, SerpentCipher, SerpentGenerator } from './serpent/index.js';
30
+ export { chacha20Init, ChaCha20, Poly1305, ChaCha20Poly1305, XChaCha20Poly1305, XChaCha20Cipher, ChaCha20Generator } from './chacha20/index.js';
31
+ export { sha2Init, SHA256, SHA224, SHA384, SHA512, SHA512_224, SHA512_256, HMAC_SHA256, HMAC_SHA512, HMAC_SHA384, HKDF_SHA256, HKDF_SHA512, SHA256Hash } from './sha2/index.js';
32
+ export { sha3Init, SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHA3_256Stream, SHA3_512Stream, SHAKE128, SHAKE256, SHAKE128Stream, SHAKE256Stream, SHA3_256Hash, CSHAKE128, CSHAKE256, KMAC128, KMAC256, KMACXOF128, KMACXOF256 } from './sha3/index.js';
22
33
  export { keccakInit } from './keccak/index.js';
23
- export { kyberInit, MlKem512, MlKem768, MlKem1024, MlKemBase, KyberSuite, _kyberReady } from './kyber/index.js';
24
- export type { KyberKeyPair, KyberEncapsulation, KyberParams } from './kyber/index.js';
34
+ export { mlkemInit, MlKem512, MlKem768, MlKem1024, MlKemBase, MlKemSuite } from './mlkem/index.js';
35
+ export { aesInit, AES, AESCbc, AESCtr, AESGCM, AESGCMSIV, AESGenerator, AESGCMSIVCipher } from './aes/index.js';
36
+ export { mldsaInit, MlDsa44, MlDsa65, MlDsa87, MlDsaBase, MLDSA44, MLDSA65, MLDSA87 } from './mldsa/index.js';
37
+ export { slhdsaInit, SlhDsaBase, SlhDsa128f, SlhDsa192f, SlhDsa256f, SLHDSA128F, SLHDSA192F, SLHDSA256F, } from './slhdsa/index.js';
38
+ export { blake3Init, BLAKE3, BLAKE3KeyedHash, BLAKE3DeriveKey, BLAKE3Stream, BLAKE3KeyedHashStream, BLAKE3DeriveKeyStream, BLAKE3OutputReader, BLAKE3Hash, } from './blake3/index.js';
39
+ export { ecdsaP256Init, EcdsaP256, pointDecompress, encodeEcPrivateKey, decodeEcPrivateKey, } from './ecdsa/index.js';
40
+ export type { EcdsaP256KeyPair } from './ecdsa/index.js';
41
+ export { ecdsaSignatureToDer, ecdsaSignatureFromDer } from './ecdsa/der.js';
42
+ export { ed25519Init, Ed25519 } from './ed25519/index.js';
43
+ export type { Ed25519KeyPair } from './ed25519/index.js';
44
+ export { x25519Init, X25519 } from './x25519/index.js';
45
+ export type { X25519KeyPair } from './x25519/index.js';
46
+ export type { MlKemKeyPair, MlKemEncapsulation, MlKemParams } from './mlkem/index.js';
47
+ export type { MlDsaKeyPair, MlDsaParams, PreHashAlgorithm } from './mldsa/index.js';
48
+ export type { SlhDsaKeyPair, SlhDsaParams } from './slhdsa/index.js';
25
49
  export { SealStream, OpenStream, Seal, SealStreamPool, FLAG_FRAMED, TAG_DATA, TAG_FINAL, HEADER_SIZE, CHUNK_MIN, CHUNK_MAX } from './stream/index.js';
26
50
  export type { CipherSuite, DerivedKeys, SealStreamOpts, PoolOpts } from './stream/index.js';
51
+ export { MemoryStorage, Sha256Hasher, Sha256Tree, Blake3Hasher, Blake3Tree, splitPoint, verifyInclusionProof, verifyConsistencyProof, buildInclusionProof, buildConsistencyProof, serializeCheckpointBody, parseCheckpointBody, emitSignedNote, parseSignedNote, deriveKeyId, suiteFormatEnumToAlgoByte, lookupAlgoEntryByFormatEnum, lookupAlgoEntryByByte, buildCosigSignedMessage, buildCosignedMessage, emitCosigSignaturePayload, parseCosigSignaturePayload, ALGO_BYTE_ED25519_NOTE, ALGO_BYTE_ED25519_COSIG, ALGO_BYTE_MLDSA44_COSIG, SignedLog, MerkleVerifier, MerkleLog, } from './merkle/index.js';
52
+ export type { Hasher, MerkleTree, MerkleStorage, VerifyInclusionInput, VerifyConsistencyInput, BuildInclusionInput, BuildConsistencyInput, GetNode, Checkpoint, SignatureLine, SignedNote, SignedTreeHead, AlgoEntry, MessageConstruction, SignaturePayload, CosignedMessageInput, SignedLogOpts, MerkleVerifierOpts, MerkleLogCreateOpts, MerkleLogGenerateOpts, } from './merkle/index.js';
53
+ export { Sign, SignStream, VerifyStream } from './sign/index.js';
54
+ export type { SignatureSuite, StreamableSignatureSuite, PrehashAlgorithm, } from './sign/index.js';
55
+ export { Ed25519Suite, Ed25519PreHashSuite, EcdsaP256Suite, MlDsa44Suite, MlDsa65Suite, MlDsa87Suite, MlDsa44PreHashSuite, MlDsa65PreHashSuite, MlDsa87PreHashSuite, SlhDsa128fSuite, SlhDsa192fSuite, SlhDsa256fSuite, SlhDsa128fPreHashSuite, SlhDsa192fPreHashSuite, SlhDsa256fPreHashSuite, MlDsa44SlhDsa128fSuite, MlDsa65SlhDsa192fSuite, MlDsa87SlhDsa256fSuite, MlDsa44Ed25519Suite, MlDsa65Ed25519Suite, MlDsa44EcdsaP256Suite, MlDsa65EcdsaP256Suite, } from './sign/index.js';
27
56
  export { Fortuna } from './fortuna.js';
28
57
  export type { Hash, KeyedHash, Blockcipher, Streamcipher, AEAD, Generator, HashFn } from './types.js';
29
58
  export { KDFChain, ratchetInit, kemRatchetEncap, kemRatchetDecap, ratchetReady, SkippedKeyStore, RatchetKeypair, } from './ratchet/index.js';
30
59
  export type { RatchetInitResult, KemEncapResult, KemDecapResult, MlKemLike, RatchetMessageHeader, ResolveHandle, SkippedKeyStoreOpts, } from './ratchet/index.js';
31
- export { hexToBytes, bytesToHex, utf8ToBytes, bytesToUtf8, base64ToBytes, bytesToBase64, constantTimeEqual, CT_MAX_BYTES, wipe, xor, concat, randomBytes, hasSIMD, } from './utils.js';
60
+ export { hexToBytes, bytesToHex, utf8ToBytes, bytesToUtf8, base64ToBytes, bytesToBase64, constantTimeEqual, CTE_MAX_BYTES, wipe, xor, concat, randomBytes, hasSIMD, } from './utils.js';
package/dist/index.js CHANGED
@@ -19,21 +19,35 @@
19
19
  // ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
20
20
  // ▀█████▀▀
21
21
  //
22
- // Root barrel re-exports everything
22
+ // Root barrel, re-exports everything
23
23
  import { serpentInit } from './serpent/index.js';
24
24
  import { chacha20Init } from './chacha20/index.js';
25
25
  import { sha2Init } from './sha2/index.js';
26
26
  import { sha3Init } from './sha3/index.js';
27
27
  import { keccakInit } from './keccak/index.js';
28
- import { kyberInit } from './kyber/index.js';
28
+ import { mlkemInit } from './mlkem/index.js';
29
+ import { aesInit } from './aes/index.js';
30
+ import { mldsaInit } from './mldsa/index.js';
31
+ import { slhdsaInit } from './slhdsa/index.js';
32
+ import { blake3Init } from './blake3/index.js';
33
+ import { ecdsaP256Init } from './ecdsa/index.js';
34
+ import { initModule } from './init.js';
29
35
  import { hasSIMD } from './utils.js';
36
+ // curve25519 backs ed25519 + x25519. Public surface is the
37
+ // per-primitive alias; 'curve25519' key accepted for Module symmetry.
30
38
  const _dispatchers = {
31
39
  serpent: serpentInit,
32
40
  chacha20: chacha20Init,
33
41
  sha2: sha2Init,
34
42
  sha3: sha3Init,
35
43
  keccak: keccakInit,
36
- kyber: kyberInit,
44
+ mlkem: mlkemInit,
45
+ aes: aesInit,
46
+ mldsa: mldsaInit,
47
+ slhdsa: slhdsaInit,
48
+ blake3: blake3Init,
49
+ curve25519: (source) => initModule('curve25519', source),
50
+ p256: ecdsaP256Init,
37
51
  };
38
52
  /**
39
53
  * Load one or more WASM modules. Each key is a module name; the value is the
@@ -45,30 +59,60 @@ const _dispatchers = {
45
59
  * import { sha2Wasm } from 'leviathan-crypto/sha2/embedded';
46
60
  * await init({ serpent: serpentWasm, sha2: sha2Wasm });
47
61
  * ```
62
+ *
63
+ * `ed25519` and `x25519` are aliases for the underlying `curve25519`
64
+ * module. `init({ ed25519: src })` and `init({ x25519: src })` both work,
65
+ * and `init({ ed25519: src, x25519: src })` is accepted (single underlying
66
+ * init). Two different sources for the same underlying module is rejected.
48
67
  */
49
68
  export async function init(sources) {
50
69
  const entries = Object.entries(sources);
51
- // SIMD preflight serpent, chacha20, and kyber modules contain SIMD instructions
52
- if (('serpent' in sources || 'chacha20' in sources || 'kyber' in sources) && !hasSIMD())
53
- throw new Error('leviathan-crypto: serpent, chacha20, and kyber require WebAssembly SIMD — '
54
- + 'this runtime does not support it');
55
- for (const [mod, src] of entries) {
56
- if (!Object.hasOwn(_dispatchers, mod))
57
- throw new Error(`leviathan-crypto: unknown module "${mod}" — expected one of: ${Object.keys(_dispatchers).join(', ')}`);
70
+ const resolved = new Map();
71
+ for (const [key, src] of entries) {
58
72
  if (src == null)
59
- throw new TypeError(`leviathan-crypto: source for "${mod}" is null or undefined`);
73
+ throw new TypeError(`leviathan-crypto: source for "${key}" is null or undefined`);
74
+ const target = (key === 'ed25519' || key === 'x25519') ? 'curve25519' : key;
75
+ if (!Object.hasOwn(_dispatchers, target))
76
+ throw new Error(`leviathan-crypto: unknown module "${key}", expected one of: `
77
+ + `${Object.keys(_dispatchers).join(', ')}, ed25519, x25519`);
78
+ const prior = resolved.get(target);
79
+ if (prior !== undefined) {
80
+ if (prior !== src)
81
+ throw new Error('leviathan-crypto: init() called with different sources for "ed25519" and "x25519" '
82
+ + '(both alias to curve25519, sources must be identical)');
83
+ continue;
84
+ }
85
+ resolved.set(target, src);
60
86
  }
61
- await Promise.all(entries.map(([mod, src]) => _dispatchers[mod](src)));
87
+ // SIMD preflight for modules that contain v128 instructions
88
+ // (see scripts/lib/modules.ts).
89
+ if ((resolved.has('serpent') || resolved.has('chacha20') || resolved.has('mlkem')
90
+ || resolved.has('aes') || resolved.has('mldsa') || resolved.has('blake3'))
91
+ && !hasSIMD())
92
+ throw new Error('leviathan-crypto: serpent, chacha20, mlkem, aes, mldsa, and blake3 require WebAssembly SIMD, '
93
+ + 'this runtime does not support it');
94
+ await Promise.all(Array.from(resolved.entries()).map(([mod, src]) => _dispatchers[mod](src)));
62
95
  }
63
96
  export { isInitialized } from './init.js';
64
- export { AuthenticationError } from './errors.js';
65
- export { serpentInit, Serpent, SerpentCtr, SerpentCbc, SerpentCipher, SerpentGenerator, _serpentReady } from './serpent/index.js';
66
- export { chacha20Init, ChaCha20, Poly1305, ChaCha20Poly1305, XChaCha20Poly1305, XChaCha20Cipher, ChaCha20Generator, _chachaReady } from './chacha20/index.js';
67
- export { sha2Init, SHA256, SHA512, SHA384, HMAC_SHA256, HMAC_SHA512, HMAC_SHA384, HKDF_SHA256, HKDF_SHA512, SHA256Hash, _sha2Ready } from './sha2/index.js';
68
- export { sha3Init, SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, SHAKE256, SHA3_256Hash, _sha3Ready } from './sha3/index.js';
97
+ export { AuthenticationError, SigningError, KeyAgreementError, MerkleCodecError, MerkleLogError } from './errors.js';
98
+ export { serpentInit, Serpent, SerpentCtr, SerpentCbc, SerpentCipher, SerpentGenerator } from './serpent/index.js';
99
+ export { chacha20Init, ChaCha20, Poly1305, ChaCha20Poly1305, XChaCha20Poly1305, XChaCha20Cipher, ChaCha20Generator } from './chacha20/index.js';
100
+ export { sha2Init, SHA256, SHA224, SHA384, SHA512, SHA512_224, SHA512_256, HMAC_SHA256, HMAC_SHA512, HMAC_SHA384, HKDF_SHA256, HKDF_SHA512, SHA256Hash } from './sha2/index.js';
101
+ export { sha3Init, SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHA3_256Stream, SHA3_512Stream, SHAKE128, SHAKE256, SHAKE128Stream, SHAKE256Stream, SHA3_256Hash, CSHAKE128, CSHAKE256, KMAC128, KMAC256, KMACXOF128, KMACXOF256 } from './sha3/index.js';
69
102
  export { keccakInit } from './keccak/index.js';
70
- export { kyberInit, MlKem512, MlKem768, MlKem1024, MlKemBase, KyberSuite, _kyberReady } from './kyber/index.js';
103
+ export { mlkemInit, MlKem512, MlKem768, MlKem1024, MlKemBase, MlKemSuite } from './mlkem/index.js';
104
+ export { aesInit, AES, AESCbc, AESCtr, AESGCM, AESGCMSIV, AESGenerator, AESGCMSIVCipher } from './aes/index.js';
105
+ export { mldsaInit, MlDsa44, MlDsa65, MlDsa87, MlDsaBase, MLDSA44, MLDSA65, MLDSA87 } from './mldsa/index.js';
106
+ export { slhdsaInit, SlhDsaBase, SlhDsa128f, SlhDsa192f, SlhDsa256f, SLHDSA128F, SLHDSA192F, SLHDSA256F, } from './slhdsa/index.js';
107
+ export { blake3Init, BLAKE3, BLAKE3KeyedHash, BLAKE3DeriveKey, BLAKE3Stream, BLAKE3KeyedHashStream, BLAKE3DeriveKeyStream, BLAKE3OutputReader, BLAKE3Hash, } from './blake3/index.js';
108
+ export { ecdsaP256Init, EcdsaP256, pointDecompress, encodeEcPrivateKey, decodeEcPrivateKey, } from './ecdsa/index.js';
109
+ export { ecdsaSignatureToDer, ecdsaSignatureFromDer } from './ecdsa/der.js';
110
+ export { ed25519Init, Ed25519 } from './ed25519/index.js';
111
+ export { x25519Init, X25519 } from './x25519/index.js';
71
112
  export { SealStream, OpenStream, Seal, SealStreamPool, FLAG_FRAMED, TAG_DATA, TAG_FINAL, HEADER_SIZE, CHUNK_MIN, CHUNK_MAX } from './stream/index.js';
113
+ export { MemoryStorage, Sha256Hasher, Sha256Tree, Blake3Hasher, Blake3Tree, splitPoint, verifyInclusionProof, verifyConsistencyProof, buildInclusionProof, buildConsistencyProof, serializeCheckpointBody, parseCheckpointBody, emitSignedNote, parseSignedNote, deriveKeyId, suiteFormatEnumToAlgoByte, lookupAlgoEntryByFormatEnum, lookupAlgoEntryByByte, buildCosigSignedMessage, buildCosignedMessage, emitCosigSignaturePayload, parseCosigSignaturePayload, ALGO_BYTE_ED25519_NOTE, ALGO_BYTE_ED25519_COSIG, ALGO_BYTE_MLDSA44_COSIG, SignedLog, MerkleVerifier, MerkleLog, } from './merkle/index.js';
114
+ export { Sign, SignStream, VerifyStream } from './sign/index.js';
115
+ export { Ed25519Suite, Ed25519PreHashSuite, EcdsaP256Suite, MlDsa44Suite, MlDsa65Suite, MlDsa87Suite, MlDsa44PreHashSuite, MlDsa65PreHashSuite, MlDsa87PreHashSuite, SlhDsa128fSuite, SlhDsa192fSuite, SlhDsa256fSuite, SlhDsa128fPreHashSuite, SlhDsa192fPreHashSuite, SlhDsa256fPreHashSuite, MlDsa44SlhDsa128fSuite, MlDsa65SlhDsa192fSuite, MlDsa87SlhDsa256fSuite, MlDsa44Ed25519Suite, MlDsa65Ed25519Suite, MlDsa44EcdsaP256Suite, MlDsa65EcdsaP256Suite, } from './sign/index.js';
72
116
  export { Fortuna } from './fortuna.js';
73
117
  export { KDFChain, ratchetInit, kemRatchetEncap, kemRatchetDecap, ratchetReady, SkippedKeyStore, RatchetKeypair, } from './ratchet/index.js';
74
- export { hexToBytes, bytesToHex, utf8ToBytes, bytesToUtf8, base64ToBytes, bytesToBase64, constantTimeEqual, CT_MAX_BYTES, wipe, xor, concat, randomBytes, hasSIMD, } from './utils.js';
118
+ export { hexToBytes, bytesToHex, utf8ToBytes, bytesToUtf8, base64ToBytes, bytesToBase64, constantTimeEqual, CTE_MAX_BYTES, wipe, xor, concat, randomBytes, hasSIMD, } from './utils.js';
package/dist/init.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { WasmSource } from './wasm-source.js';
2
- export type Module = 'serpent' | 'chacha20' | 'sha2' | 'sha3' | 'keccak' | 'kyber';
2
+ export type Module = 'serpent' | 'chacha20' | 'sha2' | 'sha3' | 'keccak' | 'mlkem' | 'aes' | 'mldsa' | 'slhdsa' | 'blake3' | 'curve25519' | 'p256';
3
3
  export declare function initModule(mod: Module, source: WasmSource): Promise<void>;
4
4
  export declare function getInstance(mod: Module): WebAssembly.Instance;
5
5
  export declare function isInitialized(mod: Module): boolean;
package/dist/init.js CHANGED
@@ -1,17 +1,15 @@
1
1
  import { loadWasm } from './loader.js';
2
2
  import { hasSIMD } from './utils.js';
3
- // 'keccak' is an alias for 'sha3' same WASM binary, same instance slot
3
+ // 'keccak' is an alias for 'sha3', same WASM binary, same instance slot
4
4
  const ALIASES = { keccak: 'sha3' };
5
5
  function resolve(mod) {
6
6
  return ALIASES[mod] ?? mod;
7
7
  }
8
- // Module-scope cache: one WebAssembly.Instance per canonical module
8
+ // Per-canonical-module instance cache.
9
9
  const instances = new Map();
10
- // Pending inits — coalesces concurrent initModule calls for the same module.
10
+ // Coalesces concurrent initModule calls.
11
11
  const pending = new Map();
12
- // Exclusivity registry: per-module ownership token held by a stateful wrapper
13
- // for its entire lifetime. Prevents shared-WASM-state clobber when two
14
- // instances from the same module would otherwise trample each other's memory.
12
+ // Per-module exclusivity token held by a stateful wrapper.
15
13
  const owners = new Map();
16
14
  export async function initModule(mod, source) {
17
15
  const resolved = resolve(mod);
@@ -22,8 +20,8 @@ export async function initModule(mod, source) {
22
20
  await inflight;
23
21
  return;
24
22
  }
25
- if ((resolved === 'serpent' || resolved === 'chacha20' || resolved === 'kyber') && !hasSIMD())
26
- throw new Error('leviathan-crypto: serpent, chacha20, and kyber require WebAssembly SIMD '
23
+ if ((resolved === 'serpent' || resolved === 'chacha20' || resolved === 'mlkem' || resolved === 'aes' || resolved === 'mldsa' || resolved === 'blake3') && !hasSIMD())
24
+ throw new Error('leviathan-crypto: serpent, chacha20, mlkem, aes, mldsa, and blake3 require WebAssembly SIMD, '
27
25
  + 'this runtime does not support it');
28
26
  const p = loadWasm(source);
29
27
  pending.set(resolved, p);
@@ -41,7 +39,7 @@ export function getInstance(mod) {
41
39
  throw new Error(`leviathan-crypto: call init({ ${mod}: ... }) before using this class`);
42
40
  }
43
41
  if (owners.has(r)) {
44
- throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module `
42
+ throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module, `
45
43
  + 'call dispose() on it before constructing a new one');
46
44
  }
47
45
  return inst;
@@ -57,7 +55,7 @@ export function isInitialized(mod) {
57
55
  export function _acquireModule(mod) {
58
56
  const r = resolve(mod);
59
57
  if (owners.has(r))
60
- throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module `
58
+ throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module, `
61
59
  + 'call dispose() on it before constructing a new one');
62
60
  const tok = Symbol(r);
63
61
  owners.set(r, tok);
@@ -80,27 +78,15 @@ export function _releaseModule(mod, tok) {
80
78
  export function _isModuleBusy(mod) {
81
79
  return owners.has(resolve(mod));
82
80
  }
83
- /**
84
- * Throw if `mod` is currently held by a stateful instance. Called at the top
85
- * of every atomic WASM-touching method so that cached-exports access paths
86
- * cannot silently clobber a live stateful instance's WASM state.
87
- *
88
- * The error message is intentionally identical to `_acquireModule`'s so that
89
- * error handlers matching on text work uniformly across construction-time and
90
- * method-time ownership failures.
91
- * @internal
92
- */
81
+ /** @internal */
93
82
  export function _assertNotOwned(mod) {
94
- // Deliberately unoptimized. Do not add caching or epoch tracking: the
95
- // check must read current ownership on every call so an atomic op cannot
96
- // race ahead of a stateful acquirer.
97
83
  const r = resolve(mod);
98
84
  if (owners.has(r))
99
- throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module `
85
+ throw new Error(`leviathan-crypto: another stateful instance is using the '${r}' WASM module, `
100
86
  + 'call dispose() on it before constructing a new one');
101
87
  }
102
88
  /**
103
- * Reset all cached instances for testing only. Clears `instances`, `pending`,
89
+ * Reset all cached instances, for testing only. Clears `instances`, `pending`,
104
90
  * and `owners` so tests can re-exercise module lifecycle (init, exclusivity,
105
91
  * race) from a known-empty state.
106
92
  * @internal
@@ -22,6 +22,6 @@
22
22
  // src/ts/keccak/embedded.ts
23
23
  //
24
24
  // Re-exports the sha3 WASM blob under the keccak name.
25
- // The keccak alias shares the sha3 binary no separate keccak.wasm exists.
25
+ // The keccak alias shares the sha3 binary, no separate keccak.wasm exists.
26
26
  // Import via `leviathan-crypto/keccak/embedded`.
27
27
  export { WASM_GZ_BASE64 as keccakWasm } from '../embedded/sha3.js';
@@ -1,4 +1,6 @@
1
1
  import type { WasmSource } from '../wasm-source.js';
2
2
  export declare function keccakInit(source: WasmSource): Promise<void>;
3
3
  export type { WasmSource };
4
+ export { isInitialized } from '../init.js';
4
5
  export { SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, SHAKE256 } from '../sha3/index.js';
6
+ export { CSHAKE128, CSHAKE256, KMAC128, KMAC256, KMACXOF128, KMACXOF256 } from '../sha3/index.js';
@@ -21,11 +21,13 @@
21
21
  //
22
22
  // src/ts/keccak/index.ts
23
23
  //
24
- // Keccak alias subpath resolves to the sha3 WASM module slot.
25
- // Consumers who prefer the Keccak name (e.g. Kyber/ML-KEM implementations)
24
+ // Keccak alias subpath, resolves to the sha3 WASM module slot.
25
+ // Consumers who prefer the Keccak name (e.g. ML-KEM implementations)
26
26
  // can import from `leviathan-crypto/keccak` instead of `leviathan-crypto/sha3`.
27
27
  import { initModule } from '../init.js';
28
28
  export async function keccakInit(source) {
29
29
  return initModule('keccak', source);
30
30
  }
31
+ export { isInitialized } from '../init.js';
31
32
  export { SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, SHAKE256 } from '../sha3/index.js';
33
+ export { CSHAKE128, CSHAKE256, KMAC128, KMAC256, KMACXOF128, KMACXOF256 } from '../sha3/index.js';
package/dist/loader.d.ts CHANGED
@@ -1,24 +1 @@
1
- import type { WasmSource } from './wasm-source.js';
2
- /**
3
- * Decode a gzip+base64 embedded WASM string to raw bytes.
4
- * Guards against missing DecompressionStream (Node <18, non-browser runtimes).
5
- * Exported for pool worker launchers that decode blobs before spawning threads.
6
- */
7
- export declare function decodeWasm(b64: string): Promise<Uint8Array>;
8
- /**
9
- * Compile a WASM source to a Module without instantiating.
10
- * Used by pool infrastructure to send compiled modules to workers.
11
- *
12
- * Thenable sources (Promise<Response>, Promise<ArrayBuffer>, etc.) are
13
- * resolved and then re-dispatched by the runtime type of the resolved value.
14
- * Depth is capped at `MAX_THENABLE_DEPTH` to prevent runaway recursion.
15
- */
16
- export declare function compileWasm(source: WasmSource, _depth?: number): Promise<WebAssembly.Module>;
17
- /**
18
- * Load a WASM module from any accepted source type.
19
- * The loading strategy is inferred from the argument type — no mode string.
20
- *
21
- * Throws `TypeError` for null, numeric, or unrecognised inputs, or if a
22
- * thenable source nests deeper than `MAX_THENABLE_DEPTH`.
23
- */
24
- export declare function loadWasm(source: WasmSource): Promise<WebAssembly.Instance>;
1
+ export {};