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/sha3.wasm CHANGED
Binary file
@@ -0,0 +1,22 @@
1
+ export declare const PKCS7_INVALID = "invalid ciphertext";
2
+ /**
3
+ * Apply PKCS7 padding to `data` so the result length is a multiple of 16.
4
+ * Padding length is always 1-16 bytes so a full pad block is appended when
5
+ * `data.length` is already block-aligned.
6
+ * @param data Input bytes of any length
7
+ * @returns New Uint8Array padded to the next 16-byte boundary
8
+ */
9
+ export declare function pkcs7Pad(data: Uint8Array): Uint8Array;
10
+ /**
11
+ * Remove PKCS7 padding from a block-aligned buffer in constant time.
12
+ *
13
+ * Branch-free over all secret bits, padding length and per-byte comparisons
14
+ * are accumulated into a single `bad` flag with no early exit. Closes the
15
+ * Vaudenay 2002 padding-oracle surface. Throws a single generic
16
+ * `RangeError('invalid ciphertext')` for every failure mode: empty input,
17
+ * non-block-aligned length, padding byte out of range 1-16, and any per-byte
18
+ * mismatch in the padding region.
19
+ * @param data Block-aligned ciphertext (length must be a multiple of 16)
20
+ * @returns Plaintext with padding removed
21
+ */
22
+ export declare function pkcs7Strip(data: Uint8Array): Uint8Array;
@@ -0,0 +1,84 @@
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/shared/pkcs7.ts
23
+ //
24
+ // Cipher-agnostic PKCS7 padding helpers (RFC 5652 §6.3). Used by every
25
+ // CBC mode wrapper in the library, `SerpentCbc`, `AESCbc`, the Serpent
26
+ // pool worker, and any future CBC-based suite. A single source of truth
27
+ // keeps the branch-free, Vaudenay-2002-closed padding check identical
28
+ // across all call sites; divergence between paths would reintroduce a
29
+ // padding-oracle.
30
+ // Generic error string used by every failure mode of `pkcs7Strip` and the
31
+ // length/alignment gates in CBC `decrypt` paths. No numeric leaks, no
32
+ // structural disclosure, a caller cannot distinguish "bad length" from
33
+ // "bad padding" by message or by timing.
34
+ export const PKCS7_INVALID = 'invalid ciphertext';
35
+ /**
36
+ * Apply PKCS7 padding to `data` so the result length is a multiple of 16.
37
+ * Padding length is always 1-16 bytes so a full pad block is appended when
38
+ * `data.length` is already block-aligned.
39
+ * @param data Input bytes of any length
40
+ * @returns New Uint8Array padded to the next 16-byte boundary
41
+ */
42
+ export function pkcs7Pad(data) {
43
+ const padLen = 16 - (data.length % 16); // 1..16
44
+ const out = new Uint8Array(data.length + padLen);
45
+ out.set(data);
46
+ out.fill(padLen, data.length);
47
+ return out;
48
+ }
49
+ /**
50
+ * Remove PKCS7 padding from a block-aligned buffer in constant time.
51
+ *
52
+ * Branch-free over all secret bits, padding length and per-byte comparisons
53
+ * are accumulated into a single `bad` flag with no early exit. Closes the
54
+ * Vaudenay 2002 padding-oracle surface. Throws a single generic
55
+ * `RangeError('invalid ciphertext')` for every failure mode: empty input,
56
+ * non-block-aligned length, padding byte out of range 1-16, and any per-byte
57
+ * mismatch in the padding region.
58
+ * @param data Block-aligned ciphertext (length must be a multiple of 16)
59
+ * @returns Plaintext with padding removed
60
+ */
61
+ export function pkcs7Strip(data) {
62
+ if (data.length === 0 || data.length % 16 !== 0)
63
+ throw new RangeError(PKCS7_INVALID);
64
+ const padLen = data[data.length - 1];
65
+ let bad = 0;
66
+ bad |= ((padLen - 1) >>> 31); // 1 if padLen == 0
67
+ bad |= ((16 - padLen) >>> 31); // 1 if padLen > 16
68
+ // Per-byte pad-region mask without branches on secret bits.
69
+ // inPadRegion = 0xff when i >= 16 - padLen
70
+ // = 0x00 otherwise
71
+ //
72
+ // (16 - padLen - i - 1) is negative iff i >= 16 - padLen. A signed
73
+ // arithmetic shift by 31 yields -1 for negative, 0 for non-negative;
74
+ // ANDing with 0xff collapses those to 0xff and 0x00.
75
+ for (let i = 0; i < 16; i++) {
76
+ const idx = data.length - 16 + i;
77
+ const mask = ((16 - padLen - i - 1) >> 31) & 0xff;
78
+ bad |= (data[idx] ^ padLen) & mask;
79
+ }
80
+ const invalid = ((bad - 1) >>> 31) ^ 1;
81
+ if (invalid)
82
+ throw new RangeError(PKCS7_INVALID);
83
+ return data.subarray(0, data.length - padLen);
84
+ }
@@ -0,0 +1,41 @@
1
+ import type { PreHashAlgorithm } from '../mldsa/hashvariant.js';
2
+ import type { PrehashAlgorithm } from './types.js';
3
+ /**
4
+ * Maximum user_ctx length in bytes. Matches the FIPS 204 (Module-Lattice-
5
+ * Based Digital Signature Standard) §3.6.1 native ctx cap; buildEffectiveCtx
6
+ * enforces it as the first check.
7
+ */
8
+ export declare const USER_CTX_MAX = 255;
9
+ /** Maximum ctxDomain length in bytes; enforced by suite factories. */
10
+ export declare const CTX_DOMAIN_MAX = 32;
11
+ /**
12
+ * Construct effective_ctx from suite domain and user-supplied ctx.
13
+ *
14
+ * Format: [domain_len: u8][domain_bytes][user_ctx_len: u8][user_ctx_bytes]
15
+ *
16
+ * Two independent length checks gate the construction:
17
+ *
18
+ * 1. user_ctx ≤ USER_CTX_MAX (255). Mirrors FIPS 204 §3.6.1's ctx cap on
19
+ * the user-supplied half before any framing is applied.
20
+ * 2. Combined effective_ctx ≤ 255. The 1-byte length prefixes plus the
21
+ * domain and user_ctx bytes must fit FIPS 204 §3.6.1's ctx parameter,
22
+ * which is what the result is ultimately passed to. The effective
23
+ * per-suite user_ctx ceiling is `253 - len(domainBytes)`.
24
+ *
25
+ * Both throws share the `sig-ctx-too-long` discriminator. The absolute
26
+ * check fires first, so callers passing user_ctx > 255 always trip the
27
+ * absolute cap regardless of ctxDomain length.
28
+ *
29
+ * @throws SigningError('sig-ctx-too-long') if user_ctx exceeds USER_CTX_MAX
30
+ * or if the combined effective_ctx exceeds 255 bytes.
31
+ * @throws Error (not SigningError) if ctxDomain exceeds CTX_DOMAIN_MAX;
32
+ * that's a developer-time mistake, not a caller mistake.
33
+ */
34
+ export declare function buildEffectiveCtx(ctxDomain: string, userCtx: Uint8Array): Uint8Array;
35
+ /**
36
+ * Map the lib's lowercase, hyphenated PrehashAlgorithm to the identifier
37
+ * MlDsaBase's signHash / verifyHash family accepts (FIPS 204 §5.4.1).
38
+ * SHAKE entries deliberately use the no-hyphen spelling 'SHAKE128' /
39
+ * 'SHAKE256' that the mldsa layer expects.
40
+ */
41
+ export declare function prehashAlgoToMldsa(algo: PrehashAlgorithm): PreHashAlgorithm;
@@ -0,0 +1,102 @@
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/ctx.ts
23
+ //
24
+ // Effective-ctx construction and prehash-algorithm mapping. Used by
25
+ // every SignatureSuite factory.
26
+ import { utf8ToBytes } from '../utils.js';
27
+ import { SigningError } from '../errors.js';
28
+ /**
29
+ * Maximum user_ctx length in bytes. Matches the FIPS 204 (Module-Lattice-
30
+ * Based Digital Signature Standard) §3.6.1 native ctx cap; buildEffectiveCtx
31
+ * enforces it as the first check.
32
+ */
33
+ export const USER_CTX_MAX = 255;
34
+ /** Maximum ctxDomain length in bytes; enforced by suite factories. */
35
+ export const CTX_DOMAIN_MAX = 32;
36
+ /**
37
+ * Maximum combined effective_ctx length in bytes. The output of
38
+ * buildEffectiveCtx is fed to the underlying primitive's ctx parameter,
39
+ * which FIPS 204 §3.6.1 caps at 255.
40
+ */
41
+ const EFFECTIVE_CTX_MAX = 255;
42
+ /**
43
+ * Construct effective_ctx from suite domain and user-supplied ctx.
44
+ *
45
+ * Format: [domain_len: u8][domain_bytes][user_ctx_len: u8][user_ctx_bytes]
46
+ *
47
+ * Two independent length checks gate the construction:
48
+ *
49
+ * 1. user_ctx ≤ USER_CTX_MAX (255). Mirrors FIPS 204 §3.6.1's ctx cap on
50
+ * the user-supplied half before any framing is applied.
51
+ * 2. Combined effective_ctx ≤ 255. The 1-byte length prefixes plus the
52
+ * domain and user_ctx bytes must fit FIPS 204 §3.6.1's ctx parameter,
53
+ * which is what the result is ultimately passed to. The effective
54
+ * per-suite user_ctx ceiling is `253 - len(domainBytes)`.
55
+ *
56
+ * Both throws share the `sig-ctx-too-long` discriminator. The absolute
57
+ * check fires first, so callers passing user_ctx > 255 always trip the
58
+ * absolute cap regardless of ctxDomain length.
59
+ *
60
+ * @throws SigningError('sig-ctx-too-long') if user_ctx exceeds USER_CTX_MAX
61
+ * or if the combined effective_ctx exceeds 255 bytes.
62
+ * @throws Error (not SigningError) if ctxDomain exceeds CTX_DOMAIN_MAX;
63
+ * that's a developer-time mistake, not a caller mistake.
64
+ */
65
+ export function buildEffectiveCtx(ctxDomain, userCtx) {
66
+ if (userCtx.length > USER_CTX_MAX)
67
+ throw new SigningError('sig-ctx-too-long', `user_ctx length ${userCtx.length} > ${USER_CTX_MAX}`);
68
+ const domainBytes = utf8ToBytes(ctxDomain);
69
+ if (domainBytes.length > CTX_DOMAIN_MAX)
70
+ throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' encodes to ${domainBytes.length} bytes (max ${CTX_DOMAIN_MAX})`);
71
+ const combined = 1 + domainBytes.length + 1 + userCtx.length;
72
+ if (combined > EFFECTIVE_CTX_MAX)
73
+ throw new SigningError('sig-ctx-too-long', `effective_ctx length ${combined} > ${EFFECTIVE_CTX_MAX} (FIPS 204 §3.6.1 ctx cap; ctxDomain ${domainBytes.length} bytes + user_ctx ${userCtx.length} bytes + 2 length prefixes)`);
74
+ const out = new Uint8Array(combined);
75
+ let pos = 0;
76
+ out[pos++] = domainBytes.length;
77
+ out.set(domainBytes, pos);
78
+ pos += domainBytes.length;
79
+ out[pos++] = userCtx.length;
80
+ out.set(userCtx, pos);
81
+ return out;
82
+ }
83
+ /**
84
+ * Map the lib's lowercase, hyphenated PrehashAlgorithm to the identifier
85
+ * MlDsaBase's signHash / verifyHash family accepts (FIPS 204 §5.4.1).
86
+ * SHAKE entries deliberately use the no-hyphen spelling 'SHAKE128' /
87
+ * 'SHAKE256' that the mldsa layer expects.
88
+ */
89
+ export function prehashAlgoToMldsa(algo) {
90
+ switch (algo) {
91
+ case 'sha-256': return 'SHA2-256';
92
+ case 'sha-512': return 'SHA2-512';
93
+ case 'sha3-256': return 'SHA3-256';
94
+ case 'sha3-512': return 'SHA3-512';
95
+ case 'shake-128': return 'SHAKE128';
96
+ case 'shake-256': return 'SHAKE256';
97
+ default: {
98
+ const _exhaustive = algo;
99
+ throw new Error(`leviathan-crypto: unknown prehash algorithm ${_exhaustive}`);
100
+ }
101
+ }
102
+ }
@@ -0,0 +1,45 @@
1
+ import type { SignatureSuite } from './types.js';
2
+ export declare class Sign {
3
+ /**
4
+ * Single-shot sign. Returns the attached envelope blob.
5
+ */
6
+ static sign(suite: SignatureSuite, sk: Uint8Array, msg: Uint8Array, ctx: Uint8Array): Uint8Array;
7
+ /**
8
+ * Single-shot verify. Returns the extracted payload on success.
9
+ *
10
+ * @throws SigningError('sig-blob-too-short') blob cannot fit the wire shape.
11
+ * @throws SigningError('sig-suite-mismatch') wire suite_byte mismatch.
12
+ * @throws SigningError('sig-ctx-mismatch') caller ctx != wire ctx.
13
+ * @throws SigningError('verify-failed') suite.verify returned false.
14
+ */
15
+ static verify(suite: SignatureSuite, pk: Uint8Array, blob: Uint8Array, ctx: Uint8Array): Uint8Array;
16
+ /**
17
+ * Detached sign. Returns just the raw signature bytes (no envelope).
18
+ * Caller is responsible for transmitting (suite, msg, sig, ctx)
19
+ * out-of-band. signDetached is the interop surface; the wire is
20
+ * exactly what the underlying primitive emits, no leviathan-specific
21
+ * framing.
22
+ */
23
+ static signDetached(suite: SignatureSuite, sk: Uint8Array, msg: Uint8Array, ctx: Uint8Array): Uint8Array;
24
+ /**
25
+ * Detached verify. Returns boolean; does NOT throw on signature failure.
26
+ * Contract violations in the suite (wrong-size key, ctx too long) still
27
+ * throw SigningError per the suite contract.
28
+ */
29
+ static verifyDetached(suite: SignatureSuite, pk: Uint8Array, msg: Uint8Array, sig: Uint8Array, ctx: Uint8Array): boolean;
30
+ /**
31
+ * Introspect a blob without verifying. Validates structural shape only
32
+ * (ctx_len and payload_len in range); does NOT call suite.verify and
33
+ * does NOT compare ctx. Returns offsets the caller can use to extract
34
+ * wire ctx, payload, and sig themselves.
35
+ *
36
+ * @throws SigningError('sig-blob-too-short') blob cannot fit the wire shape.
37
+ */
38
+ static peek(blob: Uint8Array, suite: SignatureSuite): {
39
+ suiteByte: number;
40
+ ctx: Uint8Array;
41
+ payloadOffset: number;
42
+ payloadLength: number;
43
+ sigOffset: number;
44
+ };
45
+ }
@@ -0,0 +1,152 @@
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/envelope.ts
23
+ //
24
+ // Sign, single-shot signing/verification using the attached envelope wire
25
+ // format. Mirrors the static-only-class pattern from stream/seal.ts.
26
+ //
27
+ // Wire format see: docs/signing.md#attached-envelope.
28
+ import { constantTimeEqual } from '../utils.js';
29
+ import { SigningError } from '../errors.js';
30
+ // 1 suite_byte + 1 ctx_len + 4 payload_len. Smallest legal blob carries
31
+ // at least these six header bytes plus the suite's sig.
32
+ const ENVELOPE_HEADER_FIXED = 6;
33
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class
34
+ export class Sign {
35
+ /**
36
+ * Single-shot sign. Returns the attached envelope blob.
37
+ */
38
+ static sign(suite, sk, msg, ctx) {
39
+ const sig = suite.sign(sk, msg, ctx);
40
+ return assembleBlob(suite.formatEnum, ctx, msg, sig);
41
+ }
42
+ /**
43
+ * Single-shot verify. Returns the extracted payload on success.
44
+ *
45
+ * @throws SigningError('sig-blob-too-short') blob cannot fit the wire shape.
46
+ * @throws SigningError('sig-suite-mismatch') wire suite_byte mismatch.
47
+ * @throws SigningError('sig-ctx-mismatch') caller ctx != wire ctx.
48
+ * @throws SigningError('verify-failed') suite.verify returned false.
49
+ */
50
+ static verify(suite, pk, blob, ctx) {
51
+ const { suiteByte, ctxLen, payloadLen, payloadOffset, sigOffset } = parseHeader(blob, suite);
52
+ if (suiteByte !== suite.formatEnum)
53
+ throw new SigningError('sig-suite-mismatch', `wire suite 0x${suiteByte.toString(16)} != suite.formatEnum 0x${suite.formatEnum.toString(16)}`);
54
+ const wireCtx = blob.subarray(2, 2 + ctxLen);
55
+ if (!constantTimeEqual(wireCtx, ctx))
56
+ throw new SigningError('sig-ctx-mismatch');
57
+ const payload = blob.subarray(payloadOffset, payloadOffset + payloadLen);
58
+ const sig = blob.subarray(sigOffset, blob.length);
59
+ if (!suite.verify(pk, payload, sig, wireCtx))
60
+ throw new SigningError('verify-failed');
61
+ return payload;
62
+ }
63
+ /**
64
+ * Detached sign. Returns just the raw signature bytes (no envelope).
65
+ * Caller is responsible for transmitting (suite, msg, sig, ctx)
66
+ * out-of-band. signDetached is the interop surface; the wire is
67
+ * exactly what the underlying primitive emits, no leviathan-specific
68
+ * framing.
69
+ */
70
+ static signDetached(suite, sk, msg, ctx) {
71
+ return suite.sign(sk, msg, ctx);
72
+ }
73
+ /**
74
+ * Detached verify. Returns boolean; does NOT throw on signature failure.
75
+ * Contract violations in the suite (wrong-size key, ctx too long) still
76
+ * throw SigningError per the suite contract.
77
+ */
78
+ static verifyDetached(suite, pk, msg, sig, ctx) {
79
+ return suite.verify(pk, msg, sig, ctx);
80
+ }
81
+ /**
82
+ * Introspect a blob without verifying. Validates structural shape only
83
+ * (ctx_len and payload_len in range); does NOT call suite.verify and
84
+ * does NOT compare ctx. Returns offsets the caller can use to extract
85
+ * wire ctx, payload, and sig themselves.
86
+ *
87
+ * @throws SigningError('sig-blob-too-short') blob cannot fit the wire shape.
88
+ */
89
+ static peek(blob, suite) {
90
+ const { suiteByte, ctxLen, payloadLen, payloadOffset, sigOffset } = parseHeader(blob, suite);
91
+ return {
92
+ suiteByte,
93
+ ctx: blob.subarray(2, 2 + ctxLen),
94
+ payloadOffset,
95
+ payloadLength: payloadLen,
96
+ sigOffset,
97
+ };
98
+ }
99
+ }
100
+ /**
101
+ * Parse the wire header. Throws SigningError('sig-blob-too-short')
102
+ * on every wire-shape overflow; .message carries the specifics.
103
+ */
104
+ function parseHeader(blob, suite) {
105
+ if (blob.length < ENVELOPE_HEADER_FIXED)
106
+ throw new SigningError('sig-blob-too-short', `blob length ${blob.length} < min ${ENVELOPE_HEADER_FIXED} (suite + ctx_len + payload_len header)`);
107
+ const suiteByte = blob[0];
108
+ const ctxLen = blob[1];
109
+ const payloadLenOffset = 2 + ctxLen;
110
+ const payloadOffset = payloadLenOffset + 4;
111
+ if (blob.length < payloadOffset)
112
+ throw new SigningError('sig-blob-too-short', `blob length ${blob.length} cannot fit ctx (${ctxLen} bytes) + payload_len header`);
113
+ const payloadLen = readU32BE(blob, payloadLenOffset);
114
+ const sigOffset = payloadOffset + payloadLen;
115
+ if (sigOffset > blob.length)
116
+ throw new SigningError('sig-blob-too-short', `payload_len ${payloadLen} pushes payload past blob end (blob length ${blob.length})`);
117
+ if (sigOffset + suite.sigMaxSize < blob.length)
118
+ throw new SigningError('sig-blob-too-short', `trailing sig ${blob.length - sigOffset} > suite.sigMaxSize ${suite.sigMaxSize}`);
119
+ return { suiteByte, ctxLen, payloadLen, payloadOffset, sigOffset };
120
+ }
121
+ function assembleBlob(suiteByte, ctx, payload, sig) {
122
+ if (ctx.length > 255)
123
+ throw new SigningError('sig-ctx-too-long', `ctx length ${ctx.length} > 255 (wire format ctx_len is u8)`);
124
+ if (payload.length > 0xFFFFFFFF)
125
+ throw new SigningError('sig-malformed-input', `payload length ${payload.length} > 2^32 - 1 (wire format payload_len is u32)`);
126
+ const out = new Uint8Array(2 + ctx.length + 4 + payload.length + sig.length);
127
+ let pos = 0;
128
+ out[pos++] = suiteByte;
129
+ out[pos++] = ctx.length;
130
+ out.set(ctx, pos);
131
+ pos += ctx.length;
132
+ writeU32BE(out, pos, payload.length);
133
+ pos += 4;
134
+ out.set(payload, pos);
135
+ pos += payload.length;
136
+ out.set(sig, pos);
137
+ return out;
138
+ }
139
+ function readU32BE(buf, off) {
140
+ // Multiply by 2^24 instead of <<24 so the high byte does not
141
+ // sign-extend into a negative JS number, which would propagate
142
+ // through the subsequent arithmetic and silently bypass the
143
+ // payload-overflow check.
144
+ return (buf[off] * 0x1000000
145
+ + ((buf[off + 1] << 16) | (buf[off + 2] << 8) | buf[off + 3]));
146
+ }
147
+ function writeU32BE(buf, off, value) {
148
+ buf[off] = (value >>> 24) & 0xFF;
149
+ buf[off + 1] = (value >>> 16) & 0xFF;
150
+ buf[off + 2] = (value >>> 8) & 0xFF;
151
+ buf[off + 3] = value & 0xFF;
152
+ }
@@ -0,0 +1,9 @@
1
+ import type { PrehashAlgorithm } from './types.js';
2
+ export interface RunningHash {
3
+ update(chunk: Uint8Array): void;
4
+ finalize(): Uint8Array;
5
+ dispose(): void;
6
+ }
7
+ export declare function sha256OneShot(msg: Uint8Array): Uint8Array;
8
+ export declare function sha512OneShot(msg: Uint8Array): Uint8Array;
9
+ export declare function createRunningHash(algo: PrehashAlgorithm): RunningHash;
@@ -0,0 +1,132 @@
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/hasher.ts
23
+ //
24
+ // Internal running-hash abstraction keyed on PrehashAlgorithm, used by
25
+ // SignStream and VerifyStream. SHAKE output sizes track FIPS 204 §5.4.1
26
+ // (HashML-DSA) and FIPS 205 §10.2.2 (HashSLH-DSA).
27
+ import { SHA3_256Stream, SHA3_512Stream, SHAKE128Stream, SHAKE256Stream, } from '../sha3/index.js';
28
+ import { SHA256, SHA512 } from '../sha2/index.js';
29
+ export function sha256OneShot(msg) {
30
+ const h = new SHA256();
31
+ try {
32
+ return h.hash(msg);
33
+ }
34
+ finally {
35
+ h.dispose();
36
+ }
37
+ }
38
+ export function sha512OneShot(msg) {
39
+ const h = new SHA512();
40
+ try {
41
+ return h.hash(msg);
42
+ }
43
+ finally {
44
+ h.dispose();
45
+ }
46
+ }
47
+ function sha256Buffered() {
48
+ let chunks = [];
49
+ let total = 0;
50
+ return {
51
+ update(chunk) {
52
+ const copy = new Uint8Array(chunk.length);
53
+ copy.set(chunk);
54
+ chunks.push(copy);
55
+ total += copy.length;
56
+ },
57
+ finalize() {
58
+ const buf = new Uint8Array(total);
59
+ let off = 0;
60
+ for (const c of chunks) {
61
+ buf.set(c, off);
62
+ off += c.length;
63
+ }
64
+ try {
65
+ return sha256OneShot(buf);
66
+ }
67
+ finally {
68
+ buf.fill(0);
69
+ for (const c of chunks)
70
+ c.fill(0);
71
+ chunks = [];
72
+ total = 0;
73
+ }
74
+ },
75
+ dispose() {
76
+ for (const c of chunks)
77
+ c.fill(0);
78
+ chunks = [];
79
+ total = 0;
80
+ },
81
+ };
82
+ }
83
+ function sha512Buffered() {
84
+ let chunks = [];
85
+ let total = 0;
86
+ return {
87
+ update(chunk) {
88
+ const copy = new Uint8Array(chunk.length);
89
+ copy.set(chunk);
90
+ chunks.push(copy);
91
+ total += copy.length;
92
+ },
93
+ finalize() {
94
+ const buf = new Uint8Array(total);
95
+ let off = 0;
96
+ for (const c of chunks) {
97
+ buf.set(c, off);
98
+ off += c.length;
99
+ }
100
+ try {
101
+ return sha512OneShot(buf);
102
+ }
103
+ finally {
104
+ buf.fill(0);
105
+ for (const c of chunks)
106
+ c.fill(0);
107
+ chunks = [];
108
+ total = 0;
109
+ }
110
+ },
111
+ dispose() {
112
+ for (const c of chunks)
113
+ c.fill(0);
114
+ chunks = [];
115
+ total = 0;
116
+ },
117
+ };
118
+ }
119
+ export function createRunningHash(algo) {
120
+ switch (algo) {
121
+ case 'sha3-256': return new SHA3_256Stream();
122
+ case 'sha3-512': return new SHA3_512Stream();
123
+ case 'shake-128': return new SHAKE128Stream(32);
124
+ case 'shake-256': return new SHAKE256Stream(64);
125
+ case 'sha-512': return sha512Buffered();
126
+ case 'sha-256': return sha256Buffered();
127
+ default: {
128
+ const _exhaustive = algo;
129
+ throw new Error(`leviathan-crypto: unknown prehash algorithm ${_exhaustive}`);
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,11 @@
1
+ export type { SignatureSuite, StreamableSignatureSuite, PrehashAlgorithm, } from './types.js';
2
+ export { buildEffectiveCtx, prehashAlgoToMldsa, USER_CTX_MAX, CTX_DOMAIN_MAX, } from './ctx.js';
3
+ export { Sign } from './envelope.js';
4
+ export { SignStream } from './sign-stream.js';
5
+ export { VerifyStream } from './verify-stream.js';
6
+ export { Ed25519Suite, Ed25519PreHashSuite, } from './suites/ed25519.js';
7
+ export { EcdsaP256Suite } from './suites/ecdsa-p256.js';
8
+ export { MlDsa44Suite, MlDsa65Suite, MlDsa87Suite, MlDsa44PreHashSuite, MlDsa65PreHashSuite, MlDsa87PreHashSuite, } from './suites/mldsa.js';
9
+ export { SlhDsa128fSuite, SlhDsa192fSuite, SlhDsa256fSuite, SlhDsa128fPreHashSuite, SlhDsa192fPreHashSuite, SlhDsa256fPreHashSuite, } from './suites/slhdsa.js';
10
+ export { MlDsa44SlhDsa128fSuite, MlDsa65SlhDsa192fSuite, MlDsa87SlhDsa256fSuite, } from './suites/hybrid-pq.js';
11
+ export { MlDsa44Ed25519Suite, MlDsa65Ed25519Suite, MlDsa44EcdsaP256Suite, MlDsa65EcdsaP256Suite, } from './suites/hybrid-classical.js';
@@ -0,0 +1,34 @@
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/index.ts
23
+ //
24
+ // Public barrel for the v3 sign module.
25
+ export { buildEffectiveCtx, prehashAlgoToMldsa, USER_CTX_MAX, CTX_DOMAIN_MAX, } from './ctx.js';
26
+ export { Sign } from './envelope.js';
27
+ export { SignStream } from './sign-stream.js';
28
+ export { VerifyStream } from './verify-stream.js';
29
+ export { Ed25519Suite, Ed25519PreHashSuite, } from './suites/ed25519.js';
30
+ export { EcdsaP256Suite } from './suites/ecdsa-p256.js';
31
+ export { MlDsa44Suite, MlDsa65Suite, MlDsa87Suite, MlDsa44PreHashSuite, MlDsa65PreHashSuite, MlDsa87PreHashSuite, } from './suites/mldsa.js';
32
+ export { SlhDsa128fSuite, SlhDsa192fSuite, SlhDsa256fSuite, SlhDsa128fPreHashSuite, SlhDsa192fPreHashSuite, SlhDsa256fPreHashSuite, } from './suites/slhdsa.js';
33
+ export { MlDsa44SlhDsa128fSuite, MlDsa65SlhDsa192fSuite, MlDsa87SlhDsa256fSuite, } from './suites/hybrid-pq.js';
34
+ export { MlDsa44Ed25519Suite, MlDsa65Ed25519Suite, MlDsa44EcdsaP256Suite, MlDsa65EcdsaP256Suite, } from './suites/hybrid-classical.js';