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,232 @@
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/mldsa/keygen.ts
23
+ //
24
+ // FIPS 204 §6.1 Algorithm 6, ML-DSA.KeyGen_internal.
25
+ // Implements the deterministic xi-seeded key generator used by both the
26
+ // public keygen() (random ξ) and keygenDerand(ξ) entry points. Output is
27
+ // (pk, sk) byte-encoded per Algorithms 22 (pkEncode) and 24 (skEncode).
28
+ //
29
+ // Slot map (matrix slot + 6 polyvec slots):
30
+ // MATRIX_SLOT Â (matrix, k×ℓ polynomials in NTT domain, public)
31
+ // POLYVEC_SLOT_0 s₁ (time domain, preserved for skEncode bit_pack)
32
+ // POLYVEC_SLOT_1 s₂ (time domain, preserved for skEncode bit_pack)
33
+ // POLYVEC_SLOT_2 t = NTT⁻¹(Â · ŝ₁) + s₂ (intermediate, secret-derived)
34
+ // POLYVEC_SLOT_3 t₁ (high bits of t, public, encoded into pk)
35
+ // POLYVEC_SLOT_4 t₀ (low bits of t, secret, encoded into sk)
36
+ // POLYVEC_SLOT_5 ŝ₁ (NTT-domain Montgomery-form copy of s₁; consumed by
37
+ // the matrix product, then wiped). Time-domain s₁
38
+ // must survive in slot 0 for the sk BitPack step.
39
+ //
40
+ // POLY_SLOT_7 is reserved as scratch by polyvec_pointwise_acc_montgomery
41
+ // (called via polyvec_matrix_pointwise_montgomery); we never touch it.
42
+ import { wipe } from '../utils.js';
43
+ import { shake256HashConcat } from './sha3-helpers.js';
44
+ import { expandA, expandS } from './expand.js';
45
+ const POLY_BYTES = 1024;
46
+ const D = 13; // FIPS 204 §4 Table 1, d=13 for all sets
47
+ // Bitlen helper. bitlen(n) = floor(log2(n)) + 1 for n > 0. For ML-DSA we
48
+ // only ever feed it positive n, so the n=0 branch is a defensive return.
49
+ function bitlen(n) {
50
+ let b = 0;
51
+ let x = n;
52
+ while (x > 0) {
53
+ b++;
54
+ x >>>= 1;
55
+ }
56
+ return b;
57
+ }
58
+ /**
59
+ * ML-DSA.KeyGen_internal, FIPS 204 Algorithm 6.
60
+ *
61
+ * Input ξ (32 bytes): the keygen seed. Produced internally by `keygen()`
62
+ * via `randomBytes(32)`, or supplied by `keygenDerand`.
63
+ * Output (pk, sk) byte-encoded per Alg 22 (pkEncode) and Alg 24 (skEncode).
64
+ *
65
+ * Wipe contract on return: every WASM region that held a secret or
66
+ * secret-derived intermediate is zeroed. Public regions (matrix Â, t₁,
67
+ * pk, ρ) are deliberately not wiped, they can be re-derived from the
68
+ * returned pk/sk anyway. The caller is expected to wipe the local ξ
69
+ * buffer it allocated; this function does not own that buffer.
70
+ */
71
+ export function mldsaKeygenInternal(mx, sx, params, xi) {
72
+ const { k, l, eta, paramSet, pkBytes, skBytes } = params;
73
+ const mlMem = new Uint8Array(mx.memory.buffer);
74
+ // ── Slot offsets ────────────────────────────────────────────────────
75
+ const matOff = mx.getMatrixSlot();
76
+ const s1Off = mx.getPolyvecSlot0();
77
+ const s2Off = mx.getPolyvecSlot1();
78
+ const tOff = mx.getPolyvecSlot2();
79
+ const t1Off = mx.getPolyvecSlot3();
80
+ const t0Off = mx.getPolyvecSlot4();
81
+ const s1NttOff = mx.getPolyvecSlot5();
82
+ const seedOff = mx.getSeedOffset();
83
+ const pkOff = mx.getPkOffset();
84
+ const skOff = mx.getSkOffset();
85
+ const trOff = mx.getTrOffset();
86
+ const xofOff = mx.getXofPrfOffset();
87
+ // Layout cross-check at runtime: confirm the matrix-slot sizing covers
88
+ // this parameter set's k·ℓ polys. Cheap ratchet against future changes
89
+ // to buffers.ts that might shrink the region.
90
+ const matSize = mx.getMatrixSlotSize();
91
+ if (k * l * POLY_BYTES > matSize)
92
+ throw new Error(`leviathan-crypto: mldsa MATRIX_SLOT too small for ${paramSet} `
93
+ + `(needs ${k * l * POLY_BYTES}, have ${matSize})`);
94
+ let rho;
95
+ let rhoPrime;
96
+ let kRand;
97
+ let seed128;
98
+ try {
99
+ // ── Step 1: H(ξ ‖ k_byte ‖ ℓ_byte, 1024 bits) → ρ‖ρ′‖K ─────────
100
+ // FIPS 204 §6.1 Algorithm 6 line 1. The k/ℓ domain-separator bytes
101
+ // are the post-IPD addition (FIPS 204 §D.3) defending against
102
+ // cross-parameter-set seed reuse, IntegerToBytes(k,1) and
103
+ // IntegerToBytes(ℓ,1).
104
+ const kByte = new Uint8Array([k & 0xFF]);
105
+ const lByte = new Uint8Array([l & 0xFF]);
106
+ seed128 = shake256HashConcat(sx, [xi, kByte, lByte], 128);
107
+ // Mirror H output into the WASM SEED region. This isn't strictly
108
+ // required (we only consume ρ/ρ′/K via TS-side slices below) but
109
+ // it lets the keygen-scratch-wipe gate verify that the SEED region
110
+ // is wiped, regardless of whether we pre-staged it. Wiped on exit.
111
+ mlMem.set(seed128, seedOff);
112
+ // Split: ρ(32) ‖ ρ′(64) ‖ K(32). Slice copies isolate each piece
113
+ // from the seed128 buffer so we can scrub each at known life-end.
114
+ rho = seed128.slice(0, 32);
115
+ rhoPrime = seed128.slice(32, 96);
116
+ kRand = seed128.slice(96, 128);
117
+ // ── Step 2: Â ← ExpandA(ρ) ────────────────────────────────────
118
+ // FIPS 204 Algorithm 32. Output is in NTT domain, regular form.
119
+ expandA(mx, sx, params, rho, matOff);
120
+ // ── Step 3: (s₁, s₂) ← ExpandS(ρ′) ────────────────────────────
121
+ // FIPS 204 Algorithm 33. Time-domain. expandS wipes its local
122
+ // seed scratch on exit.
123
+ expandS(mx, sx, params, rhoPrime, s1Off, s2Off);
124
+ // ── Step 4: t ← NTT⁻¹(Â · NTT(s₁)) + s₂ ───────────────────────
125
+ // FIPS 204 Algorithm 6 line 5. Stages:
126
+ // (a) Copy s₁ → ŝ₁-slot. Time-domain s₁ in slot_0 must survive
127
+ // for the BitPack step in skEncode (Algorithm 24); the
128
+ // NTT/tomont/multiply chain destroys its argument.
129
+ // (b) NTT(ŝ₁) in place, regular form.
130
+ // (c) tomont(ŝ₁): each coefficient ×R so that the subsequent
131
+ // pointwise_montgomery's R⁻¹ leaves a regular-form product.
132
+ // (d) Matrix-vector product ·ŝ₁ → polyvec_slot_2.
133
+ // (e) NTT⁻¹ in place → time-domain ·s₁.
134
+ // (f) Add s₂ coefficient-wise.
135
+ // (g) Reduce + caddq so coefficients are canonical [0, q-1],
136
+ // required by power2round per the WASM polynomial-layer contract.
137
+ mlMem.copyWithin(s1NttOff, s1Off, s1Off + l * POLY_BYTES);
138
+ mx.polyvec_ntt(s1NttOff, l);
139
+ mx.polyvec_tomont(s1NttOff, l);
140
+ mx.polyvec_matrix_pointwise_montgomery(tOff, matOff, s1NttOff, k, l);
141
+ mx.polyvec_invntt(tOff, k);
142
+ mx.polyvec_add(tOff, tOff, s2Off, k);
143
+ mx.polyvec_reduce(tOff, k);
144
+ mx.polyvec_caddq(tOff, k);
145
+ // ── Step 5: (t₁, t₀) ← Power2Round(t, d) ──────────────────────
146
+ // FIPS 204 Algorithm 35. Per-coefficient on the canonical-residue
147
+ // polyvec t.
148
+ mx.polyvec_power2round(t1Off, t0Off, tOff, k);
149
+ // ── Step 6: pk ← pkEncode(ρ, t₁) ──────────────────────────────
150
+ // FIPS 204 Algorithm 22. pk = ρ ‖ Σ SimpleBitPack(t₁[i], 2^c-1)
151
+ // where c = bitlen(q-1) - d = 23 - 13 = 10 → 320 bytes per poly.
152
+ const t1Bitlen = bitlen(8380417 - 1) - D; // 23 - 13 = 10
153
+ const t1PolyBytes = (256 * t1Bitlen) >> 3; // 320
154
+ mlMem.set(rho, pkOff);
155
+ for (let i = 0; i < k; i++) {
156
+ mx.simple_bit_pack(pkOff + 32 + i * t1PolyBytes, t1Off + i * POLY_BYTES, t1Bitlen);
157
+ }
158
+ // ── Step 7: tr ← H(pk, 512 bits) ──────────────────────────────
159
+ // 64-byte SHAKE256 of the public key. Cached in sk so signing
160
+ // doesn't have to re-derive it.
161
+ const pkBytesView = mlMem.subarray(pkOff, pkOff + pkBytes);
162
+ const tr = shake256HashConcat(sx, [pkBytesView], 64);
163
+ mlMem.set(tr, trOff);
164
+ wipe(tr);
165
+ // ── Step 8: sk ← skEncode(ρ, K, tr, s₁, s₂, t₀) ───────────────
166
+ // FIPS 204 Algorithm 24. Layout:
167
+ // ρ(32) ‖ K(32) ‖ tr(64) ‖
168
+ // BitPack(s₁[i], η, η) × ℓ each = 32·bitlen(2η)
169
+ // BitPack(s₂[i], η, η) × k
170
+ // BitPack(t₀[i], 2^(d-1)-1, 2^(d-1)) × k each = 32·d = 416
171
+ const etaBitlen = bitlen(2 * eta); // 3 (η=2) or 4 (η=4)
172
+ const etaPolyBytes = (256 * etaBitlen) >> 3; // 96 or 128
173
+ const t0PolyBytes = (256 * D) >> 3; // 416
174
+ const t0LowEdge = (1 << (D - 1)) - 1; // 4095
175
+ const t0HighEdge = (1 << (D - 1)); // 4096
176
+ mlMem.set(rho, skOff);
177
+ mlMem.set(kRand, skOff + 32);
178
+ mlMem.set(mlMem.subarray(trOff, trOff + 64), skOff + 64);
179
+ let off = skOff + 32 + 32 + 64; // = skOff + 128
180
+ for (let i = 0; i < l; i++) {
181
+ mx.bit_pack(off + i * etaPolyBytes, s1Off + i * POLY_BYTES, eta, eta);
182
+ }
183
+ off += l * etaPolyBytes;
184
+ for (let i = 0; i < k; i++) {
185
+ mx.bit_pack(off + i * etaPolyBytes, s2Off + i * POLY_BYTES, eta, eta);
186
+ }
187
+ off += k * etaPolyBytes;
188
+ for (let i = 0; i < k; i++) {
189
+ mx.bit_pack(off + i * t0PolyBytes, t0Off + i * POLY_BYTES, t0LowEdge, t0HighEdge);
190
+ }
191
+ off += k * t0PolyBytes;
192
+ // Sanity: encoded sk length must match the parameter-set size.
193
+ // A miscompute here is the kind of silent failure ACVP eventually
194
+ // catches but the layout assertion catches faster.
195
+ if (off - skOff !== skBytes)
196
+ throw new Error(`leviathan-crypto: mldsa skEncode length mismatch for ${paramSet} `
197
+ + `(wrote ${off - skOff}, expected ${skBytes})`);
198
+ // ── Step 9: slice public outputs out of WASM memory ───────────
199
+ // Use slice() (copy) so the returned arrays are independent of
200
+ // the WASM linear memory we are about to wipe.
201
+ const pk = mlMem.slice(pkOff, pkOff + pkBytes);
202
+ const sk = mlMem.slice(skOff, skOff + skBytes);
203
+ // Wipe scratch per FIPS 204 §3.6.3. See
204
+ // docs/mldsa.md#wipe-discipline for the per-region severity
205
+ // ranking.
206
+ mlMem.fill(0, seedOff, seedOff + 128); // ρ ‖ ρ′ ‖ K
207
+ mlMem.fill(0, trOff, trOff + 64); // tr (public-derived but no need to keep)
208
+ mlMem.fill(0, skOff, skOff + skBytes); // encoded sk
209
+ mlMem.fill(0, s1Off, s1Off + l * POLY_BYTES); // s₁ (time-domain)
210
+ mlMem.fill(0, s1NttOff, s1NttOff + l * POLY_BYTES); // ŝ₁ (NTT/Montgomery)
211
+ mlMem.fill(0, s2Off, s2Off + k * POLY_BYTES); // s₂
212
+ mlMem.fill(0, tOff, tOff + k * POLY_BYTES); // t
213
+ mlMem.fill(0, t0Off, t0Off + k * POLY_BYTES); // t₀
214
+ mlMem.fill(0, xofOff, xofOff + 8192); // XOF/PRF scratch
215
+ // SHA3 module's input/state/output regions held ρ′ chunks and
216
+ // the H(ξ‖k‖ℓ) output. Wipe before returning so no residue
217
+ // persists across the public-API boundary.
218
+ sx.wipeBuffers();
219
+ return { verificationKey: pk, signingKey: sk };
220
+ }
221
+ finally {
222
+ // TS-side scratch, wipe even on early throw.
223
+ if (seed128)
224
+ wipe(seed128);
225
+ if (rho)
226
+ wipe(rho);
227
+ if (rhoPrime)
228
+ wipe(rhoPrime);
229
+ if (kRand)
230
+ wipe(kRand);
231
+ }
232
+ }
@@ -0,0 +1,21 @@
1
+ export interface MlDsaParams {
2
+ paramSet: 'ML-DSA-44' | 'ML-DSA-65' | 'ML-DSA-87';
3
+ k: number;
4
+ l: number;
5
+ eta: number;
6
+ tau: number;
7
+ lambda: number;
8
+ gamma1: number;
9
+ gamma2: number;
10
+ omega: number;
11
+ beta: number;
12
+ pkBytes: number;
13
+ skBytes: number;
14
+ sigBytes: number;
15
+ }
16
+ /** ML-DSA-44, FIPS 204 §4 Table 1 (NIST security category 2). */
17
+ export declare const MLDSA44: MlDsaParams;
18
+ /** ML-DSA-65, FIPS 204 §4 Table 1 (NIST security category 3). */
19
+ export declare const MLDSA65: MlDsaParams;
20
+ /** ML-DSA-87, FIPS 204 §4 Table 1 (NIST security category 5). */
21
+ export declare const MLDSA87: MlDsaParams;
@@ -0,0 +1,55 @@
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/mldsa/params.ts
23
+ //
24
+ // ML-DSA (FIPS 204) parameter sets, values from §4 Table 1 and Table 2.
25
+ //
26
+ // Sizes are derived per parameter set:
27
+ // pk = 32 + k · 32 · (bitlen(q-1) - d) , Alg 22 pkEncode
28
+ // sk = 32 + 32 + 64 + 32·((ℓ+k)·bitlen(2η) + d·k) , Alg 24 skEncode
29
+ // sig = λ/4 + ℓ·32·(1 + bitlen(γ₁ - 1)) + ω + k , Alg 26 sigEncode
30
+ //
31
+ // β = τ · η is precomputed; it bounds ‖cs1‖∞ and ‖cs2‖∞.
32
+ /** ML-DSA-44, FIPS 204 §4 Table 1 (NIST security category 2). */
33
+ export const MLDSA44 = {
34
+ paramSet: 'ML-DSA-44',
35
+ k: 4, l: 4, eta: 2, tau: 39, lambda: 128,
36
+ gamma1: 1 << 17, gamma2: ((8380417 - 1) / 88) | 0,
37
+ omega: 80, beta: 39 * 2,
38
+ pkBytes: 1312, skBytes: 2560, sigBytes: 2420,
39
+ };
40
+ /** ML-DSA-65, FIPS 204 §4 Table 1 (NIST security category 3). */
41
+ export const MLDSA65 = {
42
+ paramSet: 'ML-DSA-65',
43
+ k: 6, l: 5, eta: 4, tau: 49, lambda: 192,
44
+ gamma1: 1 << 19, gamma2: ((8380417 - 1) / 32) | 0,
45
+ omega: 55, beta: 49 * 4,
46
+ pkBytes: 1952, skBytes: 4032, sigBytes: 3309,
47
+ };
48
+ /** ML-DSA-87, FIPS 204 §4 Table 1 (NIST security category 5). */
49
+ export const MLDSA87 = {
50
+ paramSet: 'ML-DSA-87',
51
+ k: 8, l: 7, eta: 2, tau: 60, lambda: 256,
52
+ gamma1: 1 << 19, gamma2: ((8380417 - 1) / 32) | 0,
53
+ omega: 75, beta: 60 * 2,
54
+ pkBytes: 2592, skBytes: 4896, sigBytes: 4627,
55
+ };
@@ -0,0 +1,30 @@
1
+ import type { Sha3Exports } from '../mlkem/types.js';
2
+ /** Absorb msg into the sponge in ≤168-byte chunks. Caller must have
3
+ * already invoked the appropriate Init function (shake128Init etc.). */
4
+ export declare function sha3Absorb(sx: Sha3Exports, msg: Uint8Array): void;
5
+ /** SHAKE256(msg, n), fixed-length output. Resets sha3 state. */
6
+ export declare function shake256Hash(sx: Sha3Exports, msg: Uint8Array, n: number): Uint8Array;
7
+ /** SHAKE256(p₀ ‖ p₁ ‖ … ‖ p_{n-1}, outLen). Avoids the temporary buffer
8
+ * callers would otherwise allocate just to concatenate fixed-size pieces.
9
+ * Used for keygen's H(ξ ‖ k_byte ‖ ℓ_byte, 128). */
10
+ export declare function shake256HashConcat(sx: Sha3Exports, parts: readonly Uint8Array[], outLen: number): Uint8Array;
11
+ /**
12
+ * Set up SHAKE128 over `seed` and return an incremental block-squeezer.
13
+ * Each call returns the next 168-byte block as a Uint8Array view into the
14
+ * sha3 OUT region (lifetime: until the next squeeze call). Callers copy
15
+ * into the consuming module's XOF buffer before invoking the rejection
16
+ * sampler. Used by ExpandA (FIPS 204 Algorithm 32, RejNTTPoly driver).
17
+ */
18
+ export declare function shake128Squeezer(sx: Sha3Exports, seed: Uint8Array): {
19
+ rate: number;
20
+ squeeze: () => Uint8Array;
21
+ };
22
+ /**
23
+ * Set up SHAKE256 over `seed` and return an incremental block-squeezer.
24
+ * Same shape as shake128Squeezer with rate 136. Used by ExpandS
25
+ * (FIPS 204 Algorithm 33, RejBoundedPoly driver).
26
+ */
27
+ export declare function shake256Squeezer(sx: Sha3Exports, seed: Uint8Array): {
28
+ rate: number;
29
+ squeeze: () => Uint8Array;
30
+ };
@@ -0,0 +1,124 @@
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/mldsa/sha3-helpers.ts
23
+ //
24
+ // SHAKE-driving helpers shared by ExpandA / ExpandS / keygen / sign / verify.
25
+ // All operate directly on raw Sha3Exports; no init() system involved.
26
+ //
27
+ // ML-DSA uses both SHAKE rates (FIPS 202): SHAKE128 (rate 168) for ExpandA
28
+ // and SHAKE256 (rate 136) for the rest of the scheme. The absorb path is
29
+ // rate-agnostic, keccakAbsorb consumes whatever buffer length the caller
30
+ // hands it as long as length ≤ 168 (the wider rate). One-shot SHAKE256
31
+ // helpers and the incremental SHAKE128 / SHAKE256 squeezers below cover
32
+ // every call shape ML-DSA needs.
33
+ const SHAKE128_RATE = 168;
34
+ const SHAKE256_RATE = 136;
35
+ /** Absorb msg into the sponge in ≤168-byte chunks. Caller must have
36
+ * already invoked the appropriate Init function (shake128Init etc.). */
37
+ export function sha3Absorb(sx, msg) {
38
+ const mem = new Uint8Array(sx.memory.buffer);
39
+ const inOff = sx.getInputOffset();
40
+ let pos = 0;
41
+ while (pos < msg.length) {
42
+ const chunk = Math.min(msg.length - pos, SHAKE128_RATE);
43
+ mem.set(msg.subarray(pos, pos + chunk), inOff);
44
+ sx.keccakAbsorb(chunk);
45
+ pos += chunk;
46
+ }
47
+ }
48
+ /** SHAKE256(msg, n), fixed-length output. Resets sha3 state. */
49
+ export function shake256Hash(sx, msg, n) {
50
+ sx.shake256Init();
51
+ sha3Absorb(sx, msg);
52
+ sx.shakePad();
53
+ const sha3Mem = new Uint8Array(sx.memory.buffer);
54
+ const outOff = sx.getOutOffset();
55
+ const out = new Uint8Array(n);
56
+ let pos = 0;
57
+ while (pos < n) {
58
+ sx.shakeSqueezeBlock();
59
+ const take = Math.min(n - pos, SHAKE256_RATE);
60
+ out.set(sha3Mem.subarray(outOff, outOff + take), pos);
61
+ pos += take;
62
+ }
63
+ return out;
64
+ }
65
+ /** SHAKE256(p₀ ‖ p₁ ‖ … ‖ p_{n-1}, outLen). Avoids the temporary buffer
66
+ * callers would otherwise allocate just to concatenate fixed-size pieces.
67
+ * Used for keygen's H(ξ ‖ k_byte ‖ ℓ_byte, 128). */
68
+ export function shake256HashConcat(sx, parts, outLen) {
69
+ sx.shake256Init();
70
+ for (const p of parts)
71
+ sha3Absorb(sx, p);
72
+ sx.shakePad();
73
+ const sha3Mem = new Uint8Array(sx.memory.buffer);
74
+ const outOff = sx.getOutOffset();
75
+ const out = new Uint8Array(outLen);
76
+ let pos = 0;
77
+ while (pos < outLen) {
78
+ sx.shakeSqueezeBlock();
79
+ const take = Math.min(outLen - pos, SHAKE256_RATE);
80
+ out.set(sha3Mem.subarray(outOff, outOff + take), pos);
81
+ pos += take;
82
+ }
83
+ return out;
84
+ }
85
+ /**
86
+ * Set up SHAKE128 over `seed` and return an incremental block-squeezer.
87
+ * Each call returns the next 168-byte block as a Uint8Array view into the
88
+ * sha3 OUT region (lifetime: until the next squeeze call). Callers copy
89
+ * into the consuming module's XOF buffer before invoking the rejection
90
+ * sampler. Used by ExpandA (FIPS 204 Algorithm 32, RejNTTPoly driver).
91
+ */
92
+ export function shake128Squeezer(sx, seed) {
93
+ sx.shake128Init();
94
+ sha3Absorb(sx, seed);
95
+ sx.shakePad();
96
+ const sha3Mem = new Uint8Array(sx.memory.buffer);
97
+ const outOff = sx.getOutOffset();
98
+ return {
99
+ rate: SHAKE128_RATE,
100
+ squeeze: () => {
101
+ sx.shakeSqueezeBlock();
102
+ return sha3Mem.subarray(outOff, outOff + SHAKE128_RATE);
103
+ },
104
+ };
105
+ }
106
+ /**
107
+ * Set up SHAKE256 over `seed` and return an incremental block-squeezer.
108
+ * Same shape as shake128Squeezer with rate 136. Used by ExpandS
109
+ * (FIPS 204 Algorithm 33, RejBoundedPoly driver).
110
+ */
111
+ export function shake256Squeezer(sx, seed) {
112
+ sx.shake256Init();
113
+ sha3Absorb(sx, seed);
114
+ sx.shakePad();
115
+ const sha3Mem = new Uint8Array(sx.memory.buffer);
116
+ const outOff = sx.getOutOffset();
117
+ return {
118
+ rate: SHAKE256_RATE,
119
+ squeeze: () => {
120
+ sx.shakeSqueezeBlock();
121
+ return sha3Mem.subarray(outOff, outOff + SHAKE256_RATE);
122
+ },
123
+ };
124
+ }
@@ -0,0 +1,36 @@
1
+ import type { MlDsaExports, Sha3Exports } from './types.js';
2
+ import type { MlDsaParams } from './params.js';
3
+ import { type PreHashAlgorithm } from './hashvariant.js';
4
+ /**
5
+ * ML-DSA.Sign_internal, FIPS 204 Algorithm 7.
6
+ *
7
+ * Inputs:
8
+ * sk , encoded signing key (skBytes per parameter set)
9
+ * MPrime, domain-separated message bytes (caller-built via constructMPrime)
10
+ * rnd , 32-byte randomness (random for hedged, all-zero for deterministic,
11
+ * caller-supplied for derand/CAVP)
12
+ *
13
+ * Output: σ (sigBytes), encoded per Algorithm 26 (sigEncode).
14
+ *
15
+ * Wipe contract: every WASM region that held a secret or secret-derived
16
+ * intermediate is zeroed before return. TS-side scratch (μ, ρ'', c̃, the
17
+ * w1 byte slice) wipes via try/finally even on early throw.
18
+ */
19
+ export declare function mldsaSignInternal(mx: MlDsaExports, sx: Sha3Exports, params: MlDsaParams, sk: Uint8Array, MPrime: Uint8Array, rnd: Uint8Array): Uint8Array;
20
+ /**
21
+ * HashML-DSA sign, post-prehash. FIPS 204 §5.4 Algorithm 4 lines 22-24.
22
+ * Builds M' = 0x01 ‖ |ctx| ‖ ctx ‖ OID(algo) ‖ prehash and drives
23
+ * Sign_internal with the caller-supplied rnd.
24
+ *
25
+ * The caller owns `prehash` (it may be a slice of WASM memory, a
26
+ * caller-controlled digest, or an internally-computed PH_M); this helper
27
+ * never wipes it. The caller also owns `rnd` (hedged: caller wipes a
28
+ * freshly-generated value; deterministic: rnd is zeros, no wipe; derand:
29
+ * caller-supplied per FIPS 204 §3.4 contract).
30
+ *
31
+ * The 12 approved pre-hash functions (`algo`) and their OIDs are FIPS 204
32
+ * §5.4.1's full catalog. Domain-sep byte 0x01 inside the M' construction
33
+ * separates HashML-DSA signatures from pure-ML-DSA signatures on the same
34
+ * key per §3.6.4.
35
+ */
36
+ export declare function signWithPrehash(mx: MlDsaExports, sx: Sha3Exports, params: MlDsaParams, sk: Uint8Array, prehash: Uint8Array, algo: PreHashAlgorithm, ctx: Uint8Array, rnd: Uint8Array): Uint8Array;