burnledger 0.2.1

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 (115) hide show
  1. package/README.md +182 -0
  2. package/dist/cjs/cli.d.ts +16 -0
  3. package/dist/cjs/cli.d.ts.map +1 -0
  4. package/dist/cjs/cli.js +168 -0
  5. package/dist/cjs/cli.js.map +1 -0
  6. package/dist/cjs/client.d.ts +116 -0
  7. package/dist/cjs/client.d.ts.map +1 -0
  8. package/dist/cjs/client.js +353 -0
  9. package/dist/cjs/client.js.map +1 -0
  10. package/dist/cjs/crypto-browser.d.ts +7 -0
  11. package/dist/cjs/crypto-browser.d.ts.map +1 -0
  12. package/dist/cjs/crypto-browser.js +37 -0
  13. package/dist/cjs/crypto-browser.js.map +1 -0
  14. package/dist/cjs/crypto-node.d.ts +4 -0
  15. package/dist/cjs/crypto-node.d.ts.map +1 -0
  16. package/dist/cjs/crypto-node.js +30 -0
  17. package/dist/cjs/crypto-node.js.map +1 -0
  18. package/dist/cjs/crypto.d.ts +6 -0
  19. package/dist/cjs/crypto.d.ts.map +1 -0
  20. package/dist/cjs/crypto.js +4 -0
  21. package/dist/cjs/crypto.js.map +1 -0
  22. package/dist/cjs/errors.d.ts +76 -0
  23. package/dist/cjs/errors.d.ts.map +1 -0
  24. package/dist/cjs/errors.js +119 -0
  25. package/dist/cjs/errors.js.map +1 -0
  26. package/dist/cjs/http.d.ts +35 -0
  27. package/dist/cjs/http.d.ts.map +1 -0
  28. package/dist/cjs/http.js +160 -0
  29. package/dist/cjs/http.js.map +1 -0
  30. package/dist/cjs/index.browser.d.ts +31 -0
  31. package/dist/cjs/index.browser.d.ts.map +1 -0
  32. package/dist/cjs/index.browser.js +54 -0
  33. package/dist/cjs/index.browser.js.map +1 -0
  34. package/dist/cjs/index.d.ts +26 -0
  35. package/dist/cjs/index.d.ts.map +1 -0
  36. package/dist/cjs/index.js +50 -0
  37. package/dist/cjs/index.js.map +1 -0
  38. package/dist/cjs/keys.d.ts +12 -0
  39. package/dist/cjs/keys.d.ts.map +1 -0
  40. package/dist/cjs/keys.js +17 -0
  41. package/dist/cjs/keys.js.map +1 -0
  42. package/dist/cjs/models.d.ts +197 -0
  43. package/dist/cjs/models.d.ts.map +1 -0
  44. package/dist/cjs/models.js +246 -0
  45. package/dist/cjs/models.js.map +1 -0
  46. package/dist/cjs/package.json +1 -0
  47. package/dist/cjs/pagination.d.ts +21 -0
  48. package/dist/cjs/pagination.d.ts.map +1 -0
  49. package/dist/cjs/pagination.js +50 -0
  50. package/dist/cjs/pagination.js.map +1 -0
  51. package/dist/cjs/verify.d.ts +50 -0
  52. package/dist/cjs/verify.d.ts.map +1 -0
  53. package/dist/cjs/verify.js +500 -0
  54. package/dist/cjs/verify.js.map +1 -0
  55. package/dist/cjs/webhooks.d.ts +36 -0
  56. package/dist/cjs/webhooks.d.ts.map +1 -0
  57. package/dist/cjs/webhooks.js +71 -0
  58. package/dist/cjs/webhooks.js.map +1 -0
  59. package/dist/esm/cli.d.ts +16 -0
  60. package/dist/esm/cli.d.ts.map +1 -0
  61. package/dist/esm/cli.js +164 -0
  62. package/dist/esm/cli.js.map +1 -0
  63. package/dist/esm/client.d.ts +116 -0
  64. package/dist/esm/client.d.ts.map +1 -0
  65. package/dist/esm/client.js +316 -0
  66. package/dist/esm/client.js.map +1 -0
  67. package/dist/esm/crypto-browser.d.ts +7 -0
  68. package/dist/esm/crypto-browser.d.ts.map +1 -0
  69. package/dist/esm/crypto-browser.js +34 -0
  70. package/dist/esm/crypto-browser.js.map +1 -0
  71. package/dist/esm/crypto-node.d.ts +4 -0
  72. package/dist/esm/crypto-node.d.ts.map +1 -0
  73. package/dist/esm/crypto-node.js +27 -0
  74. package/dist/esm/crypto-node.js.map +1 -0
  75. package/dist/esm/crypto.d.ts +6 -0
  76. package/dist/esm/crypto.d.ts.map +1 -0
  77. package/dist/esm/crypto.js +3 -0
  78. package/dist/esm/crypto.js.map +1 -0
  79. package/dist/esm/errors.d.ts +76 -0
  80. package/dist/esm/errors.d.ts.map +1 -0
  81. package/dist/esm/errors.js +105 -0
  82. package/dist/esm/errors.js.map +1 -0
  83. package/dist/esm/http.d.ts +35 -0
  84. package/dist/esm/http.d.ts.map +1 -0
  85. package/dist/esm/http.js +156 -0
  86. package/dist/esm/http.js.map +1 -0
  87. package/dist/esm/index.browser.d.ts +31 -0
  88. package/dist/esm/index.browser.d.ts.map +1 -0
  89. package/dist/esm/index.browser.js +31 -0
  90. package/dist/esm/index.browser.js.map +1 -0
  91. package/dist/esm/index.d.ts +26 -0
  92. package/dist/esm/index.d.ts.map +1 -0
  93. package/dist/esm/index.js +26 -0
  94. package/dist/esm/index.js.map +1 -0
  95. package/dist/esm/keys.d.ts +12 -0
  96. package/dist/esm/keys.d.ts.map +1 -0
  97. package/dist/esm/keys.js +14 -0
  98. package/dist/esm/keys.js.map +1 -0
  99. package/dist/esm/models.d.ts +197 -0
  100. package/dist/esm/models.d.ts.map +1 -0
  101. package/dist/esm/models.js +226 -0
  102. package/dist/esm/models.js.map +1 -0
  103. package/dist/esm/pagination.d.ts +21 -0
  104. package/dist/esm/pagination.d.ts.map +1 -0
  105. package/dist/esm/pagination.js +46 -0
  106. package/dist/esm/pagination.js.map +1 -0
  107. package/dist/esm/verify.d.ts +50 -0
  108. package/dist/esm/verify.d.ts.map +1 -0
  109. package/dist/esm/verify.js +491 -0
  110. package/dist/esm/verify.js.map +1 -0
  111. package/dist/esm/webhooks.d.ts +36 -0
  112. package/dist/esm/webhooks.d.ts.map +1 -0
  113. package/dist/esm/webhooks.js +67 -0
  114. package/dist/esm/webhooks.js.map +1 -0
  115. package/package.json +65 -0
@@ -0,0 +1,491 @@
1
+ /** Offline certificate and transparency verification.
2
+ *
3
+ * Ports the Go signing payload builders (core/payload.go) and Merkle tree
4
+ * verification (core/merkle.go) to TypeScript. All crypto is delegated to
5
+ * a CryptoOps provider (Node or browser).
6
+ *
7
+ * Critical encoding details:
8
+ * - Go's json.Marshal encodes []byte as base64, [N]byte as number arrays.
9
+ * - The payload builders normalize both formats to lowercase hex strings.
10
+ * - Timestamps in payloads use second-precision UTC: "YYYY-MM-DDTHH:MM:SSZ".
11
+ * - RFC 8785 canonical JSON: sorted keys recursively, no whitespace.
12
+ * - Transparency leaf = SHA-256(0x00 || issuanceBytes(cert)), NOT the
13
+ * certificate signing payload. issuanceBytes reconstructs json.Marshal
14
+ * output at issuance time (transparency_status=PENDING, no transparency).
15
+ */
16
+ import { VerificationError } from "./errors.js";
17
+ // ---------------------------------------------------------------------------
18
+ // Pure byte helpers (no Buffer, no node:crypto)
19
+ // ---------------------------------------------------------------------------
20
+ const HEX_CHARS = "0123456789abcdef";
21
+ // Signing-format v2 domain-separation tags (CR-H01). Must match the
22
+ // source-of-truth const block in Go's core/payload.go byte-for-byte.
23
+ const PAYLOAD_TYPE_ATTESTATION = "burnledger.attestation.v2";
24
+ const PAYLOAD_TYPE_VERIFICATION = "burnledger.verification.v2";
25
+ const PAYLOAD_TYPE_CERTIFICATE = "burnledger.certificate.v2";
26
+ const PAYLOAD_TYPE_TREE_HEAD = "burnledger.sth.v2";
27
+ export function hexToBytes(hex) {
28
+ const len = hex.length >>> 1;
29
+ const out = new Uint8Array(len);
30
+ for (let i = 0; i < len; i++) {
31
+ const hi = hex.charCodeAt(i * 2);
32
+ const lo = hex.charCodeAt(i * 2 + 1);
33
+ out[i] = (unhex(hi) << 4) | unhex(lo);
34
+ }
35
+ return out;
36
+ }
37
+ function unhex(c) {
38
+ // 0-9
39
+ if (c >= 48 && c <= 57)
40
+ return c - 48;
41
+ // a-f
42
+ if (c >= 97 && c <= 102)
43
+ return c - 87;
44
+ // A-F
45
+ if (c >= 65 && c <= 70)
46
+ return c - 55;
47
+ return 0;
48
+ }
49
+ export function bytesToHex(bytes) {
50
+ let out = "";
51
+ for (let i = 0; i < bytes.length; i++) {
52
+ const b = bytes[i];
53
+ out += HEX_CHARS[b >>> 4];
54
+ out += HEX_CHARS[b & 0x0f];
55
+ }
56
+ return out;
57
+ }
58
+ function concatBytes(a, b) {
59
+ const out = new Uint8Array(a.length + b.length);
60
+ out.set(a, 0);
61
+ out.set(b, a.length);
62
+ return out;
63
+ }
64
+ function bytesEqual(a, b) {
65
+ if (a.length !== b.length)
66
+ return false;
67
+ for (let i = 0; i < a.length; i++) {
68
+ if (a[i] !== b[i])
69
+ return false;
70
+ }
71
+ return true;
72
+ }
73
+ function base64ToBytes(b64) {
74
+ // Use atob for universal browser+node compatibility.
75
+ // Node 18+ has atob globally; browsers always have it.
76
+ const bin = atob(b64);
77
+ const out = new Uint8Array(bin.length);
78
+ for (let i = 0; i < bin.length; i++) {
79
+ out[i] = bin.charCodeAt(i);
80
+ }
81
+ return out;
82
+ }
83
+ function textToBytes(s) {
84
+ return new TextEncoder().encode(s);
85
+ }
86
+ export async function publicKeyFromHex(crypto, hexKey, opts) {
87
+ const raw = hexToBytes(hexKey);
88
+ if (raw.length !== 32) {
89
+ throw new VerificationError(`public key must be 32 bytes, got ${raw.length}`);
90
+ }
91
+ const hash = await crypto.sha256(raw);
92
+ const keyId = "dp_k_" + bytesToHex(hash);
93
+ return { keyBytes: raw, keyId, revoked: opts?.revoked ?? false };
94
+ }
95
+ /** Verify all signatures on a deletion certificate offline. */
96
+ export async function verifyCertificate(crypto, certificate, publicKeys) {
97
+ const issuer = certificate.issuer;
98
+ const keyId = issuer.key_id;
99
+ const pki = publicKeys.get(keyId);
100
+ if (pki === undefined)
101
+ throw new VerificationError(`unknown issuer key: ${keyId}`);
102
+ if (pki.revoked)
103
+ throw new VerificationError(`issuer key is revoked: ${keyId}`);
104
+ // 1. Attestation signature
105
+ const att = certificate.attestation;
106
+ const attPayload = buildAttestationPayload(certificate.subject, att);
107
+ const attSig = decodeSignature(att.attestation_signature);
108
+ if (!(await crypto.ed25519Verify(pki.keyBytes, attPayload, attSig))) {
109
+ throw new VerificationError("attestation signature is invalid");
110
+ }
111
+ // 2. Verification signature
112
+ const ver = certificate.verification;
113
+ const verPayload = buildVerificationPayload(certificate.attestation_id, ver);
114
+ const verSig = decodeSignature(ver.verification_signature);
115
+ if (!(await crypto.ed25519Verify(pki.keyBytes, verPayload, verSig))) {
116
+ throw new VerificationError("verification signature is invalid");
117
+ }
118
+ // 3. Certificate signature
119
+ const certPayload = buildCertificatePayload(certificate);
120
+ const certSig = decodeSignature(certificate.certificate_signature);
121
+ if (!(await crypto.ed25519Verify(pki.keyBytes, certPayload, certSig))) {
122
+ throw new VerificationError("certificate signature is invalid");
123
+ }
124
+ // 4. Now that every signature is verified (so these fields are trustworthy),
125
+ // reject certificates that are validly signed but are NOT proof of deletion.
126
+ // Mirrors core/verify.go steps 3 and 6 — without these the SDK would accept
127
+ // a revoked certificate, or one attesting data that is still present, as VALID.
128
+ if (certificate.status === "REVOKED") {
129
+ throw new VerificationError("certificate has been revoked");
130
+ }
131
+ for (const s of ver.systems ?? []) {
132
+ const recordCount = s.record_count;
133
+ if (recordCount !== 0) {
134
+ throw new VerificationError(`data still present: system "${s.system_name}" reports ${recordCount} record(s)`);
135
+ }
136
+ }
137
+ return "VALID";
138
+ }
139
+ /** Verify the transparency proof embedded in a certificate. */
140
+ export async function verifyTransparency(crypto, certificate, publicKeys) {
141
+ const transparency = certificate.transparency;
142
+ if (transparency == null) {
143
+ return "NOT_AVAILABLE";
144
+ }
145
+ const sth = transparency.signed_tree_head;
146
+ const issuer = certificate.issuer;
147
+ const keyId = issuer.key_id;
148
+ const pki = publicKeys.get(keyId);
149
+ if (pki === undefined)
150
+ throw new VerificationError(`unknown issuer key: ${keyId}`);
151
+ if (pki.revoked)
152
+ throw new VerificationError(`issuer key is revoked: ${keyId}`);
153
+ // 1. Tree head signature
154
+ const headPayload = buildTreeHeadPayload(sth);
155
+ const headSig = decodeSignature(sth.signature);
156
+ if (!(await crypto.ed25519Verify(pki.keyBytes, headPayload, headSig))) {
157
+ throw new VerificationError("tree head signature is invalid");
158
+ }
159
+ // 2. Merkle inclusion proof — leaf is hash of issuance-time certificate JSON,
160
+ // NOT the canonical signing payload. Matches Go's core.IssuanceBytes(cert).
161
+ const issuanceData = issuanceBytes(certificate);
162
+ const leaf = await hashLeaf(crypto, issuanceData);
163
+ const proofHashes = (transparency.inclusion_proof ?? []).map((h) => decodeBytes(h));
164
+ const root = decodeBytes(sth.root_hash);
165
+ const index = transparency.entry_index;
166
+ const treeSize = sth.tree_size;
167
+ if (!(await verifyInclusion(crypto, leaf, index, treeSize, proofHashes, root))) {
168
+ throw new VerificationError("merkle inclusion proof is invalid");
169
+ }
170
+ return "INCLUDED";
171
+ }
172
+ // ---------------------------------------------------------------------------
173
+ // Issuance bytes — matches Go's core.IssuanceBytes(cert)
174
+ // ---------------------------------------------------------------------------
175
+ /** Reconstruct the certificate JSON as it existed at issuance time.
176
+ *
177
+ * At issuance: transparency_status = "PENDING", transparency = nil (omitted).
178
+ * The leaf preimage is the RFC 8785 canonical JSON of that form — exactly
179
+ * Go's `CanonicalJSON(json.Marshal(cert))` in core.IssuanceBytes. It MUST be
180
+ * canonicalized (sorted keys, recursively), not serialized in insertion order:
181
+ * Go's struct field order is not alphabetical, so insertion-order stringify
182
+ * produces a different leaf hash and every genuine certificate fails inclusion
183
+ * verification (#C-01).
184
+ */
185
+ export function issuanceBytes(certificate) {
186
+ const clone = JSON.parse(JSON.stringify(certificate));
187
+ clone.transparency_status = "PENDING";
188
+ delete clone.transparency;
189
+ return canonicalJson(clone);
190
+ }
191
+ // ---------------------------------------------------------------------------
192
+ // RFC 8785 Canonical JSON
193
+ // ---------------------------------------------------------------------------
194
+ function canonicalJson(obj) {
195
+ return textToBytes(canonicalStringify(obj));
196
+ }
197
+ function canonicalStringify(val) {
198
+ if (val === null || val === undefined)
199
+ return "null";
200
+ if (typeof val === "boolean")
201
+ return val ? "true" : "false";
202
+ if (typeof val === "number")
203
+ return JSON.stringify(val);
204
+ if (typeof val === "string")
205
+ return JSON.stringify(val);
206
+ if (Array.isArray(val)) {
207
+ return "[" + val.map(canonicalStringify).join(",") + "]";
208
+ }
209
+ if (typeof val === "object") {
210
+ const obj = val;
211
+ const keys = Object.keys(obj).sort();
212
+ const pairs = keys.map((k) => JSON.stringify(k) + ":" + canonicalStringify(obj[k]));
213
+ return "{" + pairs.join(",") + "}";
214
+ }
215
+ return JSON.stringify(val);
216
+ }
217
+ // ---------------------------------------------------------------------------
218
+ // Byte encoding helpers
219
+ // ---------------------------------------------------------------------------
220
+ /** Convert a byte field to lowercase hex. Handles:
221
+ * - hex string (from hand-crafted test data)
222
+ * - base64 string (from Go's json.Marshal of []byte slices)
223
+ * - number[] (from Go's json.Marshal of [N]byte fixed arrays)
224
+ */
225
+ function toHex(value) {
226
+ if (Array.isArray(value)) {
227
+ return bytesToHex(new Uint8Array(value));
228
+ }
229
+ const str = value;
230
+ if (/^[0-9a-fA-F]+$/.test(str) && str.length % 2 === 0) {
231
+ return str.toLowerCase();
232
+ }
233
+ return bytesToHex(base64ToBytes(str));
234
+ }
235
+ /** Decode a signature field to raw bytes. Same format handling as toHex. */
236
+ function decodeSignature(value) {
237
+ if (Array.isArray(value)) {
238
+ return new Uint8Array(value);
239
+ }
240
+ const str = value;
241
+ if (/^[0-9a-fA-F]+$/.test(str)) {
242
+ const raw = hexToBytes(str);
243
+ if (raw.length === 64)
244
+ return raw;
245
+ }
246
+ return base64ToBytes(str);
247
+ }
248
+ /** Decode a hash/bytes field to raw bytes. Same format handling as toHex. */
249
+ function decodeBytes(value) {
250
+ if (Array.isArray(value)) {
251
+ return new Uint8Array(value);
252
+ }
253
+ const str = value;
254
+ if (/^[0-9a-fA-F]+$/.test(str) && str.length % 2 === 0) {
255
+ return hexToBytes(str);
256
+ }
257
+ return base64ToBytes(str);
258
+ }
259
+ function formatTimestamp(ts) {
260
+ // Strip fractional seconds, normalize to YYYY-MM-DDTHH:MM:SSZ
261
+ let s = ts;
262
+ const dotIdx = s.indexOf(".");
263
+ if (dotIdx !== -1) {
264
+ // Find the end of fractional seconds (Z, +, or end)
265
+ let endIdx = s.length;
266
+ for (let i = dotIdx + 1; i < s.length; i++) {
267
+ if (s[i] === "Z" || s[i] === "+" || s[i] === "-") {
268
+ endIdx = i;
269
+ break;
270
+ }
271
+ }
272
+ s = s.slice(0, dotIdx) + s.slice(endIdx);
273
+ }
274
+ if (s.endsWith("Z"))
275
+ return s;
276
+ // Strip timezone offset
277
+ const plusIdx = s.indexOf("+");
278
+ if (plusIdx !== -1) {
279
+ s = s.slice(0, plusIdx);
280
+ }
281
+ return s + "Z";
282
+ }
283
+ // ---------------------------------------------------------------------------
284
+ // Payload builders — exact ports of core/payload.go
285
+ // ---------------------------------------------------------------------------
286
+ function buildAttestationPayload(subject, att) {
287
+ const attestedAt = formatTimestamp(att.attested_at);
288
+ const systems = att.systems.map((s) => ({
289
+ canonical_version: s.canonical_version ?? null,
290
+ connector_type: s.connector_type,
291
+ hash_scope: s.hash_scope,
292
+ merkle_root: s.merkle_root
293
+ ? toHex(s.merkle_root)
294
+ : null,
295
+ observed_at: attestedAt,
296
+ record_count: s.record_count,
297
+ system_name: s.system_name,
298
+ }));
299
+ const payload = {
300
+ attested_at: attestedAt,
301
+ payload_type: PAYLOAD_TYPE_ATTESTATION,
302
+ proof_mode: att.proof_mode,
303
+ subject_hash: toHex(subject.identifier_hash),
304
+ systems,
305
+ };
306
+ return canonicalJson(payload);
307
+ }
308
+ function buildVerificationPayload(attestationId, ver) {
309
+ const verifiedAt = formatTimestamp(ver.verified_at);
310
+ const systems = ver.systems.map((s) => ({
311
+ observed_at: verifiedAt,
312
+ record_count: s.record_count,
313
+ system_name: s.system_name,
314
+ }));
315
+ const payload = {
316
+ attestation_id: attestationId,
317
+ payload_type: PAYLOAD_TYPE_VERIFICATION,
318
+ systems,
319
+ verified_at: verifiedAt,
320
+ };
321
+ return canonicalJson(payload);
322
+ }
323
+ function buildCertificatePayload(cert) {
324
+ const att = cert.attestation;
325
+ const ver = cert.verification;
326
+ const issuer = cert.issuer;
327
+ const subject = cert.subject;
328
+ // Attestation systems — uses "system_name" field name
329
+ const attSystems = att.systems.map((s) => ({
330
+ canonical_version: s.canonical_version ?? null,
331
+ connector_type: s.connector_type,
332
+ hash_scope: s.hash_scope,
333
+ merkle_root: s.merkle_root
334
+ ? toHex(s.merkle_root)
335
+ : null,
336
+ record_count: s.record_count,
337
+ system_name: s.system_name,
338
+ }));
339
+ const attObj = {
340
+ attestation_signature: toHex(att.attestation_signature),
341
+ attested_at: formatTimestamp(att.attested_at),
342
+ proof_mode: att.proof_mode,
343
+ systems: attSystems,
344
+ };
345
+ // Verification systems
346
+ const verSystems = ver.systems.map((s) => ({
347
+ connector_type: s.connector_type,
348
+ record_count: s.record_count,
349
+ system_name: s.system_name,
350
+ }));
351
+ const verObj = {
352
+ systems: verSystems,
353
+ verification_signature: toHex(ver.verification_signature),
354
+ verified_at: formatTimestamp(ver.verified_at),
355
+ };
356
+ const issuerObj = {
357
+ key_id: issuer.key_id,
358
+ name: issuer.name,
359
+ public_key: toHex(issuer.public_key),
360
+ };
361
+ const subjectObj = {
362
+ identifier_hash: toHex(subject.identifier_hash),
363
+ identifier_type_hint: subject.identifier_type_hint,
364
+ };
365
+ // Revocation
366
+ let revocation = null;
367
+ const rev = cert.revocation;
368
+ if (rev != null) {
369
+ revocation = {
370
+ reason: rev.reason,
371
+ replacement_certificate_id: rev.replacement_certificate_id ?? null,
372
+ revoked_at: formatTimestamp(rev.revoked_at),
373
+ };
374
+ }
375
+ const payload = {
376
+ attestation: attObj,
377
+ attestation_id: cert.attestation_id,
378
+ certificate_format_version: cert.certificate_format_version,
379
+ certificate_id: cert.certificate_id,
380
+ issued_at: formatTimestamp(cert.issued_at),
381
+ issuer: issuerObj,
382
+ payload_type: PAYLOAD_TYPE_CERTIFICATE,
383
+ revocation,
384
+ status: cert.status,
385
+ subject: subjectObj,
386
+ verification: verObj,
387
+ };
388
+ return canonicalJson(payload);
389
+ }
390
+ function buildTreeHeadPayload(head) {
391
+ const payload = {
392
+ payload_type: PAYLOAD_TYPE_TREE_HEAD,
393
+ root_hash: toHex(head.root_hash),
394
+ timestamp: formatTimestamp(head.timestamp),
395
+ tree_size: head.tree_size,
396
+ };
397
+ return canonicalJson(payload);
398
+ }
399
+ // ---------------------------------------------------------------------------
400
+ // Merkle tree (RFC 6962) — ports of core/merkle.go
401
+ // ---------------------------------------------------------------------------
402
+ async function hashLeaf(crypto, data) {
403
+ return crypto.sha256(concatBytes(new Uint8Array([0x00]), data));
404
+ }
405
+ async function hashNode(crypto, left, right) {
406
+ const prefix = new Uint8Array([0x01]);
407
+ return crypto.sha256(concatBytes(prefix, concatBytes(left, right)));
408
+ }
409
+ function splitPoint(n) {
410
+ let k = 1;
411
+ while (k * 2 < n) {
412
+ k *= 2;
413
+ }
414
+ return k;
415
+ }
416
+ async function verifyInclusion(crypto, leaf, index, size, proof, root) {
417
+ if (size === 0 || index >= size)
418
+ return false;
419
+ if (size === 1)
420
+ return proof.length === 0 && bytesEqual(leaf, root);
421
+ const [computed, consumed] = await chainInclusion(crypto, leaf, index, size, proof);
422
+ return consumed === proof.length && bytesEqual(computed, root);
423
+ }
424
+ async function chainInclusion(crypto, leaf, index, n, proof) {
425
+ if (n === 1)
426
+ return [leaf, 0];
427
+ const k = splitPoint(n);
428
+ if (index < k) {
429
+ const [inner, used] = await chainInclusion(crypto, leaf, index, k, proof);
430
+ if (used >= proof.length)
431
+ return [inner, used + 1];
432
+ return [await hashNode(crypto, inner, proof[used]), used + 1];
433
+ }
434
+ const [inner, used] = await chainInclusion(crypto, leaf, index - k, n - k, proof);
435
+ if (used >= proof.length)
436
+ return [inner, used + 1];
437
+ return [await hashNode(crypto, proof[used], inner), used + 1];
438
+ }
439
+ function isPow2(n) {
440
+ return n > 0 && (n & (n - 1)) === 0;
441
+ }
442
+ /** Verify a Merkle consistency proof (RFC 6962 Section 2.1.4).
443
+ *
444
+ * Port of Go's VerifyConsistency / Python's _verify_consistency.
445
+ */
446
+ export async function verifyConsistency(crypto, oldSize, newSize, oldRoot, newRoot, proof) {
447
+ if (oldSize === 0 || newSize === 0 || oldSize > newSize)
448
+ return false;
449
+ if (oldSize === newSize) {
450
+ return proof.length === 0 && bytesEqual(oldRoot, newRoot);
451
+ }
452
+ let pIdx = 0;
453
+ let fr;
454
+ let sr;
455
+ if (isPow2(oldSize)) {
456
+ fr = oldRoot;
457
+ sr = oldRoot;
458
+ }
459
+ else {
460
+ if (pIdx >= proof.length)
461
+ return false;
462
+ fr = proof[pIdx];
463
+ sr = proof[pIdx];
464
+ pIdx++;
465
+ }
466
+ let fn = oldSize - 1;
467
+ let sn = newSize - 1;
468
+ while ((fn & 1) === 1) {
469
+ fn >>= 1;
470
+ sn >>= 1;
471
+ }
472
+ while (pIdx < proof.length) {
473
+ const c = proof[pIdx];
474
+ pIdx++;
475
+ if ((fn & 1) === 1 || fn === sn) {
476
+ fr = await hashNode(crypto, c, fr);
477
+ sr = await hashNode(crypto, c, sr);
478
+ while (fn !== 0 && (fn & 1) === 0) {
479
+ fn >>= 1;
480
+ sn >>= 1;
481
+ }
482
+ }
483
+ else {
484
+ sr = await hashNode(crypto, sr, c);
485
+ }
486
+ fn >>= 1;
487
+ sn >>= 1;
488
+ }
489
+ return sn === 0 && bytesEqual(fr, oldRoot) && bytesEqual(sr, newRoot);
490
+ }
491
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /** Webhook signature verification for incoming BurnLedger events.
2
+ *
3
+ * The server signs webhook payloads with HMAC-SHA256 using the webhook secret.
4
+ * The signature is sent in the X-BurnLedger-Signature header as a hex string,
5
+ * and the timestamp in the X-BurnLedger-Timestamp header as an RFC3339 string.
6
+ *
7
+ * CR-M01: the signed preimage is `timestamp + "." + body`, where `timestamp` is
8
+ * the exact RFC3339 string from the X-BurnLedger-Timestamp header. Binding the
9
+ * timestamp into the MAC prevents a captured delivery from being replayed under
10
+ * a different timestamp. Receivers MUST also verify the timestamp is fresh (see
11
+ * isTimestampFresh) — the signature proves authenticity, freshness prevents
12
+ * replay of an old-but-validly-signed delivery.
13
+ *
14
+ * Node-only — webhooks are received server-side.
15
+ */
16
+ /**
17
+ * Verify that a webhook payload was signed by the expected secret.
18
+ *
19
+ * @param secret The webhook secret (raw UTF-8, as returned by the API)
20
+ * @param timestamp The RFC3339 timestamp from the X-BurnLedger-Timestamp header
21
+ * @param body The raw request body bytes
22
+ * @param signature The hex-encoded HMAC-SHA256 signature from the X-BurnLedger-Signature header
23
+ * @returns true if the signature is valid
24
+ */
25
+ export declare function verifyWebhookSignature(secret: string, timestamp: string, body: Uint8Array | string, signature: string): boolean;
26
+ /**
27
+ * Verify that the webhook timestamp is within an acceptable freshness window.
28
+ * Receivers MUST call this (in addition to verifyWebhookSignature) to prevent
29
+ * replay of an old-but-validly-signed delivery.
30
+ *
31
+ * @param timestamp The RFC3339 timestamp from the X-BurnLedger-Timestamp header
32
+ * @param toleranceSeconds Maximum accepted age/skew in seconds (default 300)
33
+ * @returns true if the timestamp parses and is within +/- tolerance of now
34
+ */
35
+ export declare function isTimestampFresh(timestamp: string, toleranceSeconds?: number): boolean;
36
+ //# sourceMappingURL=webhooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,UAAU,GAAG,MAAM,EACzB,SAAS,EAAE,MAAM,GAChB,OAAO,CAwBT;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,gBAAgB,GAAE,MAAY,GAC7B,OAAO,CAKT"}
@@ -0,0 +1,67 @@
1
+ /** Webhook signature verification for incoming BurnLedger events.
2
+ *
3
+ * The server signs webhook payloads with HMAC-SHA256 using the webhook secret.
4
+ * The signature is sent in the X-BurnLedger-Signature header as a hex string,
5
+ * and the timestamp in the X-BurnLedger-Timestamp header as an RFC3339 string.
6
+ *
7
+ * CR-M01: the signed preimage is `timestamp + "." + body`, where `timestamp` is
8
+ * the exact RFC3339 string from the X-BurnLedger-Timestamp header. Binding the
9
+ * timestamp into the MAC prevents a captured delivery from being replayed under
10
+ * a different timestamp. Receivers MUST also verify the timestamp is fresh (see
11
+ * isTimestampFresh) — the signature proves authenticity, freshness prevents
12
+ * replay of an old-but-validly-signed delivery.
13
+ *
14
+ * Node-only — webhooks are received server-side.
15
+ */
16
+ import { createHmac, timingSafeEqual } from "node:crypto";
17
+ /**
18
+ * Verify that a webhook payload was signed by the expected secret.
19
+ *
20
+ * @param secret The webhook secret (raw UTF-8, as returned by the API)
21
+ * @param timestamp The RFC3339 timestamp from the X-BurnLedger-Timestamp header
22
+ * @param body The raw request body bytes
23
+ * @param signature The hex-encoded HMAC-SHA256 signature from the X-BurnLedger-Signature header
24
+ * @returns true if the signature is valid
25
+ */
26
+ export function verifyWebhookSignature(secret, timestamp, body, signature) {
27
+ if (secret.length === 0)
28
+ return false;
29
+ if (timestamp.length === 0)
30
+ return false;
31
+ if (signature.length === 0)
32
+ return false;
33
+ // Preimage: timestamp + "." + body. An RFC3339 timestamp never contains a
34
+ // ".", so the field boundary is unambiguous.
35
+ const bodyBytes = typeof body === "string" ? Buffer.from(body, "utf-8") : Buffer.from(body);
36
+ const expected = createHmac("sha256", secret)
37
+ .update(Buffer.from(`${timestamp}.`, "utf-8"))
38
+ .update(bodyBytes)
39
+ .digest();
40
+ let received;
41
+ try {
42
+ received = Buffer.from(signature, "hex");
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ if (received.length !== expected.length)
48
+ return false;
49
+ return timingSafeEqual(expected, received);
50
+ }
51
+ /**
52
+ * Verify that the webhook timestamp is within an acceptable freshness window.
53
+ * Receivers MUST call this (in addition to verifyWebhookSignature) to prevent
54
+ * replay of an old-but-validly-signed delivery.
55
+ *
56
+ * @param timestamp The RFC3339 timestamp from the X-BurnLedger-Timestamp header
57
+ * @param toleranceSeconds Maximum accepted age/skew in seconds (default 300)
58
+ * @returns true if the timestamp parses and is within +/- tolerance of now
59
+ */
60
+ export function isTimestampFresh(timestamp, toleranceSeconds = 300) {
61
+ const parsed = Date.parse(timestamp);
62
+ if (Number.isNaN(parsed))
63
+ return false;
64
+ const ageSeconds = Math.abs(Date.now() - parsed) / 1000;
65
+ return ageSeconds <= toleranceSeconds;
66
+ }
67
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAc,EACd,SAAiB,EACjB,IAAyB,EACzB,SAAiB;IAEjB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAEzC,0EAA0E;IAC1E,6CAA6C;IAC7C,MAAM,SAAS,GACb,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5E,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;SAC1C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,GAAG,EAAE,OAAO,CAAC,CAAC;SAC7C,MAAM,CAAC,SAAS,CAAC;SACjB,MAAM,EAAE,CAAC;IAEZ,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAEtD,OAAO,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAAiB,EACjB,mBAA2B,GAAG;IAE9B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IACxD,OAAO,UAAU,IAAI,gBAAgB,CAAC;AACxC,CAAC"}