@orangecheck/stamp-ots 0.2.1 → 0.3.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.
- package/README.md +1 -1
- package/dist/index.js +57 -40
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +57 -40
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/stamp-core-verify.test.ts +74 -0
- package/src/submit.test.ts +42 -5
- package/src/submit.ts +27 -9
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @orangecheck/stamp-ots
|
|
2
2
|
|
|
3
|
-
> **Full reference:** [
|
|
3
|
+
> **Full reference:** [ochk.io/docs/sdk/stamp-ots](https://ochk.io/docs/sdk/stamp-ots) — auto-generated from the TypeScript source on every release.
|
|
4
4
|
> Hand-written prose below is the high-level overview; the docs site is the source of truth for every export, type, and signature.
|
|
5
5
|
|
|
6
6
|
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var sha2 = require('@noble/hashes/sha2');
|
|
4
3
|
var legacy = require('@noble/hashes/legacy');
|
|
4
|
+
var sha2 = require('@noble/hashes/sha2');
|
|
5
5
|
var sha3 = require('@noble/hashes/sha3');
|
|
6
6
|
|
|
7
7
|
// src/types.ts
|
|
@@ -167,44 +167,6 @@ function withTimeout(parent, ms) {
|
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
169
|
}
|
|
170
|
-
|
|
171
|
-
// src/submit.ts
|
|
172
|
-
async function submitToCalendars(idHex, opts = {}) {
|
|
173
|
-
const digest = hexDecode(idHex);
|
|
174
|
-
if (digest.byteLength !== 32) {
|
|
175
|
-
throw new Error("submitToCalendars: idHex must be 32 bytes (64 hex chars)");
|
|
176
|
-
}
|
|
177
|
-
const clients = (opts.calendars ?? DEFAULT_CALENDARS).map(
|
|
178
|
-
(c) => typeof c === "string" ? createCalendarClient(c, { fetch: opts.fetch, timeoutMs: opts.timeoutMs }) : c
|
|
179
|
-
);
|
|
180
|
-
if (clients.length === 0) {
|
|
181
|
-
throw new Error("submitToCalendars: at least one calendar is required");
|
|
182
|
-
}
|
|
183
|
-
const minSuccesses = Math.max(1, opts.minSuccesses ?? 1);
|
|
184
|
-
const settled = await Promise.allSettled(
|
|
185
|
-
clients.map(async (c) => {
|
|
186
|
-
const proof = await c.submit(digest, opts.signal);
|
|
187
|
-
return { url: c.url, proof };
|
|
188
|
-
})
|
|
189
|
-
);
|
|
190
|
-
const successes = settled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
191
|
-
const failures = settled.filter((r) => r.status === "rejected").map((r) => r.reason instanceof Error ? r.reason.message : String(r.reason));
|
|
192
|
-
if (successes.length < minSuccesses) {
|
|
193
|
-
const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join("; ")}`;
|
|
194
|
-
const err = new Error(msg);
|
|
195
|
-
err.errors = failures;
|
|
196
|
-
throw err;
|
|
197
|
-
}
|
|
198
|
-
const first = successes[0];
|
|
199
|
-
return {
|
|
200
|
-
status: "pending",
|
|
201
|
-
proof: base64Encode(first.proof),
|
|
202
|
-
calendars: successes.map((s) => s.url),
|
|
203
|
-
blockHeight: null,
|
|
204
|
-
blockHash: null,
|
|
205
|
-
upgradedAt: null
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
170
|
var HEADER_MAGIC = new Uint8Array([
|
|
209
171
|
0,
|
|
210
172
|
79,
|
|
@@ -479,7 +441,62 @@ function bytesEqual(a, b) {
|
|
|
479
441
|
return true;
|
|
480
442
|
}
|
|
481
443
|
|
|
482
|
-
// src/
|
|
444
|
+
// src/submit.ts
|
|
445
|
+
async function submitToCalendars(idHex, opts = {}) {
|
|
446
|
+
const digest = hexDecode(idHex);
|
|
447
|
+
if (digest.byteLength !== 32) {
|
|
448
|
+
throw new Error("submitToCalendars: idHex must be 32 bytes (64 hex chars)");
|
|
449
|
+
}
|
|
450
|
+
const clients = (opts.calendars ?? DEFAULT_CALENDARS).map(
|
|
451
|
+
(c) => typeof c === "string" ? createCalendarClient(c, { fetch: opts.fetch, timeoutMs: opts.timeoutMs }) : c
|
|
452
|
+
);
|
|
453
|
+
if (clients.length === 0) {
|
|
454
|
+
throw new Error("submitToCalendars: at least one calendar is required");
|
|
455
|
+
}
|
|
456
|
+
const minSuccesses = Math.max(1, opts.minSuccesses ?? 1);
|
|
457
|
+
const settled = await Promise.allSettled(
|
|
458
|
+
clients.map(async (c) => {
|
|
459
|
+
const proof = await c.submit(digest, opts.signal);
|
|
460
|
+
return { url: c.url, proof };
|
|
461
|
+
})
|
|
462
|
+
);
|
|
463
|
+
const successes = settled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
464
|
+
const failures = settled.filter((r) => r.status === "rejected").map((r) => r.reason instanceof Error ? r.reason.message : String(r.reason));
|
|
465
|
+
if (successes.length < minSuccesses) {
|
|
466
|
+
const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join("; ")}`;
|
|
467
|
+
const err = new Error(msg);
|
|
468
|
+
err.errors = failures;
|
|
469
|
+
throw err;
|
|
470
|
+
}
|
|
471
|
+
let tree = null;
|
|
472
|
+
const merged = [];
|
|
473
|
+
for (const s of successes) {
|
|
474
|
+
let receipt;
|
|
475
|
+
try {
|
|
476
|
+
receipt = parseTimestamp(s.proof, digest);
|
|
477
|
+
} catch (e) {
|
|
478
|
+
failures.push(`${s.url}: unreadable proof (${e instanceof Error ? e.message : String(e)})`);
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
if (tree) mergeAt(tree, receipt);
|
|
482
|
+
else tree = receipt;
|
|
483
|
+
merged.push(s.url);
|
|
484
|
+
}
|
|
485
|
+
if (!tree || merged.length < minSuccesses) {
|
|
486
|
+
const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join("; ")}`;
|
|
487
|
+
const err = new Error(msg);
|
|
488
|
+
err.errors = failures;
|
|
489
|
+
throw err;
|
|
490
|
+
}
|
|
491
|
+
return {
|
|
492
|
+
status: "pending",
|
|
493
|
+
proof: base64Encode(serializeTimestamp(tree)),
|
|
494
|
+
calendars: merged,
|
|
495
|
+
blockHeight: null,
|
|
496
|
+
blockHash: null,
|
|
497
|
+
upgradedAt: null
|
|
498
|
+
};
|
|
499
|
+
}
|
|
483
500
|
async function walkOtsProof(input) {
|
|
484
501
|
try {
|
|
485
502
|
const anchors = bitcoinAnchors(parseProof(input.proofBytes, input.digest));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/base64.ts","../src/calendar.ts","../src/submit.ts","../src/ots.ts","../src/anchor.ts","../src/upgrade.ts"],"names":["sha256","ripemd160","sha1","keccak_256","tag"],"mappings":"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","file":"index.js","sourcesContent":["// Types for @orangecheck/stamp-ots.\n\nimport type { StampOts } from '@orangecheck/stamp-core';\n\nexport type OtsProofStatus = 'pending' | 'confirmed';\n\nexport interface OtsProof {\n status: OtsProofStatus;\n /** OTS timestamp rooted at the envelope id (or a detached .ots file), base64. */\n proof: string;\n /** Calendar URLs that contain this proof, in submission order. */\n calendars: string[];\n /** Bitcoin block height at which this proof is anchored (null if pending). */\n blockHeight: number | null;\n /** Bitcoin block hash (hex, lowercase) at the anchor block (null if pending). */\n blockHash: string | null;\n /** ISO 8601 UTC of the upgrade (null if pending). */\n upgradedAt: string | null;\n}\n\nexport interface CalendarClient {\n /** Base URL of the calendar, e.g. \"https://alice.btc.calendar.opentimestamps.org\". */\n readonly url: string;\n\n /**\n * Submit a 32-byte digest to the calendar for aggregation. Returns the raw\n * pending proof bytes.\n *\n * OTS calendar HTTP API: POST <url>/digest with the raw bytes as the body,\n * Content-Type: application/vnd.opentimestamps.v1, returns the proof bytes\n * as the response body.\n */\n submit(digest: Uint8Array, signal?: AbortSignal): Promise<Uint8Array>;\n\n /**\n * Fetch the continuation of a pending proof. `commitment` is the message\n * at the calendar's pending attestation (see `pendingCommitments`), not\n * the submitted digest. Returns null if the calendar has nothing yet.\n *\n * OTS calendar HTTP API: GET <url>/timestamp/<hex(commitment)>, returns a\n * timestamp rooted at the commitment, or 404.\n */\n fetchProof(commitment: Uint8Array, signal?: AbortSignal): Promise<Uint8Array | null>;\n}\n\nexport interface AnchorVerificationInput {\n /** Raw OTS proof bytes (base64-decoded by the caller). */\n proofBytes: Uint8Array;\n /** 32-byte digest that the proof commits to. */\n digest: Uint8Array;\n /** Declared block height from the envelope. */\n blockHeight: number;\n /** Declared block hash (hex) from the envelope. */\n blockHash: string;\n /**\n * Optional block header source. If provided, the verifier uses this to\n * fetch the header at `blockHeight` and compare its Merkle root to the\n * one derived from walking the proof.\n *\n * If omitted, the verifier MAY still parse the proof and report\n * structural validity but CANNOT report a bound anchor.\n */\n headerSource?: BlockHeaderSource;\n}\n\nexport interface BlockHeaderSource {\n /** Return the 80-byte raw block header at the given height, or null if unknown. */\n getHeaderAt(height: number): Promise<Uint8Array | null>;\n}\n\nexport type AnchorVerifier = (input: AnchorVerificationInput) => Promise<AnchorVerificationResult>;\n\nexport type AnchorVerificationResult =\n | { ok: true; merkleRoot: string }\n | { ok: false; reason: string };\n\n/**\n * Convert an OtsProof (library type) to the StampOts field shape that the\n * envelope carries. The two are isomorphic; this function exists to keep\n * stamp-core's type surface narrow.\n */\nexport function toStampOts(p: OtsProof): StampOts {\n return {\n status: p.status,\n proof: p.proof,\n calendars: p.calendars,\n block_height: p.blockHeight,\n block_hash: p.blockHash,\n upgraded_at: p.upgradedAt,\n };\n}\n\nexport function fromStampOts(s: StampOts): OtsProof {\n return {\n status: s.status,\n proof: s.proof,\n calendars: s.calendars,\n blockHeight: s.block_height,\n blockHash: s.block_hash,\n upgradedAt: s.upgraded_at,\n };\n}\n","// Minimal, dependency-free base64 <-> Uint8Array helpers. OTS proof bytes\n// are carried as base64 inside OC Stamp envelopes so they survive any text\n// transport (URL fragment, JSON, Nostr event content).\n\nconst B64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\nconst B64_DECODE_TABLE = (() => {\n const t = new Int16Array(128).fill(-1);\n for (let i = 0; i < B64_CHARS.length; i++) t[B64_CHARS.charCodeAt(i)] = i;\n t['='.charCodeAt(0)] = -2;\n return t;\n})();\n\nexport function base64Encode(bytes: Uint8Array): string {\n let out = '';\n let i = 0;\n for (; i + 2 < bytes.length; i += 3) {\n const a = bytes[i]!;\n const b = bytes[i + 1]!;\n const c = bytes[i + 2]!;\n out +=\n B64_CHARS[a >> 2]! +\n B64_CHARS[((a & 0x03) << 4) | (b >> 4)]! +\n B64_CHARS[((b & 0x0f) << 2) | (c >> 6)]! +\n B64_CHARS[c & 0x3f]!;\n }\n if (i < bytes.length) {\n const a = bytes[i]!;\n const b = i + 1 < bytes.length ? bytes[i + 1]! : 0;\n out += B64_CHARS[a >> 2]!;\n out += B64_CHARS[((a & 0x03) << 4) | (b >> 4)]!;\n out += i + 1 < bytes.length ? B64_CHARS[(b & 0x0f) << 2]! : '=';\n out += '=';\n }\n return out;\n}\n\nexport function base64Decode(s: string): Uint8Array {\n const str = s.replace(/\\s+/g, '');\n const len = str.length;\n if (len === 0) return new Uint8Array(0);\n if (len % 4 !== 0) throw new Error('base64: bad length');\n let padding = 0;\n if (str[len - 1] === '=') padding++;\n if (str[len - 2] === '=') padding++;\n const outLen = (len / 4) * 3 - padding;\n const out = new Uint8Array(outLen);\n let o = 0;\n for (let i = 0; i < len; i += 4) {\n const c0 = B64_DECODE_TABLE[str.charCodeAt(i)]!;\n const c1 = B64_DECODE_TABLE[str.charCodeAt(i + 1)]!;\n const c2 = B64_DECODE_TABLE[str.charCodeAt(i + 2)]!;\n const c3 = B64_DECODE_TABLE[str.charCodeAt(i + 3)]!;\n if (c0 < 0 || c1 < 0 || c2 < -2 || c3 < -2) throw new Error('base64: bad char');\n out[o++] = (c0 << 2) | (c1 >> 4);\n if (c2 >= 0) out[o++] = ((c1 & 0x0f) << 4) | (c2 >> 2);\n if (c3 >= 0) out[o++] = ((c2 & 0x03) << 6) | c3;\n }\n return out;\n}\n\nexport function hexDecode(s: string): Uint8Array {\n if (s.length % 2 !== 0) throw new Error('hex: odd length');\n const out = new Uint8Array(s.length / 2);\n for (let i = 0; i < out.length; i++) {\n const hi = parseInt(s[i * 2]!, 16);\n const lo = parseInt(s[i * 2 + 1]!, 16);\n if (Number.isNaN(hi) || Number.isNaN(lo)) throw new Error('hex: bad char');\n out[i] = (hi << 4) | lo;\n }\n return out;\n}\n\nexport function hexEncode(bytes: Uint8Array): string {\n const HEX = '0123456789abcdef';\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n const b = bytes[i]!;\n out += HEX[(b >> 4) & 0x0f]! + HEX[b & 0x0f]!;\n }\n return out;\n}\n","// HTTP client for an OpenTimestamps calendar. Implements the minimal subset\n// of the calendar protocol that an OC Stamp implementation needs:\n//\n// POST <url>/digest body = raw digest bytes -> pending proof bytes\n// GET <url>/timestamp/<hex(commitment)> -> continuation, or 404\n//\n// The client moves bytes only; ./ots.ts parses them.\n\nimport type { CalendarClient } from './types.js';\nimport { hexEncode } from './base64.js';\n\nexport const DEFAULT_CALENDARS: readonly string[] = [\n 'https://alice.btc.calendar.opentimestamps.org',\n 'https://bob.btc.calendar.opentimestamps.org',\n 'https://finney.calendar.eternitywall.com',\n];\n\nexport interface HttpCalendarOptions {\n /**\n * Custom fetch implementation. Defaults to global `fetch`. Useful in\n * environments that need a specific adapter (Node < 18, Cloudflare\n * Workers, proxies).\n */\n fetch?: typeof fetch;\n /** Request timeout in milliseconds. Default 30_000. */\n timeoutMs?: number;\n}\n\nexport function createCalendarClient(url: string, opts: HttpCalendarOptions = {}): CalendarClient {\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') {\n throw new Error(\n '@orangecheck/stamp-ots: no fetch implementation available. Pass one via { fetch }.'\n );\n }\n const timeoutMs = opts.timeoutMs ?? 30_000;\n const base = url.replace(/\\/$/, '');\n\n return {\n url: base,\n async submit(digest, signal) {\n if (digest.byteLength !== 32) {\n throw new Error('OTS: digest must be exactly 32 bytes');\n }\n const ac = withTimeout(signal, timeoutMs);\n // Uint8Array is a valid fetch body at runtime in Node 18+ and all\n // modern browsers, but TypeScript's DOM typings don't accept it\n // directly under `strict` + `noUncheckedIndexedAccess`. The cast is\n // narrow and intentional.\n // No Content-Type: a non-safelisted type makes browsers send a\n // CORS preflight, and OTS calendars answer OPTIONS with 501.\n const resp = await fetchImpl(`${base}/digest`, {\n method: 'POST',\n body: digest as unknown as BodyInit,\n signal: ac.signal,\n });\n ac.clear();\n if (!resp.ok) {\n throw new Error(`OTS calendar ${base} submit failed: HTTP ${resp.status}`);\n }\n const buf = await resp.arrayBuffer();\n return new Uint8Array(buf);\n },\n async fetchProof(commitment, signal) {\n if (commitment.byteLength === 0 || commitment.byteLength > 64) {\n throw new Error('OTS: commitment must be 1-64 bytes');\n }\n const ac = withTimeout(signal, timeoutMs);\n const resp = await fetchImpl(`${base}/timestamp/${hexEncode(commitment)}`, {\n method: 'GET',\n headers: { Accept: 'application/vnd.opentimestamps.v1' },\n signal: ac.signal,\n });\n ac.clear();\n if (resp.status === 404) return null;\n if (!resp.ok) {\n throw new Error(`OTS calendar ${base} fetchProof failed: HTTP ${resp.status}`);\n }\n const buf = await resp.arrayBuffer();\n return new Uint8Array(buf);\n },\n };\n}\n\nfunction withTimeout(parent: AbortSignal | undefined, ms: number): { signal: AbortSignal; clear: () => void } {\n const ac = new AbortController();\n const onParent = () => ac.abort((parent as AbortSignal & { reason?: unknown }).reason);\n if (parent) {\n if (parent.aborted) ac.abort((parent as AbortSignal & { reason?: unknown }).reason);\n else parent.addEventListener('abort', onParent, { once: true });\n }\n const t = setTimeout(() => ac.abort(new Error(`OTS request timed out after ${ms}ms`)), ms);\n return {\n signal: ac.signal,\n clear: () => {\n clearTimeout(t);\n if (parent) parent.removeEventListener('abort', onParent);\n },\n };\n}\n","// Submit an envelope id to one or more OTS calendars. Returns a pending proof.\n// See SPEC.md §6.1.\n//\n// The submission strategy: try each calendar in parallel, take the first\n// success, report which calendar produced it. A stamp that only reaches one\n// calendar is a single point of failure for upgrade; the reference app\n// submits to at least two calendars for redundancy.\n\nimport { base64Encode, hexDecode } from './base64.js';\nimport { createCalendarClient, DEFAULT_CALENDARS } from './calendar.js';\nimport type { CalendarClient, OtsProof } from './types.js';\n\nexport interface SubmitOptions {\n /**\n * Calendars to submit to. Defaults to DEFAULT_CALENDARS. Can be strings\n * (URLs) or pre-built CalendarClient instances.\n */\n calendars?: readonly (string | CalendarClient)[];\n /**\n * Minimum number of calendars that must succeed. Defaults to 1.\n * If fewer than `minSuccesses` calendars respond with a proof,\n * submit() throws an aggregate error.\n */\n minSuccesses?: number;\n /** Optional custom fetch passed through to calendar clients. */\n fetch?: typeof fetch;\n /** Request timeout per calendar. Default 30_000ms. */\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/**\n * Submit the envelope `id` (64-hex) to OTS calendars and return an OtsProof in\n * pending state. The caller merges this into the envelope's `ots` field.\n *\n * Implementation note: the raw proof bytes returned by OTS calendars are not\n * a superset of the digest alone — they encode the calendar's commitment.\n * Because different calendars return different pending-proof bytes for the\n * same digest, we carry the FIRST successful calendar's bytes in the\n * envelope. Upgrade (see upgrade.ts) can fetch richer proofs from any of the\n * submitted-to calendars later.\n */\nexport async function submitToCalendars(idHex: string, opts: SubmitOptions = {}): Promise<OtsProof> {\n const digest = hexDecode(idHex);\n if (digest.byteLength !== 32) {\n throw new Error('submitToCalendars: idHex must be 32 bytes (64 hex chars)');\n }\n\n const clients = (opts.calendars ?? DEFAULT_CALENDARS).map((c) =>\n typeof c === 'string'\n ? createCalendarClient(c, { fetch: opts.fetch, timeoutMs: opts.timeoutMs })\n : c\n );\n if (clients.length === 0) {\n throw new Error('submitToCalendars: at least one calendar is required');\n }\n const minSuccesses = Math.max(1, opts.minSuccesses ?? 1);\n\n const settled = await Promise.allSettled(\n clients.map(async (c) => {\n const proof = await c.submit(digest, opts.signal);\n return { url: c.url, proof };\n })\n );\n const successes = settled\n .filter((r): r is PromiseFulfilledResult<{ url: string; proof: Uint8Array }> => r.status === 'fulfilled')\n .map((r) => r.value);\n const failures = settled\n .filter((r): r is PromiseRejectedResult => r.status === 'rejected')\n .map((r) => (r.reason instanceof Error ? r.reason.message : String(r.reason)));\n\n if (successes.length < minSuccesses) {\n // AggregateError would be nicer but targets ES2021; Error keeps us at ES2020.\n const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join('; ')}`;\n const err = new Error(msg) as Error & { errors: string[] };\n err.errors = failures;\n throw err;\n }\n\n const first = successes[0]!;\n return {\n status: 'pending',\n proof: base64Encode(first.proof),\n calendars: successes.map((s) => s.url),\n blockHeight: null,\n blockHash: null,\n upgradedAt: null,\n };\n}\n","// OpenTimestamps proof format: parse, walk, serialize, merge.\n//\n// Follows python-opentimestamps (core/timestamp.py, core/op.py,\n// core/notary.py). Two encodings are accepted:\n//\n// - a bare timestamp rooted at the digest (what an OTS calendar returns from\n// POST /digest, and what OC Stamp envelopes carry in `ots.proof`);\n// - a detached `.ots` file (magic header + file-hash op + digest + timestamp).\n\nimport { ripemd160, sha1 } from '@noble/hashes/legacy';\nimport { sha256 } from '@noble/hashes/sha2';\nimport { keccak_256 } from '@noble/hashes/sha3';\n\nimport { hexEncode } from './base64.js';\n\nconst HEADER_MAGIC = new Uint8Array([\n 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x00,\n 0x00, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x00, 0xbf, 0x89, 0xe2, 0xe8, 0x84, 0xe8, 0x92, 0x94,\n]);\n\nconst TAG_BITCOIN = '0588960d73d71901';\nconst TAG_PENDING = '83dfe30d2ef90c8e';\n\nconst MAX_DEPTH = 256;\nconst MAX_MSG = 4096;\n\nexport type OtsOp =\n | { kind: 'sha256' | 'ripemd160' | 'sha1' | 'keccak256' | 'reverse' | 'hexlify' }\n | { kind: 'append' | 'prepend'; arg: Uint8Array };\n\nexport type OtsAttestation =\n | { kind: 'bitcoin'; height: number }\n | { kind: 'pending'; uri: string }\n | { kind: 'unknown'; tag: string; payload: Uint8Array };\n\nexport interface OtsTimestamp {\n /** The message at this node: the digest after every op on the path to it. */\n msg: Uint8Array;\n attestations: OtsAttestation[];\n ops: { op: OtsOp; child: OtsTimestamp }[];\n}\n\nclass Reader {\n private pos = 0;\n constructor(private readonly buf: Uint8Array) {}\n byte(): number {\n if (this.pos >= this.buf.length) throw new Error('ots: unexpected end of proof');\n return this.buf[this.pos++]!;\n }\n bytes(n: number): Uint8Array {\n if (n < 0 || this.pos + n > this.buf.length) throw new Error('ots: unexpected end of proof');\n const out = this.buf.subarray(this.pos, this.pos + n);\n this.pos += n;\n return out;\n }\n varuint(): number {\n let value = 0;\n let shift = 0;\n for (;;) {\n const b = this.byte();\n value += (b & 0x7f) * 2 ** shift;\n if (!(b & 0x80)) return value;\n shift += 7;\n if (shift > 49) throw new Error('ots: varuint too large');\n }\n }\n varbytes(max: number): Uint8Array {\n const n = this.varuint();\n if (n > max) throw new Error('ots: varbytes too long');\n return this.bytes(n);\n }\n get done(): boolean {\n return this.pos === this.buf.length;\n }\n}\n\nconst UNARY: Record<number, OtsOp['kind']> = {\n 0x02: 'sha1',\n 0x03: 'ripemd160',\n 0x08: 'sha256',\n 0x67: 'keccak256',\n 0xf2: 'reverse',\n 0xf3: 'hexlify',\n};\n\nexport function applyOp(op: OtsOp, msg: Uint8Array): Uint8Array {\n switch (op.kind) {\n case 'sha256':\n return sha256(msg);\n case 'ripemd160':\n return ripemd160(msg);\n case 'sha1':\n return sha1(msg);\n case 'keccak256':\n return keccak_256(msg);\n case 'reverse':\n return new Uint8Array(msg).reverse();\n case 'hexlify':\n return new TextEncoder().encode(hexEncode(msg));\n case 'append':\n return concat(msg, op.arg);\n case 'prepend':\n return concat(op.arg, msg);\n }\n}\n\nfunction readOp(r: Reader, tag: number): OtsOp {\n const unary = UNARY[tag];\n if (unary) return { kind: unary } as OtsOp;\n if (tag === 0xf0) return { kind: 'append', arg: r.varbytes(MAX_MSG) };\n if (tag === 0xf1) return { kind: 'prepend', arg: r.varbytes(MAX_MSG) };\n throw new Error(`ots: unknown op tag 0x${tag.toString(16)}`);\n}\n\nfunction readAttestation(r: Reader): OtsAttestation {\n const tag = hexEncode(r.bytes(8));\n const payload = r.varbytes(8192);\n const p = new Reader(payload);\n if (tag === TAG_BITCOIN) return { kind: 'bitcoin', height: p.varuint() };\n if (tag === TAG_PENDING) return { kind: 'pending', uri: new TextDecoder().decode(p.varbytes(1000)) };\n return { kind: 'unknown', tag, payload };\n}\n\nfunction readTimestamp(r: Reader, msg: Uint8Array, depth: number): OtsTimestamp {\n if (depth > MAX_DEPTH) throw new Error('ots: proof too deep');\n const node: OtsTimestamp = { msg, attestations: [], ops: [] };\n const item = (tag: number) => {\n if (tag === 0x00) {\n node.attestations.push(readAttestation(r));\n return;\n }\n const op = readOp(r, tag);\n const next = applyOp(op, msg);\n if (next.length > MAX_MSG) throw new Error('ots: message too long');\n node.ops.push({ op, child: readTimestamp(r, next, depth + 1) });\n };\n let tag = r.byte();\n while (tag === 0xff) {\n item(r.byte());\n tag = r.byte();\n }\n item(tag);\n return node;\n}\n\n/** Parse a bare timestamp whose root message is `digest`. */\nexport function parseTimestamp(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp {\n const r = new Reader(bytes);\n const ts = readTimestamp(r, digest, 0);\n if (!r.done) throw new Error('ots: trailing bytes after timestamp');\n return ts;\n}\n\nexport function isDetached(bytes: Uint8Array): boolean {\n return bytes.length > HEADER_MAGIC.length && bytesEqual(bytes.subarray(0, HEADER_MAGIC.length), HEADER_MAGIC);\n}\n\n/** Parse a detached `.ots` file. Only sha256 file digests are accepted. */\nexport function parseDetached(bytes: Uint8Array): { digest: Uint8Array; timestamp: OtsTimestamp } {\n if (!isDetached(bytes)) throw new Error('ots: missing detached-file header');\n const r = new Reader(bytes.subarray(HEADER_MAGIC.length));\n const major = r.varuint();\n if (major !== 1) throw new Error(`ots: unsupported file version ${major}`);\n if (r.byte() !== 0x08) throw new Error('ots: only sha256 file digests are supported');\n const digest = new Uint8Array(r.bytes(32));\n const timestamp = readTimestamp(r, digest, 0);\n if (!r.done) throw new Error('ots: trailing bytes after timestamp');\n return { digest, timestamp };\n}\n\n/**\n * Parse either encoding and require that it commits to `digest`. A detached\n * file for some other digest is rejected rather than walked.\n */\nexport function parseProof(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp {\n if (!isDetached(bytes)) return parseTimestamp(bytes, digest);\n const d = parseDetached(bytes);\n if (!bytesEqual(d.digest, digest)) throw new Error('ots: proof commits to a different digest');\n return d.timestamp;\n}\n\n/** Every attestation in the tree with the message it attests to. */\nexport function attestations(ts: OtsTimestamp): { msg: Uint8Array; attestation: OtsAttestation }[] {\n const out: { msg: Uint8Array; attestation: OtsAttestation }[] = [];\n const walk = (n: OtsTimestamp) => {\n for (const a of n.attestations) out.push({ msg: n.msg, attestation: a });\n for (const { child } of n.ops) walk(child);\n };\n walk(ts);\n return out;\n}\n\n/**\n * Bitcoin attestations, lowest height first. `merkleRoot` is the message at\n * the attestation, which equals the block header's Merkle root in header\n * byte order.\n */\nexport function bitcoinAnchors(ts: OtsTimestamp): { blockHeight: number; merkleRoot: Uint8Array }[] {\n return attestations(ts)\n .flatMap(({ msg, attestation }) =>\n attestation.kind === 'bitcoin' ? [{ blockHeight: attestation.height, merkleRoot: msg }] : []\n )\n .sort((a, b) => a.blockHeight - b.blockHeight);\n}\n\n/** Pending calendar attestations: where to ask, and the commitment to ask for. */\nexport function pendingCommitments(ts: OtsTimestamp): { uri: string; commitment: Uint8Array }[] {\n return attestations(ts).flatMap(({ msg, attestation }) =>\n attestation.kind === 'pending' ? [{ uri: attestation.uri, commitment: msg }] : []\n );\n}\n\n/**\n * Graft `upgrade` (a timestamp rooted at some node's message) onto the node\n * with that message, as python-opentimestamps' Timestamp.merge does. Returns\n * false when no node carries that message.\n */\nexport function mergeAt(ts: OtsTimestamp, upgrade: OtsTimestamp): boolean {\n if (bytesEqual(ts.msg, upgrade.msg)) {\n for (const a of upgrade.attestations) {\n if (!ts.attestations.some((b) => attestationKey(b) === attestationKey(a))) ts.attestations.push(a);\n }\n for (const { op, child } of upgrade.ops) {\n const same = ts.ops.find((o) => opKey(o.op) === opKey(op));\n if (same) mergeAt(same.child, child);\n else ts.ops.push({ op, child });\n }\n return true;\n }\n return ts.ops.some(({ child }) => mergeAt(child, upgrade));\n}\n\nfunction writeVaruint(out: number[], n: number) {\n do {\n let b = n % 128;\n n = Math.floor(n / 128);\n if (n > 0) b |= 0x80;\n out.push(b);\n } while (n > 0);\n}\n\nfunction writeVarbytes(out: number[], bytes: Uint8Array) {\n writeVaruint(out, bytes.length);\n out.push(...bytes);\n}\n\nconst OP_TAG: Record<OtsOp['kind'], number> = {\n sha1: 0x02,\n ripemd160: 0x03,\n sha256: 0x08,\n keccak256: 0x67,\n append: 0xf0,\n prepend: 0xf1,\n reverse: 0xf2,\n hexlify: 0xf3,\n};\n\nfunction writeAttestation(out: number[], a: OtsAttestation) {\n const payload: number[] = [];\n let tag: string;\n if (a.kind === 'bitcoin') {\n tag = TAG_BITCOIN;\n writeVaruint(payload, a.height);\n } else if (a.kind === 'pending') {\n tag = TAG_PENDING;\n writeVarbytes(payload, new TextEncoder().encode(a.uri));\n } else {\n tag = a.tag;\n payload.push(...a.payload);\n }\n out.push(0x00);\n for (let i = 0; i < 16; i += 2) out.push(parseInt(tag.slice(i, i + 2), 16));\n writeVarbytes(out, new Uint8Array(payload));\n}\n\nfunction writeTimestamp(out: number[], ts: OtsTimestamp) {\n const items: (() => void)[] = [\n ...ts.attestations.map((a) => () => writeAttestation(out, a)),\n ...ts.ops.map(({ op, child }) => () => {\n out.push(OP_TAG[op.kind]);\n if (op.kind === 'append' || op.kind === 'prepend') writeVarbytes(out, op.arg);\n writeTimestamp(out, child);\n }),\n ];\n if (items.length === 0) throw new Error('ots: cannot serialize an empty timestamp node');\n items.forEach((write, i) => {\n if (i < items.length - 1) out.push(0xff);\n write();\n });\n}\n\n/** Serialize as a bare timestamp (the encoding carried in `ots.proof`). */\nexport function serializeTimestamp(ts: OtsTimestamp): Uint8Array {\n const out: number[] = [];\n writeTimestamp(out, ts);\n return new Uint8Array(out);\n}\n\nfunction attestationKey(a: OtsAttestation): string {\n if (a.kind === 'bitcoin') return `b:${a.height}`;\n if (a.kind === 'pending') return `p:${a.uri}`;\n return `u:${a.tag}:${hexEncode(a.payload)}`;\n}\n\nfunction opKey(op: OtsOp): string {\n return 'arg' in op ? `${op.kind}:${hexEncode(op.arg)}` : op.kind;\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.length + b.length);\n out.set(a, 0);\n out.set(b, a.length);\n return out;\n}\n\nexport function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) return false;\n for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n","// Anchor verification. See SPEC.md §6.3.\n//\n// A confirmed anchor holds when all three are true:\n// 1. the proof commits to the envelope id and walks to a Bitcoin\n// attestation at the declared height;\n// 2. the message at that attestation equals the Merkle root in the block\n// header at that height;\n// 3. that header double-SHA256es to the declared block hash.\n//\n// The resulting function is what `@orangecheck/stamp-core` expects at the\n// `verifyOtsAnchor` input of `verify()`.\n\nimport { sha256 } from '@noble/hashes/sha2';\n\nimport { base64Decode, hexDecode, hexEncode } from './base64.js';\nimport { bitcoinAnchors, bytesEqual, parseProof } from './ots.js';\nimport type {\n AnchorVerificationInput,\n AnchorVerificationResult,\n AnchorVerifier,\n BlockHeaderSource,\n} from './types.js';\n\nexport interface AnchorVerifierConfig {\n /**\n * Parse the proof bytes and return the Merkle root the proof walks to,\n * plus its block height. Optional: the built-in OTS parser is used when\n * omitted. `blockHeight` is the declared height, for proofs that carry\n * attestations at more than one height.\n */\n walkProof?: (input: {\n proofBytes: Uint8Array;\n digest: Uint8Array;\n blockHeight?: number;\n }) => Promise<{ merkleRoot: Uint8Array; blockHeight: number } | null>;\n /**\n * Source of Bitcoin block headers: a full node, SPV, a headers snapshot,\n * or `mempoolHeaderSource()`. This is the verifier's trust anchor.\n */\n headerSource: BlockHeaderSource;\n}\n\n/** Built-in walker: parse the OTS proof and pick the Bitcoin attestation. */\nexport async function walkOtsProof(input: {\n proofBytes: Uint8Array;\n digest: Uint8Array;\n blockHeight?: number;\n}): Promise<{ merkleRoot: Uint8Array; blockHeight: number } | null> {\n try {\n const anchors = bitcoinAnchors(parseProof(input.proofBytes, input.digest));\n return anchors.find((a) => a.blockHeight === input.blockHeight) ?? anchors[0] ?? null;\n } catch {\n return null;\n }\n}\n\n/** Block hash (display hex) of an 80-byte header. */\nexport function blockHashOf(header: Uint8Array): string {\n return hexEncode(sha256(sha256(header)).reverse());\n}\n\nexport function makeAnchorVerifier(\n cfg: AnchorVerifierConfig\n): (proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean> {\n const walkProof = cfg.walkProof ?? walkOtsProof;\n const verifier: AnchorVerifier = async (\n input: AnchorVerificationInput\n ): Promise<AnchorVerificationResult> => {\n const walked = await walkProof({\n proofBytes: input.proofBytes,\n digest: input.digest,\n blockHeight: input.blockHeight,\n });\n if (!walked) {\n return { ok: false, reason: 'proof could not be walked to a Bitcoin commitment' };\n }\n if (walked.blockHeight !== input.blockHeight) {\n return {\n ok: false,\n reason: `proof anchors at block ${walked.blockHeight}, envelope declares ${input.blockHeight}`,\n };\n }\n const header = await cfg.headerSource.getHeaderAt(input.blockHeight);\n if (!header || header.byteLength !== 80) {\n return { ok: false, reason: `no block header available at height ${input.blockHeight}` };\n }\n if (blockHashOf(header) !== input.blockHash.toLowerCase()) {\n return { ok: false, reason: 'block header does not hash to the declared block hash' };\n }\n // OTS attests to the Merkle root in header byte order (offset 36).\n const headerMerkle = header.subarray(36, 68);\n if (!bytesEqual(headerMerkle, walked.merkleRoot)) {\n return { ok: false, reason: 'block header Merkle root does not match walked proof root' };\n }\n return { ok: true, merkleRoot: hexEncode(headerMerkle) };\n };\n\n return async (proofB64, blockHeight, blockHash, envelopeId) => {\n const r = await verifier({\n proofBytes: base64Decode(proofB64),\n digest: hexDecode(envelopeId),\n blockHeight,\n blockHash,\n });\n return r.ok;\n };\n}\n\n/**\n * Anchor verifier using the built-in OTS parser. Kept async for callers of the\n * 0.1 API, which lazily loaded an optional parser here.\n */\nexport async function makeDefaultAnchorVerifier(opts: {\n headerSource: BlockHeaderSource;\n}): Promise<\n (proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean>\n> {\n return makeAnchorVerifier({ headerSource: opts.headerSource });\n}\n\nexport interface MempoolHeaderSourceOptions {\n /** Esplora-compatible API base. Default https://mempool.space/api. */\n baseUrl?: string;\n fetch?: typeof fetch;\n}\n\n/**\n * Block headers from an Esplora-compatible API. The verifier checks each\n * header against the declared block hash, so this source is trusted only to\n * report which block is at a height.\n */\nexport function mempoolHeaderSource(opts: MempoolHeaderSourceOptions = {}): BlockHeaderSource {\n const base = (opts.baseUrl ?? 'https://mempool.space/api').replace(/\\/+$/, '');\n const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);\n return {\n async getHeaderAt(height) {\n const h = await fetchImpl(`${base}/block-height/${height}`);\n if (!h.ok) return null;\n const hash = (await h.text()).trim();\n if (!/^[0-9a-f]{64}$/.test(hash)) return null;\n const r = await fetchImpl(`${base}/block/${hash}/header`);\n if (!r.ok) return null;\n const hex = (await r.text()).trim();\n return /^[0-9a-f]{160}$/.test(hex) ? hexDecode(hex) : null;\n },\n };\n}\n","// Upgrade a pending OTS proof to a confirmed one. See SPEC.md §6.2.\n//\n// A pending proof ends in calendar attestations, each naming a calendar and\n// the commitment (the message at that leaf) the calendar will later anchor.\n// Calendars index upgrades by that commitment, not by the submitted digest.\n// For each pending leaf we ask its calendar for the continuation, graft it on,\n// and report the proof as confirmed once it reaches a Bitcoin attestation\n// whose block header checks out.\n\nimport { blockHashOf } from './anchor.js';\nimport { base64Decode, base64Encode, hexDecode } from './base64.js';\nimport { createCalendarClient } from './calendar.js';\nimport {\n bitcoinAnchors,\n bytesEqual,\n mergeAt,\n parseProof,\n parseTimestamp,\n pendingCommitments,\n serializeTimestamp,\n} from './ots.js';\nimport type { BlockHeaderSource, OtsProof } from './types.js';\n\nexport interface UpgradeOptions {\n /**\n * Header source used to resolve the anchor's block hash and to check that\n * the proof's Merkle root is in that block.\n */\n headerSource?: BlockHeaderSource;\n /**\n * Alternative to `headerSource`: given the merged proof bytes, return the\n * anchor if the proof is confirmed, else null.\n */\n parseAnchor?: (proofBytes: Uint8Array) => Promise<{ blockHeight: number; blockHash: string } | null>;\n /** Optional custom fetch passed through to calendar clients. */\n fetch?: typeof fetch;\n /** Request timeout per calendar. Default 30_000ms. */\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\nconst norm = (u: string) => u.replace(/\\/+$/, '');\n\nexport async function upgradeProof(\n current: OtsProof,\n idHex: string,\n opts: UpgradeOptions\n): Promise<OtsProof> {\n if (current.status === 'confirmed') return current; // idempotent\n if (!opts.headerSource && !opts.parseAnchor) {\n throw new Error('upgradeProof: pass headerSource or parseAnchor');\n }\n\n const before = base64Decode(current.proof);\n const tree = parseProof(before, hexDecode(idHex));\n\n // Only ask calendars this proof was submitted to.\n const listed = new Set(current.calendars.map(norm));\n const pending = pendingCommitments(tree).filter((p) => listed.has(norm(p.uri)));\n if (pending.length === 0 && bitcoinAnchors(tree).length === 0) {\n throw new Error('upgradeProof: proof has no pending attestation from a listed calendar');\n }\n\n const answered: string[] = [];\n await Promise.allSettled(\n pending.map(async ({ uri, commitment }) => {\n const client = createCalendarClient(uri, { fetch: opts.fetch, timeoutMs: opts.timeoutMs });\n const bytes = await client.fetchProof(commitment, opts.signal);\n if (!bytes) return;\n if (mergeAt(tree, parseTimestamp(bytes, commitment))) answered.push(norm(uri));\n })\n );\n\n const merged = serializeTimestamp(tree);\n const anchor = await resolveAnchor(merged, tree, opts);\n const calendars = [...answered, ...current.calendars.filter((c) => !answered.includes(norm(c)))];\n\n if (anchor) {\n return {\n status: 'confirmed',\n proof: base64Encode(merged),\n calendars,\n blockHeight: anchor.blockHeight,\n blockHash: anchor.blockHash,\n upgradedAt: new Date().toISOString().replace(/\\.\\d+Z$/, 'Z'),\n };\n }\n if (!bytesEqual(merged, before)) {\n return { ...current, proof: base64Encode(merged), calendars };\n }\n return current;\n}\n\nasync function resolveAnchor(\n merged: Uint8Array,\n tree: ReturnType<typeof parseTimestamp>,\n opts: UpgradeOptions\n): Promise<{ blockHeight: number; blockHash: string } | null> {\n if (opts.parseAnchor) return opts.parseAnchor(merged);\n for (const a of bitcoinAnchors(tree)) {\n const header = await opts.headerSource!.getHeaderAt(a.blockHeight);\n if (header && header.byteLength === 80 && bytesEqual(header.subarray(36, 68), a.merkleRoot)) {\n return { blockHeight: a.blockHeight, blockHash: blockHashOf(header) };\n }\n }\n return null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/base64.ts","../src/calendar.ts","../src/ots.ts","../src/submit.ts","../src/anchor.ts","../src/upgrade.ts"],"names":["sha256","ripemd160","sha1","keccak_256","tag"],"mappings":"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","file":"index.js","sourcesContent":["// Types for @orangecheck/stamp-ots.\n\nimport type { StampOts } from '@orangecheck/stamp-core';\n\nexport type OtsProofStatus = 'pending' | 'confirmed';\n\nexport interface OtsProof {\n status: OtsProofStatus;\n /** OTS timestamp rooted at the envelope id (or a detached .ots file), base64. */\n proof: string;\n /** Calendar URLs that contain this proof, in submission order. */\n calendars: string[];\n /** Bitcoin block height at which this proof is anchored (null if pending). */\n blockHeight: number | null;\n /** Bitcoin block hash (hex, lowercase) at the anchor block (null if pending). */\n blockHash: string | null;\n /** ISO 8601 UTC of the upgrade (null if pending). */\n upgradedAt: string | null;\n}\n\nexport interface CalendarClient {\n /** Base URL of the calendar, e.g. \"https://alice.btc.calendar.opentimestamps.org\". */\n readonly url: string;\n\n /**\n * Submit a 32-byte digest to the calendar for aggregation. Returns the raw\n * pending proof bytes.\n *\n * OTS calendar HTTP API: POST <url>/digest with the raw bytes as the body,\n * Content-Type: application/vnd.opentimestamps.v1, returns the proof bytes\n * as the response body.\n */\n submit(digest: Uint8Array, signal?: AbortSignal): Promise<Uint8Array>;\n\n /**\n * Fetch the continuation of a pending proof. `commitment` is the message\n * at the calendar's pending attestation (see `pendingCommitments`), not\n * the submitted digest. Returns null if the calendar has nothing yet.\n *\n * OTS calendar HTTP API: GET <url>/timestamp/<hex(commitment)>, returns a\n * timestamp rooted at the commitment, or 404.\n */\n fetchProof(commitment: Uint8Array, signal?: AbortSignal): Promise<Uint8Array | null>;\n}\n\nexport interface AnchorVerificationInput {\n /** Raw OTS proof bytes (base64-decoded by the caller). */\n proofBytes: Uint8Array;\n /** 32-byte digest that the proof commits to. */\n digest: Uint8Array;\n /** Declared block height from the envelope. */\n blockHeight: number;\n /** Declared block hash (hex) from the envelope. */\n blockHash: string;\n /**\n * Optional block header source. If provided, the verifier uses this to\n * fetch the header at `blockHeight` and compare its Merkle root to the\n * one derived from walking the proof.\n *\n * If omitted, the verifier MAY still parse the proof and report\n * structural validity but CANNOT report a bound anchor.\n */\n headerSource?: BlockHeaderSource;\n}\n\nexport interface BlockHeaderSource {\n /** Return the 80-byte raw block header at the given height, or null if unknown. */\n getHeaderAt(height: number): Promise<Uint8Array | null>;\n}\n\nexport type AnchorVerifier = (input: AnchorVerificationInput) => Promise<AnchorVerificationResult>;\n\nexport type AnchorVerificationResult =\n | { ok: true; merkleRoot: string }\n | { ok: false; reason: string };\n\n/**\n * Convert an OtsProof (library type) to the StampOts field shape that the\n * envelope carries. The two are isomorphic; this function exists to keep\n * stamp-core's type surface narrow.\n */\nexport function toStampOts(p: OtsProof): StampOts {\n return {\n status: p.status,\n proof: p.proof,\n calendars: p.calendars,\n block_height: p.blockHeight,\n block_hash: p.blockHash,\n upgraded_at: p.upgradedAt,\n };\n}\n\nexport function fromStampOts(s: StampOts): OtsProof {\n return {\n status: s.status,\n proof: s.proof,\n calendars: s.calendars,\n blockHeight: s.block_height,\n blockHash: s.block_hash,\n upgradedAt: s.upgraded_at,\n };\n}\n","// Minimal, dependency-free base64 <-> Uint8Array helpers. OTS proof bytes\n// are carried as base64 inside OC Stamp envelopes so they survive any text\n// transport (URL fragment, JSON, Nostr event content).\n\nconst B64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\nconst B64_DECODE_TABLE = (() => {\n const t = new Int16Array(128).fill(-1);\n for (let i = 0; i < B64_CHARS.length; i++) t[B64_CHARS.charCodeAt(i)] = i;\n t['='.charCodeAt(0)] = -2;\n return t;\n})();\n\nexport function base64Encode(bytes: Uint8Array): string {\n let out = '';\n let i = 0;\n for (; i + 2 < bytes.length; i += 3) {\n const a = bytes[i]!;\n const b = bytes[i + 1]!;\n const c = bytes[i + 2]!;\n out +=\n B64_CHARS[a >> 2]! +\n B64_CHARS[((a & 0x03) << 4) | (b >> 4)]! +\n B64_CHARS[((b & 0x0f) << 2) | (c >> 6)]! +\n B64_CHARS[c & 0x3f]!;\n }\n if (i < bytes.length) {\n const a = bytes[i]!;\n const b = i + 1 < bytes.length ? bytes[i + 1]! : 0;\n out += B64_CHARS[a >> 2]!;\n out += B64_CHARS[((a & 0x03) << 4) | (b >> 4)]!;\n out += i + 1 < bytes.length ? B64_CHARS[(b & 0x0f) << 2]! : '=';\n out += '=';\n }\n return out;\n}\n\nexport function base64Decode(s: string): Uint8Array {\n const str = s.replace(/\\s+/g, '');\n const len = str.length;\n if (len === 0) return new Uint8Array(0);\n if (len % 4 !== 0) throw new Error('base64: bad length');\n let padding = 0;\n if (str[len - 1] === '=') padding++;\n if (str[len - 2] === '=') padding++;\n const outLen = (len / 4) * 3 - padding;\n const out = new Uint8Array(outLen);\n let o = 0;\n for (let i = 0; i < len; i += 4) {\n const c0 = B64_DECODE_TABLE[str.charCodeAt(i)]!;\n const c1 = B64_DECODE_TABLE[str.charCodeAt(i + 1)]!;\n const c2 = B64_DECODE_TABLE[str.charCodeAt(i + 2)]!;\n const c3 = B64_DECODE_TABLE[str.charCodeAt(i + 3)]!;\n if (c0 < 0 || c1 < 0 || c2 < -2 || c3 < -2) throw new Error('base64: bad char');\n out[o++] = (c0 << 2) | (c1 >> 4);\n if (c2 >= 0) out[o++] = ((c1 & 0x0f) << 4) | (c2 >> 2);\n if (c3 >= 0) out[o++] = ((c2 & 0x03) << 6) | c3;\n }\n return out;\n}\n\nexport function hexDecode(s: string): Uint8Array {\n if (s.length % 2 !== 0) throw new Error('hex: odd length');\n const out = new Uint8Array(s.length / 2);\n for (let i = 0; i < out.length; i++) {\n const hi = parseInt(s[i * 2]!, 16);\n const lo = parseInt(s[i * 2 + 1]!, 16);\n if (Number.isNaN(hi) || Number.isNaN(lo)) throw new Error('hex: bad char');\n out[i] = (hi << 4) | lo;\n }\n return out;\n}\n\nexport function hexEncode(bytes: Uint8Array): string {\n const HEX = '0123456789abcdef';\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n const b = bytes[i]!;\n out += HEX[(b >> 4) & 0x0f]! + HEX[b & 0x0f]!;\n }\n return out;\n}\n","// HTTP client for an OpenTimestamps calendar. Implements the minimal subset\n// of the calendar protocol that an OC Stamp implementation needs:\n//\n// POST <url>/digest body = raw digest bytes -> pending proof bytes\n// GET <url>/timestamp/<hex(commitment)> -> continuation, or 404\n//\n// The client moves bytes only; ./ots.ts parses them.\n\nimport type { CalendarClient } from './types.js';\nimport { hexEncode } from './base64.js';\n\nexport const DEFAULT_CALENDARS: readonly string[] = [\n 'https://alice.btc.calendar.opentimestamps.org',\n 'https://bob.btc.calendar.opentimestamps.org',\n 'https://finney.calendar.eternitywall.com',\n];\n\nexport interface HttpCalendarOptions {\n /**\n * Custom fetch implementation. Defaults to global `fetch`. Useful in\n * environments that need a specific adapter (Node < 18, Cloudflare\n * Workers, proxies).\n */\n fetch?: typeof fetch;\n /** Request timeout in milliseconds. Default 30_000. */\n timeoutMs?: number;\n}\n\nexport function createCalendarClient(url: string, opts: HttpCalendarOptions = {}): CalendarClient {\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') {\n throw new Error(\n '@orangecheck/stamp-ots: no fetch implementation available. Pass one via { fetch }.'\n );\n }\n const timeoutMs = opts.timeoutMs ?? 30_000;\n const base = url.replace(/\\/$/, '');\n\n return {\n url: base,\n async submit(digest, signal) {\n if (digest.byteLength !== 32) {\n throw new Error('OTS: digest must be exactly 32 bytes');\n }\n const ac = withTimeout(signal, timeoutMs);\n // Uint8Array is a valid fetch body at runtime in Node 18+ and all\n // modern browsers, but TypeScript's DOM typings don't accept it\n // directly under `strict` + `noUncheckedIndexedAccess`. The cast is\n // narrow and intentional.\n // No Content-Type: a non-safelisted type makes browsers send a\n // CORS preflight, and OTS calendars answer OPTIONS with 501.\n const resp = await fetchImpl(`${base}/digest`, {\n method: 'POST',\n body: digest as unknown as BodyInit,\n signal: ac.signal,\n });\n ac.clear();\n if (!resp.ok) {\n throw new Error(`OTS calendar ${base} submit failed: HTTP ${resp.status}`);\n }\n const buf = await resp.arrayBuffer();\n return new Uint8Array(buf);\n },\n async fetchProof(commitment, signal) {\n if (commitment.byteLength === 0 || commitment.byteLength > 64) {\n throw new Error('OTS: commitment must be 1-64 bytes');\n }\n const ac = withTimeout(signal, timeoutMs);\n const resp = await fetchImpl(`${base}/timestamp/${hexEncode(commitment)}`, {\n method: 'GET',\n headers: { Accept: 'application/vnd.opentimestamps.v1' },\n signal: ac.signal,\n });\n ac.clear();\n if (resp.status === 404) return null;\n if (!resp.ok) {\n throw new Error(`OTS calendar ${base} fetchProof failed: HTTP ${resp.status}`);\n }\n const buf = await resp.arrayBuffer();\n return new Uint8Array(buf);\n },\n };\n}\n\nfunction withTimeout(parent: AbortSignal | undefined, ms: number): { signal: AbortSignal; clear: () => void } {\n const ac = new AbortController();\n const onParent = () => ac.abort((parent as AbortSignal & { reason?: unknown }).reason);\n if (parent) {\n if (parent.aborted) ac.abort((parent as AbortSignal & { reason?: unknown }).reason);\n else parent.addEventListener('abort', onParent, { once: true });\n }\n const t = setTimeout(() => ac.abort(new Error(`OTS request timed out after ${ms}ms`)), ms);\n return {\n signal: ac.signal,\n clear: () => {\n clearTimeout(t);\n if (parent) parent.removeEventListener('abort', onParent);\n },\n };\n}\n","// OpenTimestamps proof format: parse, walk, serialize, merge.\n//\n// Follows python-opentimestamps (core/timestamp.py, core/op.py,\n// core/notary.py). Two encodings are accepted:\n//\n// - a bare timestamp rooted at the digest (what an OTS calendar returns from\n// POST /digest, and what OC Stamp envelopes carry in `ots.proof`);\n// - a detached `.ots` file (magic header + file-hash op + digest + timestamp).\n\nimport { ripemd160, sha1 } from '@noble/hashes/legacy';\nimport { sha256 } from '@noble/hashes/sha2';\nimport { keccak_256 } from '@noble/hashes/sha3';\n\nimport { hexEncode } from './base64.js';\n\nconst HEADER_MAGIC = new Uint8Array([\n 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x00,\n 0x00, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x00, 0xbf, 0x89, 0xe2, 0xe8, 0x84, 0xe8, 0x92, 0x94,\n]);\n\nconst TAG_BITCOIN = '0588960d73d71901';\nconst TAG_PENDING = '83dfe30d2ef90c8e';\n\nconst MAX_DEPTH = 256;\nconst MAX_MSG = 4096;\n\nexport type OtsOp =\n | { kind: 'sha256' | 'ripemd160' | 'sha1' | 'keccak256' | 'reverse' | 'hexlify' }\n | { kind: 'append' | 'prepend'; arg: Uint8Array };\n\nexport type OtsAttestation =\n | { kind: 'bitcoin'; height: number }\n | { kind: 'pending'; uri: string }\n | { kind: 'unknown'; tag: string; payload: Uint8Array };\n\nexport interface OtsTimestamp {\n /** The message at this node: the digest after every op on the path to it. */\n msg: Uint8Array;\n attestations: OtsAttestation[];\n ops: { op: OtsOp; child: OtsTimestamp }[];\n}\n\nclass Reader {\n private pos = 0;\n constructor(private readonly buf: Uint8Array) {}\n byte(): number {\n if (this.pos >= this.buf.length) throw new Error('ots: unexpected end of proof');\n return this.buf[this.pos++]!;\n }\n bytes(n: number): Uint8Array {\n if (n < 0 || this.pos + n > this.buf.length) throw new Error('ots: unexpected end of proof');\n const out = this.buf.subarray(this.pos, this.pos + n);\n this.pos += n;\n return out;\n }\n varuint(): number {\n let value = 0;\n let shift = 0;\n for (;;) {\n const b = this.byte();\n value += (b & 0x7f) * 2 ** shift;\n if (!(b & 0x80)) return value;\n shift += 7;\n if (shift > 49) throw new Error('ots: varuint too large');\n }\n }\n varbytes(max: number): Uint8Array {\n const n = this.varuint();\n if (n > max) throw new Error('ots: varbytes too long');\n return this.bytes(n);\n }\n get done(): boolean {\n return this.pos === this.buf.length;\n }\n}\n\nconst UNARY: Record<number, OtsOp['kind']> = {\n 0x02: 'sha1',\n 0x03: 'ripemd160',\n 0x08: 'sha256',\n 0x67: 'keccak256',\n 0xf2: 'reverse',\n 0xf3: 'hexlify',\n};\n\nexport function applyOp(op: OtsOp, msg: Uint8Array): Uint8Array {\n switch (op.kind) {\n case 'sha256':\n return sha256(msg);\n case 'ripemd160':\n return ripemd160(msg);\n case 'sha1':\n return sha1(msg);\n case 'keccak256':\n return keccak_256(msg);\n case 'reverse':\n return new Uint8Array(msg).reverse();\n case 'hexlify':\n return new TextEncoder().encode(hexEncode(msg));\n case 'append':\n return concat(msg, op.arg);\n case 'prepend':\n return concat(op.arg, msg);\n }\n}\n\nfunction readOp(r: Reader, tag: number): OtsOp {\n const unary = UNARY[tag];\n if (unary) return { kind: unary } as OtsOp;\n if (tag === 0xf0) return { kind: 'append', arg: r.varbytes(MAX_MSG) };\n if (tag === 0xf1) return { kind: 'prepend', arg: r.varbytes(MAX_MSG) };\n throw new Error(`ots: unknown op tag 0x${tag.toString(16)}`);\n}\n\nfunction readAttestation(r: Reader): OtsAttestation {\n const tag = hexEncode(r.bytes(8));\n const payload = r.varbytes(8192);\n const p = new Reader(payload);\n if (tag === TAG_BITCOIN) return { kind: 'bitcoin', height: p.varuint() };\n if (tag === TAG_PENDING) return { kind: 'pending', uri: new TextDecoder().decode(p.varbytes(1000)) };\n return { kind: 'unknown', tag, payload };\n}\n\nfunction readTimestamp(r: Reader, msg: Uint8Array, depth: number): OtsTimestamp {\n if (depth > MAX_DEPTH) throw new Error('ots: proof too deep');\n const node: OtsTimestamp = { msg, attestations: [], ops: [] };\n const item = (tag: number) => {\n if (tag === 0x00) {\n node.attestations.push(readAttestation(r));\n return;\n }\n const op = readOp(r, tag);\n const next = applyOp(op, msg);\n if (next.length > MAX_MSG) throw new Error('ots: message too long');\n node.ops.push({ op, child: readTimestamp(r, next, depth + 1) });\n };\n let tag = r.byte();\n while (tag === 0xff) {\n item(r.byte());\n tag = r.byte();\n }\n item(tag);\n return node;\n}\n\n/** Parse a bare timestamp whose root message is `digest`. */\nexport function parseTimestamp(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp {\n const r = new Reader(bytes);\n const ts = readTimestamp(r, digest, 0);\n if (!r.done) throw new Error('ots: trailing bytes after timestamp');\n return ts;\n}\n\nexport function isDetached(bytes: Uint8Array): boolean {\n return bytes.length > HEADER_MAGIC.length && bytesEqual(bytes.subarray(0, HEADER_MAGIC.length), HEADER_MAGIC);\n}\n\n/** Parse a detached `.ots` file. Only sha256 file digests are accepted. */\nexport function parseDetached(bytes: Uint8Array): { digest: Uint8Array; timestamp: OtsTimestamp } {\n if (!isDetached(bytes)) throw new Error('ots: missing detached-file header');\n const r = new Reader(bytes.subarray(HEADER_MAGIC.length));\n const major = r.varuint();\n if (major !== 1) throw new Error(`ots: unsupported file version ${major}`);\n if (r.byte() !== 0x08) throw new Error('ots: only sha256 file digests are supported');\n const digest = new Uint8Array(r.bytes(32));\n const timestamp = readTimestamp(r, digest, 0);\n if (!r.done) throw new Error('ots: trailing bytes after timestamp');\n return { digest, timestamp };\n}\n\n/**\n * Parse either encoding and require that it commits to `digest`. A detached\n * file for some other digest is rejected rather than walked.\n */\nexport function parseProof(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp {\n if (!isDetached(bytes)) return parseTimestamp(bytes, digest);\n const d = parseDetached(bytes);\n if (!bytesEqual(d.digest, digest)) throw new Error('ots: proof commits to a different digest');\n return d.timestamp;\n}\n\n/** Every attestation in the tree with the message it attests to. */\nexport function attestations(ts: OtsTimestamp): { msg: Uint8Array; attestation: OtsAttestation }[] {\n const out: { msg: Uint8Array; attestation: OtsAttestation }[] = [];\n const walk = (n: OtsTimestamp) => {\n for (const a of n.attestations) out.push({ msg: n.msg, attestation: a });\n for (const { child } of n.ops) walk(child);\n };\n walk(ts);\n return out;\n}\n\n/**\n * Bitcoin attestations, lowest height first. `merkleRoot` is the message at\n * the attestation, which equals the block header's Merkle root in header\n * byte order.\n */\nexport function bitcoinAnchors(ts: OtsTimestamp): { blockHeight: number; merkleRoot: Uint8Array }[] {\n return attestations(ts)\n .flatMap(({ msg, attestation }) =>\n attestation.kind === 'bitcoin' ? [{ blockHeight: attestation.height, merkleRoot: msg }] : []\n )\n .sort((a, b) => a.blockHeight - b.blockHeight);\n}\n\n/** Pending calendar attestations: where to ask, and the commitment to ask for. */\nexport function pendingCommitments(ts: OtsTimestamp): { uri: string; commitment: Uint8Array }[] {\n return attestations(ts).flatMap(({ msg, attestation }) =>\n attestation.kind === 'pending' ? [{ uri: attestation.uri, commitment: msg }] : []\n );\n}\n\n/**\n * Graft `upgrade` (a timestamp rooted at some node's message) onto the node\n * with that message, as python-opentimestamps' Timestamp.merge does. Returns\n * false when no node carries that message.\n */\nexport function mergeAt(ts: OtsTimestamp, upgrade: OtsTimestamp): boolean {\n if (bytesEqual(ts.msg, upgrade.msg)) {\n for (const a of upgrade.attestations) {\n if (!ts.attestations.some((b) => attestationKey(b) === attestationKey(a))) ts.attestations.push(a);\n }\n for (const { op, child } of upgrade.ops) {\n const same = ts.ops.find((o) => opKey(o.op) === opKey(op));\n if (same) mergeAt(same.child, child);\n else ts.ops.push({ op, child });\n }\n return true;\n }\n return ts.ops.some(({ child }) => mergeAt(child, upgrade));\n}\n\nfunction writeVaruint(out: number[], n: number) {\n do {\n let b = n % 128;\n n = Math.floor(n / 128);\n if (n > 0) b |= 0x80;\n out.push(b);\n } while (n > 0);\n}\n\nfunction writeVarbytes(out: number[], bytes: Uint8Array) {\n writeVaruint(out, bytes.length);\n out.push(...bytes);\n}\n\nconst OP_TAG: Record<OtsOp['kind'], number> = {\n sha1: 0x02,\n ripemd160: 0x03,\n sha256: 0x08,\n keccak256: 0x67,\n append: 0xf0,\n prepend: 0xf1,\n reverse: 0xf2,\n hexlify: 0xf3,\n};\n\nfunction writeAttestation(out: number[], a: OtsAttestation) {\n const payload: number[] = [];\n let tag: string;\n if (a.kind === 'bitcoin') {\n tag = TAG_BITCOIN;\n writeVaruint(payload, a.height);\n } else if (a.kind === 'pending') {\n tag = TAG_PENDING;\n writeVarbytes(payload, new TextEncoder().encode(a.uri));\n } else {\n tag = a.tag;\n payload.push(...a.payload);\n }\n out.push(0x00);\n for (let i = 0; i < 16; i += 2) out.push(parseInt(tag.slice(i, i + 2), 16));\n writeVarbytes(out, new Uint8Array(payload));\n}\n\nfunction writeTimestamp(out: number[], ts: OtsTimestamp) {\n const items: (() => void)[] = [\n ...ts.attestations.map((a) => () => writeAttestation(out, a)),\n ...ts.ops.map(({ op, child }) => () => {\n out.push(OP_TAG[op.kind]);\n if (op.kind === 'append' || op.kind === 'prepend') writeVarbytes(out, op.arg);\n writeTimestamp(out, child);\n }),\n ];\n if (items.length === 0) throw new Error('ots: cannot serialize an empty timestamp node');\n items.forEach((write, i) => {\n if (i < items.length - 1) out.push(0xff);\n write();\n });\n}\n\n/** Serialize as a bare timestamp (the encoding carried in `ots.proof`). */\nexport function serializeTimestamp(ts: OtsTimestamp): Uint8Array {\n const out: number[] = [];\n writeTimestamp(out, ts);\n return new Uint8Array(out);\n}\n\nfunction attestationKey(a: OtsAttestation): string {\n if (a.kind === 'bitcoin') return `b:${a.height}`;\n if (a.kind === 'pending') return `p:${a.uri}`;\n return `u:${a.tag}:${hexEncode(a.payload)}`;\n}\n\nfunction opKey(op: OtsOp): string {\n return 'arg' in op ? `${op.kind}:${hexEncode(op.arg)}` : op.kind;\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.length + b.length);\n out.set(a, 0);\n out.set(b, a.length);\n return out;\n}\n\nexport function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) return false;\n for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n","// Submit an envelope id to one or more OTS calendars. Returns a pending proof.\n// See SPEC.md §6.1.\n//\n// The submission strategy: try each calendar in parallel, take the first\n// success, report which calendar produced it. A stamp that only reaches one\n// calendar is a single point of failure for upgrade; the reference app\n// submits to at least two calendars for redundancy.\n\nimport { base64Encode, hexDecode } from './base64.js';\nimport { createCalendarClient, DEFAULT_CALENDARS } from './calendar.js';\nimport { mergeAt, parseTimestamp, serializeTimestamp, type OtsTimestamp } from './ots.js';\nimport type { CalendarClient, OtsProof } from './types.js';\n\nexport interface SubmitOptions {\n /**\n * Calendars to submit to. Defaults to DEFAULT_CALENDARS. Can be strings\n * (URLs) or pre-built CalendarClient instances.\n */\n calendars?: readonly (string | CalendarClient)[];\n /**\n * Minimum number of calendars that must succeed. Defaults to 1.\n * If fewer than `minSuccesses` calendars respond with a proof,\n * submit() throws an aggregate error.\n */\n minSuccesses?: number;\n /** Optional custom fetch passed through to calendar clients. */\n fetch?: typeof fetch;\n /** Request timeout per calendar. Default 30_000ms. */\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/**\n * Submit the envelope `id` (64-hex) to OTS calendars and return an OtsProof in\n * pending state. The caller merges this into the envelope's `ots` field.\n *\n * Each calendar answers with its own pending timestamp for the digest. They are\n * merged into one proof, so upgrade (see upgrade.ts) can ask any calendar that\n * answered. A calendar whose answer does not parse counts as a failure.\n */\nexport async function submitToCalendars(idHex: string, opts: SubmitOptions = {}): Promise<OtsProof> {\n const digest = hexDecode(idHex);\n if (digest.byteLength !== 32) {\n throw new Error('submitToCalendars: idHex must be 32 bytes (64 hex chars)');\n }\n\n const clients = (opts.calendars ?? DEFAULT_CALENDARS).map((c) =>\n typeof c === 'string'\n ? createCalendarClient(c, { fetch: opts.fetch, timeoutMs: opts.timeoutMs })\n : c\n );\n if (clients.length === 0) {\n throw new Error('submitToCalendars: at least one calendar is required');\n }\n const minSuccesses = Math.max(1, opts.minSuccesses ?? 1);\n\n const settled = await Promise.allSettled(\n clients.map(async (c) => {\n const proof = await c.submit(digest, opts.signal);\n return { url: c.url, proof };\n })\n );\n const successes = settled\n .filter((r): r is PromiseFulfilledResult<{ url: string; proof: Uint8Array }> => r.status === 'fulfilled')\n .map((r) => r.value);\n const failures = settled\n .filter((r): r is PromiseRejectedResult => r.status === 'rejected')\n .map((r) => (r.reason instanceof Error ? r.reason.message : String(r.reason)));\n\n if (successes.length < minSuccesses) {\n // AggregateError would be nicer but targets ES2021; Error keeps us at ES2020.\n const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join('; ')}`;\n const err = new Error(msg) as Error & { errors: string[] };\n err.errors = failures;\n throw err;\n }\n\n // Keep every calendar's receipt in one proof, so any of them can upgrade it.\n let tree: OtsTimestamp | null = null;\n const merged: string[] = [];\n for (const s of successes) {\n let receipt: OtsTimestamp;\n try {\n receipt = parseTimestamp(s.proof, digest);\n } catch (e) {\n failures.push(`${s.url}: unreadable proof (${e instanceof Error ? e.message : String(e)})`);\n continue;\n }\n if (tree) mergeAt(tree, receipt);\n else tree = receipt;\n merged.push(s.url);\n }\n if (!tree || merged.length < minSuccesses) {\n const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join('; ')}`;\n const err = new Error(msg) as Error & { errors: string[] };\n err.errors = failures;\n throw err;\n }\n return {\n status: 'pending',\n proof: base64Encode(serializeTimestamp(tree)),\n calendars: merged,\n blockHeight: null,\n blockHash: null,\n upgradedAt: null,\n };\n}\n","// Anchor verification. See SPEC.md §6.3.\n//\n// A confirmed anchor holds when all three are true:\n// 1. the proof commits to the envelope id and walks to a Bitcoin\n// attestation at the declared height;\n// 2. the message at that attestation equals the Merkle root in the block\n// header at that height;\n// 3. that header double-SHA256es to the declared block hash.\n//\n// The resulting function is what `@orangecheck/stamp-core` expects at the\n// `verifyOtsAnchor` input of `verify()`.\n\nimport { sha256 } from '@noble/hashes/sha2';\n\nimport { base64Decode, hexDecode, hexEncode } from './base64.js';\nimport { bitcoinAnchors, bytesEqual, parseProof } from './ots.js';\nimport type {\n AnchorVerificationInput,\n AnchorVerificationResult,\n AnchorVerifier,\n BlockHeaderSource,\n} from './types.js';\n\nexport interface AnchorVerifierConfig {\n /**\n * Parse the proof bytes and return the Merkle root the proof walks to,\n * plus its block height. Optional: the built-in OTS parser is used when\n * omitted. `blockHeight` is the declared height, for proofs that carry\n * attestations at more than one height.\n */\n walkProof?: (input: {\n proofBytes: Uint8Array;\n digest: Uint8Array;\n blockHeight?: number;\n }) => Promise<{ merkleRoot: Uint8Array; blockHeight: number } | null>;\n /**\n * Source of Bitcoin block headers: a full node, SPV, a headers snapshot,\n * or `mempoolHeaderSource()`. This is the verifier's trust anchor.\n */\n headerSource: BlockHeaderSource;\n}\n\n/** Built-in walker: parse the OTS proof and pick the Bitcoin attestation. */\nexport async function walkOtsProof(input: {\n proofBytes: Uint8Array;\n digest: Uint8Array;\n blockHeight?: number;\n}): Promise<{ merkleRoot: Uint8Array; blockHeight: number } | null> {\n try {\n const anchors = bitcoinAnchors(parseProof(input.proofBytes, input.digest));\n return anchors.find((a) => a.blockHeight === input.blockHeight) ?? anchors[0] ?? null;\n } catch {\n return null;\n }\n}\n\n/** Block hash (display hex) of an 80-byte header. */\nexport function blockHashOf(header: Uint8Array): string {\n return hexEncode(sha256(sha256(header)).reverse());\n}\n\nexport function makeAnchorVerifier(\n cfg: AnchorVerifierConfig\n): (proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean> {\n const walkProof = cfg.walkProof ?? walkOtsProof;\n const verifier: AnchorVerifier = async (\n input: AnchorVerificationInput\n ): Promise<AnchorVerificationResult> => {\n const walked = await walkProof({\n proofBytes: input.proofBytes,\n digest: input.digest,\n blockHeight: input.blockHeight,\n });\n if (!walked) {\n return { ok: false, reason: 'proof could not be walked to a Bitcoin commitment' };\n }\n if (walked.blockHeight !== input.blockHeight) {\n return {\n ok: false,\n reason: `proof anchors at block ${walked.blockHeight}, envelope declares ${input.blockHeight}`,\n };\n }\n const header = await cfg.headerSource.getHeaderAt(input.blockHeight);\n if (!header || header.byteLength !== 80) {\n return { ok: false, reason: `no block header available at height ${input.blockHeight}` };\n }\n if (blockHashOf(header) !== input.blockHash.toLowerCase()) {\n return { ok: false, reason: 'block header does not hash to the declared block hash' };\n }\n // OTS attests to the Merkle root in header byte order (offset 36).\n const headerMerkle = header.subarray(36, 68);\n if (!bytesEqual(headerMerkle, walked.merkleRoot)) {\n return { ok: false, reason: 'block header Merkle root does not match walked proof root' };\n }\n return { ok: true, merkleRoot: hexEncode(headerMerkle) };\n };\n\n return async (proofB64, blockHeight, blockHash, envelopeId) => {\n const r = await verifier({\n proofBytes: base64Decode(proofB64),\n digest: hexDecode(envelopeId),\n blockHeight,\n blockHash,\n });\n return r.ok;\n };\n}\n\n/**\n * Anchor verifier using the built-in OTS parser. Kept async for callers of the\n * 0.1 API, which lazily loaded an optional parser here.\n */\nexport async function makeDefaultAnchorVerifier(opts: {\n headerSource: BlockHeaderSource;\n}): Promise<\n (proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean>\n> {\n return makeAnchorVerifier({ headerSource: opts.headerSource });\n}\n\nexport interface MempoolHeaderSourceOptions {\n /** Esplora-compatible API base. Default https://mempool.space/api. */\n baseUrl?: string;\n fetch?: typeof fetch;\n}\n\n/**\n * Block headers from an Esplora-compatible API. The verifier checks each\n * header against the declared block hash, so this source is trusted only to\n * report which block is at a height.\n */\nexport function mempoolHeaderSource(opts: MempoolHeaderSourceOptions = {}): BlockHeaderSource {\n const base = (opts.baseUrl ?? 'https://mempool.space/api').replace(/\\/+$/, '');\n const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);\n return {\n async getHeaderAt(height) {\n const h = await fetchImpl(`${base}/block-height/${height}`);\n if (!h.ok) return null;\n const hash = (await h.text()).trim();\n if (!/^[0-9a-f]{64}$/.test(hash)) return null;\n const r = await fetchImpl(`${base}/block/${hash}/header`);\n if (!r.ok) return null;\n const hex = (await r.text()).trim();\n return /^[0-9a-f]{160}$/.test(hex) ? hexDecode(hex) : null;\n },\n };\n}\n","// Upgrade a pending OTS proof to a confirmed one. See SPEC.md §6.2.\n//\n// A pending proof ends in calendar attestations, each naming a calendar and\n// the commitment (the message at that leaf) the calendar will later anchor.\n// Calendars index upgrades by that commitment, not by the submitted digest.\n// For each pending leaf we ask its calendar for the continuation, graft it on,\n// and report the proof as confirmed once it reaches a Bitcoin attestation\n// whose block header checks out.\n\nimport { blockHashOf } from './anchor.js';\nimport { base64Decode, base64Encode, hexDecode } from './base64.js';\nimport { createCalendarClient } from './calendar.js';\nimport {\n bitcoinAnchors,\n bytesEqual,\n mergeAt,\n parseProof,\n parseTimestamp,\n pendingCommitments,\n serializeTimestamp,\n} from './ots.js';\nimport type { BlockHeaderSource, OtsProof } from './types.js';\n\nexport interface UpgradeOptions {\n /**\n * Header source used to resolve the anchor's block hash and to check that\n * the proof's Merkle root is in that block.\n */\n headerSource?: BlockHeaderSource;\n /**\n * Alternative to `headerSource`: given the merged proof bytes, return the\n * anchor if the proof is confirmed, else null.\n */\n parseAnchor?: (proofBytes: Uint8Array) => Promise<{ blockHeight: number; blockHash: string } | null>;\n /** Optional custom fetch passed through to calendar clients. */\n fetch?: typeof fetch;\n /** Request timeout per calendar. Default 30_000ms. */\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\nconst norm = (u: string) => u.replace(/\\/+$/, '');\n\nexport async function upgradeProof(\n current: OtsProof,\n idHex: string,\n opts: UpgradeOptions\n): Promise<OtsProof> {\n if (current.status === 'confirmed') return current; // idempotent\n if (!opts.headerSource && !opts.parseAnchor) {\n throw new Error('upgradeProof: pass headerSource or parseAnchor');\n }\n\n const before = base64Decode(current.proof);\n const tree = parseProof(before, hexDecode(idHex));\n\n // Only ask calendars this proof was submitted to.\n const listed = new Set(current.calendars.map(norm));\n const pending = pendingCommitments(tree).filter((p) => listed.has(norm(p.uri)));\n if (pending.length === 0 && bitcoinAnchors(tree).length === 0) {\n throw new Error('upgradeProof: proof has no pending attestation from a listed calendar');\n }\n\n const answered: string[] = [];\n await Promise.allSettled(\n pending.map(async ({ uri, commitment }) => {\n const client = createCalendarClient(uri, { fetch: opts.fetch, timeoutMs: opts.timeoutMs });\n const bytes = await client.fetchProof(commitment, opts.signal);\n if (!bytes) return;\n if (mergeAt(tree, parseTimestamp(bytes, commitment))) answered.push(norm(uri));\n })\n );\n\n const merged = serializeTimestamp(tree);\n const anchor = await resolveAnchor(merged, tree, opts);\n const calendars = [...answered, ...current.calendars.filter((c) => !answered.includes(norm(c)))];\n\n if (anchor) {\n return {\n status: 'confirmed',\n proof: base64Encode(merged),\n calendars,\n blockHeight: anchor.blockHeight,\n blockHash: anchor.blockHash,\n upgradedAt: new Date().toISOString().replace(/\\.\\d+Z$/, 'Z'),\n };\n }\n if (!bytesEqual(merged, before)) {\n return { ...current, proof: base64Encode(merged), calendars };\n }\n return current;\n}\n\nasync function resolveAnchor(\n merged: Uint8Array,\n tree: ReturnType<typeof parseTimestamp>,\n opts: UpgradeOptions\n): Promise<{ blockHeight: number; blockHash: string } | null> {\n if (opts.parseAnchor) return opts.parseAnchor(merged);\n for (const a of bitcoinAnchors(tree)) {\n const header = await opts.headerSource!.getHeaderAt(a.blockHeight);\n if (header && header.byteLength === 80 && bytesEqual(header.subarray(36, 68), a.merkleRoot)) {\n return { blockHeight: a.blockHeight, blockHash: blockHashOf(header) };\n }\n }\n return null;\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { sha256 } from '@noble/hashes/sha2';
|
|
2
1
|
import { sha1, ripemd160 } from '@noble/hashes/legacy';
|
|
2
|
+
import { sha256 } from '@noble/hashes/sha2';
|
|
3
3
|
import { keccak_256 } from '@noble/hashes/sha3';
|
|
4
4
|
|
|
5
5
|
// src/types.ts
|
|
@@ -165,44 +165,6 @@ function withTimeout(parent, ms) {
|
|
|
165
165
|
}
|
|
166
166
|
};
|
|
167
167
|
}
|
|
168
|
-
|
|
169
|
-
// src/submit.ts
|
|
170
|
-
async function submitToCalendars(idHex, opts = {}) {
|
|
171
|
-
const digest = hexDecode(idHex);
|
|
172
|
-
if (digest.byteLength !== 32) {
|
|
173
|
-
throw new Error("submitToCalendars: idHex must be 32 bytes (64 hex chars)");
|
|
174
|
-
}
|
|
175
|
-
const clients = (opts.calendars ?? DEFAULT_CALENDARS).map(
|
|
176
|
-
(c) => typeof c === "string" ? createCalendarClient(c, { fetch: opts.fetch, timeoutMs: opts.timeoutMs }) : c
|
|
177
|
-
);
|
|
178
|
-
if (clients.length === 0) {
|
|
179
|
-
throw new Error("submitToCalendars: at least one calendar is required");
|
|
180
|
-
}
|
|
181
|
-
const minSuccesses = Math.max(1, opts.minSuccesses ?? 1);
|
|
182
|
-
const settled = await Promise.allSettled(
|
|
183
|
-
clients.map(async (c) => {
|
|
184
|
-
const proof = await c.submit(digest, opts.signal);
|
|
185
|
-
return { url: c.url, proof };
|
|
186
|
-
})
|
|
187
|
-
);
|
|
188
|
-
const successes = settled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
189
|
-
const failures = settled.filter((r) => r.status === "rejected").map((r) => r.reason instanceof Error ? r.reason.message : String(r.reason));
|
|
190
|
-
if (successes.length < minSuccesses) {
|
|
191
|
-
const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join("; ")}`;
|
|
192
|
-
const err = new Error(msg);
|
|
193
|
-
err.errors = failures;
|
|
194
|
-
throw err;
|
|
195
|
-
}
|
|
196
|
-
const first = successes[0];
|
|
197
|
-
return {
|
|
198
|
-
status: "pending",
|
|
199
|
-
proof: base64Encode(first.proof),
|
|
200
|
-
calendars: successes.map((s) => s.url),
|
|
201
|
-
blockHeight: null,
|
|
202
|
-
blockHash: null,
|
|
203
|
-
upgradedAt: null
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
168
|
var HEADER_MAGIC = new Uint8Array([
|
|
207
169
|
0,
|
|
208
170
|
79,
|
|
@@ -477,7 +439,62 @@ function bytesEqual(a, b) {
|
|
|
477
439
|
return true;
|
|
478
440
|
}
|
|
479
441
|
|
|
480
|
-
// src/
|
|
442
|
+
// src/submit.ts
|
|
443
|
+
async function submitToCalendars(idHex, opts = {}) {
|
|
444
|
+
const digest = hexDecode(idHex);
|
|
445
|
+
if (digest.byteLength !== 32) {
|
|
446
|
+
throw new Error("submitToCalendars: idHex must be 32 bytes (64 hex chars)");
|
|
447
|
+
}
|
|
448
|
+
const clients = (opts.calendars ?? DEFAULT_CALENDARS).map(
|
|
449
|
+
(c) => typeof c === "string" ? createCalendarClient(c, { fetch: opts.fetch, timeoutMs: opts.timeoutMs }) : c
|
|
450
|
+
);
|
|
451
|
+
if (clients.length === 0) {
|
|
452
|
+
throw new Error("submitToCalendars: at least one calendar is required");
|
|
453
|
+
}
|
|
454
|
+
const minSuccesses = Math.max(1, opts.minSuccesses ?? 1);
|
|
455
|
+
const settled = await Promise.allSettled(
|
|
456
|
+
clients.map(async (c) => {
|
|
457
|
+
const proof = await c.submit(digest, opts.signal);
|
|
458
|
+
return { url: c.url, proof };
|
|
459
|
+
})
|
|
460
|
+
);
|
|
461
|
+
const successes = settled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
462
|
+
const failures = settled.filter((r) => r.status === "rejected").map((r) => r.reason instanceof Error ? r.reason.message : String(r.reason));
|
|
463
|
+
if (successes.length < minSuccesses) {
|
|
464
|
+
const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join("; ")}`;
|
|
465
|
+
const err = new Error(msg);
|
|
466
|
+
err.errors = failures;
|
|
467
|
+
throw err;
|
|
468
|
+
}
|
|
469
|
+
let tree = null;
|
|
470
|
+
const merged = [];
|
|
471
|
+
for (const s of successes) {
|
|
472
|
+
let receipt;
|
|
473
|
+
try {
|
|
474
|
+
receipt = parseTimestamp(s.proof, digest);
|
|
475
|
+
} catch (e) {
|
|
476
|
+
failures.push(`${s.url}: unreadable proof (${e instanceof Error ? e.message : String(e)})`);
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
if (tree) mergeAt(tree, receipt);
|
|
480
|
+
else tree = receipt;
|
|
481
|
+
merged.push(s.url);
|
|
482
|
+
}
|
|
483
|
+
if (!tree || merged.length < minSuccesses) {
|
|
484
|
+
const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join("; ")}`;
|
|
485
|
+
const err = new Error(msg);
|
|
486
|
+
err.errors = failures;
|
|
487
|
+
throw err;
|
|
488
|
+
}
|
|
489
|
+
return {
|
|
490
|
+
status: "pending",
|
|
491
|
+
proof: base64Encode(serializeTimestamp(tree)),
|
|
492
|
+
calendars: merged,
|
|
493
|
+
blockHeight: null,
|
|
494
|
+
blockHash: null,
|
|
495
|
+
upgradedAt: null
|
|
496
|
+
};
|
|
497
|
+
}
|
|
481
498
|
async function walkOtsProof(input) {
|
|
482
499
|
try {
|
|
483
500
|
const anchors = bitcoinAnchors(parseProof(input.proofBytes, input.digest));
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/base64.ts","../src/calendar.ts","../src/submit.ts","../src/ots.ts","../src/anchor.ts","../src/upgrade.ts"],"names":["tag","sha256"],"mappings":"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","file":"index.mjs","sourcesContent":["// Types for @orangecheck/stamp-ots.\n\nimport type { StampOts } from '@orangecheck/stamp-core';\n\nexport type OtsProofStatus = 'pending' | 'confirmed';\n\nexport interface OtsProof {\n status: OtsProofStatus;\n /** OTS timestamp rooted at the envelope id (or a detached .ots file), base64. */\n proof: string;\n /** Calendar URLs that contain this proof, in submission order. */\n calendars: string[];\n /** Bitcoin block height at which this proof is anchored (null if pending). */\n blockHeight: number | null;\n /** Bitcoin block hash (hex, lowercase) at the anchor block (null if pending). */\n blockHash: string | null;\n /** ISO 8601 UTC of the upgrade (null if pending). */\n upgradedAt: string | null;\n}\n\nexport interface CalendarClient {\n /** Base URL of the calendar, e.g. \"https://alice.btc.calendar.opentimestamps.org\". */\n readonly url: string;\n\n /**\n * Submit a 32-byte digest to the calendar for aggregation. Returns the raw\n * pending proof bytes.\n *\n * OTS calendar HTTP API: POST <url>/digest with the raw bytes as the body,\n * Content-Type: application/vnd.opentimestamps.v1, returns the proof bytes\n * as the response body.\n */\n submit(digest: Uint8Array, signal?: AbortSignal): Promise<Uint8Array>;\n\n /**\n * Fetch the continuation of a pending proof. `commitment` is the message\n * at the calendar's pending attestation (see `pendingCommitments`), not\n * the submitted digest. Returns null if the calendar has nothing yet.\n *\n * OTS calendar HTTP API: GET <url>/timestamp/<hex(commitment)>, returns a\n * timestamp rooted at the commitment, or 404.\n */\n fetchProof(commitment: Uint8Array, signal?: AbortSignal): Promise<Uint8Array | null>;\n}\n\nexport interface AnchorVerificationInput {\n /** Raw OTS proof bytes (base64-decoded by the caller). */\n proofBytes: Uint8Array;\n /** 32-byte digest that the proof commits to. */\n digest: Uint8Array;\n /** Declared block height from the envelope. */\n blockHeight: number;\n /** Declared block hash (hex) from the envelope. */\n blockHash: string;\n /**\n * Optional block header source. If provided, the verifier uses this to\n * fetch the header at `blockHeight` and compare its Merkle root to the\n * one derived from walking the proof.\n *\n * If omitted, the verifier MAY still parse the proof and report\n * structural validity but CANNOT report a bound anchor.\n */\n headerSource?: BlockHeaderSource;\n}\n\nexport interface BlockHeaderSource {\n /** Return the 80-byte raw block header at the given height, or null if unknown. */\n getHeaderAt(height: number): Promise<Uint8Array | null>;\n}\n\nexport type AnchorVerifier = (input: AnchorVerificationInput) => Promise<AnchorVerificationResult>;\n\nexport type AnchorVerificationResult =\n | { ok: true; merkleRoot: string }\n | { ok: false; reason: string };\n\n/**\n * Convert an OtsProof (library type) to the StampOts field shape that the\n * envelope carries. The two are isomorphic; this function exists to keep\n * stamp-core's type surface narrow.\n */\nexport function toStampOts(p: OtsProof): StampOts {\n return {\n status: p.status,\n proof: p.proof,\n calendars: p.calendars,\n block_height: p.blockHeight,\n block_hash: p.blockHash,\n upgraded_at: p.upgradedAt,\n };\n}\n\nexport function fromStampOts(s: StampOts): OtsProof {\n return {\n status: s.status,\n proof: s.proof,\n calendars: s.calendars,\n blockHeight: s.block_height,\n blockHash: s.block_hash,\n upgradedAt: s.upgraded_at,\n };\n}\n","// Minimal, dependency-free base64 <-> Uint8Array helpers. OTS proof bytes\n// are carried as base64 inside OC Stamp envelopes so they survive any text\n// transport (URL fragment, JSON, Nostr event content).\n\nconst B64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\nconst B64_DECODE_TABLE = (() => {\n const t = new Int16Array(128).fill(-1);\n for (let i = 0; i < B64_CHARS.length; i++) t[B64_CHARS.charCodeAt(i)] = i;\n t['='.charCodeAt(0)] = -2;\n return t;\n})();\n\nexport function base64Encode(bytes: Uint8Array): string {\n let out = '';\n let i = 0;\n for (; i + 2 < bytes.length; i += 3) {\n const a = bytes[i]!;\n const b = bytes[i + 1]!;\n const c = bytes[i + 2]!;\n out +=\n B64_CHARS[a >> 2]! +\n B64_CHARS[((a & 0x03) << 4) | (b >> 4)]! +\n B64_CHARS[((b & 0x0f) << 2) | (c >> 6)]! +\n B64_CHARS[c & 0x3f]!;\n }\n if (i < bytes.length) {\n const a = bytes[i]!;\n const b = i + 1 < bytes.length ? bytes[i + 1]! : 0;\n out += B64_CHARS[a >> 2]!;\n out += B64_CHARS[((a & 0x03) << 4) | (b >> 4)]!;\n out += i + 1 < bytes.length ? B64_CHARS[(b & 0x0f) << 2]! : '=';\n out += '=';\n }\n return out;\n}\n\nexport function base64Decode(s: string): Uint8Array {\n const str = s.replace(/\\s+/g, '');\n const len = str.length;\n if (len === 0) return new Uint8Array(0);\n if (len % 4 !== 0) throw new Error('base64: bad length');\n let padding = 0;\n if (str[len - 1] === '=') padding++;\n if (str[len - 2] === '=') padding++;\n const outLen = (len / 4) * 3 - padding;\n const out = new Uint8Array(outLen);\n let o = 0;\n for (let i = 0; i < len; i += 4) {\n const c0 = B64_DECODE_TABLE[str.charCodeAt(i)]!;\n const c1 = B64_DECODE_TABLE[str.charCodeAt(i + 1)]!;\n const c2 = B64_DECODE_TABLE[str.charCodeAt(i + 2)]!;\n const c3 = B64_DECODE_TABLE[str.charCodeAt(i + 3)]!;\n if (c0 < 0 || c1 < 0 || c2 < -2 || c3 < -2) throw new Error('base64: bad char');\n out[o++] = (c0 << 2) | (c1 >> 4);\n if (c2 >= 0) out[o++] = ((c1 & 0x0f) << 4) | (c2 >> 2);\n if (c3 >= 0) out[o++] = ((c2 & 0x03) << 6) | c3;\n }\n return out;\n}\n\nexport function hexDecode(s: string): Uint8Array {\n if (s.length % 2 !== 0) throw new Error('hex: odd length');\n const out = new Uint8Array(s.length / 2);\n for (let i = 0; i < out.length; i++) {\n const hi = parseInt(s[i * 2]!, 16);\n const lo = parseInt(s[i * 2 + 1]!, 16);\n if (Number.isNaN(hi) || Number.isNaN(lo)) throw new Error('hex: bad char');\n out[i] = (hi << 4) | lo;\n }\n return out;\n}\n\nexport function hexEncode(bytes: Uint8Array): string {\n const HEX = '0123456789abcdef';\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n const b = bytes[i]!;\n out += HEX[(b >> 4) & 0x0f]! + HEX[b & 0x0f]!;\n }\n return out;\n}\n","// HTTP client for an OpenTimestamps calendar. Implements the minimal subset\n// of the calendar protocol that an OC Stamp implementation needs:\n//\n// POST <url>/digest body = raw digest bytes -> pending proof bytes\n// GET <url>/timestamp/<hex(commitment)> -> continuation, or 404\n//\n// The client moves bytes only; ./ots.ts parses them.\n\nimport type { CalendarClient } from './types.js';\nimport { hexEncode } from './base64.js';\n\nexport const DEFAULT_CALENDARS: readonly string[] = [\n 'https://alice.btc.calendar.opentimestamps.org',\n 'https://bob.btc.calendar.opentimestamps.org',\n 'https://finney.calendar.eternitywall.com',\n];\n\nexport interface HttpCalendarOptions {\n /**\n * Custom fetch implementation. Defaults to global `fetch`. Useful in\n * environments that need a specific adapter (Node < 18, Cloudflare\n * Workers, proxies).\n */\n fetch?: typeof fetch;\n /** Request timeout in milliseconds. Default 30_000. */\n timeoutMs?: number;\n}\n\nexport function createCalendarClient(url: string, opts: HttpCalendarOptions = {}): CalendarClient {\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') {\n throw new Error(\n '@orangecheck/stamp-ots: no fetch implementation available. Pass one via { fetch }.'\n );\n }\n const timeoutMs = opts.timeoutMs ?? 30_000;\n const base = url.replace(/\\/$/, '');\n\n return {\n url: base,\n async submit(digest, signal) {\n if (digest.byteLength !== 32) {\n throw new Error('OTS: digest must be exactly 32 bytes');\n }\n const ac = withTimeout(signal, timeoutMs);\n // Uint8Array is a valid fetch body at runtime in Node 18+ and all\n // modern browsers, but TypeScript's DOM typings don't accept it\n // directly under `strict` + `noUncheckedIndexedAccess`. The cast is\n // narrow and intentional.\n // No Content-Type: a non-safelisted type makes browsers send a\n // CORS preflight, and OTS calendars answer OPTIONS with 501.\n const resp = await fetchImpl(`${base}/digest`, {\n method: 'POST',\n body: digest as unknown as BodyInit,\n signal: ac.signal,\n });\n ac.clear();\n if (!resp.ok) {\n throw new Error(`OTS calendar ${base} submit failed: HTTP ${resp.status}`);\n }\n const buf = await resp.arrayBuffer();\n return new Uint8Array(buf);\n },\n async fetchProof(commitment, signal) {\n if (commitment.byteLength === 0 || commitment.byteLength > 64) {\n throw new Error('OTS: commitment must be 1-64 bytes');\n }\n const ac = withTimeout(signal, timeoutMs);\n const resp = await fetchImpl(`${base}/timestamp/${hexEncode(commitment)}`, {\n method: 'GET',\n headers: { Accept: 'application/vnd.opentimestamps.v1' },\n signal: ac.signal,\n });\n ac.clear();\n if (resp.status === 404) return null;\n if (!resp.ok) {\n throw new Error(`OTS calendar ${base} fetchProof failed: HTTP ${resp.status}`);\n }\n const buf = await resp.arrayBuffer();\n return new Uint8Array(buf);\n },\n };\n}\n\nfunction withTimeout(parent: AbortSignal | undefined, ms: number): { signal: AbortSignal; clear: () => void } {\n const ac = new AbortController();\n const onParent = () => ac.abort((parent as AbortSignal & { reason?: unknown }).reason);\n if (parent) {\n if (parent.aborted) ac.abort((parent as AbortSignal & { reason?: unknown }).reason);\n else parent.addEventListener('abort', onParent, { once: true });\n }\n const t = setTimeout(() => ac.abort(new Error(`OTS request timed out after ${ms}ms`)), ms);\n return {\n signal: ac.signal,\n clear: () => {\n clearTimeout(t);\n if (parent) parent.removeEventListener('abort', onParent);\n },\n };\n}\n","// Submit an envelope id to one or more OTS calendars. Returns a pending proof.\n// See SPEC.md §6.1.\n//\n// The submission strategy: try each calendar in parallel, take the first\n// success, report which calendar produced it. A stamp that only reaches one\n// calendar is a single point of failure for upgrade; the reference app\n// submits to at least two calendars for redundancy.\n\nimport { base64Encode, hexDecode } from './base64.js';\nimport { createCalendarClient, DEFAULT_CALENDARS } from './calendar.js';\nimport type { CalendarClient, OtsProof } from './types.js';\n\nexport interface SubmitOptions {\n /**\n * Calendars to submit to. Defaults to DEFAULT_CALENDARS. Can be strings\n * (URLs) or pre-built CalendarClient instances.\n */\n calendars?: readonly (string | CalendarClient)[];\n /**\n * Minimum number of calendars that must succeed. Defaults to 1.\n * If fewer than `minSuccesses` calendars respond with a proof,\n * submit() throws an aggregate error.\n */\n minSuccesses?: number;\n /** Optional custom fetch passed through to calendar clients. */\n fetch?: typeof fetch;\n /** Request timeout per calendar. Default 30_000ms. */\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/**\n * Submit the envelope `id` (64-hex) to OTS calendars and return an OtsProof in\n * pending state. The caller merges this into the envelope's `ots` field.\n *\n * Implementation note: the raw proof bytes returned by OTS calendars are not\n * a superset of the digest alone — they encode the calendar's commitment.\n * Because different calendars return different pending-proof bytes for the\n * same digest, we carry the FIRST successful calendar's bytes in the\n * envelope. Upgrade (see upgrade.ts) can fetch richer proofs from any of the\n * submitted-to calendars later.\n */\nexport async function submitToCalendars(idHex: string, opts: SubmitOptions = {}): Promise<OtsProof> {\n const digest = hexDecode(idHex);\n if (digest.byteLength !== 32) {\n throw new Error('submitToCalendars: idHex must be 32 bytes (64 hex chars)');\n }\n\n const clients = (opts.calendars ?? DEFAULT_CALENDARS).map((c) =>\n typeof c === 'string'\n ? createCalendarClient(c, { fetch: opts.fetch, timeoutMs: opts.timeoutMs })\n : c\n );\n if (clients.length === 0) {\n throw new Error('submitToCalendars: at least one calendar is required');\n }\n const minSuccesses = Math.max(1, opts.minSuccesses ?? 1);\n\n const settled = await Promise.allSettled(\n clients.map(async (c) => {\n const proof = await c.submit(digest, opts.signal);\n return { url: c.url, proof };\n })\n );\n const successes = settled\n .filter((r): r is PromiseFulfilledResult<{ url: string; proof: Uint8Array }> => r.status === 'fulfilled')\n .map((r) => r.value);\n const failures = settled\n .filter((r): r is PromiseRejectedResult => r.status === 'rejected')\n .map((r) => (r.reason instanceof Error ? r.reason.message : String(r.reason)));\n\n if (successes.length < minSuccesses) {\n // AggregateError would be nicer but targets ES2021; Error keeps us at ES2020.\n const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join('; ')}`;\n const err = new Error(msg) as Error & { errors: string[] };\n err.errors = failures;\n throw err;\n }\n\n const first = successes[0]!;\n return {\n status: 'pending',\n proof: base64Encode(first.proof),\n calendars: successes.map((s) => s.url),\n blockHeight: null,\n blockHash: null,\n upgradedAt: null,\n };\n}\n","// OpenTimestamps proof format: parse, walk, serialize, merge.\n//\n// Follows python-opentimestamps (core/timestamp.py, core/op.py,\n// core/notary.py). Two encodings are accepted:\n//\n// - a bare timestamp rooted at the digest (what an OTS calendar returns from\n// POST /digest, and what OC Stamp envelopes carry in `ots.proof`);\n// - a detached `.ots` file (magic header + file-hash op + digest + timestamp).\n\nimport { ripemd160, sha1 } from '@noble/hashes/legacy';\nimport { sha256 } from '@noble/hashes/sha2';\nimport { keccak_256 } from '@noble/hashes/sha3';\n\nimport { hexEncode } from './base64.js';\n\nconst HEADER_MAGIC = new Uint8Array([\n 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x00,\n 0x00, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x00, 0xbf, 0x89, 0xe2, 0xe8, 0x84, 0xe8, 0x92, 0x94,\n]);\n\nconst TAG_BITCOIN = '0588960d73d71901';\nconst TAG_PENDING = '83dfe30d2ef90c8e';\n\nconst MAX_DEPTH = 256;\nconst MAX_MSG = 4096;\n\nexport type OtsOp =\n | { kind: 'sha256' | 'ripemd160' | 'sha1' | 'keccak256' | 'reverse' | 'hexlify' }\n | { kind: 'append' | 'prepend'; arg: Uint8Array };\n\nexport type OtsAttestation =\n | { kind: 'bitcoin'; height: number }\n | { kind: 'pending'; uri: string }\n | { kind: 'unknown'; tag: string; payload: Uint8Array };\n\nexport interface OtsTimestamp {\n /** The message at this node: the digest after every op on the path to it. */\n msg: Uint8Array;\n attestations: OtsAttestation[];\n ops: { op: OtsOp; child: OtsTimestamp }[];\n}\n\nclass Reader {\n private pos = 0;\n constructor(private readonly buf: Uint8Array) {}\n byte(): number {\n if (this.pos >= this.buf.length) throw new Error('ots: unexpected end of proof');\n return this.buf[this.pos++]!;\n }\n bytes(n: number): Uint8Array {\n if (n < 0 || this.pos + n > this.buf.length) throw new Error('ots: unexpected end of proof');\n const out = this.buf.subarray(this.pos, this.pos + n);\n this.pos += n;\n return out;\n }\n varuint(): number {\n let value = 0;\n let shift = 0;\n for (;;) {\n const b = this.byte();\n value += (b & 0x7f) * 2 ** shift;\n if (!(b & 0x80)) return value;\n shift += 7;\n if (shift > 49) throw new Error('ots: varuint too large');\n }\n }\n varbytes(max: number): Uint8Array {\n const n = this.varuint();\n if (n > max) throw new Error('ots: varbytes too long');\n return this.bytes(n);\n }\n get done(): boolean {\n return this.pos === this.buf.length;\n }\n}\n\nconst UNARY: Record<number, OtsOp['kind']> = {\n 0x02: 'sha1',\n 0x03: 'ripemd160',\n 0x08: 'sha256',\n 0x67: 'keccak256',\n 0xf2: 'reverse',\n 0xf3: 'hexlify',\n};\n\nexport function applyOp(op: OtsOp, msg: Uint8Array): Uint8Array {\n switch (op.kind) {\n case 'sha256':\n return sha256(msg);\n case 'ripemd160':\n return ripemd160(msg);\n case 'sha1':\n return sha1(msg);\n case 'keccak256':\n return keccak_256(msg);\n case 'reverse':\n return new Uint8Array(msg).reverse();\n case 'hexlify':\n return new TextEncoder().encode(hexEncode(msg));\n case 'append':\n return concat(msg, op.arg);\n case 'prepend':\n return concat(op.arg, msg);\n }\n}\n\nfunction readOp(r: Reader, tag: number): OtsOp {\n const unary = UNARY[tag];\n if (unary) return { kind: unary } as OtsOp;\n if (tag === 0xf0) return { kind: 'append', arg: r.varbytes(MAX_MSG) };\n if (tag === 0xf1) return { kind: 'prepend', arg: r.varbytes(MAX_MSG) };\n throw new Error(`ots: unknown op tag 0x${tag.toString(16)}`);\n}\n\nfunction readAttestation(r: Reader): OtsAttestation {\n const tag = hexEncode(r.bytes(8));\n const payload = r.varbytes(8192);\n const p = new Reader(payload);\n if (tag === TAG_BITCOIN) return { kind: 'bitcoin', height: p.varuint() };\n if (tag === TAG_PENDING) return { kind: 'pending', uri: new TextDecoder().decode(p.varbytes(1000)) };\n return { kind: 'unknown', tag, payload };\n}\n\nfunction readTimestamp(r: Reader, msg: Uint8Array, depth: number): OtsTimestamp {\n if (depth > MAX_DEPTH) throw new Error('ots: proof too deep');\n const node: OtsTimestamp = { msg, attestations: [], ops: [] };\n const item = (tag: number) => {\n if (tag === 0x00) {\n node.attestations.push(readAttestation(r));\n return;\n }\n const op = readOp(r, tag);\n const next = applyOp(op, msg);\n if (next.length > MAX_MSG) throw new Error('ots: message too long');\n node.ops.push({ op, child: readTimestamp(r, next, depth + 1) });\n };\n let tag = r.byte();\n while (tag === 0xff) {\n item(r.byte());\n tag = r.byte();\n }\n item(tag);\n return node;\n}\n\n/** Parse a bare timestamp whose root message is `digest`. */\nexport function parseTimestamp(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp {\n const r = new Reader(bytes);\n const ts = readTimestamp(r, digest, 0);\n if (!r.done) throw new Error('ots: trailing bytes after timestamp');\n return ts;\n}\n\nexport function isDetached(bytes: Uint8Array): boolean {\n return bytes.length > HEADER_MAGIC.length && bytesEqual(bytes.subarray(0, HEADER_MAGIC.length), HEADER_MAGIC);\n}\n\n/** Parse a detached `.ots` file. Only sha256 file digests are accepted. */\nexport function parseDetached(bytes: Uint8Array): { digest: Uint8Array; timestamp: OtsTimestamp } {\n if (!isDetached(bytes)) throw new Error('ots: missing detached-file header');\n const r = new Reader(bytes.subarray(HEADER_MAGIC.length));\n const major = r.varuint();\n if (major !== 1) throw new Error(`ots: unsupported file version ${major}`);\n if (r.byte() !== 0x08) throw new Error('ots: only sha256 file digests are supported');\n const digest = new Uint8Array(r.bytes(32));\n const timestamp = readTimestamp(r, digest, 0);\n if (!r.done) throw new Error('ots: trailing bytes after timestamp');\n return { digest, timestamp };\n}\n\n/**\n * Parse either encoding and require that it commits to `digest`. A detached\n * file for some other digest is rejected rather than walked.\n */\nexport function parseProof(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp {\n if (!isDetached(bytes)) return parseTimestamp(bytes, digest);\n const d = parseDetached(bytes);\n if (!bytesEqual(d.digest, digest)) throw new Error('ots: proof commits to a different digest');\n return d.timestamp;\n}\n\n/** Every attestation in the tree with the message it attests to. */\nexport function attestations(ts: OtsTimestamp): { msg: Uint8Array; attestation: OtsAttestation }[] {\n const out: { msg: Uint8Array; attestation: OtsAttestation }[] = [];\n const walk = (n: OtsTimestamp) => {\n for (const a of n.attestations) out.push({ msg: n.msg, attestation: a });\n for (const { child } of n.ops) walk(child);\n };\n walk(ts);\n return out;\n}\n\n/**\n * Bitcoin attestations, lowest height first. `merkleRoot` is the message at\n * the attestation, which equals the block header's Merkle root in header\n * byte order.\n */\nexport function bitcoinAnchors(ts: OtsTimestamp): { blockHeight: number; merkleRoot: Uint8Array }[] {\n return attestations(ts)\n .flatMap(({ msg, attestation }) =>\n attestation.kind === 'bitcoin' ? [{ blockHeight: attestation.height, merkleRoot: msg }] : []\n )\n .sort((a, b) => a.blockHeight - b.blockHeight);\n}\n\n/** Pending calendar attestations: where to ask, and the commitment to ask for. */\nexport function pendingCommitments(ts: OtsTimestamp): { uri: string; commitment: Uint8Array }[] {\n return attestations(ts).flatMap(({ msg, attestation }) =>\n attestation.kind === 'pending' ? [{ uri: attestation.uri, commitment: msg }] : []\n );\n}\n\n/**\n * Graft `upgrade` (a timestamp rooted at some node's message) onto the node\n * with that message, as python-opentimestamps' Timestamp.merge does. Returns\n * false when no node carries that message.\n */\nexport function mergeAt(ts: OtsTimestamp, upgrade: OtsTimestamp): boolean {\n if (bytesEqual(ts.msg, upgrade.msg)) {\n for (const a of upgrade.attestations) {\n if (!ts.attestations.some((b) => attestationKey(b) === attestationKey(a))) ts.attestations.push(a);\n }\n for (const { op, child } of upgrade.ops) {\n const same = ts.ops.find((o) => opKey(o.op) === opKey(op));\n if (same) mergeAt(same.child, child);\n else ts.ops.push({ op, child });\n }\n return true;\n }\n return ts.ops.some(({ child }) => mergeAt(child, upgrade));\n}\n\nfunction writeVaruint(out: number[], n: number) {\n do {\n let b = n % 128;\n n = Math.floor(n / 128);\n if (n > 0) b |= 0x80;\n out.push(b);\n } while (n > 0);\n}\n\nfunction writeVarbytes(out: number[], bytes: Uint8Array) {\n writeVaruint(out, bytes.length);\n out.push(...bytes);\n}\n\nconst OP_TAG: Record<OtsOp['kind'], number> = {\n sha1: 0x02,\n ripemd160: 0x03,\n sha256: 0x08,\n keccak256: 0x67,\n append: 0xf0,\n prepend: 0xf1,\n reverse: 0xf2,\n hexlify: 0xf3,\n};\n\nfunction writeAttestation(out: number[], a: OtsAttestation) {\n const payload: number[] = [];\n let tag: string;\n if (a.kind === 'bitcoin') {\n tag = TAG_BITCOIN;\n writeVaruint(payload, a.height);\n } else if (a.kind === 'pending') {\n tag = TAG_PENDING;\n writeVarbytes(payload, new TextEncoder().encode(a.uri));\n } else {\n tag = a.tag;\n payload.push(...a.payload);\n }\n out.push(0x00);\n for (let i = 0; i < 16; i += 2) out.push(parseInt(tag.slice(i, i + 2), 16));\n writeVarbytes(out, new Uint8Array(payload));\n}\n\nfunction writeTimestamp(out: number[], ts: OtsTimestamp) {\n const items: (() => void)[] = [\n ...ts.attestations.map((a) => () => writeAttestation(out, a)),\n ...ts.ops.map(({ op, child }) => () => {\n out.push(OP_TAG[op.kind]);\n if (op.kind === 'append' || op.kind === 'prepend') writeVarbytes(out, op.arg);\n writeTimestamp(out, child);\n }),\n ];\n if (items.length === 0) throw new Error('ots: cannot serialize an empty timestamp node');\n items.forEach((write, i) => {\n if (i < items.length - 1) out.push(0xff);\n write();\n });\n}\n\n/** Serialize as a bare timestamp (the encoding carried in `ots.proof`). */\nexport function serializeTimestamp(ts: OtsTimestamp): Uint8Array {\n const out: number[] = [];\n writeTimestamp(out, ts);\n return new Uint8Array(out);\n}\n\nfunction attestationKey(a: OtsAttestation): string {\n if (a.kind === 'bitcoin') return `b:${a.height}`;\n if (a.kind === 'pending') return `p:${a.uri}`;\n return `u:${a.tag}:${hexEncode(a.payload)}`;\n}\n\nfunction opKey(op: OtsOp): string {\n return 'arg' in op ? `${op.kind}:${hexEncode(op.arg)}` : op.kind;\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.length + b.length);\n out.set(a, 0);\n out.set(b, a.length);\n return out;\n}\n\nexport function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) return false;\n for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n","// Anchor verification. See SPEC.md §6.3.\n//\n// A confirmed anchor holds when all three are true:\n// 1. the proof commits to the envelope id and walks to a Bitcoin\n// attestation at the declared height;\n// 2. the message at that attestation equals the Merkle root in the block\n// header at that height;\n// 3. that header double-SHA256es to the declared block hash.\n//\n// The resulting function is what `@orangecheck/stamp-core` expects at the\n// `verifyOtsAnchor` input of `verify()`.\n\nimport { sha256 } from '@noble/hashes/sha2';\n\nimport { base64Decode, hexDecode, hexEncode } from './base64.js';\nimport { bitcoinAnchors, bytesEqual, parseProof } from './ots.js';\nimport type {\n AnchorVerificationInput,\n AnchorVerificationResult,\n AnchorVerifier,\n BlockHeaderSource,\n} from './types.js';\n\nexport interface AnchorVerifierConfig {\n /**\n * Parse the proof bytes and return the Merkle root the proof walks to,\n * plus its block height. Optional: the built-in OTS parser is used when\n * omitted. `blockHeight` is the declared height, for proofs that carry\n * attestations at more than one height.\n */\n walkProof?: (input: {\n proofBytes: Uint8Array;\n digest: Uint8Array;\n blockHeight?: number;\n }) => Promise<{ merkleRoot: Uint8Array; blockHeight: number } | null>;\n /**\n * Source of Bitcoin block headers: a full node, SPV, a headers snapshot,\n * or `mempoolHeaderSource()`. This is the verifier's trust anchor.\n */\n headerSource: BlockHeaderSource;\n}\n\n/** Built-in walker: parse the OTS proof and pick the Bitcoin attestation. */\nexport async function walkOtsProof(input: {\n proofBytes: Uint8Array;\n digest: Uint8Array;\n blockHeight?: number;\n}): Promise<{ merkleRoot: Uint8Array; blockHeight: number } | null> {\n try {\n const anchors = bitcoinAnchors(parseProof(input.proofBytes, input.digest));\n return anchors.find((a) => a.blockHeight === input.blockHeight) ?? anchors[0] ?? null;\n } catch {\n return null;\n }\n}\n\n/** Block hash (display hex) of an 80-byte header. */\nexport function blockHashOf(header: Uint8Array): string {\n return hexEncode(sha256(sha256(header)).reverse());\n}\n\nexport function makeAnchorVerifier(\n cfg: AnchorVerifierConfig\n): (proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean> {\n const walkProof = cfg.walkProof ?? walkOtsProof;\n const verifier: AnchorVerifier = async (\n input: AnchorVerificationInput\n ): Promise<AnchorVerificationResult> => {\n const walked = await walkProof({\n proofBytes: input.proofBytes,\n digest: input.digest,\n blockHeight: input.blockHeight,\n });\n if (!walked) {\n return { ok: false, reason: 'proof could not be walked to a Bitcoin commitment' };\n }\n if (walked.blockHeight !== input.blockHeight) {\n return {\n ok: false,\n reason: `proof anchors at block ${walked.blockHeight}, envelope declares ${input.blockHeight}`,\n };\n }\n const header = await cfg.headerSource.getHeaderAt(input.blockHeight);\n if (!header || header.byteLength !== 80) {\n return { ok: false, reason: `no block header available at height ${input.blockHeight}` };\n }\n if (blockHashOf(header) !== input.blockHash.toLowerCase()) {\n return { ok: false, reason: 'block header does not hash to the declared block hash' };\n }\n // OTS attests to the Merkle root in header byte order (offset 36).\n const headerMerkle = header.subarray(36, 68);\n if (!bytesEqual(headerMerkle, walked.merkleRoot)) {\n return { ok: false, reason: 'block header Merkle root does not match walked proof root' };\n }\n return { ok: true, merkleRoot: hexEncode(headerMerkle) };\n };\n\n return async (proofB64, blockHeight, blockHash, envelopeId) => {\n const r = await verifier({\n proofBytes: base64Decode(proofB64),\n digest: hexDecode(envelopeId),\n blockHeight,\n blockHash,\n });\n return r.ok;\n };\n}\n\n/**\n * Anchor verifier using the built-in OTS parser. Kept async for callers of the\n * 0.1 API, which lazily loaded an optional parser here.\n */\nexport async function makeDefaultAnchorVerifier(opts: {\n headerSource: BlockHeaderSource;\n}): Promise<\n (proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean>\n> {\n return makeAnchorVerifier({ headerSource: opts.headerSource });\n}\n\nexport interface MempoolHeaderSourceOptions {\n /** Esplora-compatible API base. Default https://mempool.space/api. */\n baseUrl?: string;\n fetch?: typeof fetch;\n}\n\n/**\n * Block headers from an Esplora-compatible API. The verifier checks each\n * header against the declared block hash, so this source is trusted only to\n * report which block is at a height.\n */\nexport function mempoolHeaderSource(opts: MempoolHeaderSourceOptions = {}): BlockHeaderSource {\n const base = (opts.baseUrl ?? 'https://mempool.space/api').replace(/\\/+$/, '');\n const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);\n return {\n async getHeaderAt(height) {\n const h = await fetchImpl(`${base}/block-height/${height}`);\n if (!h.ok) return null;\n const hash = (await h.text()).trim();\n if (!/^[0-9a-f]{64}$/.test(hash)) return null;\n const r = await fetchImpl(`${base}/block/${hash}/header`);\n if (!r.ok) return null;\n const hex = (await r.text()).trim();\n return /^[0-9a-f]{160}$/.test(hex) ? hexDecode(hex) : null;\n },\n };\n}\n","// Upgrade a pending OTS proof to a confirmed one. See SPEC.md §6.2.\n//\n// A pending proof ends in calendar attestations, each naming a calendar and\n// the commitment (the message at that leaf) the calendar will later anchor.\n// Calendars index upgrades by that commitment, not by the submitted digest.\n// For each pending leaf we ask its calendar for the continuation, graft it on,\n// and report the proof as confirmed once it reaches a Bitcoin attestation\n// whose block header checks out.\n\nimport { blockHashOf } from './anchor.js';\nimport { base64Decode, base64Encode, hexDecode } from './base64.js';\nimport { createCalendarClient } from './calendar.js';\nimport {\n bitcoinAnchors,\n bytesEqual,\n mergeAt,\n parseProof,\n parseTimestamp,\n pendingCommitments,\n serializeTimestamp,\n} from './ots.js';\nimport type { BlockHeaderSource, OtsProof } from './types.js';\n\nexport interface UpgradeOptions {\n /**\n * Header source used to resolve the anchor's block hash and to check that\n * the proof's Merkle root is in that block.\n */\n headerSource?: BlockHeaderSource;\n /**\n * Alternative to `headerSource`: given the merged proof bytes, return the\n * anchor if the proof is confirmed, else null.\n */\n parseAnchor?: (proofBytes: Uint8Array) => Promise<{ blockHeight: number; blockHash: string } | null>;\n /** Optional custom fetch passed through to calendar clients. */\n fetch?: typeof fetch;\n /** Request timeout per calendar. Default 30_000ms. */\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\nconst norm = (u: string) => u.replace(/\\/+$/, '');\n\nexport async function upgradeProof(\n current: OtsProof,\n idHex: string,\n opts: UpgradeOptions\n): Promise<OtsProof> {\n if (current.status === 'confirmed') return current; // idempotent\n if (!opts.headerSource && !opts.parseAnchor) {\n throw new Error('upgradeProof: pass headerSource or parseAnchor');\n }\n\n const before = base64Decode(current.proof);\n const tree = parseProof(before, hexDecode(idHex));\n\n // Only ask calendars this proof was submitted to.\n const listed = new Set(current.calendars.map(norm));\n const pending = pendingCommitments(tree).filter((p) => listed.has(norm(p.uri)));\n if (pending.length === 0 && bitcoinAnchors(tree).length === 0) {\n throw new Error('upgradeProof: proof has no pending attestation from a listed calendar');\n }\n\n const answered: string[] = [];\n await Promise.allSettled(\n pending.map(async ({ uri, commitment }) => {\n const client = createCalendarClient(uri, { fetch: opts.fetch, timeoutMs: opts.timeoutMs });\n const bytes = await client.fetchProof(commitment, opts.signal);\n if (!bytes) return;\n if (mergeAt(tree, parseTimestamp(bytes, commitment))) answered.push(norm(uri));\n })\n );\n\n const merged = serializeTimestamp(tree);\n const anchor = await resolveAnchor(merged, tree, opts);\n const calendars = [...answered, ...current.calendars.filter((c) => !answered.includes(norm(c)))];\n\n if (anchor) {\n return {\n status: 'confirmed',\n proof: base64Encode(merged),\n calendars,\n blockHeight: anchor.blockHeight,\n blockHash: anchor.blockHash,\n upgradedAt: new Date().toISOString().replace(/\\.\\d+Z$/, 'Z'),\n };\n }\n if (!bytesEqual(merged, before)) {\n return { ...current, proof: base64Encode(merged), calendars };\n }\n return current;\n}\n\nasync function resolveAnchor(\n merged: Uint8Array,\n tree: ReturnType<typeof parseTimestamp>,\n opts: UpgradeOptions\n): Promise<{ blockHeight: number; blockHash: string } | null> {\n if (opts.parseAnchor) return opts.parseAnchor(merged);\n for (const a of bitcoinAnchors(tree)) {\n const header = await opts.headerSource!.getHeaderAt(a.blockHeight);\n if (header && header.byteLength === 80 && bytesEqual(header.subarray(36, 68), a.merkleRoot)) {\n return { blockHeight: a.blockHeight, blockHash: blockHashOf(header) };\n }\n }\n return null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/base64.ts","../src/calendar.ts","../src/ots.ts","../src/submit.ts","../src/anchor.ts","../src/upgrade.ts"],"names":["tag","sha256"],"mappings":"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","file":"index.mjs","sourcesContent":["// Types for @orangecheck/stamp-ots.\n\nimport type { StampOts } from '@orangecheck/stamp-core';\n\nexport type OtsProofStatus = 'pending' | 'confirmed';\n\nexport interface OtsProof {\n status: OtsProofStatus;\n /** OTS timestamp rooted at the envelope id (or a detached .ots file), base64. */\n proof: string;\n /** Calendar URLs that contain this proof, in submission order. */\n calendars: string[];\n /** Bitcoin block height at which this proof is anchored (null if pending). */\n blockHeight: number | null;\n /** Bitcoin block hash (hex, lowercase) at the anchor block (null if pending). */\n blockHash: string | null;\n /** ISO 8601 UTC of the upgrade (null if pending). */\n upgradedAt: string | null;\n}\n\nexport interface CalendarClient {\n /** Base URL of the calendar, e.g. \"https://alice.btc.calendar.opentimestamps.org\". */\n readonly url: string;\n\n /**\n * Submit a 32-byte digest to the calendar for aggregation. Returns the raw\n * pending proof bytes.\n *\n * OTS calendar HTTP API: POST <url>/digest with the raw bytes as the body,\n * Content-Type: application/vnd.opentimestamps.v1, returns the proof bytes\n * as the response body.\n */\n submit(digest: Uint8Array, signal?: AbortSignal): Promise<Uint8Array>;\n\n /**\n * Fetch the continuation of a pending proof. `commitment` is the message\n * at the calendar's pending attestation (see `pendingCommitments`), not\n * the submitted digest. Returns null if the calendar has nothing yet.\n *\n * OTS calendar HTTP API: GET <url>/timestamp/<hex(commitment)>, returns a\n * timestamp rooted at the commitment, or 404.\n */\n fetchProof(commitment: Uint8Array, signal?: AbortSignal): Promise<Uint8Array | null>;\n}\n\nexport interface AnchorVerificationInput {\n /** Raw OTS proof bytes (base64-decoded by the caller). */\n proofBytes: Uint8Array;\n /** 32-byte digest that the proof commits to. */\n digest: Uint8Array;\n /** Declared block height from the envelope. */\n blockHeight: number;\n /** Declared block hash (hex) from the envelope. */\n blockHash: string;\n /**\n * Optional block header source. If provided, the verifier uses this to\n * fetch the header at `blockHeight` and compare its Merkle root to the\n * one derived from walking the proof.\n *\n * If omitted, the verifier MAY still parse the proof and report\n * structural validity but CANNOT report a bound anchor.\n */\n headerSource?: BlockHeaderSource;\n}\n\nexport interface BlockHeaderSource {\n /** Return the 80-byte raw block header at the given height, or null if unknown. */\n getHeaderAt(height: number): Promise<Uint8Array | null>;\n}\n\nexport type AnchorVerifier = (input: AnchorVerificationInput) => Promise<AnchorVerificationResult>;\n\nexport type AnchorVerificationResult =\n | { ok: true; merkleRoot: string }\n | { ok: false; reason: string };\n\n/**\n * Convert an OtsProof (library type) to the StampOts field shape that the\n * envelope carries. The two are isomorphic; this function exists to keep\n * stamp-core's type surface narrow.\n */\nexport function toStampOts(p: OtsProof): StampOts {\n return {\n status: p.status,\n proof: p.proof,\n calendars: p.calendars,\n block_height: p.blockHeight,\n block_hash: p.blockHash,\n upgraded_at: p.upgradedAt,\n };\n}\n\nexport function fromStampOts(s: StampOts): OtsProof {\n return {\n status: s.status,\n proof: s.proof,\n calendars: s.calendars,\n blockHeight: s.block_height,\n blockHash: s.block_hash,\n upgradedAt: s.upgraded_at,\n };\n}\n","// Minimal, dependency-free base64 <-> Uint8Array helpers. OTS proof bytes\n// are carried as base64 inside OC Stamp envelopes so they survive any text\n// transport (URL fragment, JSON, Nostr event content).\n\nconst B64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\nconst B64_DECODE_TABLE = (() => {\n const t = new Int16Array(128).fill(-1);\n for (let i = 0; i < B64_CHARS.length; i++) t[B64_CHARS.charCodeAt(i)] = i;\n t['='.charCodeAt(0)] = -2;\n return t;\n})();\n\nexport function base64Encode(bytes: Uint8Array): string {\n let out = '';\n let i = 0;\n for (; i + 2 < bytes.length; i += 3) {\n const a = bytes[i]!;\n const b = bytes[i + 1]!;\n const c = bytes[i + 2]!;\n out +=\n B64_CHARS[a >> 2]! +\n B64_CHARS[((a & 0x03) << 4) | (b >> 4)]! +\n B64_CHARS[((b & 0x0f) << 2) | (c >> 6)]! +\n B64_CHARS[c & 0x3f]!;\n }\n if (i < bytes.length) {\n const a = bytes[i]!;\n const b = i + 1 < bytes.length ? bytes[i + 1]! : 0;\n out += B64_CHARS[a >> 2]!;\n out += B64_CHARS[((a & 0x03) << 4) | (b >> 4)]!;\n out += i + 1 < bytes.length ? B64_CHARS[(b & 0x0f) << 2]! : '=';\n out += '=';\n }\n return out;\n}\n\nexport function base64Decode(s: string): Uint8Array {\n const str = s.replace(/\\s+/g, '');\n const len = str.length;\n if (len === 0) return new Uint8Array(0);\n if (len % 4 !== 0) throw new Error('base64: bad length');\n let padding = 0;\n if (str[len - 1] === '=') padding++;\n if (str[len - 2] === '=') padding++;\n const outLen = (len / 4) * 3 - padding;\n const out = new Uint8Array(outLen);\n let o = 0;\n for (let i = 0; i < len; i += 4) {\n const c0 = B64_DECODE_TABLE[str.charCodeAt(i)]!;\n const c1 = B64_DECODE_TABLE[str.charCodeAt(i + 1)]!;\n const c2 = B64_DECODE_TABLE[str.charCodeAt(i + 2)]!;\n const c3 = B64_DECODE_TABLE[str.charCodeAt(i + 3)]!;\n if (c0 < 0 || c1 < 0 || c2 < -2 || c3 < -2) throw new Error('base64: bad char');\n out[o++] = (c0 << 2) | (c1 >> 4);\n if (c2 >= 0) out[o++] = ((c1 & 0x0f) << 4) | (c2 >> 2);\n if (c3 >= 0) out[o++] = ((c2 & 0x03) << 6) | c3;\n }\n return out;\n}\n\nexport function hexDecode(s: string): Uint8Array {\n if (s.length % 2 !== 0) throw new Error('hex: odd length');\n const out = new Uint8Array(s.length / 2);\n for (let i = 0; i < out.length; i++) {\n const hi = parseInt(s[i * 2]!, 16);\n const lo = parseInt(s[i * 2 + 1]!, 16);\n if (Number.isNaN(hi) || Number.isNaN(lo)) throw new Error('hex: bad char');\n out[i] = (hi << 4) | lo;\n }\n return out;\n}\n\nexport function hexEncode(bytes: Uint8Array): string {\n const HEX = '0123456789abcdef';\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n const b = bytes[i]!;\n out += HEX[(b >> 4) & 0x0f]! + HEX[b & 0x0f]!;\n }\n return out;\n}\n","// HTTP client for an OpenTimestamps calendar. Implements the minimal subset\n// of the calendar protocol that an OC Stamp implementation needs:\n//\n// POST <url>/digest body = raw digest bytes -> pending proof bytes\n// GET <url>/timestamp/<hex(commitment)> -> continuation, or 404\n//\n// The client moves bytes only; ./ots.ts parses them.\n\nimport type { CalendarClient } from './types.js';\nimport { hexEncode } from './base64.js';\n\nexport const DEFAULT_CALENDARS: readonly string[] = [\n 'https://alice.btc.calendar.opentimestamps.org',\n 'https://bob.btc.calendar.opentimestamps.org',\n 'https://finney.calendar.eternitywall.com',\n];\n\nexport interface HttpCalendarOptions {\n /**\n * Custom fetch implementation. Defaults to global `fetch`. Useful in\n * environments that need a specific adapter (Node < 18, Cloudflare\n * Workers, proxies).\n */\n fetch?: typeof fetch;\n /** Request timeout in milliseconds. Default 30_000. */\n timeoutMs?: number;\n}\n\nexport function createCalendarClient(url: string, opts: HttpCalendarOptions = {}): CalendarClient {\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') {\n throw new Error(\n '@orangecheck/stamp-ots: no fetch implementation available. Pass one via { fetch }.'\n );\n }\n const timeoutMs = opts.timeoutMs ?? 30_000;\n const base = url.replace(/\\/$/, '');\n\n return {\n url: base,\n async submit(digest, signal) {\n if (digest.byteLength !== 32) {\n throw new Error('OTS: digest must be exactly 32 bytes');\n }\n const ac = withTimeout(signal, timeoutMs);\n // Uint8Array is a valid fetch body at runtime in Node 18+ and all\n // modern browsers, but TypeScript's DOM typings don't accept it\n // directly under `strict` + `noUncheckedIndexedAccess`. The cast is\n // narrow and intentional.\n // No Content-Type: a non-safelisted type makes browsers send a\n // CORS preflight, and OTS calendars answer OPTIONS with 501.\n const resp = await fetchImpl(`${base}/digest`, {\n method: 'POST',\n body: digest as unknown as BodyInit,\n signal: ac.signal,\n });\n ac.clear();\n if (!resp.ok) {\n throw new Error(`OTS calendar ${base} submit failed: HTTP ${resp.status}`);\n }\n const buf = await resp.arrayBuffer();\n return new Uint8Array(buf);\n },\n async fetchProof(commitment, signal) {\n if (commitment.byteLength === 0 || commitment.byteLength > 64) {\n throw new Error('OTS: commitment must be 1-64 bytes');\n }\n const ac = withTimeout(signal, timeoutMs);\n const resp = await fetchImpl(`${base}/timestamp/${hexEncode(commitment)}`, {\n method: 'GET',\n headers: { Accept: 'application/vnd.opentimestamps.v1' },\n signal: ac.signal,\n });\n ac.clear();\n if (resp.status === 404) return null;\n if (!resp.ok) {\n throw new Error(`OTS calendar ${base} fetchProof failed: HTTP ${resp.status}`);\n }\n const buf = await resp.arrayBuffer();\n return new Uint8Array(buf);\n },\n };\n}\n\nfunction withTimeout(parent: AbortSignal | undefined, ms: number): { signal: AbortSignal; clear: () => void } {\n const ac = new AbortController();\n const onParent = () => ac.abort((parent as AbortSignal & { reason?: unknown }).reason);\n if (parent) {\n if (parent.aborted) ac.abort((parent as AbortSignal & { reason?: unknown }).reason);\n else parent.addEventListener('abort', onParent, { once: true });\n }\n const t = setTimeout(() => ac.abort(new Error(`OTS request timed out after ${ms}ms`)), ms);\n return {\n signal: ac.signal,\n clear: () => {\n clearTimeout(t);\n if (parent) parent.removeEventListener('abort', onParent);\n },\n };\n}\n","// OpenTimestamps proof format: parse, walk, serialize, merge.\n//\n// Follows python-opentimestamps (core/timestamp.py, core/op.py,\n// core/notary.py). Two encodings are accepted:\n//\n// - a bare timestamp rooted at the digest (what an OTS calendar returns from\n// POST /digest, and what OC Stamp envelopes carry in `ots.proof`);\n// - a detached `.ots` file (magic header + file-hash op + digest + timestamp).\n\nimport { ripemd160, sha1 } from '@noble/hashes/legacy';\nimport { sha256 } from '@noble/hashes/sha2';\nimport { keccak_256 } from '@noble/hashes/sha3';\n\nimport { hexEncode } from './base64.js';\n\nconst HEADER_MAGIC = new Uint8Array([\n 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x00,\n 0x00, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x00, 0xbf, 0x89, 0xe2, 0xe8, 0x84, 0xe8, 0x92, 0x94,\n]);\n\nconst TAG_BITCOIN = '0588960d73d71901';\nconst TAG_PENDING = '83dfe30d2ef90c8e';\n\nconst MAX_DEPTH = 256;\nconst MAX_MSG = 4096;\n\nexport type OtsOp =\n | { kind: 'sha256' | 'ripemd160' | 'sha1' | 'keccak256' | 'reverse' | 'hexlify' }\n | { kind: 'append' | 'prepend'; arg: Uint8Array };\n\nexport type OtsAttestation =\n | { kind: 'bitcoin'; height: number }\n | { kind: 'pending'; uri: string }\n | { kind: 'unknown'; tag: string; payload: Uint8Array };\n\nexport interface OtsTimestamp {\n /** The message at this node: the digest after every op on the path to it. */\n msg: Uint8Array;\n attestations: OtsAttestation[];\n ops: { op: OtsOp; child: OtsTimestamp }[];\n}\n\nclass Reader {\n private pos = 0;\n constructor(private readonly buf: Uint8Array) {}\n byte(): number {\n if (this.pos >= this.buf.length) throw new Error('ots: unexpected end of proof');\n return this.buf[this.pos++]!;\n }\n bytes(n: number): Uint8Array {\n if (n < 0 || this.pos + n > this.buf.length) throw new Error('ots: unexpected end of proof');\n const out = this.buf.subarray(this.pos, this.pos + n);\n this.pos += n;\n return out;\n }\n varuint(): number {\n let value = 0;\n let shift = 0;\n for (;;) {\n const b = this.byte();\n value += (b & 0x7f) * 2 ** shift;\n if (!(b & 0x80)) return value;\n shift += 7;\n if (shift > 49) throw new Error('ots: varuint too large');\n }\n }\n varbytes(max: number): Uint8Array {\n const n = this.varuint();\n if (n > max) throw new Error('ots: varbytes too long');\n return this.bytes(n);\n }\n get done(): boolean {\n return this.pos === this.buf.length;\n }\n}\n\nconst UNARY: Record<number, OtsOp['kind']> = {\n 0x02: 'sha1',\n 0x03: 'ripemd160',\n 0x08: 'sha256',\n 0x67: 'keccak256',\n 0xf2: 'reverse',\n 0xf3: 'hexlify',\n};\n\nexport function applyOp(op: OtsOp, msg: Uint8Array): Uint8Array {\n switch (op.kind) {\n case 'sha256':\n return sha256(msg);\n case 'ripemd160':\n return ripemd160(msg);\n case 'sha1':\n return sha1(msg);\n case 'keccak256':\n return keccak_256(msg);\n case 'reverse':\n return new Uint8Array(msg).reverse();\n case 'hexlify':\n return new TextEncoder().encode(hexEncode(msg));\n case 'append':\n return concat(msg, op.arg);\n case 'prepend':\n return concat(op.arg, msg);\n }\n}\n\nfunction readOp(r: Reader, tag: number): OtsOp {\n const unary = UNARY[tag];\n if (unary) return { kind: unary } as OtsOp;\n if (tag === 0xf0) return { kind: 'append', arg: r.varbytes(MAX_MSG) };\n if (tag === 0xf1) return { kind: 'prepend', arg: r.varbytes(MAX_MSG) };\n throw new Error(`ots: unknown op tag 0x${tag.toString(16)}`);\n}\n\nfunction readAttestation(r: Reader): OtsAttestation {\n const tag = hexEncode(r.bytes(8));\n const payload = r.varbytes(8192);\n const p = new Reader(payload);\n if (tag === TAG_BITCOIN) return { kind: 'bitcoin', height: p.varuint() };\n if (tag === TAG_PENDING) return { kind: 'pending', uri: new TextDecoder().decode(p.varbytes(1000)) };\n return { kind: 'unknown', tag, payload };\n}\n\nfunction readTimestamp(r: Reader, msg: Uint8Array, depth: number): OtsTimestamp {\n if (depth > MAX_DEPTH) throw new Error('ots: proof too deep');\n const node: OtsTimestamp = { msg, attestations: [], ops: [] };\n const item = (tag: number) => {\n if (tag === 0x00) {\n node.attestations.push(readAttestation(r));\n return;\n }\n const op = readOp(r, tag);\n const next = applyOp(op, msg);\n if (next.length > MAX_MSG) throw new Error('ots: message too long');\n node.ops.push({ op, child: readTimestamp(r, next, depth + 1) });\n };\n let tag = r.byte();\n while (tag === 0xff) {\n item(r.byte());\n tag = r.byte();\n }\n item(tag);\n return node;\n}\n\n/** Parse a bare timestamp whose root message is `digest`. */\nexport function parseTimestamp(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp {\n const r = new Reader(bytes);\n const ts = readTimestamp(r, digest, 0);\n if (!r.done) throw new Error('ots: trailing bytes after timestamp');\n return ts;\n}\n\nexport function isDetached(bytes: Uint8Array): boolean {\n return bytes.length > HEADER_MAGIC.length && bytesEqual(bytes.subarray(0, HEADER_MAGIC.length), HEADER_MAGIC);\n}\n\n/** Parse a detached `.ots` file. Only sha256 file digests are accepted. */\nexport function parseDetached(bytes: Uint8Array): { digest: Uint8Array; timestamp: OtsTimestamp } {\n if (!isDetached(bytes)) throw new Error('ots: missing detached-file header');\n const r = new Reader(bytes.subarray(HEADER_MAGIC.length));\n const major = r.varuint();\n if (major !== 1) throw new Error(`ots: unsupported file version ${major}`);\n if (r.byte() !== 0x08) throw new Error('ots: only sha256 file digests are supported');\n const digest = new Uint8Array(r.bytes(32));\n const timestamp = readTimestamp(r, digest, 0);\n if (!r.done) throw new Error('ots: trailing bytes after timestamp');\n return { digest, timestamp };\n}\n\n/**\n * Parse either encoding and require that it commits to `digest`. A detached\n * file for some other digest is rejected rather than walked.\n */\nexport function parseProof(bytes: Uint8Array, digest: Uint8Array): OtsTimestamp {\n if (!isDetached(bytes)) return parseTimestamp(bytes, digest);\n const d = parseDetached(bytes);\n if (!bytesEqual(d.digest, digest)) throw new Error('ots: proof commits to a different digest');\n return d.timestamp;\n}\n\n/** Every attestation in the tree with the message it attests to. */\nexport function attestations(ts: OtsTimestamp): { msg: Uint8Array; attestation: OtsAttestation }[] {\n const out: { msg: Uint8Array; attestation: OtsAttestation }[] = [];\n const walk = (n: OtsTimestamp) => {\n for (const a of n.attestations) out.push({ msg: n.msg, attestation: a });\n for (const { child } of n.ops) walk(child);\n };\n walk(ts);\n return out;\n}\n\n/**\n * Bitcoin attestations, lowest height first. `merkleRoot` is the message at\n * the attestation, which equals the block header's Merkle root in header\n * byte order.\n */\nexport function bitcoinAnchors(ts: OtsTimestamp): { blockHeight: number; merkleRoot: Uint8Array }[] {\n return attestations(ts)\n .flatMap(({ msg, attestation }) =>\n attestation.kind === 'bitcoin' ? [{ blockHeight: attestation.height, merkleRoot: msg }] : []\n )\n .sort((a, b) => a.blockHeight - b.blockHeight);\n}\n\n/** Pending calendar attestations: where to ask, and the commitment to ask for. */\nexport function pendingCommitments(ts: OtsTimestamp): { uri: string; commitment: Uint8Array }[] {\n return attestations(ts).flatMap(({ msg, attestation }) =>\n attestation.kind === 'pending' ? [{ uri: attestation.uri, commitment: msg }] : []\n );\n}\n\n/**\n * Graft `upgrade` (a timestamp rooted at some node's message) onto the node\n * with that message, as python-opentimestamps' Timestamp.merge does. Returns\n * false when no node carries that message.\n */\nexport function mergeAt(ts: OtsTimestamp, upgrade: OtsTimestamp): boolean {\n if (bytesEqual(ts.msg, upgrade.msg)) {\n for (const a of upgrade.attestations) {\n if (!ts.attestations.some((b) => attestationKey(b) === attestationKey(a))) ts.attestations.push(a);\n }\n for (const { op, child } of upgrade.ops) {\n const same = ts.ops.find((o) => opKey(o.op) === opKey(op));\n if (same) mergeAt(same.child, child);\n else ts.ops.push({ op, child });\n }\n return true;\n }\n return ts.ops.some(({ child }) => mergeAt(child, upgrade));\n}\n\nfunction writeVaruint(out: number[], n: number) {\n do {\n let b = n % 128;\n n = Math.floor(n / 128);\n if (n > 0) b |= 0x80;\n out.push(b);\n } while (n > 0);\n}\n\nfunction writeVarbytes(out: number[], bytes: Uint8Array) {\n writeVaruint(out, bytes.length);\n out.push(...bytes);\n}\n\nconst OP_TAG: Record<OtsOp['kind'], number> = {\n sha1: 0x02,\n ripemd160: 0x03,\n sha256: 0x08,\n keccak256: 0x67,\n append: 0xf0,\n prepend: 0xf1,\n reverse: 0xf2,\n hexlify: 0xf3,\n};\n\nfunction writeAttestation(out: number[], a: OtsAttestation) {\n const payload: number[] = [];\n let tag: string;\n if (a.kind === 'bitcoin') {\n tag = TAG_BITCOIN;\n writeVaruint(payload, a.height);\n } else if (a.kind === 'pending') {\n tag = TAG_PENDING;\n writeVarbytes(payload, new TextEncoder().encode(a.uri));\n } else {\n tag = a.tag;\n payload.push(...a.payload);\n }\n out.push(0x00);\n for (let i = 0; i < 16; i += 2) out.push(parseInt(tag.slice(i, i + 2), 16));\n writeVarbytes(out, new Uint8Array(payload));\n}\n\nfunction writeTimestamp(out: number[], ts: OtsTimestamp) {\n const items: (() => void)[] = [\n ...ts.attestations.map((a) => () => writeAttestation(out, a)),\n ...ts.ops.map(({ op, child }) => () => {\n out.push(OP_TAG[op.kind]);\n if (op.kind === 'append' || op.kind === 'prepend') writeVarbytes(out, op.arg);\n writeTimestamp(out, child);\n }),\n ];\n if (items.length === 0) throw new Error('ots: cannot serialize an empty timestamp node');\n items.forEach((write, i) => {\n if (i < items.length - 1) out.push(0xff);\n write();\n });\n}\n\n/** Serialize as a bare timestamp (the encoding carried in `ots.proof`). */\nexport function serializeTimestamp(ts: OtsTimestamp): Uint8Array {\n const out: number[] = [];\n writeTimestamp(out, ts);\n return new Uint8Array(out);\n}\n\nfunction attestationKey(a: OtsAttestation): string {\n if (a.kind === 'bitcoin') return `b:${a.height}`;\n if (a.kind === 'pending') return `p:${a.uri}`;\n return `u:${a.tag}:${hexEncode(a.payload)}`;\n}\n\nfunction opKey(op: OtsOp): string {\n return 'arg' in op ? `${op.kind}:${hexEncode(op.arg)}` : op.kind;\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.length + b.length);\n out.set(a, 0);\n out.set(b, a.length);\n return out;\n}\n\nexport function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) return false;\n for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n","// Submit an envelope id to one or more OTS calendars. Returns a pending proof.\n// See SPEC.md §6.1.\n//\n// The submission strategy: try each calendar in parallel, take the first\n// success, report which calendar produced it. A stamp that only reaches one\n// calendar is a single point of failure for upgrade; the reference app\n// submits to at least two calendars for redundancy.\n\nimport { base64Encode, hexDecode } from './base64.js';\nimport { createCalendarClient, DEFAULT_CALENDARS } from './calendar.js';\nimport { mergeAt, parseTimestamp, serializeTimestamp, type OtsTimestamp } from './ots.js';\nimport type { CalendarClient, OtsProof } from './types.js';\n\nexport interface SubmitOptions {\n /**\n * Calendars to submit to. Defaults to DEFAULT_CALENDARS. Can be strings\n * (URLs) or pre-built CalendarClient instances.\n */\n calendars?: readonly (string | CalendarClient)[];\n /**\n * Minimum number of calendars that must succeed. Defaults to 1.\n * If fewer than `minSuccesses` calendars respond with a proof,\n * submit() throws an aggregate error.\n */\n minSuccesses?: number;\n /** Optional custom fetch passed through to calendar clients. */\n fetch?: typeof fetch;\n /** Request timeout per calendar. Default 30_000ms. */\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/**\n * Submit the envelope `id` (64-hex) to OTS calendars and return an OtsProof in\n * pending state. The caller merges this into the envelope's `ots` field.\n *\n * Each calendar answers with its own pending timestamp for the digest. They are\n * merged into one proof, so upgrade (see upgrade.ts) can ask any calendar that\n * answered. A calendar whose answer does not parse counts as a failure.\n */\nexport async function submitToCalendars(idHex: string, opts: SubmitOptions = {}): Promise<OtsProof> {\n const digest = hexDecode(idHex);\n if (digest.byteLength !== 32) {\n throw new Error('submitToCalendars: idHex must be 32 bytes (64 hex chars)');\n }\n\n const clients = (opts.calendars ?? DEFAULT_CALENDARS).map((c) =>\n typeof c === 'string'\n ? createCalendarClient(c, { fetch: opts.fetch, timeoutMs: opts.timeoutMs })\n : c\n );\n if (clients.length === 0) {\n throw new Error('submitToCalendars: at least one calendar is required');\n }\n const minSuccesses = Math.max(1, opts.minSuccesses ?? 1);\n\n const settled = await Promise.allSettled(\n clients.map(async (c) => {\n const proof = await c.submit(digest, opts.signal);\n return { url: c.url, proof };\n })\n );\n const successes = settled\n .filter((r): r is PromiseFulfilledResult<{ url: string; proof: Uint8Array }> => r.status === 'fulfilled')\n .map((r) => r.value);\n const failures = settled\n .filter((r): r is PromiseRejectedResult => r.status === 'rejected')\n .map((r) => (r.reason instanceof Error ? r.reason.message : String(r.reason)));\n\n if (successes.length < minSuccesses) {\n // AggregateError would be nicer but targets ES2021; Error keeps us at ES2020.\n const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join('; ')}`;\n const err = new Error(msg) as Error & { errors: string[] };\n err.errors = failures;\n throw err;\n }\n\n // Keep every calendar's receipt in one proof, so any of them can upgrade it.\n let tree: OtsTimestamp | null = null;\n const merged: string[] = [];\n for (const s of successes) {\n let receipt: OtsTimestamp;\n try {\n receipt = parseTimestamp(s.proof, digest);\n } catch (e) {\n failures.push(`${s.url}: unreadable proof (${e instanceof Error ? e.message : String(e)})`);\n continue;\n }\n if (tree) mergeAt(tree, receipt);\n else tree = receipt;\n merged.push(s.url);\n }\n if (!tree || merged.length < minSuccesses) {\n const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join('; ')}`;\n const err = new Error(msg) as Error & { errors: string[] };\n err.errors = failures;\n throw err;\n }\n return {\n status: 'pending',\n proof: base64Encode(serializeTimestamp(tree)),\n calendars: merged,\n blockHeight: null,\n blockHash: null,\n upgradedAt: null,\n };\n}\n","// Anchor verification. See SPEC.md §6.3.\n//\n// A confirmed anchor holds when all three are true:\n// 1. the proof commits to the envelope id and walks to a Bitcoin\n// attestation at the declared height;\n// 2. the message at that attestation equals the Merkle root in the block\n// header at that height;\n// 3. that header double-SHA256es to the declared block hash.\n//\n// The resulting function is what `@orangecheck/stamp-core` expects at the\n// `verifyOtsAnchor` input of `verify()`.\n\nimport { sha256 } from '@noble/hashes/sha2';\n\nimport { base64Decode, hexDecode, hexEncode } from './base64.js';\nimport { bitcoinAnchors, bytesEqual, parseProof } from './ots.js';\nimport type {\n AnchorVerificationInput,\n AnchorVerificationResult,\n AnchorVerifier,\n BlockHeaderSource,\n} from './types.js';\n\nexport interface AnchorVerifierConfig {\n /**\n * Parse the proof bytes and return the Merkle root the proof walks to,\n * plus its block height. Optional: the built-in OTS parser is used when\n * omitted. `blockHeight` is the declared height, for proofs that carry\n * attestations at more than one height.\n */\n walkProof?: (input: {\n proofBytes: Uint8Array;\n digest: Uint8Array;\n blockHeight?: number;\n }) => Promise<{ merkleRoot: Uint8Array; blockHeight: number } | null>;\n /**\n * Source of Bitcoin block headers: a full node, SPV, a headers snapshot,\n * or `mempoolHeaderSource()`. This is the verifier's trust anchor.\n */\n headerSource: BlockHeaderSource;\n}\n\n/** Built-in walker: parse the OTS proof and pick the Bitcoin attestation. */\nexport async function walkOtsProof(input: {\n proofBytes: Uint8Array;\n digest: Uint8Array;\n blockHeight?: number;\n}): Promise<{ merkleRoot: Uint8Array; blockHeight: number } | null> {\n try {\n const anchors = bitcoinAnchors(parseProof(input.proofBytes, input.digest));\n return anchors.find((a) => a.blockHeight === input.blockHeight) ?? anchors[0] ?? null;\n } catch {\n return null;\n }\n}\n\n/** Block hash (display hex) of an 80-byte header. */\nexport function blockHashOf(header: Uint8Array): string {\n return hexEncode(sha256(sha256(header)).reverse());\n}\n\nexport function makeAnchorVerifier(\n cfg: AnchorVerifierConfig\n): (proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean> {\n const walkProof = cfg.walkProof ?? walkOtsProof;\n const verifier: AnchorVerifier = async (\n input: AnchorVerificationInput\n ): Promise<AnchorVerificationResult> => {\n const walked = await walkProof({\n proofBytes: input.proofBytes,\n digest: input.digest,\n blockHeight: input.blockHeight,\n });\n if (!walked) {\n return { ok: false, reason: 'proof could not be walked to a Bitcoin commitment' };\n }\n if (walked.blockHeight !== input.blockHeight) {\n return {\n ok: false,\n reason: `proof anchors at block ${walked.blockHeight}, envelope declares ${input.blockHeight}`,\n };\n }\n const header = await cfg.headerSource.getHeaderAt(input.blockHeight);\n if (!header || header.byteLength !== 80) {\n return { ok: false, reason: `no block header available at height ${input.blockHeight}` };\n }\n if (blockHashOf(header) !== input.blockHash.toLowerCase()) {\n return { ok: false, reason: 'block header does not hash to the declared block hash' };\n }\n // OTS attests to the Merkle root in header byte order (offset 36).\n const headerMerkle = header.subarray(36, 68);\n if (!bytesEqual(headerMerkle, walked.merkleRoot)) {\n return { ok: false, reason: 'block header Merkle root does not match walked proof root' };\n }\n return { ok: true, merkleRoot: hexEncode(headerMerkle) };\n };\n\n return async (proofB64, blockHeight, blockHash, envelopeId) => {\n const r = await verifier({\n proofBytes: base64Decode(proofB64),\n digest: hexDecode(envelopeId),\n blockHeight,\n blockHash,\n });\n return r.ok;\n };\n}\n\n/**\n * Anchor verifier using the built-in OTS parser. Kept async for callers of the\n * 0.1 API, which lazily loaded an optional parser here.\n */\nexport async function makeDefaultAnchorVerifier(opts: {\n headerSource: BlockHeaderSource;\n}): Promise<\n (proofB64: string, blockHeight: number, blockHash: string, envelopeId: string) => Promise<boolean>\n> {\n return makeAnchorVerifier({ headerSource: opts.headerSource });\n}\n\nexport interface MempoolHeaderSourceOptions {\n /** Esplora-compatible API base. Default https://mempool.space/api. */\n baseUrl?: string;\n fetch?: typeof fetch;\n}\n\n/**\n * Block headers from an Esplora-compatible API. The verifier checks each\n * header against the declared block hash, so this source is trusted only to\n * report which block is at a height.\n */\nexport function mempoolHeaderSource(opts: MempoolHeaderSourceOptions = {}): BlockHeaderSource {\n const base = (opts.baseUrl ?? 'https://mempool.space/api').replace(/\\/+$/, '');\n const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);\n return {\n async getHeaderAt(height) {\n const h = await fetchImpl(`${base}/block-height/${height}`);\n if (!h.ok) return null;\n const hash = (await h.text()).trim();\n if (!/^[0-9a-f]{64}$/.test(hash)) return null;\n const r = await fetchImpl(`${base}/block/${hash}/header`);\n if (!r.ok) return null;\n const hex = (await r.text()).trim();\n return /^[0-9a-f]{160}$/.test(hex) ? hexDecode(hex) : null;\n },\n };\n}\n","// Upgrade a pending OTS proof to a confirmed one. See SPEC.md §6.2.\n//\n// A pending proof ends in calendar attestations, each naming a calendar and\n// the commitment (the message at that leaf) the calendar will later anchor.\n// Calendars index upgrades by that commitment, not by the submitted digest.\n// For each pending leaf we ask its calendar for the continuation, graft it on,\n// and report the proof as confirmed once it reaches a Bitcoin attestation\n// whose block header checks out.\n\nimport { blockHashOf } from './anchor.js';\nimport { base64Decode, base64Encode, hexDecode } from './base64.js';\nimport { createCalendarClient } from './calendar.js';\nimport {\n bitcoinAnchors,\n bytesEqual,\n mergeAt,\n parseProof,\n parseTimestamp,\n pendingCommitments,\n serializeTimestamp,\n} from './ots.js';\nimport type { BlockHeaderSource, OtsProof } from './types.js';\n\nexport interface UpgradeOptions {\n /**\n * Header source used to resolve the anchor's block hash and to check that\n * the proof's Merkle root is in that block.\n */\n headerSource?: BlockHeaderSource;\n /**\n * Alternative to `headerSource`: given the merged proof bytes, return the\n * anchor if the proof is confirmed, else null.\n */\n parseAnchor?: (proofBytes: Uint8Array) => Promise<{ blockHeight: number; blockHash: string } | null>;\n /** Optional custom fetch passed through to calendar clients. */\n fetch?: typeof fetch;\n /** Request timeout per calendar. Default 30_000ms. */\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\nconst norm = (u: string) => u.replace(/\\/+$/, '');\n\nexport async function upgradeProof(\n current: OtsProof,\n idHex: string,\n opts: UpgradeOptions\n): Promise<OtsProof> {\n if (current.status === 'confirmed') return current; // idempotent\n if (!opts.headerSource && !opts.parseAnchor) {\n throw new Error('upgradeProof: pass headerSource or parseAnchor');\n }\n\n const before = base64Decode(current.proof);\n const tree = parseProof(before, hexDecode(idHex));\n\n // Only ask calendars this proof was submitted to.\n const listed = new Set(current.calendars.map(norm));\n const pending = pendingCommitments(tree).filter((p) => listed.has(norm(p.uri)));\n if (pending.length === 0 && bitcoinAnchors(tree).length === 0) {\n throw new Error('upgradeProof: proof has no pending attestation from a listed calendar');\n }\n\n const answered: string[] = [];\n await Promise.allSettled(\n pending.map(async ({ uri, commitment }) => {\n const client = createCalendarClient(uri, { fetch: opts.fetch, timeoutMs: opts.timeoutMs });\n const bytes = await client.fetchProof(commitment, opts.signal);\n if (!bytes) return;\n if (mergeAt(tree, parseTimestamp(bytes, commitment))) answered.push(norm(uri));\n })\n );\n\n const merged = serializeTimestamp(tree);\n const anchor = await resolveAnchor(merged, tree, opts);\n const calendars = [...answered, ...current.calendars.filter((c) => !answered.includes(norm(c)))];\n\n if (anchor) {\n return {\n status: 'confirmed',\n proof: base64Encode(merged),\n calendars,\n blockHeight: anchor.blockHeight,\n blockHash: anchor.blockHash,\n upgradedAt: new Date().toISOString().replace(/\\.\\d+Z$/, 'Z'),\n };\n }\n if (!bytesEqual(merged, before)) {\n return { ...current, proof: base64Encode(merged), calendars };\n }\n return current;\n}\n\nasync function resolveAnchor(\n merged: Uint8Array,\n tree: ReturnType<typeof parseTimestamp>,\n opts: UpgradeOptions\n): Promise<{ blockHeight: number; blockHash: string } | null> {\n if (opts.parseAnchor) return opts.parseAnchor(merged);\n for (const a of bitcoinAnchors(tree)) {\n const header = await opts.headerSource!.getHeaderAt(a.blockHeight);\n if (header && header.byteLength === 80 && bytesEqual(header.subarray(36, 68), a.merkleRoot)) {\n return { blockHeight: a.blockHeight, blockHash: blockHashOf(header) };\n }\n }\n return null;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orangecheck/stamp-ots",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "OpenTimestamps calendar client, proof helpers, and anchor-verification hooks for OC Stamp envelopes. See https://github.com/orangecheck/oc-stamp-protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bitcoin",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@noble/hashes": "^1.8.0",
|
|
52
|
-
"@orangecheck/stamp-core": "^0.
|
|
52
|
+
"@orangecheck/stamp-core": "^1.0.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/node": "^22.10.2",
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// The anchor verifier plugged into @orangecheck/stamp-core 1.x verify(), end
|
|
2
|
+
// to end: SPEC §8 step 5 through the `verifyOtsAnchor` hook.
|
|
3
|
+
|
|
4
|
+
import { verify, type StampEnvelope } from '@orangecheck/stamp-core';
|
|
5
|
+
import { sha256 } from '@noble/hashes/sha2';
|
|
6
|
+
import { describe, expect, it } from 'vitest';
|
|
7
|
+
|
|
8
|
+
import { blockHashOf, makeAnchorVerifier } from './anchor.js';
|
|
9
|
+
import { base64Encode, hexDecode } from './base64.js';
|
|
10
|
+
import { serializeTimestamp, type OtsTimestamp } from './ots.js';
|
|
11
|
+
|
|
12
|
+
// oc-stamp-protocol test-vectors/v01-minimal.json (placeholder signature).
|
|
13
|
+
const ENVELOPE = {
|
|
14
|
+
v: 1,
|
|
15
|
+
kind: 'stamp',
|
|
16
|
+
id: 'ad30c983dfc872a8c53cd70eb4d84e1869967a4b8433586beec7ba468b03c3de',
|
|
17
|
+
content: {
|
|
18
|
+
hash: 'sha256:1111111111111111111111111111111111111111111111111111111111111111',
|
|
19
|
+
length: 42,
|
|
20
|
+
mime: 'text/plain',
|
|
21
|
+
ref: null,
|
|
22
|
+
},
|
|
23
|
+
signer: { address: 'bc1qalice000000000000000000000000000000000', alg: 'bip322' },
|
|
24
|
+
signed_at: '2026-04-24T18:30:00Z',
|
|
25
|
+
stake: null,
|
|
26
|
+
ots: null,
|
|
27
|
+
sig: { alg: 'bip322', pubkey: 'bc1qalice000000000000000000000000000000000', value: 'ZmFrZS1zaWduYXR1cmU=' },
|
|
28
|
+
} as unknown as StampEnvelope;
|
|
29
|
+
|
|
30
|
+
const HEIGHT = 900_000;
|
|
31
|
+
const idBytes = hexDecode(ENVELOPE.id);
|
|
32
|
+
const root = sha256(idBytes);
|
|
33
|
+
// id --sha256--> root, attested at HEIGHT.
|
|
34
|
+
const proofTree: OtsTimestamp = {
|
|
35
|
+
msg: idBytes,
|
|
36
|
+
attestations: [],
|
|
37
|
+
ops: [{ op: { kind: 'sha256' }, child: { msg: root, attestations: [{ kind: 'bitcoin', height: HEIGHT }], ops: [] } }],
|
|
38
|
+
};
|
|
39
|
+
const header = new Uint8Array(80);
|
|
40
|
+
header.set(root, 36);
|
|
41
|
+
const HASH = blockHashOf(header);
|
|
42
|
+
const headers = { getHeaderAt: async (h: number) => (h === HEIGHT ? header : null) };
|
|
43
|
+
|
|
44
|
+
function withOts(blockHash = HASH): StampEnvelope {
|
|
45
|
+
return {
|
|
46
|
+
...ENVELOPE,
|
|
47
|
+
ots: {
|
|
48
|
+
status: 'confirmed',
|
|
49
|
+
proof: base64Encode(serializeTimestamp(proofTree)),
|
|
50
|
+
calendars: ['https://alice.btc.calendar.opentimestamps.org'],
|
|
51
|
+
block_height: HEIGHT,
|
|
52
|
+
block_hash: blockHash,
|
|
53
|
+
upgraded_at: '2026-09-24T00:00:00Z',
|
|
54
|
+
},
|
|
55
|
+
} as StampEnvelope;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe('stamp-core verify() with makeAnchorVerifier', () => {
|
|
59
|
+
const verifyOtsAnchor = makeAnchorVerifier({ headerSource: headers });
|
|
60
|
+
|
|
61
|
+
it('reports a verified confirmed anchor', async () => {
|
|
62
|
+
const r = await verify({ envelope: withOts(), skipSignatureVerification: true, verifyOtsAnchor });
|
|
63
|
+
expect(r.ok && r.anchor).toEqual({ status: 'confirmed', blockHeight: HEIGHT, blockHash: HASH, verified: true });
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('fails E_BAD_ANCHOR when the claimed block hash is not the header at that height', async () => {
|
|
67
|
+
const r = await verify({
|
|
68
|
+
envelope: withOts('00'.repeat(32)),
|
|
69
|
+
skipSignatureVerification: true,
|
|
70
|
+
verifyOtsAnchor,
|
|
71
|
+
});
|
|
72
|
+
expect(r.ok ? 'ok' : r.code).toBe('E_BAD_ANCHOR');
|
|
73
|
+
});
|
|
74
|
+
});
|
package/src/submit.test.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
import { describe, expect, it } from 'vitest';
|
|
5
5
|
|
|
6
|
+
import { base64Decode, hexDecode } from './base64.js';
|
|
7
|
+
import { parseProof, pendingCommitments } from './ots.js';
|
|
6
8
|
import { submitToCalendars } from './submit.js';
|
|
7
9
|
import { upgradeProof } from './upgrade.js';
|
|
8
10
|
import type { CalendarClient, OtsProof } from './types.js';
|
|
@@ -32,22 +34,57 @@ function fakeCalendar(opts: {
|
|
|
32
34
|
};
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
// A calendar's answer to POST /digest: append a nonce, sha256, pending attestation for its URL.
|
|
38
|
+
function pendingReceipt(url: string, nonceByte: number): Uint8Array {
|
|
39
|
+
const uri = new TextEncoder().encode(url);
|
|
40
|
+
const nonce = new Uint8Array(16).fill(nonceByte);
|
|
41
|
+
const pendingTag = [0x83, 0xdf, 0xe3, 0x0d, 0x2e, 0xf9, 0x0c, 0x8e];
|
|
42
|
+
return new Uint8Array([0xf0, 0x10, ...nonce, 0x08, 0x00, ...pendingTag, uri.length + 1, uri.length, ...uri]);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const pendingUris = (p: OtsProof) =>
|
|
46
|
+
pendingCommitments(parseProof(base64Decode(p.proof), hexDecode(FIXED_ID))).map((c) => c.uri);
|
|
47
|
+
|
|
35
48
|
describe('submitToCalendars', () => {
|
|
36
|
-
it('
|
|
37
|
-
const cal1 = fakeCalendar({ url: 'https://a.example', submitResult:
|
|
38
|
-
const cal2 = fakeCalendar({ url: 'https://b.example', submitResult:
|
|
49
|
+
it('keeps every calendar receipt in the proof and lists each calendar', async () => {
|
|
50
|
+
const cal1 = fakeCalendar({ url: 'https://a.example', submitResult: pendingReceipt('https://a.example', 1) });
|
|
51
|
+
const cal2 = fakeCalendar({ url: 'https://b.example', submitResult: pendingReceipt('https://b.example', 2) });
|
|
39
52
|
const out = await submitToCalendars(FIXED_ID, { calendars: [cal1, cal2] });
|
|
40
53
|
expect(out.status).toBe('pending');
|
|
41
54
|
expect(out.calendars).toEqual(['https://a.example', 'https://b.example']);
|
|
42
55
|
expect(out.blockHeight).toBeNull();
|
|
43
|
-
expect(out.
|
|
56
|
+
expect(pendingUris(out).sort()).toEqual(['https://a.example', 'https://b.example']);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('lets a second calendar upgrade the proof when the first is gone', async () => {
|
|
60
|
+
const cal1 = fakeCalendar({ url: 'https://a.example', submitResult: pendingReceipt('https://a.example', 1) });
|
|
61
|
+
const cal2 = fakeCalendar({ url: 'https://b.example', submitResult: pendingReceipt('https://b.example', 2) });
|
|
62
|
+
const out = await submitToCalendars(FIXED_ID, { calendars: [cal1, cal2] });
|
|
63
|
+
const asked: string[] = [];
|
|
64
|
+
await upgradeProof(out, FIXED_ID, {
|
|
65
|
+
parseAnchor: async () => null,
|
|
66
|
+
fetch: (async (url: string) => {
|
|
67
|
+
asked.push(new URL(url).origin);
|
|
68
|
+
return new Response(null, { status: 404 });
|
|
69
|
+
}) as unknown as typeof fetch,
|
|
70
|
+
});
|
|
71
|
+
expect(asked.sort()).toEqual(['https://a.example', 'https://b.example']);
|
|
44
72
|
});
|
|
45
73
|
|
|
46
74
|
it('tolerates one calendar failure when minSuccesses defaults to 1', async () => {
|
|
47
75
|
const bad = fakeCalendar({ url: 'https://bad.example', submitShouldFail: true });
|
|
48
|
-
const good = fakeCalendar({ url: 'https://good.example', submitResult:
|
|
76
|
+
const good = fakeCalendar({ url: 'https://good.example', submitResult: pendingReceipt('https://good.example', 9) });
|
|
49
77
|
const out = await submitToCalendars(FIXED_ID, { calendars: [bad, good] });
|
|
50
78
|
expect(out.calendars).toEqual(['https://good.example']);
|
|
79
|
+
expect(pendingUris(out)).toEqual(['https://good.example']);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('counts an unreadable receipt as a failure', async () => {
|
|
83
|
+
const junk = fakeCalendar({ url: 'https://junk.example', submitResult: new Uint8Array([1, 2, 3]) });
|
|
84
|
+
const good = fakeCalendar({ url: 'https://good.example', submitResult: pendingReceipt('https://good.example', 9) });
|
|
85
|
+
const out = await submitToCalendars(FIXED_ID, { calendars: [junk, good] });
|
|
86
|
+
expect(out.calendars).toEqual(['https://good.example']);
|
|
87
|
+
await expect(submitToCalendars(FIXED_ID, { calendars: [junk] })).rejects.toThrow(/unreadable proof/);
|
|
51
88
|
});
|
|
52
89
|
|
|
53
90
|
it('throws when minSuccesses is not met', async () => {
|
package/src/submit.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { base64Encode, hexDecode } from './base64.js';
|
|
10
10
|
import { createCalendarClient, DEFAULT_CALENDARS } from './calendar.js';
|
|
11
|
+
import { mergeAt, parseTimestamp, serializeTimestamp, type OtsTimestamp } from './ots.js';
|
|
11
12
|
import type { CalendarClient, OtsProof } from './types.js';
|
|
12
13
|
|
|
13
14
|
export interface SubmitOptions {
|
|
@@ -33,12 +34,9 @@ export interface SubmitOptions {
|
|
|
33
34
|
* Submit the envelope `id` (64-hex) to OTS calendars and return an OtsProof in
|
|
34
35
|
* pending state. The caller merges this into the envelope's `ots` field.
|
|
35
36
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* same digest, we carry the FIRST successful calendar's bytes in the
|
|
40
|
-
* envelope. Upgrade (see upgrade.ts) can fetch richer proofs from any of the
|
|
41
|
-
* submitted-to calendars later.
|
|
37
|
+
* Each calendar answers with its own pending timestamp for the digest. They are
|
|
38
|
+
* merged into one proof, so upgrade (see upgrade.ts) can ask any calendar that
|
|
39
|
+
* answered. A calendar whose answer does not parse counts as a failure.
|
|
42
40
|
*/
|
|
43
41
|
export async function submitToCalendars(idHex: string, opts: SubmitOptions = {}): Promise<OtsProof> {
|
|
44
42
|
const digest = hexDecode(idHex);
|
|
@@ -77,11 +75,31 @@ export async function submitToCalendars(idHex: string, opts: SubmitOptions = {})
|
|
|
77
75
|
throw err;
|
|
78
76
|
}
|
|
79
77
|
|
|
80
|
-
|
|
78
|
+
// Keep every calendar's receipt in one proof, so any of them can upgrade it.
|
|
79
|
+
let tree: OtsTimestamp | null = null;
|
|
80
|
+
const merged: string[] = [];
|
|
81
|
+
for (const s of successes) {
|
|
82
|
+
let receipt: OtsTimestamp;
|
|
83
|
+
try {
|
|
84
|
+
receipt = parseTimestamp(s.proof, digest);
|
|
85
|
+
} catch (e) {
|
|
86
|
+
failures.push(`${s.url}: unreadable proof (${e instanceof Error ? e.message : String(e)})`);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (tree) mergeAt(tree, receipt);
|
|
90
|
+
else tree = receipt;
|
|
91
|
+
merged.push(s.url);
|
|
92
|
+
}
|
|
93
|
+
if (!tree || merged.length < minSuccesses) {
|
|
94
|
+
const msg = `OTS submission did not reach ${minSuccesses} calendar(s). Errors: ${failures.join('; ')}`;
|
|
95
|
+
const err = new Error(msg) as Error & { errors: string[] };
|
|
96
|
+
err.errors = failures;
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
81
99
|
return {
|
|
82
100
|
status: 'pending',
|
|
83
|
-
proof: base64Encode(
|
|
84
|
-
calendars:
|
|
101
|
+
proof: base64Encode(serializeTimestamp(tree)),
|
|
102
|
+
calendars: merged,
|
|
85
103
|
blockHeight: null,
|
|
86
104
|
blockHash: null,
|
|
87
105
|
upgradedAt: null,
|