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
@@ -0,0 +1,33 @@
1
+ import type { Hasher, MerkleTree } from './tree.js';
2
+ import type { MerkleStorage } from './storage.js';
3
+ /**
4
+ * RFC 9162 §2.1.1, Merkle Hash Trees. The CT-flavoured SHA-256 hash
5
+ * function: empty-tree value `MTH({}) = SHA-256()`, leaf prefix `0x00`,
6
+ * internal-node prefix `0x01`.
7
+ *
8
+ * Stateless and reentrant: each method takes the sha2 module fresh,
9
+ * runs SHA-256 once, and releases. No `dispose()` is needed.
10
+ */
11
+ export declare const Sha256Hasher: Hasher;
12
+ /**
13
+ * Stateful SHA-256 Merkle log. Stores leaf hashes and every perfect
14
+ * aligned internal subtree's hash via the injected `MerkleStorage`;
15
+ * partial right-edge subtrees are recomputed on demand from the
16
+ * stored perfect subtrees.
17
+ *
18
+ * Constructed empty. `append` is the only mutator and is the leaf-hash
19
+ * factory; consumers feed leaf bytes, not pre-computed leaf hashes.
20
+ */
21
+ export declare class Sha256Tree implements MerkleTree {
22
+ readonly hasher: Hasher;
23
+ private readonly storage;
24
+ constructor(storage: MerkleStorage);
25
+ size(): number;
26
+ rootHash(): Uint8Array;
27
+ append(leafBytes: Uint8Array): {
28
+ leafIndex: number;
29
+ leafHash: Uint8Array;
30
+ };
31
+ getInclusionProof(leafIndex: number, treeSize?: number): Uint8Array[];
32
+ getConsistencyProof(oldSize: number, newSize: number): Uint8Array[];
33
+ }
@@ -0,0 +1,145 @@
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/merkle/sha256-tree.ts
23
+ //
24
+ // SHA-256 specialisation of the Hasher / MerkleTree interfaces. Wraps
25
+ // the existing `SHA256` class from the sha2 module under the RFC 9162
26
+ // (Certificate Transparency Version 2.0) §2.1.1 leaf and internal-node
27
+ // domain separators.
28
+ //
29
+ // Per-call WASM lifecycle: every Sha256Hasher method instantiates a
30
+ // fresh SHA256 inside a try / finally + dispose pattern. There is no
31
+ // long-lived module ownership; concurrent users are serialised by the
32
+ // per-module exclusivity guard in the sha2 substrate. This mirrors
33
+ // the SignatureSuite factories under src/ts/sign/suites/.
34
+ import { SHA256 } from '../sha2/index.js';
35
+ import { buildConsistencyProof, buildInclusionProof, subtreeHash, } from './proof.js';
36
+ // ── Sha256Hasher const ──────────────────────────────────────────────────────
37
+ const SHA256_OUTPUT = 32;
38
+ const LEAF_PREFIX = new Uint8Array([0x00]);
39
+ const INTERNAL_PREFIX = new Uint8Array([0x01]);
40
+ const SHA256_WASM_MODULES = Object.freeze(['sha2']);
41
+ function sha256Hash(input) {
42
+ const h = new SHA256();
43
+ try {
44
+ return h.hash(input);
45
+ }
46
+ finally {
47
+ h.dispose();
48
+ }
49
+ }
50
+ /**
51
+ * RFC 9162 §2.1.1, Merkle Hash Trees. The CT-flavoured SHA-256 hash
52
+ * function: empty-tree value `MTH({}) = SHA-256()`, leaf prefix `0x00`,
53
+ * internal-node prefix `0x01`.
54
+ *
55
+ * Stateless and reentrant: each method takes the sha2 module fresh,
56
+ * runs SHA-256 once, and releases. No `dispose()` is needed.
57
+ */
58
+ export const Sha256Hasher = Object.freeze({
59
+ name: 'sha256',
60
+ outputSize: SHA256_OUTPUT,
61
+ wasmModules: SHA256_WASM_MODULES,
62
+ hashEmpty() {
63
+ // RFC 9162 §2.1.1: MTH({}) is the hash of an empty bit-string.
64
+ return sha256Hash(new Uint8Array(0));
65
+ },
66
+ hashLeaf(leaf) {
67
+ // RFC 9162 §2.1.1: MTH({d}) = HASH(0x00 || d). The 0x00 prefix
68
+ // is the domain separator that prevents an internal-node hash
69
+ // from being mistaken for a leaf hash.
70
+ const buf = new Uint8Array(1 + leaf.length);
71
+ buf.set(LEAF_PREFIX, 0);
72
+ buf.set(leaf, 1);
73
+ return sha256Hash(buf);
74
+ },
75
+ hashInternal(left, right) {
76
+ // RFC 9162 §2.1.1: MTH(D[n]) = HASH(0x01 || MTH(D[0:k]) ||
77
+ // MTH(D[k:n])). The 0x01 prefix is the other half of the
78
+ // second-preimage-resistance domain separator.
79
+ const buf = new Uint8Array(1 + left.length + right.length);
80
+ buf.set(INTERNAL_PREFIX, 0);
81
+ buf.set(left, 1);
82
+ buf.set(right, 1 + left.length);
83
+ return sha256Hash(buf);
84
+ },
85
+ });
86
+ // ── Sha256Tree class ────────────────────────────────────────────────────────
87
+ /**
88
+ * Stateful SHA-256 Merkle log. Stores leaf hashes and every perfect
89
+ * aligned internal subtree's hash via the injected `MerkleStorage`;
90
+ * partial right-edge subtrees are recomputed on demand from the
91
+ * stored perfect subtrees.
92
+ *
93
+ * Constructed empty. `append` is the only mutator and is the leaf-hash
94
+ * factory; consumers feed leaf bytes, not pre-computed leaf hashes.
95
+ */
96
+ export class Sha256Tree {
97
+ hasher = Sha256Hasher;
98
+ storage;
99
+ constructor(storage) {
100
+ this.storage = storage;
101
+ }
102
+ size() {
103
+ return this.storage.size();
104
+ }
105
+ rootHash() {
106
+ const n = this.storage.size();
107
+ if (n === 0)
108
+ return this.hasher.hashEmpty();
109
+ const getNode = (level, index) => this.storage.getNode(level, index);
110
+ return subtreeHash(this.hasher, 0, n, getNode);
111
+ }
112
+ append(leafBytes) {
113
+ const leafIndex = this.storage.size();
114
+ const leafHash = this.hasher.hashLeaf(leafBytes);
115
+ this.storage.appendLeaf(leafIndex, leafHash);
116
+ // Propagate completed internal nodes up the right edge. RFC 9162
117
+ // §2.1.1 makes the tree fill left-to-right; whenever a node lands
118
+ // at an odd index its left sibling already exists, so the parent
119
+ // becomes computable for free.
120
+ let level = 0;
121
+ let idx = leafIndex;
122
+ while ((idx & 1) === 1) {
123
+ const left = this.storage.getNode(level, idx - 1);
124
+ const right = this.storage.getNode(level, idx);
125
+ const parent = this.hasher.hashInternal(left, right);
126
+ this.storage.putNode(level + 1, idx >>> 1, parent);
127
+ idx = idx >>> 1;
128
+ level++;
129
+ }
130
+ return { leafIndex, leafHash };
131
+ }
132
+ getInclusionProof(leafIndex, treeSize) {
133
+ const ts = treeSize ?? this.storage.size();
134
+ if (!Number.isInteger(ts) || ts < 1 || ts > this.storage.size())
135
+ throw new RangeError(`Sha256Tree.getInclusionProof: treeSize ${ts} out of range [1, ${this.storage.size()}]`);
136
+ const getNode = (level, index) => this.storage.getNode(level, index);
137
+ return buildInclusionProof({ hasher: this.hasher, leafIndex, treeSize: ts, getNode });
138
+ }
139
+ getConsistencyProof(oldSize, newSize) {
140
+ if (!Number.isInteger(newSize) || newSize < 0 || newSize > this.storage.size())
141
+ throw new RangeError(`Sha256Tree.getConsistencyProof: newSize ${newSize} out of range [0, ${this.storage.size()}]`);
142
+ const getNode = (level, index) => this.storage.getNode(level, index);
143
+ return buildConsistencyProof({ hasher: this.hasher, oldSize, newSize, getNode });
144
+ }
145
+ }
@@ -0,0 +1,156 @@
1
+ import type { SignedTreeHead } from './sth.js';
2
+ import type { MerkleTree } from './tree.js';
3
+ import type { SignatureSuite } from '../sign/types.js';
4
+ /**
5
+ * Constructor options for `SignedLog`.
6
+ */
7
+ export interface SignedLogOpts<S extends SignatureSuite> {
8
+ /** Underlying Merkle tree, holds the stateful append + proof surface. */
9
+ tree: MerkleTree;
10
+ /**
11
+ * Signature suite. Must have an entry in the C2SP cosignature
12
+ * algorithm-byte registry (currently `Ed25519Suite` and
13
+ * `MlDsa44Suite`); other suites throw `SigningError`.
14
+ */
15
+ suite: S;
16
+ /**
17
+ * Log identity, the first line of every checkpoint body. Validated
18
+ * at construction (non-empty, no whitespace, no plus characters)
19
+ * per c2sp.org/tlog-checkpoint §Note text.
20
+ */
21
+ origin: string;
22
+ /**
23
+ * Signing key, exactly `suite.skSize` bytes. The SignedLog stores
24
+ * a private copy; `dispose()` zeroes that copy. The caller's view
25
+ * of the buffer is left untouched.
26
+ */
27
+ signingKey: Uint8Array;
28
+ /**
29
+ * Public key, exactly `suite.pkSize` bytes. Used to derive the
30
+ * 4-byte keyId stamped on every emitted signature line and to
31
+ * match incoming signature lines during verify.
32
+ */
33
+ pubkey: Uint8Array;
34
+ }
35
+ /**
36
+ * Signed transparency log substrate. Combines a `MerkleTree` with a
37
+ * registered cosignature `SignatureSuite` and an origin string;
38
+ * exposes append, proof, and cosignature sign / verify operations.
39
+ *
40
+ * Per-call WASM lifecycle is enforced by the suite itself (see the
41
+ * SignatureSuite factories under `src/ts/sign/suites/`). `SignedLog`
42
+ * does not wrap additional try/finally around `suite.sign` /
43
+ * `suite.verify` because the suite already does. Internally the
44
+ * SignedLog owns a private copy of the signing key wiped by
45
+ * `dispose()`.
46
+ */
47
+ export declare class SignedLog<S extends SignatureSuite> {
48
+ readonly tree: MerkleTree;
49
+ readonly suite: S;
50
+ readonly origin: string;
51
+ readonly pubkey: Uint8Array;
52
+ readonly wasmModules: readonly string[];
53
+ private readonly _algoEntry;
54
+ private readonly _keyId;
55
+ private _signingKey;
56
+ private _disposed;
57
+ constructor(opts: SignedLogOpts<S>);
58
+ /**
59
+ * Append a leaf to the underlying tree and return the new leaf's
60
+ * index, hash, and inclusion proof against the post-append tree size.
61
+ */
62
+ append(leafBytes: Uint8Array): {
63
+ leafIndex: number;
64
+ leafHash: Uint8Array;
65
+ inclusionProof: Uint8Array[];
66
+ };
67
+ size(): number;
68
+ rootHash(): Uint8Array;
69
+ getInclusionProof(leafIndex: number, treeSize?: number): Uint8Array[];
70
+ getConsistencyProof(oldSize: number, newSize: number): Uint8Array[];
71
+ /**
72
+ * Issue a cosignature over the current checkpoint and emit the
73
+ * signed-note envelope per c2sp.org/signed-note §Format. The
74
+ * signature line carries the `timestamped_signature` payload
75
+ * from c2sp.org/tlog-cosignature §Format; the bytes the suite
76
+ * signs are dispatched on the algorithm's
77
+ * `messageConstruction`:
78
+ *
79
+ * - `'cosig'` → `buildCosigSignedMessage(body, ts)`
80
+ * (Ed25519, §"Ed25519 signed message")
81
+ * - `'cosigned-message'` → `buildCosignedMessage(...)`
82
+ * (ML-DSA-44, §"ML-DSA-44 signed message")
83
+ *
84
+ * `timestamp` defaults to current wall-clock POSIX seconds. The
85
+ * c2sp.org/tlog-witness `add-checkpoint` rule mandates a non-zero
86
+ * timestamp on production cosignatures; `0` is accepted by this
87
+ * function for test reproducibility but witness verifiers will
88
+ * reject envelopes that carry it. Tests and vector generators
89
+ * pass an explicit value to lock byte stability.
90
+ */
91
+ signCheckpoint(opts?: {
92
+ timestamp?: number;
93
+ }): Uint8Array;
94
+ /**
95
+ * Parse a signed-note envelope into the structured `SignedTreeHead`
96
+ * form per c2sp.org/signed-note §Format. Surfaces the body's
97
+ * decoded `Checkpoint`, the signature lines that survived the
98
+ * permissive signed-note parse, and the primary log cosignature's
99
+ * POSIX-seconds timestamp (extracted via
100
+ * `parseCosigSignaturePayload` on the line whose keyId matches
101
+ * this log's pubkey-derived keyId).
102
+ *
103
+ * If no signature line matches, `timestamp` is reported as 0. The
104
+ * field is informational at parse time; cryptographic verification
105
+ * lives in `verifyCheckpoint`. Throws `RangeError` on whole-envelope
106
+ * structural failure (the parseSignedNote / parseCheckpointBody
107
+ * contract); does not throw on signature line content issues.
108
+ */
109
+ parseCheckpoint(bytes: Uint8Array): SignedTreeHead;
110
+ /**
111
+ * Verify a signed-note envelope against this SignedLog's origin,
112
+ * pubkey, suite, and tree hasher. Returns `true` iff the envelope
113
+ * parses, carries a signature line whose keyId matches this log's
114
+ * pubkey-derived keyId, the `timestamped_signature` payload on
115
+ * that line decodes cleanly, and the signature verifies under
116
+ * `suite.verify` over the cosignature signed message reconstructed
117
+ * with the parsed timestamp.
118
+ *
119
+ * Returns `false` on every soft-fail mode: wrong origin, wrong
120
+ * root-hash length, no matching keyId line, malformed payload,
121
+ * signature failure. Throws only on this log's own disposed
122
+ * state; never on envelope content (envelope content is public,
123
+ * so timing distinctions on its content are not security-sensitive).
124
+ *
125
+ * The keyId comparison uses `constantTimeEqual` for hygiene around
126
+ * key-material-adjacent state; the origin and root-hash-length
127
+ * early returns are intentional non-constant-time exits since
128
+ * both fields are public per the spec.
129
+ */
130
+ verifyCheckpoint(bytes: Uint8Array): boolean;
131
+ /**
132
+ * Zero the stored signing-key copy. Idempotent. Subsequent calls
133
+ * to any public method throw.
134
+ */
135
+ dispose(): void;
136
+ private _assertNotDisposed;
137
+ /**
138
+ * Dispatch the cosignature signed-message construction on the
139
+ * algorithm-byte registry entry's `messageConstruction`. The
140
+ * `body` argument is the canonical checkpoint body from
141
+ * `serializeCheckpointBody`, ending in 0x0A.
142
+ *
143
+ * 'cosig' c2sp.org/tlog-cosignature §"Ed25519 signed
144
+ * message". The full envelope body is
145
+ * embedded verbatim after the
146
+ * cosignature/v1 + time prefix.
147
+ *
148
+ * 'cosigned-message' c2sp.org/tlog-cosignature §"ML-DSA-44
149
+ * signed message". The body is decomposed
150
+ * into origin, tree size, and root hash;
151
+ * cosigner_name == origin (Phase 7 logs sign
152
+ * their own checkpoints); start == 0; end ==
153
+ * tree size; hash == root hash.
154
+ */
155
+ private _buildSignedMessage;
156
+ }