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
@@ -0,0 +1,234 @@
1
+ // ▄▄▄▄▄▄▄▄▄▄
2
+ // ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
3
+ // ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
4
+ // ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
5
+ // ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
6
+ // ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
7
+ // ███████▌ ▀██▀ ███
8
+ // ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
9
+ // ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
10
+ // ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
11
+ // ▀████▄ ▄██▄
12
+ // ▐████ ▐███ Author: xero (https://x-e.ro)
13
+ // ▄▄██████████ ▐███ ▄▄ License: MIT
14
+ // ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
15
+ // ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
16
+ // ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
17
+ // ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
18
+ // █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
19
+ // ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
20
+ // ▀█████▀▀
21
+ //
22
+ // src/ts/sign/suites/hybrid-pq.ts
23
+ //
24
+ // MldsaSlhdsaHybridSuite factory (internal). Three exported PQ-only
25
+ // hybrid consts:
26
+ // 0x30 MlDsa44SlhDsa128fSuite (cat-1)
27
+ // 0x31 MlDsa65SlhDsa192fSuite (cat-3)
28
+ // 0x32 MlDsa87SlhDsa256fSuite (cat-5)
29
+ //
30
+ // Wire is leviathan-defined (no composite-sigs entry covers PQ-only
31
+ // pairs); ML-DSA first, no length prefixes (per-hybrid sizes catalog-
32
+ // fixed).
33
+ //
34
+ // Both halves sign the same prehash digest under the same effective_ctx.
35
+ // FIPS 204 §5.4 Alg 4 and FIPS 205 §10.2 Alg 22 produce byte-identical
36
+ // M' = toByte(1,1) || toByte(|ctx|,1) || ctx || OID(ph) || PH_M given a
37
+ // common (digest, ph, ctx); SHAKE128 / SHAKE256 share OIDs across the
38
+ // two specs (FIPS 204 §5.4.1 Table 1 = FIPS 205 §10.2 Table 11).
39
+ //
40
+ // verifyPrehashed ALWAYS runs both sub-verifies before AND-reduce
41
+ // (constant-time gate). Per-hybrid ctxDomain prevents cross-suite and
42
+ // cross-hybrid forgery.
43
+ //
44
+ // Wire layout, M' construction, ctxDomain table, constant-time
45
+ // discipline, and threat model:
46
+ // docs/signaturesuite.md#pq-only-hybrid-composite-encoding.
47
+ import { concat } from '../../utils.js';
48
+ import { wipe, utf8ToBytes } from '../../utils.js';
49
+ import { SigningError } from '../../errors.js';
50
+ import { MlDsa44, MlDsa65, MlDsa87, MLDSA44, MLDSA65, MLDSA87, } from '../../mldsa/index.js';
51
+ import { SlhDsa128f, SlhDsa192f, SlhDsa256f, SLHDSA128F, SLHDSA192F, SLHDSA256F, } from '../../slhdsa/index.js';
52
+ import { buildEffectiveCtx, CTX_DOMAIN_MAX } from '../ctx.js';
53
+ import { createRunningHash } from '../hasher.js';
54
+ // Lowercase public sign-surface → uppercase ML-DSA-side algorithm name.
55
+ // Mirrors prehashAlgoToMldsa in ctx.ts but only covers the two SHAKE
56
+ // entries actually used by hybrid suites; the hybrid catalog is locked
57
+ // to shake-128 (cat-1) and shake-256 (cat-3 / cat-5).
58
+ function prehashAlgoToMldsaLocal(algo) {
59
+ switch (algo) {
60
+ case 'shake-128': return 'SHAKE128';
61
+ case 'shake-256': return 'SHAKE256';
62
+ case 'sha-256': return 'SHA2-256';
63
+ case 'sha-512': return 'SHA2-512';
64
+ case 'sha3-256': return 'SHA3-256';
65
+ case 'sha3-512': return 'SHA3-512';
66
+ default: {
67
+ const _exhaustive = algo;
68
+ throw new Error(`leviathan-crypto: unknown prehash algorithm ${_exhaustive}`);
69
+ }
70
+ }
71
+ }
72
+ function prehashAlgoToSlhdsaLocal(algo) {
73
+ switch (algo) {
74
+ case 'shake-128': return 'SHAKE128';
75
+ case 'shake-256': return 'SHAKE256';
76
+ case 'sha-256': return 'SHA2-256';
77
+ case 'sha-512': return 'SHA2-512';
78
+ case 'sha3-256': return 'SHA3-256';
79
+ case 'sha3-512': return 'SHA3-512';
80
+ default: {
81
+ const _exhaustive = algo;
82
+ throw new Error(`leviathan-crypto: unknown prehash algorithm ${_exhaustive}`);
83
+ }
84
+ }
85
+ }
86
+ // ── Factory ─────────────────────────────────────────────────────────────────
87
+ function MldsaSlhdsaHybridSuite(MlDsaClass, mldsaParams, SlhDsaClass, slhdsaParams, formatEnum, formatName, ctxDomain, prehashAlgorithm, prehashSize) {
88
+ if (utf8ToBytes(ctxDomain).length > CTX_DOMAIN_MAX)
89
+ throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' too long for ${formatName}`);
90
+ const pkSize = mldsaParams.pkBytes + slhdsaParams.pkBytes;
91
+ const skSize = mldsaParams.skBytes + slhdsaParams.skBytes;
92
+ const sigMaxSize = mldsaParams.sigBytes + slhdsaParams.sigBytes;
93
+ const wasmModules = Object.freeze(['mldsa', 'sha3', 'slhdsa']);
94
+ const mldsaHashAlgo = prehashAlgoToMldsaLocal(prehashAlgorithm);
95
+ const slhdsaHashAlgo = prehashAlgoToSlhdsaLocal(prehashAlgorithm);
96
+ return {
97
+ formatEnum,
98
+ formatName,
99
+ ctxDomain,
100
+ pkSize,
101
+ skSize,
102
+ sigMaxSize,
103
+ wasmModules,
104
+ prehashAlgorithm,
105
+ prehashSize,
106
+ sign(sk, msg, ctx) {
107
+ const h = createRunningHash(prehashAlgorithm);
108
+ try {
109
+ h.update(msg);
110
+ const digest = h.finalize();
111
+ try {
112
+ return this.signPrehashed(sk, digest, ctx);
113
+ }
114
+ finally {
115
+ wipe(digest);
116
+ }
117
+ }
118
+ catch (e) {
119
+ h.dispose();
120
+ throw e;
121
+ }
122
+ },
123
+ verify(pk, msg, sig, ctx) {
124
+ const h = createRunningHash(prehashAlgorithm);
125
+ try {
126
+ h.update(msg);
127
+ const digest = h.finalize();
128
+ try {
129
+ return this.verifyPrehashed(pk, digest, sig, ctx);
130
+ }
131
+ finally {
132
+ wipe(digest);
133
+ }
134
+ }
135
+ catch (e) {
136
+ h.dispose();
137
+ throw e;
138
+ }
139
+ },
140
+ keygen() {
141
+ const mldsaInst = new MlDsaClass();
142
+ let mldsaKp;
143
+ try {
144
+ mldsaKp = mldsaInst.keygen();
145
+ }
146
+ finally {
147
+ mldsaInst.dispose();
148
+ }
149
+ const slhdsaInst = new SlhDsaClass();
150
+ let slhdsaKp;
151
+ try {
152
+ slhdsaKp = slhdsaInst.keygen();
153
+ }
154
+ finally {
155
+ slhdsaInst.dispose();
156
+ }
157
+ return {
158
+ pk: concat(mldsaKp.verificationKey, slhdsaKp.verificationKey),
159
+ sk: concat(mldsaKp.signingKey, slhdsaKp.signingKey),
160
+ };
161
+ },
162
+ signPrehashed(sk, digest, ctx) {
163
+ if (digest.length !== prehashSize)
164
+ throw new SigningError('sig-malformed-input', `digest length ${digest.length} != ${prehashSize} for ${formatName}`);
165
+ if (sk.length !== skSize)
166
+ throw new SigningError('sig-key-size', `sk length ${sk.length} != ${skSize} for ${formatName}`);
167
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
168
+ const skMldsa = sk.subarray(0, mldsaParams.skBytes);
169
+ const skSlhdsa = sk.subarray(mldsaParams.skBytes);
170
+ const mldsaInst = new MlDsaClass();
171
+ let sigMldsa;
172
+ try {
173
+ sigMldsa = mldsaInst.signHashPrehashed(skMldsa, digest, mldsaHashAlgo, effectiveCtx);
174
+ }
175
+ finally {
176
+ mldsaInst.dispose();
177
+ }
178
+ const slhdsaInst = new SlhDsaClass();
179
+ let sigSlhdsa;
180
+ try {
181
+ sigSlhdsa = slhdsaInst.signHashPrehashed(skSlhdsa, digest, slhdsaHashAlgo, effectiveCtx);
182
+ }
183
+ finally {
184
+ slhdsaInst.dispose();
185
+ }
186
+ try {
187
+ return concat(sigMldsa, sigSlhdsa);
188
+ }
189
+ finally {
190
+ wipe(effectiveCtx);
191
+ }
192
+ },
193
+ verifyPrehashed(pk, digest, sig, ctx) {
194
+ if (pk.length !== pkSize)
195
+ return false;
196
+ if (sig.length !== sigMaxSize)
197
+ return false;
198
+ if (digest.length !== prehashSize)
199
+ throw new SigningError('sig-malformed-input', `digest length ${digest.length} != ${prehashSize} for ${formatName}`);
200
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
201
+ const pkMldsa = pk.subarray(0, mldsaParams.pkBytes);
202
+ const pkSlhdsa = pk.subarray(mldsaParams.pkBytes);
203
+ const sigMldsa = sig.subarray(0, mldsaParams.sigBytes);
204
+ const sigSlhdsa = sig.subarray(mldsaParams.sigBytes);
205
+ let mldsaOk;
206
+ let slhdsaOk;
207
+ try {
208
+ const mldsaInst = new MlDsaClass();
209
+ try {
210
+ mldsaOk = mldsaInst.verifyHashPrehashed(pkMldsa, digest, sigMldsa, mldsaHashAlgo, effectiveCtx);
211
+ }
212
+ finally {
213
+ mldsaInst.dispose();
214
+ }
215
+ const slhdsaInst = new SlhDsaClass();
216
+ try {
217
+ slhdsaOk = slhdsaInst.verifyHashPrehashed(pkSlhdsa, digest, sigSlhdsa, slhdsaHashAlgo, effectiveCtx);
218
+ }
219
+ finally {
220
+ slhdsaInst.dispose();
221
+ }
222
+ }
223
+ finally {
224
+ wipe(effectiveCtx);
225
+ }
226
+ // Do NOT wipe sub-sig subarrays; they alias caller-owned `sig`.
227
+ return mldsaOk && slhdsaOk;
228
+ },
229
+ };
230
+ }
231
+ // ── Exported suite consts ───────────────────────────────────────────────────
232
+ export const MlDsa44SlhDsa128fSuite = MldsaSlhdsaHybridSuite(MlDsa44, MLDSA44, SlhDsa128f, SLHDSA128F, 0x30, 'mldsa44-slhdsa128f', 'mldsa44-slhdsa128f-envelope-v3', 'shake-128', 32);
233
+ export const MlDsa65SlhDsa192fSuite = MldsaSlhdsaHybridSuite(MlDsa65, MLDSA65, SlhDsa192f, SLHDSA192F, 0x31, 'mldsa65-slhdsa192f', 'mldsa65-slhdsa192f-envelope-v3', 'shake-256', 64);
234
+ export const MlDsa87SlhDsa256fSuite = MldsaSlhdsaHybridSuite(MlDsa87, MLDSA87, SlhDsa256f, SLHDSA256F, 0x32, 'mldsa87-slhdsa256f', 'mldsa87-slhdsa256f-envelope-v3', 'shake-256', 64);
@@ -0,0 +1,7 @@
1
+ import type { SignatureSuite, StreamableSignatureSuite } from '../types.js';
2
+ export declare const MlDsa44Suite: SignatureSuite;
3
+ export declare const MlDsa65Suite: SignatureSuite;
4
+ export declare const MlDsa87Suite: SignatureSuite;
5
+ export declare const MlDsa44PreHashSuite: StreamableSignatureSuite;
6
+ export declare const MlDsa65PreHashSuite: StreamableSignatureSuite;
7
+ export declare const MlDsa87PreHashSuite: StreamableSignatureSuite;
@@ -0,0 +1,161 @@
1
+ // ▄▄▄▄▄▄▄▄▄▄
2
+ // ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
3
+ // ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
4
+ // ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
5
+ // ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
6
+ // ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
7
+ // ███████▌ ▀██▀ ███
8
+ // ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
9
+ // ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
10
+ // ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
11
+ // ▀████▄ ▄██▄
12
+ // ▐████ ▐███ Author: xero (https://x-e.ro)
13
+ // ▄▄██████████ ▐███ ▄▄ License: MIT
14
+ // ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
15
+ // ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
16
+ // ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
17
+ // ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
18
+ // █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
19
+ // ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
20
+ // ▀█████▀▀
21
+ //
22
+ // src/ts/sign/suites/mldsa.ts
23
+ //
24
+ // Pure (0x03/0x04/0x05) and prehash (0x13/0x14/0x15) ML-DSA suites,
25
+ // FIPS 204.
26
+ //
27
+ // Catalog + prehash mapping: docs/signaturesuite.md, docs/mldsa.md.
28
+ import { utf8ToBytes, wipe } from '../../utils.js';
29
+ import { SigningError } from '../../errors.js';
30
+ import { MlDsa44, MlDsa65, MlDsa87, MLDSA44, MLDSA65, MLDSA87, } from '../../mldsa/index.js';
31
+ import { buildEffectiveCtx, prehashAlgoToMldsa, CTX_DOMAIN_MAX, } from '../ctx.js';
32
+ // ── Pure-mode factory ───────────────────────────────────────────────────────
33
+ function MldsaPureSuite(MlDsaClass, params, formatEnum, formatName, ctxDomain) {
34
+ if (utf8ToBytes(ctxDomain).length > CTX_DOMAIN_MAX)
35
+ throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' too long for ${formatName}`);
36
+ const wasmModules = Object.freeze(['mldsa', 'sha3']);
37
+ return {
38
+ formatEnum,
39
+ formatName,
40
+ ctxDomain,
41
+ pkSize: params.pkBytes,
42
+ skSize: params.skBytes,
43
+ sigMaxSize: params.sigBytes,
44
+ wasmModules,
45
+ sign(sk, msg, ctx) {
46
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
47
+ const inst = new MlDsaClass();
48
+ try {
49
+ return inst.sign(sk, msg, effectiveCtx);
50
+ }
51
+ finally {
52
+ inst.dispose();
53
+ wipe(effectiveCtx);
54
+ }
55
+ },
56
+ verify(pk, msg, sig, ctx) {
57
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
58
+ const inst = new MlDsaClass();
59
+ try {
60
+ return inst.verify(pk, msg, sig, effectiveCtx);
61
+ }
62
+ finally {
63
+ inst.dispose();
64
+ wipe(effectiveCtx);
65
+ }
66
+ },
67
+ keygen() {
68
+ const inst = new MlDsaClass();
69
+ try {
70
+ const kp = inst.keygen();
71
+ return { pk: kp.verificationKey, sk: kp.signingKey };
72
+ }
73
+ finally {
74
+ inst.dispose();
75
+ }
76
+ },
77
+ };
78
+ }
79
+ // ── Prehash-mode factory ────────────────────────────────────────────────────
80
+ function MldsaPrehashSuite(MlDsaClass, params, formatEnum, formatName, ctxDomain, prehashAlgorithm, prehashSize) {
81
+ if (utf8ToBytes(ctxDomain).length > CTX_DOMAIN_MAX)
82
+ throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' too long for ${formatName}`);
83
+ const wasmModules = Object.freeze(['mldsa', 'sha3']);
84
+ const mldsaHashAlgo = prehashAlgoToMldsa(prehashAlgorithm);
85
+ return {
86
+ formatEnum,
87
+ formatName,
88
+ ctxDomain,
89
+ pkSize: params.pkBytes,
90
+ skSize: params.skBytes,
91
+ sigMaxSize: params.sigBytes,
92
+ wasmModules,
93
+ prehashAlgorithm,
94
+ prehashSize,
95
+ sign(sk, msg, ctx) {
96
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
97
+ const inst = new MlDsaClass();
98
+ try {
99
+ return inst.signHash(sk, msg, mldsaHashAlgo, effectiveCtx);
100
+ }
101
+ finally {
102
+ inst.dispose();
103
+ wipe(effectiveCtx);
104
+ }
105
+ },
106
+ verify(pk, msg, sig, ctx) {
107
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
108
+ const inst = new MlDsaClass();
109
+ try {
110
+ return inst.verifyHash(pk, msg, sig, mldsaHashAlgo, effectiveCtx);
111
+ }
112
+ finally {
113
+ inst.dispose();
114
+ wipe(effectiveCtx);
115
+ }
116
+ },
117
+ keygen() {
118
+ const inst = new MlDsaClass();
119
+ try {
120
+ const kp = inst.keygen();
121
+ return { pk: kp.verificationKey, sk: kp.signingKey };
122
+ }
123
+ finally {
124
+ inst.dispose();
125
+ }
126
+ },
127
+ signPrehashed(sk, digest, ctx) {
128
+ if (digest.length !== prehashSize)
129
+ throw new SigningError('sig-malformed-input', `digest length ${digest.length} != expected ${prehashSize} for ${formatName}`);
130
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
131
+ const inst = new MlDsaClass();
132
+ try {
133
+ return inst.signHashPrehashed(sk, digest, mldsaHashAlgo, effectiveCtx);
134
+ }
135
+ finally {
136
+ inst.dispose();
137
+ wipe(effectiveCtx);
138
+ }
139
+ },
140
+ verifyPrehashed(pk, digest, sig, ctx) {
141
+ if (digest.length !== prehashSize)
142
+ throw new SigningError('sig-malformed-input', `digest length ${digest.length} != expected ${prehashSize} for ${formatName}`);
143
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
144
+ const inst = new MlDsaClass();
145
+ try {
146
+ return inst.verifyHashPrehashed(pk, digest, sig, mldsaHashAlgo, effectiveCtx);
147
+ }
148
+ finally {
149
+ inst.dispose();
150
+ wipe(effectiveCtx);
151
+ }
152
+ },
153
+ };
154
+ }
155
+ // ── Exported suite consts ───────────────────────────────────────────────────
156
+ export const MlDsa44Suite = MldsaPureSuite(MlDsa44, MLDSA44, 0x03, 'mldsa44', 'mldsa44-envelope-v3');
157
+ export const MlDsa65Suite = MldsaPureSuite(MlDsa65, MLDSA65, 0x04, 'mldsa65', 'mldsa65-envelope-v3');
158
+ export const MlDsa87Suite = MldsaPureSuite(MlDsa87, MLDSA87, 0x05, 'mldsa87', 'mldsa87-envelope-v3');
159
+ export const MlDsa44PreHashSuite = MldsaPrehashSuite(MlDsa44, MLDSA44, 0x13, 'mldsa44-prehash', 'mldsa44-prehash-envelope-v3', 'sha3-256', 32);
160
+ export const MlDsa65PreHashSuite = MldsaPrehashSuite(MlDsa65, MLDSA65, 0x14, 'mldsa65-prehash', 'mldsa65-prehash-envelope-v3', 'sha3-256', 32);
161
+ export const MlDsa87PreHashSuite = MldsaPrehashSuite(MlDsa87, MLDSA87, 0x15, 'mldsa87-prehash', 'mldsa87-prehash-envelope-v3', 'sha3-512', 64);
@@ -0,0 +1,7 @@
1
+ import type { SignatureSuite, StreamableSignatureSuite } from '../types.js';
2
+ export declare const SlhDsa128fSuite: SignatureSuite;
3
+ export declare const SlhDsa192fSuite: SignatureSuite;
4
+ export declare const SlhDsa256fSuite: SignatureSuite;
5
+ export declare const SlhDsa128fPreHashSuite: StreamableSignatureSuite;
6
+ export declare const SlhDsa192fPreHashSuite: StreamableSignatureSuite;
7
+ export declare const SlhDsa256fPreHashSuite: StreamableSignatureSuite;
@@ -0,0 +1,176 @@
1
+ // ▄▄▄▄▄▄▄▄▄▄
2
+ // ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
3
+ // ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
4
+ // ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
5
+ // ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
6
+ // ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
7
+ // ███████▌ ▀██▀ ███
8
+ // ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
9
+ // ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
10
+ // ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
11
+ // ▀████▄ ▄██▄
12
+ // ▐████ ▐███ Author: xero (https://x-e.ro)
13
+ // ▄▄██████████ ▐███ ▄▄ License: MIT
14
+ // ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
15
+ // ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
16
+ // ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
17
+ // ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
18
+ // █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
19
+ // ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
20
+ // ▀█████▀▀
21
+ //
22
+ // src/ts/sign/suites/slhdsa.ts
23
+ //
24
+ // Pure (0x06/0x07/0x08) and prehash (0x16/0x17/0x18) SLH-DSA SHAKE-family
25
+ // fast suites, FIPS 205. Hash pinning per §10.2.2: 128f→SHAKE128 cat 1,
26
+ // 192f→SHAKE256 cat 3, 256f→SHAKE256 cat 5.
27
+ //
28
+ // Catalog + prehash mapping: docs/signaturesuite.md, docs/slhdsa.md.
29
+ import { utf8ToBytes, wipe } from '../../utils.js';
30
+ import { SigningError } from '../../errors.js';
31
+ import { SlhDsa128f, SlhDsa192f, SlhDsa256f, SLHDSA128F, SLHDSA192F, SLHDSA256F, } from '../../slhdsa/index.js';
32
+ import { buildEffectiveCtx, CTX_DOMAIN_MAX } from '../ctx.js';
33
+ function prehashAlgoToSlhdsa(algo) {
34
+ switch (algo) {
35
+ case 'shake-128': return 'SHAKE128';
36
+ case 'shake-256': return 'SHAKE256';
37
+ case 'sha-256': return 'SHA2-256';
38
+ case 'sha-512': return 'SHA2-512';
39
+ case 'sha3-256': return 'SHA3-256';
40
+ case 'sha3-512': return 'SHA3-512';
41
+ default: {
42
+ const _exhaustive = algo;
43
+ throw new Error(`leviathan-crypto: unknown prehash algorithm ${_exhaustive}`);
44
+ }
45
+ }
46
+ }
47
+ // ── Pure-mode factory ───────────────────────────────────────────────────────
48
+ function SlhdsaPureSuite(SlhDsaClass, params, formatEnum, formatName, ctxDomain) {
49
+ if (utf8ToBytes(ctxDomain).length > CTX_DOMAIN_MAX)
50
+ throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' too long for ${formatName}`);
51
+ const wasmModules = Object.freeze(['slhdsa']);
52
+ return {
53
+ formatEnum,
54
+ formatName,
55
+ ctxDomain,
56
+ pkSize: params.pkBytes,
57
+ skSize: params.skBytes,
58
+ sigMaxSize: params.sigBytes,
59
+ wasmModules,
60
+ sign(sk, msg, ctx) {
61
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
62
+ const inst = new SlhDsaClass();
63
+ try {
64
+ return inst.sign(sk, msg, effectiveCtx);
65
+ }
66
+ finally {
67
+ inst.dispose();
68
+ wipe(effectiveCtx);
69
+ }
70
+ },
71
+ verify(pk, msg, sig, ctx) {
72
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
73
+ const inst = new SlhDsaClass();
74
+ try {
75
+ return inst.verify(pk, msg, sig, effectiveCtx);
76
+ }
77
+ finally {
78
+ inst.dispose();
79
+ wipe(effectiveCtx);
80
+ }
81
+ },
82
+ keygen() {
83
+ const inst = new SlhDsaClass();
84
+ try {
85
+ const kp = inst.keygen();
86
+ return { pk: kp.verificationKey, sk: kp.signingKey };
87
+ }
88
+ finally {
89
+ inst.dispose();
90
+ }
91
+ },
92
+ };
93
+ }
94
+ // ── Prehash-mode factory ────────────────────────────────────────────────────
95
+ function SlhdsaPrehashSuite(SlhDsaClass, params, formatEnum, formatName, ctxDomain, prehashAlgorithm, prehashSize) {
96
+ if (utf8ToBytes(ctxDomain).length > CTX_DOMAIN_MAX)
97
+ throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' too long for ${formatName}`);
98
+ const wasmModules = Object.freeze(['slhdsa', 'sha3']);
99
+ const slhHashAlgo = prehashAlgoToSlhdsa(prehashAlgorithm);
100
+ return {
101
+ formatEnum,
102
+ formatName,
103
+ ctxDomain,
104
+ pkSize: params.pkBytes,
105
+ skSize: params.skBytes,
106
+ sigMaxSize: params.sigBytes,
107
+ wasmModules,
108
+ prehashAlgorithm,
109
+ prehashSize,
110
+ sign(sk, msg, ctx) {
111
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
112
+ const inst = new SlhDsaClass();
113
+ try {
114
+ return inst.signHash(sk, msg, slhHashAlgo, effectiveCtx);
115
+ }
116
+ finally {
117
+ inst.dispose();
118
+ wipe(effectiveCtx);
119
+ }
120
+ },
121
+ verify(pk, msg, sig, ctx) {
122
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
123
+ const inst = new SlhDsaClass();
124
+ try {
125
+ return inst.verifyHash(pk, msg, sig, slhHashAlgo, effectiveCtx);
126
+ }
127
+ finally {
128
+ inst.dispose();
129
+ wipe(effectiveCtx);
130
+ }
131
+ },
132
+ keygen() {
133
+ const inst = new SlhDsaClass();
134
+ try {
135
+ const kp = inst.keygen();
136
+ return { pk: kp.verificationKey, sk: kp.signingKey };
137
+ }
138
+ finally {
139
+ inst.dispose();
140
+ }
141
+ },
142
+ signPrehashed(sk, digest, ctx) {
143
+ if (digest.length !== prehashSize)
144
+ throw new SigningError('sig-malformed-input', `digest length ${digest.length} != expected ${prehashSize} for ${formatName}`);
145
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
146
+ const inst = new SlhDsaClass();
147
+ try {
148
+ return inst.signHashPrehashed(sk, digest, slhHashAlgo, effectiveCtx);
149
+ }
150
+ finally {
151
+ inst.dispose();
152
+ wipe(effectiveCtx);
153
+ }
154
+ },
155
+ verifyPrehashed(pk, digest, sig, ctx) {
156
+ if (digest.length !== prehashSize)
157
+ throw new SigningError('sig-malformed-input', `digest length ${digest.length} != expected ${prehashSize} for ${formatName}`);
158
+ const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
159
+ const inst = new SlhDsaClass();
160
+ try {
161
+ return inst.verifyHashPrehashed(pk, digest, sig, slhHashAlgo, effectiveCtx);
162
+ }
163
+ finally {
164
+ inst.dispose();
165
+ wipe(effectiveCtx);
166
+ }
167
+ },
168
+ };
169
+ }
170
+ // ── Exported suite consts ───────────────────────────────────────────────────
171
+ export const SlhDsa128fSuite = SlhdsaPureSuite(SlhDsa128f, SLHDSA128F, 0x06, 'slhdsa128f', 'slhdsa128f-envelope-v3');
172
+ export const SlhDsa192fSuite = SlhdsaPureSuite(SlhDsa192f, SLHDSA192F, 0x07, 'slhdsa192f', 'slhdsa192f-envelope-v3');
173
+ export const SlhDsa256fSuite = SlhdsaPureSuite(SlhDsa256f, SLHDSA256F, 0x08, 'slhdsa256f', 'slhdsa256f-envelope-v3');
174
+ export const SlhDsa128fPreHashSuite = SlhdsaPrehashSuite(SlhDsa128f, SLHDSA128F, 0x16, 'slhdsa128f-prehash', 'slhdsa128f-prehash-envelope-v3', 'shake-128', 32);
175
+ export const SlhDsa192fPreHashSuite = SlhdsaPrehashSuite(SlhDsa192f, SLHDSA192F, 0x17, 'slhdsa192f-prehash', 'slhdsa192f-prehash-envelope-v3', 'shake-256', 64);
176
+ export const SlhDsa256fPreHashSuite = SlhdsaPrehashSuite(SlhDsa256f, SLHDSA256F, 0x18, 'slhdsa256f-prehash', 'slhdsa256f-prehash-envelope-v3', 'shake-256', 64);