@aleutian/verification 0.0.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +597 -0
- package/LICENSE +201 -0
- package/README.md +485 -0
- package/dist/browser/index.d.ts +3093 -0
- package/dist/browser/index.global.js +9747 -0
- package/dist/browser/index.global.js.map +1 -0
- package/dist/browser/index.js +5358 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/cli/aleutian-verify.js +3841 -0
- package/dist/cli/aleutian-verify.js.map +1 -0
- package/dist/index.cjs +5758 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3505 -0
- package/dist/index.d.ts +3505 -0
- package/dist/index.js +5609 -0
- package/dist/index.js.map +1 -0
- package/package.json +96 -5
- package/testdata/v3_golden_capture_request.json +85 -0
- package/testdata/v3_golden_capture_signed.json +27 -0
- package/testdata/v3_golden_sar_acknowledged.json +21 -0
- package/testdata/v3_golden_sar_extended.json +40 -0
- package/testdata/v3_golden_sar_fulfilled.json +46 -0
- package/testdata/v3_golden_sar_intent.json +60 -0
- package/testdata/v3_golden_sar_rejected.json +40 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/errors.ts","../../src/hash.ts","../../src/tombstone.ts","../../src/chain.ts","../../src/anchorChainHash.ts","../../src/fixtures/embedded-keys-dev.json","../../src/fixtures/embedded-keys-staging.json","../../src/fixtures/embedded-keys-prod.json","../../src/keys.ts","../../src/canonicalBase64.ts","../../src/anchorCanonical.ts","../../src/anchor.ts","../../src/strictJson.ts","../../src/strictText.ts","../../src/anchorLoaders.ts","../../src/chainV4.ts","../../src/internal/constantTime.ts","../../src/verify.ts","../../src/manifestFreshness.ts","../../src/keyId.ts","../../src/sarEntries.ts","../../src/canonicalV3.ts","../../src/proofBundleReader.ts","../../src/commitment.ts","../../src/proofBundleHashes.ts","../../src/sinkShapes.ts","../../src/recordEnvelope.ts","../../src/proofBundle.ts","../../src/proofKeyFile.ts","../../src/fixtures/trust-root-dev.json","../../src/fixtures/trust-root-staging.json","../../src/fixtures/trust-root-prod.json","../../src/trustManifest.ts","../../src/cli/verifyProofBundle.ts","../../src/cli/verifyBundle.ts","../../src/cli/aleutian-verify.ts"],"names":["MAX_INT64","LONE_SURROGATE","utf8ToBytes","bytesToHex","sha512","expectedHash","concat","QUOTE","HEX_128","HEX_64","MAX_GLOBAL_SEQ","MLDSA65_PUBLIC_KEY_SIZE","EMPTY_CONTEXT","ml_dsa65","MLDSA65_SIGNATURE_SIZE","parseArgs","readFile"],"mappings":"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","file":"aleutian-verify.js","sourcesContent":["// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Error thrown when anchor signature verification fails.\n */\nexport class AnchorVerificationError extends Error {\n override readonly name = \"AnchorVerificationError\";\n\n constructor(message: string) {\n super(message);\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, AnchorVerificationError);\n }\n }\n}\n\n/**\n * Error thrown when chain verification encounters an unrecoverable error.\n */\nexport class ChainVerificationError extends Error {\n override readonly name = \"ChainVerificationError\";\n\n constructor(message: string) {\n super(message);\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ChainVerificationError);\n }\n }\n}\n\n/**\n * Thrown when the text of an entries file is not entries (format-spec §11):\n * not JSON, an empty document, an export bundle, an anchor, or an entry with a\n * repeated, misspelled, missing or wrongly typed member.\n *\n * This is an ERROR, never a broken chain: a file that is not entries says\n * nothing about any chain. Messages name a member, never a value.\n */\nexport class EntriesFormatError extends Error {\n override readonly name = \"EntriesFormatError\";\n\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, EntriesFormatError.prototype);\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, EntriesFormatError);\n }\n }\n}\n\n/**\n * Error codes for webhook verification failures.\n */\nexport type WebhookErrorCode =\n | \"INVALID_FORMAT\"\n | \"INVALID_TIMESTAMP\"\n | \"EXPIRED\"\n | \"FUTURE\"\n | \"INVALID_SIGNATURE\"\n | \"NO_MATCHING_SECRET\"\n | \"SECRET_TOO_SHORT\";\n\n/**\n * Error thrown when webhook signature verification fails.\n */\nexport class WebhookVerificationError extends Error {\n override readonly name = \"WebhookVerificationError\";\n readonly code: WebhookErrorCode;\n\n constructor(code: WebhookErrorCode, message: string) {\n super(`[${code}] ${message}`);\n this.code = code;\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, WebhookVerificationError);\n }\n }\n}\n\n/**\n * Thrown when a ConsentChainEntry fails canonical field validation.\n *\n * Error messages include the field name but NEVER the field value, to prevent\n * log injection from caller-controlled content.\n */\nexport class InvalidConsentEntryError extends Error {\n override readonly name = \"InvalidConsentEntryError\";\n\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, InvalidConsentEntryError.prototype);\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, InvalidConsentEntryError);\n }\n }\n}\n\n/**\n * Thrown when consent chain entry verification fails for cryptographic reasons:\n * unknown key ID, wrong signature length, content hash mismatch, or failed\n * ML-DSA-65 verification.\n *\n * Error messages do not include signature bytes or key material.\n */\nexport class ConsentVerificationError extends Error {\n override readonly name = \"ConsentVerificationError\";\n\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, ConsentVerificationError.prototype);\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ConsentVerificationError);\n }\n }\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * SHA-512 hash abstraction using WebCrypto (requires Node.js >= 19 or any modern browser).\n */\n\n/**\n * Convert a base64 string to Uint8Array.\n *\n * Works in both browser (atob) and Node.js (Buffer).\n *\n * @param base64 - Base64 encoded string\n * @returns Decoded bytes as Uint8Array\n */\nexport function base64ToUint8Array(base64: string): Uint8Array {\n if (typeof Buffer !== \"undefined\") {\n // Node.js\n return new Uint8Array(Buffer.from(base64, \"base64\"));\n } else {\n // Browser\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n }\n}\n\n/**\n * Convert Uint8Array to base64 string.\n *\n * @param bytes - Bytes to encode\n * @returns Base64 encoded string\n */\nexport function uint8ArrayToBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") {\n // Node.js\n return Buffer.from(bytes).toString(\"base64\");\n } else {\n // Browser\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n return btoa(binary);\n }\n}\n\n/**\n * Convert Uint8Array to lowercase hex string.\n *\n * @param bytes - Bytes to encode\n * @returns Lowercase hex string\n */\nexport function uint8ArrayToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Compute SHA-512 hash, returning lowercase hex string.\n *\n * Uses the WebCrypto API (globalThis.crypto.subtle), which is available\n * natively in all modern browsers and in Node.js >= 19 (without flags).\n * Node.js 20+ (LTS) is recommended. Node.js < 19 is not supported for\n * chain hash computation.\n *\n * This function is async because WebCrypto's `digest` is always async.\n * (Historical note: a sync `sha256Hex` predated the project-wide\n * SHA-256 → SHA-512 upgrade — see `dsar_chain_f_pre_js_webhook_sha512`\n * — and was removed; this is the only SHA hash entry point now.)\n *\n * @param data - String to hash (encoded as UTF-8)\n * @returns Promise resolving to 128-character lowercase hex string\n */\nexport async function sha512Hex(data: string): Promise<string> {\n const encoder = new TextEncoder();\n const bytes = encoder.encode(data);\n const hashBuffer = await crypto.subtle.digest(\"SHA-512\", bytes);\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Compute SHA-512 hash of raw bytes, returning lowercase hex string.\n *\n * Unlike {@link sha512Hex}, this function accepts a pre-built Uint8Array\n * directly. Use this when the preimage is already assembled as bytes —\n * avoids a string round-trip and correctly handles arbitrary binary data.\n *\n * @param data - Raw bytes to hash\n * @returns Promise resolving to 128-character lowercase hex string\n */\nexport async function sha512HexRaw(data: Uint8Array): Promise<string> {\n const hashBuffer = await crypto.subtle.digest(\"SHA-512\", data);\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Convert hex string to Uint8Array.\n *\n * @param hex - Hex encoded string\n * @returns Decoded bytes as Uint8Array\n */\nexport function hexToUint8Array(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Tombstone detection and validation for the Aleutian verification SDK.\n *\n * Tombstones are GDPR deletion markers that replace original entries while\n * preserving chain integrity. They have specific format requirements that\n * must be validated during chain verification.\n */\n\n/**\n * Prefix for tombstone content hashes.\n */\nexport const TOMBSTONE_CONTENT_HASH_PREFIX = \"TOMBSTONE:\";\n\n/**\n * Prefix for tombstone entry IDs.\n */\nexport const TOMBSTONE_ENTRY_ID_PREFIX = \"tomb_\";\n\n/**\n * Entry type value for tombstones.\n */\nexport const TOMBSTONE_ENTRY_TYPE = \"tombstone\";\n\n/**\n * Regex for validating tombstone content hash hex suffix.\n * Must be exactly 64 lowercase hex characters (32 random bytes, hex-encoded).\n */\nconst HEX_PATTERN = /^[0-9a-f]{64}$/;\n\n/**\n * Check if an entry is a tombstone based on entryType and entryId.\n *\n * Both conditions must be true:\n * - entryType === \"tombstone\"\n * - entryId starts with \"tomb_\"\n *\n * @param entryType - The entry's type field\n * @param entryId - The entry's ID field\n * @returns True if entry is a tombstone\n *\n * @example\n * ```typescript\n * if (isTombstone(entry.entryType, entry.entryId)) {\n * // Handle tombstone entry\n * }\n * ```\n */\nexport function isTombstone(entryType: string, entryId: string): boolean {\n return (\n entryType === TOMBSTONE_ENTRY_TYPE &&\n entryId.startsWith(TOMBSTONE_ENTRY_ID_PREFIX)\n );\n}\n\n/**\n * Check if a contentHash uses tombstone format (prefix check only).\n *\n * This is a lightweight check for hot paths. Use validateTombstoneContentHash\n * for full format validation.\n *\n * @param contentHash - The content hash to check\n * @returns True if content hash starts with \"TOMBSTONE:\"\n *\n * @example\n * ```typescript\n * if (isTombstoneContentHash(entry.contentHash)) {\n * // Content was deleted, original data not available\n * }\n * ```\n */\nexport function isTombstoneContentHash(contentHash: string): boolean {\n return contentHash.startsWith(TOMBSTONE_CONTENT_HASH_PREFIX);\n}\n\n/**\n * Fully validate tombstone content hash format.\n *\n * Valid format: \"TOMBSTONE:\" + 64 lowercase hex characters (32 random bytes)\n * Total length: 74 characters (10 prefix + 64 hex)\n *\n * @param contentHash - The content hash to validate\n * @returns True if format is valid\n *\n * @example\n * ```typescript\n * if (isTombstone(entry.entryType, entry.entryId)) {\n * if (!validateTombstoneContentHash(entry.contentHash)) {\n * // Invalid tombstone format - chain integrity issue\n * }\n * }\n * ```\n */\nexport function validateTombstoneContentHash(contentHash: string): boolean {\n // Total length: \"TOMBSTONE:\" (10) + 64 hex = 74\n if (contentHash.length !== 74) {\n return false;\n }\n if (!contentHash.startsWith(TOMBSTONE_CONTENT_HASH_PREFIX)) {\n return false;\n }\n const hexPart = contentHash.slice(10);\n return HEX_PATTERN.test(hexPart);\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Chain hash computation for the Aleutian verification SDK.\n *\n * Uses Aleutian's chain hash formula:\n * SHA512(\"aleutian.chain.v2:\" + prev + \"|\" + runID + \"|\" + seq + \"|\" + ts + \"|\" + content)\n *\n * Timestamp format: \"2006-01-02T15:04:05.000000Z\" (microsecond precision, 6 digits)\n *\n * NOTE: Unlike what the security review suggested (M-9), the Go SDK does NOT use\n * NFC normalization. This SDK matches Go behavior for cross-SDK compatibility.\n */\n\nimport { sha512Hex } from \"./hash.js\";\nimport { validateTombstoneContentHash } from \"./tombstone.js\";\n\n/**\n * Domain prefix for chain hash computation.\n * This provides domain separation for the hash function.\n */\nexport const CHAIN_HASH_PREFIX = \"aleutian.chain.v2:\";\n\n/**\n * Domain prefix for the v3 chain hash.\n *\n * The \":\" terminator separates the prefix from field data, which is\n * \"|\"-delimited.\n */\nexport const CHAIN_HASH_PREFIX_V3 = \"aleutian.chain.v3:\";\n\n/**\n * Chain hash format versions.\n *\n * An entry records WHICH preimage produced its hash, because the two cannot be\n * told apart by looking at the digest. A verifier that guesses is a verifier\n * that reports false breaks.\n *\n * ZERO MEANS V2, deliberately: every entry written before v3 existed has no\n * version field at all, and an absent field decodes as zero. Treating zero as\n * \"the format that was current when versions were not recorded\" is what keeps\n * those entries verifiable without rewriting them.\n */\nexport const FORMAT_V2 = 2;\nexport const FORMAT_V3 = 3;\n\n// A SHA-512 digest as format-spec §2.1 writes it: exactly 128 lowercase hex.\nconst HASH_HEX = /^[0-9a-f]{128}$/;\n// format-spec §4: UTC, exactly six fractional digits, \"Z\". ASCII digits only\n// (`\\d` would do, but the class says so outright).\nconst TIMESTAMP_FORM =\n /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})\\.[0-9]{6}Z$/;\n// global_seq is a signed 64-bit integer in every implementation (format-spec §2.1).\nconst MAX_GLOBAL_SEQ = 2n ** 63n - 1n;\n\n/**\n * Report whether a value is a SHA-512 digest as the format writes it: exactly\n * 128 lowercase hex characters (format-spec §1). Uppercase is invalid, not\n * equivalent.\n *\n * @param value - The value to check; anything but a string is not a digest\n * @returns True for exactly 128 lowercase hex characters\n */\nexport function isChainDigest(value: unknown): value is string {\n return typeof value === \"string\" && HASH_HEX.test(value);\n}\n\n/**\n * Report whether a stored timestamp is exactly the form the chain hash covers:\n * `YYYY-MM-DDTHH:MM:SS.ffffffZ` (format-spec §4), naming a real calendar\n * instant.\n *\n * Any other spelling of the same instant (an offset such as `+05:30`, no\n * fractional digits, three, or more than six, a lowercase `z`) is refused: the\n * hash covers one spelling, and a second one that hashed the same would be a\n * field an editor could change without detection.\n *\n * @param value - The stored timestamp; anything but a string is refused\n * @returns True only for the exact §4 form\n */\nexport function isChainTimestamp(value: unknown): value is string {\n if (typeof value !== \"string\") return false;\n const m = TIMESTAMP_FORM.exec(value);\n if (!m) return false;\n const year = Number(m[1]);\n const month = Number(m[2]);\n const day = Number(m[3]);\n if (month < 1 || month > 12 || day < 1) return false;\n const leap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n if (day > days[month - 1]!) return false;\n return Number(m[4]) <= 23 && Number(m[5]) <= 59 && Number(m[6]) <= 59;\n}\n\n/**\n * Map a stored format version onto a known format.\n *\n * Zero — an absent field on an entry written before versions were recorded —\n * means v2. Every other value is returned unchanged, INCLUDING unknown ones, so\n * a caller can reject them explicitly rather than have them quietly treated as\n * a format they are not.\n */\nexport function normalizeFormatVersion(version: number | undefined): number {\n return !version ? FORMAT_V2 : version;\n}\n\n/**\n * Compute the SHA-512 v3 chain hash for an entry.\n *\n * v3 exists to make a chain a property of its ENTRIES rather than of the API\n * calls that happened to create it:\n *\n * ```\n * v2 SHA512(\"aleutian.chain.v2:\" + prev + \"|\" + runID + \"|\" + seq + \"|\" + ts + \"|\" + content)\n * v3 SHA512(\"aleutian.chain.v3:\" + prev + \"|\" + globalSeq + \"|\" + ts + \"|\" + content)\n * ```\n *\n * v2 binds runId and a BATCH-LOCAL sequenceNum, so the same entries in the same\n * order hash differently depending on how they were grouped into append calls.\n * That makes a chain impossible to reconstruct from its entries alone, because\n * the batch boundaries are part of the artifact and are recorded nowhere. v3\n * binds globalSeq — the entry's chain-wide position, which v2 never hashed at\n * all — and is batch-independent.\n *\n * ## Why globalSeq accepts a bigint\n *\n * The format's sequence is a 64-bit integer, and JavaScript's `number` holds\n * only 53 bits exactly. `9007199254740993` — one of the reference\n * implementation's own test vectors — becomes `…992` as a literal AND through\n * `JSON.parse`. Passing a `number` above `Number.MAX_SAFE_INTEGER` therefore\n * throws rather than silently hashing a value that is not the one on the wire:\n * a wrong hash reported as a chain break is far worse than a refusal.\n *\n * @param previousHash - Previous entry's chain_hash, or \"\" for the first entry\n * @param globalSeq - The entry's chain-wide position. Pass a bigint beyond 2^53.\n * @param timestamp - RFC 3339 with microsecond precision, exactly as stored\n * @param contentHash - SHA-512 hex of content, or a tombstone content hash\n * @returns 128-character lowercase hex SHA-512 hash\n */\nexport async function computeChainHashV3(\n previousHash: string,\n globalSeq: number | bigint,\n timestamp: string,\n contentHash: string\n): Promise<string> {\n if (typeof globalSeq === \"number\") {\n if (!Number.isSafeInteger(globalSeq)) {\n throw new Error(\n `globalSeq ${globalSeq} is not a safe integer; pass a bigint for values ` +\n `beyond Number.MAX_SAFE_INTEGER — a rounded value would hash to a ` +\n `digest that is not this entry's`\n );\n }\n if (globalSeq < 0) {\n throw new Error(`globalSeq must be non-negative, got ${globalSeq}`);\n }\n } else if (globalSeq < 0n) {\n throw new Error(`globalSeq must be non-negative, got ${globalSeq}`);\n } else if (globalSeq > MAX_GLOBAL_SEQ) {\n throw new Error(`globalSeq must be at most 2^63 - 1, got ${globalSeq}`);\n }\n // format-spec §2.1 and §3: the preimage is \"|\"-delimited and NOT\n // self-delimiting. Every field but previous_hash has a fixed shape, and\n // previous_hash must be empty or one; a malformed field could shift a\n // boundary and make two different entries hash alike.\n if (previousHash !== \"\" && !HASH_HEX.test(previousHash)) {\n throw new Error(\"previousHash must be empty or exactly 128 lowercase hex characters\");\n }\n if (!isChainTimestamp(timestamp)) {\n throw new Error(\"timestamp must be YYYY-MM-DDTHH:MM:SS.ffffffZ (UTC, six digits)\");\n }\n if (!HASH_HEX.test(contentHash) && !validateTombstoneContentHash(contentHash)) {\n throw new Error(\n 'contentHash must be 128 lowercase hex characters, or a tombstone value (\"TOMBSTONE:\" + 64 lowercase hex)'\n );\n }\n\n const preimage =\n CHAIN_HASH_PREFIX_V3 +\n previousHash +\n \"|\" +\n globalSeq.toString() +\n \"|\" +\n timestamp +\n \"|\" +\n contentHash;\n\n return sha512Hex(preimage);\n}\n\n/**\n * Compute the SHA-512 chain hash for an entry.\n *\n * Uses Aleutian's chain hash formula with domain separation:\n * SHA512(\"aleutian.chain.v2:\" + prev + \"|\" + runID + \"|\" + seq + \"|\" + ts + \"|\" + content)\n *\n * @param previousHash - Previous entry's chain_hash (empty string for first in run)\n * @param runId - Batch run identifier\n * @param sequenceNum - 0-indexed position within batch\n * @param timestamp - Entry timestamp in ISO 8601 format with microsecond precision\n * @param contentHash - SHA-512 hex of content, or tombstone content hash\n * @returns Promise resolving to 128-character lowercase hex SHA-512 hash\n *\n * @example\n * ```typescript\n * const hash = await computeChainHash(\n * 'abc123...',\n * 'run_xyz',\n * 42,\n * '2026-01-20T15:30:00.123456Z',\n * 'def456...'\n * );\n * ```\n */\nexport async function computeChainHash(\n previousHash: string,\n runId: string,\n sequenceNum: number,\n timestamp: string,\n contentHash: string\n): Promise<string> {\n if (!Number.isSafeInteger(sequenceNum)) {\n throw new Error(`sequenceNum ${sequenceNum} exceeds Number.MAX_SAFE_INTEGER`);\n }\n // Build preimage with domain separation\n // No NFC normalization - matches Go SDK behavior\n const preimage =\n CHAIN_HASH_PREFIX +\n previousHash +\n \"|\" +\n runId +\n \"|\" +\n sequenceNum.toString() +\n \"|\" +\n timestamp +\n \"|\" +\n contentHash;\n\n return sha512Hex(preimage);\n}\n\n/**\n * Format a Unix millisecond timestamp as ISO 8601 with microsecond precision.\n *\n * Converts Unix milliseconds to the format: \"2006-01-02T15:04:05.000000Z\"\n * Since JavaScript Date only has millisecond precision, the last 3 digits\n * of the microseconds are always \"000\".\n *\n * @param timestampMs - Unix timestamp in milliseconds\n * @returns ISO 8601 string with 6-digit microseconds (last 3 always \"000\")\n */\nexport function formatTimestampMicro(timestampMs: number): string {\n const date = new Date(timestampMs);\n const iso = date.toISOString(); // \"2026-01-20T15:30:00.123Z\"\n // Replace \".123Z\" with \".123000Z\" for microsecond format\n return iso.replace(/\\.(\\d{3})Z$/, \".$1000Z\");\n}\n\n/**\n * Compute chain hash using Unix milliseconds timestamp.\n *\n * This is a convenience function that converts Unix milliseconds to\n * ISO 8601 format before computing the hash. Use this when you have\n * a numeric timestamp instead of a string.\n *\n * @param previousHash - Previous entry's chain_hash (empty string for first in run)\n * @param runId - Batch run identifier\n * @param sequenceNum - 0-indexed position within batch\n * @param timestampMs - Entry timestamp as Unix milliseconds. Sub-millisecond\n * precision is discarded. Always use `Date.now()` or `time.UnixMilli()` values\n * rather than dividing a nanosecond timestamp, which silently truncates and\n * produces a hash that won't match Go/Python.\n * @param contentHash - SHA-512 hex of content, or tombstone content hash\n * @returns Promise resolving to 128-character lowercase hex SHA-512 hash\n *\n * @example\n * ```typescript\n * const hash = await computeChainHashMs(\n * 'abc123...',\n * 'run_xyz',\n * 42,\n * 1706108400123,\n * 'def456...'\n * );\n * ```\n */\nexport async function computeChainHashMs(\n previousHash: string,\n runId: string,\n sequenceNum: number,\n timestampMs: number,\n contentHash: string\n): Promise<string> {\n const timestamp = formatTimestampMicro(timestampMs);\n return computeChainHash(previousHash, runId, sequenceNum, timestamp, contentHash);\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Anchor-of-anchors chain hash (anchor.v2 domain).\n *\n * The audit chain uses TWO distinct SHA-512 domain separators:\n *\n * - `\"aleutian.chain.v2:\"` — per-entry chain links (see `chain.ts`).\n * Stored in `audit_entries.chain_hash`.\n * - `\"aleutian.anchor.v2:\"` — anchor-of-anchors chain (this file).\n * Stored in `anchors.chain_hash`. Binds an\n * anchor to its tip entry AND to the previous\n * anchor.\n *\n * An anchor's `chain_hash` is NOT the tip entry's `chain_hash` — it is a\n * domain-separated SHA-512 over (previousAnchorHash, companyID,\n * startEntryID, endEntryID, tipChainHash). Verifiers MUST recompute this\n * and compare; do not assume byte-equality with the tip entry's hash.\n *\n * Byte-identical to the Go SDK `ComputeAnchorChainHash` at\n * `sdk/verification-go/anchor_chain_hash.go`, the Python SDK\n * `compute_anchor_chain_hash`, and the producer at\n * `internal/chainlinker/anchor_generator.go`.\n *\n * @module\n */\n\nimport { sha512 } from \"@noble/hashes/sha2.js\";\nimport { bytesToHex, utf8ToBytes } from \"@noble/hashes/utils.js\";\n\nimport { sha512Hex } from \"./hash.js\";\n\n/**\n * SHA-512 domain separator for the anchor-of-anchors chain.\n * Must be byte-identical across Go/Python/JS SDKs.\n */\nexport const ANCHOR_CHAIN_DOMAIN_V2 = \"aleutian.anchor.v2:\";\n\n/**\n * Genesis previousAnchorHash used for the very first anchor in a\n * company's chain. Computed as `SHA-512(\"aleutian.anchor.seed.v2\")`.\n *\n * Byte-identical to the producer constant at\n * `internal/storage/verification_types.go` and the other SDK constants.\n */\nexport const SEED_ANCHOR_HASH =\n \"03443d96d3b369839f63f98b712463efba04c00551822743108d60c5f291627859\" +\n \"ff0b7dc29f99e3c847b07b0b18bb385426c744847c1b070563f8dd07271f27\";\n\n/**\n * Sentinel `previousAnchorId` value indicating a genesis anchor.\n */\nexport const SEED_ANCHOR_ID = \"anchor_00000000-0000-0000-0000-000000000000\";\n\n/**\n * Bind an anchor to its tip entry and prior anchor.\n *\n * Returns a Promise resolving to the hex-encoded SHA-512 digest over a\n * domain-separated, pipe-delimited concatenation of the inputs.\n * Byte-identical to the Go SDK `ComputeAnchorChainHash` and the producer\n * at `internal/chainlinker/anchor_generator.go`.\n *\n * Async because the JS SDK uses WebCrypto (`crypto.subtle.digest`), which\n * is always async — same pattern as `computeChainHash`.\n *\n * @param previousAnchorHash - The prior anchor's `chain_hash`, or\n * {@link SEED_ANCHOR_HASH} for a genesis anchor\n * (`previousAnchorId === SEED_ANCHOR_ID`).\n * @param companyId - The `company_id` field of the anchor being computed.\n * @param startEntryId - `anchor.range.startEntryId`.\n * @param endEntryId - `anchor.range.endEntryId`.\n * @param tipChainHash - The chain_hash of the entry identified by\n * `endEntryId`, as computed by walking the per-entry chain (NOT the\n * stored value if verifying potentially-tampered data — the verifier\n * walks and recomputes).\n * @returns Promise resolving to hex-encoded 128-char SHA-512 digest.\n */\nexport async function computeAnchorChainHash(\n previousAnchorHash: string,\n companyId: string,\n startEntryId: string,\n endEntryId: string,\n tipChainHash: string,\n): Promise<string> {\n const preimage =\n ANCHOR_CHAIN_DOMAIN_V2 +\n previousAnchorHash +\n \"|\" +\n companyId +\n \"|\" +\n startEntryId +\n \"|\" +\n endEntryId +\n \"|\" +\n tipChainHash;\n return sha512Hex(preimage);\n}\n\n/**\n * SHA-512 domain separator for the v7 anchor chain hash (format-spec §9.4).\n */\nexport const ANCHOR_CHAIN_DOMAIN_V7 = \"aleutian.anchor.v7:\";\n\nconst HEX_128 = /^[0-9a-f]{128}$/;\nconst DECIMAL = /^(0|[1-9][0-9]*)$/;\nconst MAX_INT64 = 2n ** 63n - 1n;\n\n/** A sequence number in format-spec §2.1's decimal grammar, as text. */\nfunction seqText(v: bigint | number | string, field: string): string {\n const s = typeof v === \"number\" && Number.isSafeInteger(v) ? String(v) : typeof v === \"bigint\" ? v.toString() : v;\n if (typeof s !== \"string\" || !DECIMAL.test(s) || s.length > 19 || BigInt(s) > MAX_INT64) {\n throw new Error(`${field} must be an integer from 0 to 2^63 - 1 (a bigint or decimal string beyond 2^53)`);\n }\n return s;\n}\n\n/**\n * The v7 anchor chain hash over fields already checked, synchronously.\n *\n * @internal Validates nothing; see {@link computeAnchorChainHashV7}.\n */\nexport function anchorChainHashV7Sync(\n previousAnchorHash: string,\n subject: string,\n startSeq: string,\n endSeq: string,\n tipChainHash: string\n): string {\n const subjectBytes = utf8ToBytes(subject);\n const head = utf8ToBytes(ANCHOR_CHAIN_DOMAIN_V7 + previousAnchorHash + \"|\");\n const tail = utf8ToBytes(\"|\" + startSeq + \"|\" + endSeq + \"|\" + tipChainHash);\n const n = subjectBytes.length;\n const out = new Uint8Array(head.length + 4 + n + tail.length);\n out.set(head, 0);\n out.set([(n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff], head.length);\n out.set(subjectBytes, head.length + 4);\n out.set(tail, head.length + 4 + n);\n return bytesToHex(sha512(out));\n}\n\n/**\n * Compute a v7 anchor's chain hash (format-spec §9.4).\n *\n * # Description\n *\n * `SHA-512(\"aleutian.anchor.v7:\" ‖ previous_anchor_hash ‖ \"|\" ‖ len(subject)\n * ‖ subject ‖ \"|\" ‖ start_seq ‖ \"|\" ‖ end_seq ‖ \"|\" ‖ tip_chain_hash)`, `len`\n * a 4-byte big-endian byte count. The subject is hashed as its UTF-8 bytes,\n * never normalised, and is length-prefixed, so it may contain `|`.\n *\n * Unlike v1-v6, the range is named by sequence: erasing any entry of it (v4,\n * format-spec §5.0) changes nothing this hash covers.\n *\n * # Inputs\n *\n * - previousAnchorHash: the anchor's own `previous_anchor_hash` (the\n * previous anchor's chain hash, or {@link SEED_ANCHOR_HASH}); 128 hex\n * - subject: the anchor's subject, non-empty\n * - startSeq, endSeq: the range, 0 to 2^63 - 1, as bigint, safe number or\n * decimal text\n * - tipChainHash: the chain hash of the entry at `endSeq`; 128 hex\n *\n * # Outputs\n *\n * - Promise<string>: 128 lowercase hex\n * - Error: thrown (as a rejection) when an input is malformed\n *\n * # Example\n *\n * const h = await computeAnchorChainHashV7(SEED_ANCHOR_HASH, \"orders\", 0n, 2n, tip);\n *\n * # Limitations\n *\n * - Not a bind: compare the result with the anchor's `chainHash`.\n *\n * # Assumptions\n *\n * - None.\n */\nexport function computeAnchorChainHashV7(\n previousAnchorHash: string,\n subject: string,\n startSeq: bigint | number | string,\n endSeq: bigint | number | string,\n tipChainHash: string\n): Promise<string> {\n // The executor's throw becomes the rejection.\n return new Promise((resolve) =>\n resolve(anchorChainHashV7Checked(previousAnchorHash, subject, startSeq, endSeq, tipChainHash))\n );\n}\n\nfunction anchorChainHashV7Checked(\n previousAnchorHash: string,\n subject: string,\n startSeq: bigint | number | string,\n endSeq: bigint | number | string,\n tipChainHash: string\n): string {\n if (typeof previousAnchorHash !== \"string\" || !HEX_128.test(previousAnchorHash)) {\n throw new Error(\"previousAnchorHash must be exactly 128 lowercase hex characters\");\n }\n if (typeof subject !== \"string\" || subject === \"\") {\n throw new Error(\"subject must be a non-empty string\");\n }\n if (typeof tipChainHash !== \"string\" || !HEX_128.test(tipChainHash)) {\n throw new Error(\"tipChainHash must be exactly 128 lowercase hex characters\");\n }\n return anchorChainHashV7Sync(\n previousAnchorHash,\n subject,\n seqText(startSeq, \"startSeq\"),\n seqText(endSeq, \"endSeq\"),\n tipChainHash\n );\n}\n","{\n \"aleutian-ml-dsa-65-2026-v1\": \"MIIHsjALBglghkgBZQMEAxIDggehAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\",\n \"aleutian-ml-dsa-65-2025-v1\": \"MIIHsjALBglghkgBZQMEAxIDggehAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"\n}\n","{\n \"aleutian-ml-dsa-65-2026-v1\": \"MIIHsjALBglghkgBZQMEAxIDggehAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\",\n \"aleutian-ml-dsa-65-2025-v1\": \"MIIHsjALBglghkgBZQMEAxIDggehAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"\n}\n","{\n \"aleutian-ml-dsa-65-2026-v1\": \"MIIHsjALBglghkgBZQMEAxIDggehAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\",\n \"aleutian-ml-dsa-65-2025-v1\": \"MIIHsjALBglghkgBZQMEAxIDggehAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Embedded ML-DSA-65 public keys for offline anchor verification.\n *\n * Keys are stored as SubjectPublicKeyInfo (SPKI) DER base64, matching the\n * format returned by Cloud KMS. On load, the raw 1952-byte key is extracted.\n *\n * Key rotation schedule:\n * - New keys are generated annually\n * - Old keys remain valid for 90 days after rotation\n * - SDK releases bundle current + previous key\n */\n\nimport { base64ToUint8Array } from \"./hash.js\";\n\n/** ML-DSA-65 raw public key size per FIPS 204. */\nexport const MLDSA_PUB_KEY_SIZE = 1952;\n\n/**\n * URL for fetching current public keys from Aleutian's servers.\n *\n * This endpoint can be used to:\n * 1. Check for key revocations\n * 2. Fetch newly rotated keys before SDK updates\n * 3. Verify embedded keys match server-side keys\n *\n * For fully offline verification, use the embedded keys instead.\n */\nexport const PUBLIC_KEYS_ENDPOINT =\n \"https://keys.aleutian.ai/.well-known/anchor-signing-keys.json\";\n\n/**\n * Parse DER length encoding, returning [length, newOffset].\n *\n * RS-1: Bounds-checks all byte accesses to prevent out-of-bounds reads\n * on truncated or malformed DER input.\n */\nfunction readDerLength(data: Uint8Array, offset: number): [number, number] {\n if (offset >= data.length) {\n throw new Error(\"DER: unexpected end of data\");\n }\n const b = data[offset]!;\n offset += 1;\n if (b < 0x80) {\n return [b, offset];\n }\n const numBytes = b & 0x7f;\n if (offset + numBytes > data.length) {\n throw new Error(\"DER: length encoding truncated\");\n }\n let length = 0;\n for (let i = 0; i < numBytes; i++) {\n length = (length << 8) | data[offset]!;\n offset += 1;\n }\n return [length, offset];\n}\n\n/**\n * Decode a SubjectPublicKeyInfo (SPKI) DER base64 ML-DSA-65 public key\n * to raw 1952 bytes.\n *\n * SPKI structure: SEQUENCE { AlgorithmIdentifier SEQUENCE, BIT STRING }\n * The BIT STRING contains: 0x00 (unused bits) + raw 1952-byte key.\n */\nfunction decodeSpkiDer(keyB64: string): Uint8Array {\n const der = base64ToUint8Array(keyB64);\n\n if (der.length < MLDSA_PUB_KEY_SIZE + 20) {\n throw new Error(`Invalid SPKI DER: too short (${der.length} bytes)`);\n }\n\n let pos = 0;\n\n // Skip outer SEQUENCE tag (0x30)\n if (der[pos] !== 0x30) {\n throw new Error(\"Invalid SPKI: expected SEQUENCE tag\");\n }\n pos += 1;\n\n // CR-2: Validate outer SEQUENCE length so truncated DER is caught early.\n const [outerLen, contentStart] = readDerLength(der, pos);\n if (contentStart + outerLen > der.length) {\n throw new Error(\"SPKI DER: outer SEQUENCE truncated\");\n }\n pos = contentStart;\n\n // Skip AlgorithmIdentifier SEQUENCE\n if (der[pos] !== 0x30) {\n throw new Error(\"Invalid SPKI: expected AlgorithmIdentifier SEQUENCE\");\n }\n pos += 1;\n const [algLen, algContentStart] = readDerLength(der, pos);\n pos = algContentStart + algLen;\n\n // Read BIT STRING tag (0x03)\n if (der[pos] !== 0x03) {\n throw new Error(\"Invalid SPKI: expected BIT STRING tag\");\n }\n pos += 1;\n const [bitStringLen, bitStringStart] = readDerLength(der, pos);\n pos = bitStringStart;\n\n // First byte of BIT STRING is unused-bits count (must be 0x00 for keys)\n if (der[pos] !== 0x00) {\n throw new Error(\"Invalid SPKI BIT STRING: non-zero unused bits\");\n }\n pos += 1;\n\n const raw = der.slice(pos, pos + bitStringLen - 1);\n if (raw.length !== MLDSA_PUB_KEY_SIZE) {\n throw new Error(\n `Invalid ML-DSA-65 key size: got ${raw.length} bytes, want ${MLDSA_PUB_KEY_SIZE}`\n );\n }\n return raw;\n}\n\n// Embedded ML-DSA-65 public keys as SPKI DER base64.\n//\n// # Pinning strategy (15n_fix_A4, 2026-05-17)\n//\n// Keys are loaded at module-import time from a per-env JSON fixture file\n// under src/fixtures/. Selection is by the ALEUTIAN_ENV environment\n// variable at process start (defaults to \"dev\").\n//\n// All three env fixtures are statically imported so a bundler that\n// tree-shakes unused branches still keeps the env-selection logic\n// intact. Per-env wheel artifacts (single-fixture bundles) would require\n// build-time customisation — out of scope for v1.\n//\n// # Bootstrap (15n_fix_A4 ceremony)\n//\n// The fixture files ship with all-zero placeholder data. Step 3 of the\n// ceremony overwrites them with real KMS-exported SPKI-DER-base64 entries.\n\nimport devFixture from \"./fixtures/embedded-keys-dev.json\" with { type: \"json\" };\nimport stagingFixture from \"./fixtures/embedded-keys-staging.json\" with { type: \"json\" };\nimport prodFixture from \"./fixtures/embedded-keys-prod.json\" with { type: \"json\" };\n\nfunction loadFixture(): Record<string, string> {\n // process.env is only available in Node-like runtimes; browsers\n // default to dev.\n const env =\n typeof process !== \"undefined\" && process.env && process.env.ALEUTIAN_ENV\n ? process.env.ALEUTIAN_ENV\n : \"dev\";\n switch (env) {\n case \"prod\":\n return prodFixture as Record<string, string>;\n case \"staging\":\n return stagingFixture as Record<string, string>;\n default:\n return devFixture as Record<string, string>;\n }\n}\n\nconst _EMBEDDED_PUBLIC_KEYS_B64: ReadonlyMap<string, string> = new Map(\n Object.entries(loadFixture())\n);\n\n\n/**\n * Embedded ML-DSA-65 public keys for offline anchor verification.\n *\n * Keys are raw 1952-byte Uint8Arrays, decoded from SPKI DER at load time.\n */\nexport const EMBEDDED_PUBLIC_KEYS: ReadonlyMap<string, Uint8Array> = new Map(\n Array.from(_EMBEDDED_PUBLIC_KEYS_B64.entries()).map(([id, b64]) => [\n id,\n decodeSpkiDer(b64),\n ])\n);\n\n/**\n * Get an embedded public key by ID.\n *\n * @param keyId - The key identifier from anchor.signature.publicKeyId\n * @returns The raw 1952-byte ML-DSA-65 public key bytes\n * @throws Error if key ID is not found in embedded keys\n */\nexport function getPublicKey(keyId: string): Uint8Array {\n const key = EMBEDDED_PUBLIC_KEYS.get(keyId);\n if (!key) {\n throw new Error(`Unknown public key ID: ${keyId}`);\n }\n // Defensive copy: callers must not be able to mutate the embedded\n // public key bytes. Mirrors V3 H6 (trust manifest immutability).\n // Ticket: dsar_js_trust_manifest_key_mutability.\n return new Uint8Array(key);\n}\n\n/**\n * Check if a key ID is known (exists in embedded keys).\n *\n * @param keyId - The key identifier to check\n * @returns True if the key ID is known\n */\nexport function isKnownKey(keyId: string): boolean {\n return EMBEDDED_PUBLIC_KEYS.has(keyId);\n}\n\n/**\n * List all known key IDs.\n *\n * @returns Array of key IDs sorted alphabetically\n */\nexport function listKeyIds(): string[] {\n return Array.from(EMBEDDED_PUBLIC_KEYS.keys()).sort();\n}\n\n/**\n * SC-1: Validate that no embedded key is an all-zero development placeholder.\n *\n * Production deployments MUST call this function at startup and handle the\n * thrown error (e.g., fail fast before serving traffic). The embedded keys\n * in this SDK release are development placeholders and MUST be replaced with\n * real keys before production use.\n *\n * @throws Error if any embedded key consists entirely of zero bytes\n */\nexport function validateEmbeddedKeys(): void {\n for (const [id, key] of EMBEDDED_PUBLIC_KEYS.entries()) {\n if (key.every((b) => b === 0)) {\n throw new Error(\n `Embedded key \"${id}\" is a development placeholder (all-zero bytes). ` +\n \"Replace with a real ML-DSA-65 public key before production use.\"\n );\n }\n }\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Strict decoding of CANONICAL base64 (bundle-format §3).\n *\n * Canonical means the standard alphabet with padding (RFC 4648 §4), no\n * whitespace, and the unused bits of the last character zero. Exactly one text\n * decodes to any given bytes, so a value that is not canonical is refused here\n * rather than \"repaired\" by a lenient decoder (`atob`, `Buffer.from`), which\n * would accept several spellings of one value.\n *\n * Browser-safe: no Node APIs.\n */\n\nconst ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\nconst DECODE: Int16Array = (() => {\n const table = new Int16Array(128).fill(-1);\n for (let i = 0; i < ALPHABET.length; i++) table[ALPHABET.charCodeAt(i)] = i;\n return table;\n})();\n\nfunction sextet(code: number): number {\n return code < 128 ? DECODE[code]! : -1;\n}\n\n/**\n * Decode canonical base64, or return null when the text is not canonical.\n *\n * # Description\n *\n * Accepts only the standard alphabet, with `=` padding to a multiple of four\n * characters, no whitespace, and zero unused bits in the last character. The\n * empty string decodes to zero bytes.\n *\n * # Inputs\n *\n * - text: the base64 text to decode\n *\n * # Outputs\n *\n * - Uint8Array: the decoded bytes, or null when `text` is not canonical\n *\n * # Example\n *\n * decodeCanonicalBase64(\"YQ==\") // Uint8Array [0x61]\n * decodeCanonicalBase64(\"YR==\") // null: unused bits not zero\n *\n * # Limitations\n *\n * - Never throws; the caller decides what a refusal means.\n *\n * # Assumptions\n *\n * - None.\n */\nexport function decodeCanonicalBase64(text: string): Uint8Array | null {\n const len = text.length;\n if (len % 4 !== 0) return null;\n if (len === 0) return new Uint8Array(0);\n\n let pad = 0;\n if (text.charCodeAt(len - 1) === 0x3d) pad = text.charCodeAt(len - 2) === 0x3d ? 2 : 1;\n const out = new Uint8Array((len / 4) * 3 - pad);\n\n let o = 0;\n for (let i = 0; i < len; i += 4) {\n const last = i + 4 === len;\n const a = sextet(text.charCodeAt(i));\n const b = sextet(text.charCodeAt(i + 1));\n if (a < 0 || b < 0) return null;\n if (last && pad === 2) {\n if ((b & 0x0f) !== 0) return null;\n out[o++] = (a << 2) | (b >> 4);\n break;\n }\n const c = sextet(text.charCodeAt(i + 2));\n if (c < 0) return null;\n if (last && pad === 1) {\n if ((c & 0x03) !== 0) return null;\n out[o++] = (a << 2) | (b >> 4);\n out[o++] = ((b & 0x0f) << 4) | (c >> 2);\n break;\n }\n const d = sextet(text.charCodeAt(i + 3));\n if (d < 0) return null;\n out[o++] = (a << 2) | (b >> 4);\n out[o++] = ((b & 0x0f) << 4) | (c >> 2);\n out[o++] = ((c & 0x03) << 6) | d;\n }\n return out;\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Anchor canonical bytes that need no keys (format-spec §9.2): the v6 form,\n * and the string and int64 encoders every version's form uses.\n *\n * Split out of `anchor.ts` so a module that only canonicalizes (the proof\n * bundle verifier) does not import `keys.ts` and its embedded key fixtures,\n * which would otherwise land in browser bundles. `anchor.ts` re-exports\n * `canonicalizeAnchorV6`, so its public API is unchanged.\n */\n\nimport { SEED_ANCHOR_HASH, SEED_ANCHOR_ID } from \"./anchorChainHash.js\";\nimport { AnchorVerificationError } from \"./errors.js\";\nimport type { Anchor } from \"./types.js\";\n\n/**\n * The ML-DSA context a v7 anchor signature is made with (format-spec §9.5).\n * v1-v6 use the empty context.\n */\nexport const ANCHOR_SIGNATURE_CONTEXT_V7 = \"aleutian.proof.anchor.v7\";\n\nconst HEX_128 = /^[0-9a-f]{128}$/;\nconst LONE_SURROGATE =\n /[\\ud800-\\udbff](?![\\udc00-\\udfff])|(?<![\\ud800-\\udbff])[\\udc00-\\udfff]/g;\n// The same, for a test: a /g regex keeps its lastIndex between calls.\nconst HAS_LONE_SURROGATE = new RegExp(LONE_SURROGATE.source);\n\n/**\n * Encode an `bigint | number` int64 field as a bare decimal token\n * suitable for direct concatenation into canonical JSON.\n *\n * `JSON.stringify` does NOT support `bigint` (throws TypeError) and\n * `Number.toString` silently truncates integers above\n * `Number.MAX_SAFE_INTEGER`. We accept either input, validate that\n * `number` inputs are safe integers, and emit the raw decimal text.\n *\n * Ticket: dsar_js_anchor_int64_widening.\n *\n * @internal\n */\nexport function encodeInt64Token(v: bigint | number): string {\n if (typeof v === \"bigint\") {\n return v.toString();\n }\n if (!Number.isFinite(v) || !Number.isInteger(v)) {\n throw new AnchorVerificationError(\n \"anchor int64 field: number must be a finite integer\"\n );\n }\n if (!Number.isSafeInteger(v)) {\n throw new AnchorVerificationError(\n \"anchor int64 field: number exceeds Number.MAX_SAFE_INTEGER; pass as bigint to avoid precision loss\"\n );\n }\n return v.toString();\n}\n\n/** Read an anchor int64 field exactly, or refuse the anchor. */\nfunction anchorInteger(v: unknown): bigint {\n if (typeof v === \"bigint\") return v;\n if (typeof v === \"number\" && Number.isSafeInteger(v)) return BigInt(v);\n throw new AnchorVerificationError(\n \"anchor int64 field: must be an integer (a bigint beyond Number.MAX_SAFE_INTEGER)\"\n );\n}\n\n/**\n * Refuse a malformed anchor (format-spec §9.3 and §9.8).\n *\n * # Description\n *\n * Checks what an anchor must satisfy before its canonical form is built or it\n * is bound to a chain:\n *\n * - `version` is 1, 2, 3, 4, 6 or 7. Version 5 is withdrawn and is refused\n * by name; any other version is refused, never treated as the closest form.\n * - v7 (§9.3, §9.8): a non-empty `subject`, `anchorId` and\n * `previousAnchorId`, each valid UTF-8 (no lone surrogate) as is\n * `signingKeyId`; `range.startSeq` and\n * `range.endSeq` integers from 0 to 2^63 - 1 with `startSeq <= endSeq`;\n * `entryCount = endSeq - startSeq + 1`; `previousAnchorHash` 128 lowercase\n * hex; `previousAnchorId` is the seed id exactly when `previousAnchorHash`\n * is the seed hash; `chainHash` 128 lowercase hex; `createdAtMs >= 0`; no\n * `verifiedThrough` and no entry-id range. v1-v6 carry no\n * `previousAnchorHash` and no sequence range.\n * - version invariants (§9.3): v1-v3 carry `verifiedThrough` 0; v4 and v6\n * carry it positive; v6 carries a non-empty `subject`.\n * - counts, v4 and v6 (§9.8): `entryCount >= 1`,\n * `0 < verifiedThrough <= entryCount`, `createdAtMs >= 0`.\n * - `signingKeyId` is not empty (§9.8).\n *\n * `version` is inside the signed bytes, so an anchor that breaks these carries\n * a valid signature over malformed content. That is reported as malformed, not\n * as tampering, and never as a bind outcome.\n *\n * # Inputs\n *\n * - anchor: The anchor to check\n *\n * # Outputs\n *\n * - void: Returns normally when the anchor is well formed\n * - AnchorVerificationError: Thrown otherwise. Messages name a field, never\n * its value.\n *\n * # Example\n *\n * checkAnchorWellFormed(parseAnchorText(text));\n *\n * # Limitations\n *\n * - Checks neither the signature nor the binding to a chain.\n *\n * # Assumptions\n *\n * - None.\n */\nexport function checkAnchorWellFormed(anchor: Anchor): void {\n const version: unknown = anchor.version;\n if (typeof version !== \"number\" || !Number.isInteger(version)) {\n throw new AnchorVerificationError(\"anchor version must be an integer\");\n }\n if (version === 5) {\n throw new AnchorVerificationError(\n \"unsupported anchor version: 5 is withdrawn and has no canonical form\"\n );\n }\n if (version < 1 || version > 7) {\n throw new AnchorVerificationError(\"unsupported anchor version\");\n }\n if (version === 7) {\n checkAnchorV7WellFormed(anchor);\n return;\n }\n // §9.8, the wrong range shape: a v1-v6 anchor names its range by entry id.\n if (\n anchor.range?.startSeq !== undefined ||\n anchor.range?.endSeq !== undefined ||\n anchor.previousAnchorHash !== undefined\n ) {\n throw new AnchorVerificationError(\n `Version=${version} anchor must not carry previous_anchor_hash, start_seq or end_seq`\n );\n }\n // Normalize to bigint so number-vs-bigint comparisons are well-defined\n // (strict `!== 0` would always be true for `0n`).\n const verifiedThrough = anchorInteger(anchor.verifiedThrough ?? 0);\n const entryCount = anchorInteger(anchor.entryCount);\n const createdAtMs = anchorInteger(anchor.createdAtMs);\n\n if (version <= 3) {\n if (verifiedThrough !== 0n) {\n throw new AnchorVerificationError(\n \"Version<=3 anchor must have verified_through=0\"\n );\n }\n } else {\n if (verifiedThrough <= 0n) {\n throw new AnchorVerificationError(\n `Version=${version} anchor must have positive verified_through`\n );\n }\n if (version === 6 && !anchor.subject) {\n // The subject is the replay protection: an anchor that does not commit to\n // one could be presented against another chain.\n throw new AnchorVerificationError(\n \"Version=6 anchor must have a non-empty subject\"\n );\n }\n if (entryCount < 1n) {\n throw new AnchorVerificationError(\"anchor entry_count must be at least 1\");\n }\n if (verifiedThrough > entryCount) {\n throw new AnchorVerificationError(\n \"anchor verified_through must not exceed entry_count\"\n );\n }\n if (createdAtMs < 0n) {\n throw new AnchorVerificationError(\"anchor created_at_ms must not be negative\");\n }\n }\n\n if (typeof anchor.signingKeyId !== \"string\" || anchor.signingKeyId === \"\") {\n throw new AnchorVerificationError(\"anchor signing_key_id must not be empty\");\n }\n}\n\nconst MAX_INT64 = 2n ** 63n - 1n;\n\n/** The v7 rules of format-spec §9.3 and §9.8. */\nfunction checkAnchorV7WellFormed(anchor: Anchor): void {\n if (typeof anchor.subject !== \"string\" || anchor.subject === \"\") {\n throw new AnchorVerificationError(\"Version=7 anchor must have a non-empty subject\");\n }\n if (typeof anchor.anchorId !== \"string\" || anchor.anchorId === \"\") {\n throw new AnchorVerificationError(\"Version=7 anchor must have a non-empty anchor_id\");\n }\n if (typeof anchor.previousAnchorId !== \"string\" || anchor.previousAnchorId === \"\") {\n throw new AnchorVerificationError(\n \"Version=7 anchor must have a non-empty previous_anchor_id\"\n );\n }\n // §9.3: these strings are signed and hashed as UTF-8. A lone surrogate has\n // no UTF-8 form, so the bytes signed would not be the string held.\n for (const [name, value] of [\n [\"subject\", anchor.subject],\n [\"anchor_id\", anchor.anchorId],\n [\"previous_anchor_id\", anchor.previousAnchorId],\n [\"signing_key_id\", anchor.signingKeyId],\n ] as const) {\n if (typeof value === \"string\" && HAS_LONE_SURROGATE.test(value)) {\n throw new AnchorVerificationError(`Version=7 anchor ${name} must be valid UTF-8`);\n }\n }\n if (anchor.range === undefined || anchor.range.startSeq === undefined || anchor.range.endSeq === undefined) {\n throw new AnchorVerificationError(\"Version=7 anchor must name its range by start_seq and end_seq\");\n }\n if (anchor.range.startEntryId || anchor.range.endEntryId) {\n throw new AnchorVerificationError(\"Version=7 anchor must not name its range by entry id\");\n }\n if (anchor.verifiedThrough !== undefined && anchorInteger(anchor.verifiedThrough) !== 0n) {\n throw new AnchorVerificationError(\"Version=7 anchor has no verified_through\");\n }\n const start = anchorInteger(anchor.range.startSeq);\n const end = anchorInteger(anchor.range.endSeq);\n const count = anchorInteger(anchor.entryCount);\n for (const n of [start, end, count]) {\n if (n < 0n || n > MAX_INT64) {\n throw new AnchorVerificationError(\n \"Version=7 anchor sequence numbers and entry_count must be from 0 to 2^63 - 1\"\n );\n }\n }\n if (start > end) {\n throw new AnchorVerificationError(\"Version=7 anchor start_seq must not exceed end_seq\");\n }\n if (count !== end - start + 1n) {\n throw new AnchorVerificationError(\n \"Version=7 anchor entry_count must equal end_seq - start_seq + 1\"\n );\n }\n const prevHash: unknown = anchor.previousAnchorHash;\n if (typeof prevHash !== \"string\" || !HEX_128.test(prevHash)) {\n throw new AnchorVerificationError(\n \"Version=7 anchor previous_anchor_hash must be 128 lowercase hex characters\"\n );\n }\n if ((anchor.previousAnchorId === SEED_ANCHOR_ID) !== (prevHash === SEED_ANCHOR_HASH)) {\n throw new AnchorVerificationError(\n \"Version=7 anchor names the seed id exactly when it names the seed hash\"\n );\n }\n if (typeof anchor.chainHash !== \"string\" || !HEX_128.test(anchor.chainHash)) {\n throw new AnchorVerificationError(\"Version=7 anchor chain_hash must be 128 lowercase hex characters\");\n }\n if (anchorInteger(anchor.createdAtMs) < 0n) {\n throw new AnchorVerificationError(\"anchor created_at_ms must not be negative\");\n }\n if (typeof anchor.signingKeyId !== \"string\" || anchor.signingKeyId === \"\") {\n throw new AnchorVerificationError(\"anchor signing_key_id must not be empty\");\n }\n}\n\n/**\n * JSON-encode a single string value exactly as Go's `encoding/json` does,\n * with HTML escaping on (its default, and how proof signs): format-spec §9.2.\n *\n * `JSON.stringify` leaves `<`, `>`, `&`, U+2028 and U+2029 as they are; Go\n * writes them as `\\u` escapes. Replacing them in the output is exact: none of\n * them is part of any escape `JSON.stringify` writes.\n *\n * @internal\n */\nexport function encodeJsonString(s: string): string {\n // A lone surrogate cannot be encoded as UTF-8: Go writes U+FFFD in its place,\n // where JSON.stringify would write a \"\\\\udXXX\" escape.\n const wellFormed = s.replace(LONE_SURROGATE, \"\\ufffd\");\n return JSON.stringify(wellFormed).replace(\n /[<>&\\u2028\\u2029]/g,\n (c) => \"\\\\u\" + c.charCodeAt(0).toString(16).padStart(4, \"0\")\n );\n}\n\n/**\n * Version=6 canonical form: v4's layout with `company_id` as `subject`.\n *\n * THE FIELD MOVES. Keys are alphabetical, as in every version, and\n * `\"signing_key_id\" < \"subject\" < \"verified_through\" < \"version\"` — so the\n * renamed field sorts EIGHTH where `company_id` sorted THIRD. That movement is\n * precisely why this is a new version and not an edit: the key is inside the\n * bytes the signature covers.\n *\n * Built on v4, NOT v5. v5 commits to a Merkle root that no implementation can\n * verify, so v6 carries no `root_hash`/`tree_size`.\n *\n * Cross-language byte equivalence with Go's `canonicalV6` and Python's\n * `canonicalize_anchor_v6` is mandatory.\n */\nexport function canonicalizeAnchorV6(anchor: Anchor): string {\n const verifiedThrough = anchor.verifiedThrough ?? 0;\n const parts: string[] = [\n `\"anchor_id\":${encodeJsonString(anchor.anchorId)}`,\n `\"chain_hash\":${encodeJsonString(anchor.chainHash)}`,\n `\"created_at_ms\":${encodeInt64Token(anchor.createdAtMs)}`,\n `\"entry_count\":${encodeInt64Token(anchor.entryCount)}`,\n `\"previous_anchor_id\":${encodeJsonString(anchor.previousAnchorId)}`,\n `\"range\":{\"end_entry_id\":${encodeJsonString(anchor.range.endEntryId)},\"start_entry_id\":${encodeJsonString(anchor.range.startEntryId)}}`,\n `\"signing_key_id\":${encodeJsonString(anchor.signingKeyId)}`,\n `\"subject\":${encodeJsonString(anchor.subject)}`,\n `\"verified_through\":${encodeInt64Token(verifiedThrough)}`,\n `\"version\":${anchor.version}`,\n ];\n return `{${parts.join(\",\")}}`;\n}\n\n/**\n * Version=7 canonical form (format-spec §9.2): the bytes a v7 signature covers.\n *\n * Ten fields, alphabetical: `anchor_id`, `chain_hash`, `created_at_ms`,\n * `entry_count`, `previous_anchor_hash`, `previous_anchor_id`, `range`\n * (`end_seq`, `start_seq`), `signing_key_id`, `subject`, `version`.\n * `previous_anchor_hash` sorts before `previous_anchor_id`. `entry_count`,\n * `end_seq` and `start_seq` are JSON STRINGS of their decimal value, so that a\n * value above 2^53 survives every JSON reader exactly.\n *\n * Builds bytes only: call `checkAnchorWellFormed` first (`verifyAnchorLocally`\n * does).\n */\nexport function canonicalizeAnchorV7(anchor: Anchor): string {\n const range = anchor.range;\n if (range.startSeq === undefined || range.endSeq === undefined) {\n throw new AnchorVerificationError(\"Version=7 anchor must name its range by start_seq and end_seq\");\n }\n const decimal = (v: bigint | number): string => JSON.stringify(encodeInt64Token(v));\n const parts: string[] = [\n `\"anchor_id\":${encodeJsonString(anchor.anchorId)}`,\n `\"chain_hash\":${encodeJsonString(anchor.chainHash)}`,\n `\"created_at_ms\":${encodeInt64Token(anchor.createdAtMs)}`,\n `\"entry_count\":${decimal(anchor.entryCount)}`,\n `\"previous_anchor_hash\":${encodeJsonString(anchor.previousAnchorHash ?? \"\")}`,\n `\"previous_anchor_id\":${encodeJsonString(anchor.previousAnchorId)}`,\n `\"range\":{\"end_seq\":${decimal(range.endSeq)},\"start_seq\":${decimal(range.startSeq)}}`,\n `\"signing_key_id\":${encodeJsonString(anchor.signingKeyId)}`,\n `\"subject\":${encodeJsonString(anchor.subject)}`,\n `\"version\":${anchor.version}`,\n ];\n return `{${parts.join(\",\")}}`;\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Anchor verification and parsing for the Aleutian verification SDK.\n *\n * This module provides functions to verify anchor signatures and parse\n * anchor data from JSON. Anchor verification uses ML-DSA-65 (FIPS 204).\n * No SHA-256 pre-hash — ML-DSA-65 handles hashing internally.\n */\n\nimport { ml_dsa65 } from \"@noble/post-quantum/ml-dsa.js\";\nimport { AnchorVerificationError } from \"./errors.js\";\nimport { decodeCanonicalBase64 } from \"./canonicalBase64.js\";\nimport {\n ANCHOR_SIGNATURE_CONTEXT_V7,\n canonicalizeAnchorV6,\n canonicalizeAnchorV7,\n checkAnchorWellFormed,\n encodeInt64Token,\n encodeJsonString,\n} from \"./anchorCanonical.js\";\nimport { getPublicKey, MLDSA_PUB_KEY_SIZE } from \"./keys.js\";\nimport type { Anchor, AnchorRange, ExportedEntry } from \"./types.js\";\n\n// The v6 canonical form and the encoders live in anchorCanonical.ts, which\n// imports no keys, so the bundle verifier can use them without pulling the\n// embedded keys into a browser bundle. Re-exported here unchanged.\nexport { ANCHOR_SIGNATURE_CONTEXT_V7, canonicalizeAnchorV6, canonicalizeAnchorV7, checkAnchorWellFormed };\n\nconst EMPTY_CONTEXT = new Uint8Array(0);\nconst CONTEXT_V7 = new TextEncoder().encode(ANCHOR_SIGNATURE_CONTEXT_V7);\n\n/**\n * Verify an anchor signature without network access.\n *\n * # Description\n *\n * Verifies the ML-DSA-65 (FIPS 204) signature of an anchor using embedded\n * or provided public keys. This enables fully offline anchor verification.\n *\n * No SHA-256 pre-hash is applied — ML-DSA-65 handles message hashing\n * internally per FIPS 204, matching the Cloud KMS signing path.\n *\n * # Inputs\n *\n * - anchor: The anchor to verify\n * - publicKey: Optional raw 1952-byte ML-DSA-65 public key. If undefined,\n * uses embedded keys based on anchor.signingKeyId\n *\n * # Outputs\n *\n * - void: Returns normally if verification succeeds\n * - AnchorVerificationError: Thrown if signature verification fails\n * - Error: Thrown if public key ID is not found in embedded keys\n *\n * # Example\n *\n * const anchor = await loadAnchor('anchor-2026-01-20.json');\n * try {\n * verifyAnchorLocally(anchor);\n * console.log('Anchor is cryptographically valid');\n * } catch (e) {\n * console.error('Verification failed:', e.message);\n * }\n *\n * # Limitations\n *\n * - Requires embedded keys to be non-placeholder for production use\n * - Does not verify anchor chain linkage (previousAnchorId), and takes no\n * predecessor hash: binding an anchor to a chain and to its predecessor is\n * `bindAnchorToEntries`\n * - Refuses a malformed anchor before any cryptography (format-spec §9.3,\n * §9.8): an unsupported or withdrawn version, a broken version invariant,\n * v4/v6 counts out of range, an empty signingKeyId\n *\n * # Assumptions\n *\n * - anchor.signature is the canonical base64 (standard alphabet, padded, no\n * line breaks, zero trailing bits) of an ML-DSA-65 signature (3309 bytes)\n * - publicKey, if provided, is exactly MLDSA_PUB_KEY_SIZE (1952) bytes\n */\nexport function verifyAnchorLocally(\n anchor: Anchor,\n publicKey?: Uint8Array\n): void {\n // Version-dispatch invariants (ui_chainops_18 C1/M5), the v4/v6 counts and\n // the key id rule (format-spec §9.3, §9.8).\n // MUST happen BEFORE canonicalization so a malicious anchor cannot\n // downgrade or upgrade the canonical form via the version field.\n checkAnchorWellFormed(anchor);\n\n const key = publicKey ?? getPublicKey(anchor.signingKeyId);\n\n if (key.length !== MLDSA_PUB_KEY_SIZE) {\n throw new AnchorVerificationError(\"Invalid public key size\");\n }\n\n // Canonicalize anchor — ML-DSA-65 signs directly over canonical JSON bytes.\n // Dispatch by version; never probe by signature prefix or field presence.\n const canonical = canonicalizeAnchorForVersion(anchor);\n const canonicalBytes = new TextEncoder().encode(canonical);\n\n // Decode signature. format-spec §9.5: standard base64 with padding, and no\n // other spelling of it. A lenient decoder (`atob`, `Buffer.from`) accepts a\n // line break, missing padding and non-zero trailing bits, so several texts\n // would pass for one signature.\n const sigBytes =\n typeof anchor.signature === \"string\" ? decodeCanonicalBase64(anchor.signature) : null;\n if (sigBytes === null) {\n throw new AnchorVerificationError(\"Invalid signature encoding\");\n }\n\n if (sigBytes.length !== 3309) {\n throw new AnchorVerificationError(\"Invalid signature length\");\n }\n\n // Verify ML-DSA-65 signature (pure, no pre-hash per FIPS 204). format-spec\n // §9.5: the context is chosen from the DECLARED version, never from the\n // signature: \"aleutian.proof.anchor.v7\" for v7, empty for v1-v6.\n // @noble/post-quantum API: verify(sig, msg, pubKey, { context }) → boolean\n const context = anchor.version === 7 ? CONTEXT_V7 : EMPTY_CONTEXT;\n let valid: boolean;\n try {\n valid = ml_dsa65.verify(sigBytes, canonicalBytes, key, { context });\n } catch {\n valid = false;\n }\n if (!valid) {\n throw new AnchorVerificationError(\"Signature verification failed\");\n }\n}\n\n/**\n * Return canonical JSON for signature verification.\n *\n * # Description\n *\n * Builds the canonical JSON representation of an anchor for signature\n * verification. Uses explicit alphabetical key ordering matching the\n * AnchorCanonicalJSON format defined by the backend. The `signature`\n * field is excluded. All SDKs (Go, Python, JS) must produce identical output.\n *\n * Key ordering (alphabetical):\n * anchor_id, chain_hash, company_id, created_at_ms, entry_count,\n * previous_anchor_id, range, signing_key_id, version\n * range sub-keys: end_entry_id, start_entry_id\n *\n * # Inputs\n *\n * - anchor: The anchor to canonicalize\n *\n * # Outputs\n *\n * - string: Canonical JSON string with no extra whitespace\n *\n * # Example\n *\n * const json = canonicalizeAnchor(anchor);\n * // '{\"anchor_id\":\"...\",\"chain_hash\":\"...\",\"company_id\":\"...\",...}'\n *\n * # Limitations\n *\n * - ES2015+ preserves insertion order for string keys; relies on this behavior\n *\n * # Assumptions\n *\n * - All anchor fields are populated (empty strings / zero values for missing)\n */\n/**\n * Dispatch by anchor.version to the right canonical form\n * (ui_chainops_18 C3/M5). NEVER probe by signature prefix or by\n * field presence; probing creates a downgrade oracle.\n */\nexport function canonicalizeAnchorForVersion(anchor: Anchor): string {\n switch (anchor.version) {\n case 7:\n return canonicalizeAnchorV7(anchor);\n case 6:\n return canonicalizeAnchorV6(anchor);\n case 4:\n return canonicalizeAnchorV4(anchor);\n case 1:\n case 2:\n case 3:\n return canonicalizeAnchor(anchor);\n default:\n // format-spec §9.2: any other version (5 is withdrawn) has no canonical\n // form. Never canonicalize it as the closest known one.\n throw new AnchorVerificationError(\"unsupported anchor version\");\n }\n}\n\nfunction subjectFrom(data: Record<string, unknown>): string {\n // v3-v5 spell it `company_id`; v6 spells it `subject`. Both are accepted so\n // an anchor of either version loads.\n //\n // Two DIFFERENT values under the two spellings is an error, never a\n // precedence rule: canonicalizing either reading produces bytes the signature\n // does not cover, so silently preferring one would turn a malformed anchor\n // into a confidently wrong verdict.\n const subject = ((data.subject ?? data.subjectId) as string) ?? \"\";\n const company = ((data.company_id ?? data.companyId) as string) ?? \"\";\n if (subject && company && subject !== company) {\n throw new AnchorVerificationError(\n \"anchor carries both 'subject' and 'company_id' with different values; \" +\n \"which one the signature covers cannot be determined\"\n );\n }\n return subject || company;\n}\n\n/**\n * Version=4 canonical form (ui_chainops_18). Adds verified_through to\n * the v3 layout. Fields remain in alphabetical order per RFC 8785;\n * verified_through sorts between range and signing_key_id.\n *\n * Cross-language byte equivalence with Go canonicalAnchorV4Data and\n * Python canonicalize_anchor_v4 is mandatory.\n */\nexport function canonicalizeAnchorV4(anchor: Anchor): string {\n // Manual assembly so int64 fields can be emitted with full precision\n // for `bigint` inputs. Key order is alphabetical per RFC 8785,\n // matching Go canonicalAnchorV4Data and Python canonicalize_anchor_v4.\n const verifiedThrough = anchor.verifiedThrough ?? 0;\n const parts: string[] = [\n `\"anchor_id\":${encodeJsonString(anchor.anchorId)}`,\n `\"chain_hash\":${encodeJsonString(anchor.chainHash)}`,\n `\"company_id\":${encodeJsonString(anchor.subject)}`,\n `\"created_at_ms\":${encodeInt64Token(anchor.createdAtMs)}`,\n `\"entry_count\":${encodeInt64Token(anchor.entryCount)}`,\n `\"previous_anchor_id\":${encodeJsonString(anchor.previousAnchorId)}`,\n `\"range\":{\"end_entry_id\":${encodeJsonString(anchor.range.endEntryId)},\"start_entry_id\":${encodeJsonString(anchor.range.startEntryId)}}`,\n `\"signing_key_id\":${encodeJsonString(anchor.signingKeyId)}`,\n `\"verified_through\":${encodeInt64Token(verifiedThrough)}`,\n `\"version\":${anchor.version}`,\n ];\n return `{${parts.join(\",\")}}`;\n}\n\nexport function canonicalizeAnchor(anchor: Anchor): string {\n // Manual assembly so int64 fields can be emitted with full precision\n // for `bigint` inputs. Key order matches AnchorCanonicalJSON (alphabetical).\n const parts: string[] = [\n `\"anchor_id\":${encodeJsonString(anchor.anchorId)}`,\n `\"chain_hash\":${encodeJsonString(anchor.chainHash)}`,\n `\"company_id\":${encodeJsonString(anchor.subject)}`,\n `\"created_at_ms\":${encodeInt64Token(anchor.createdAtMs)}`,\n `\"entry_count\":${encodeInt64Token(anchor.entryCount)}`,\n `\"previous_anchor_id\":${encodeJsonString(anchor.previousAnchorId)}`,\n `\"range\":{\"end_entry_id\":${encodeJsonString(anchor.range.endEntryId)},\"start_entry_id\":${encodeJsonString(anchor.range.startEntryId)}}`,\n `\"signing_key_id\":${encodeJsonString(anchor.signingKeyId)}`,\n `\"version\":${anchor.version}`,\n ];\n return `{${parts.join(\",\")}}`;\n}\n\n// =============================================================================\n// Parsing Functions\n// =============================================================================\n\n/**\n * Parse an anchor from a JSON object (flat snake_case format).\n *\n * # Description\n *\n * Parses an anchor from the flat JSON format delivered by the Aleutian\n * backend. Handles snake_case keys (primary) with camelCase as fallback\n * for backward compatibility.\n *\n * # Inputs\n *\n * - data: Dictionary containing anchor data with snake_case keys\n *\n * # Outputs\n *\n * - Anchor: Parsed Anchor object\n *\n * # Example\n *\n * const anchor = parseAnchor(JSON.parse(anchorJson));\n *\n * # Limitations\n *\n * - Does not validate field values beyond type coercion\n * - LENIENT, and so not a reader for anchor files: `data` has already been\n * through `JSON.parse`, which kept the last of any repeated member and\n * rounded integers above 2^53, and this function also accepts camelCase\n * names and unknown members. To read an anchor's text as format-spec §9.8\n * requires, use `parseAnchorText` (which `loadAnchor` does).\n *\n * # Assumptions\n *\n * - data is a flat object (not nested with chain_state/metadata sub-objects)\n */\n/**\n * Coerce a JSON int64-field value to `bigint | number`.\n *\n * Accepts:\n * - JS `number` ≤ `Number.MAX_SAFE_INTEGER` — returned as `number`\n * (legacy callers see no API change)\n * - JS `number` > `Number.MAX_SAFE_INTEGER` — promoted to `bigint`\n * to preserve the (possibly-lossy) parsed value\n * - JS `string` — parsed as `bigint` for full-precision int64 values\n * that exceed JSON's safe-integer range\n * - JS `bigint` — passed through unchanged\n * - `undefined`/`null` — returns the default\n *\n * Ticket: dsar_js_anchor_int64_widening.\n */\nfunction coerceInt64Field(\n v: unknown,\n defaultValue: bigint | number,\n): bigint | number {\n if (v === undefined || v === null) {\n return defaultValue;\n }\n if (typeof v === \"bigint\") {\n return v;\n }\n if (typeof v === \"number\") {\n if (!Number.isFinite(v)) {\n return defaultValue;\n }\n if (Number.isSafeInteger(v)) {\n return v;\n }\n // Above MAX_SAFE_INTEGER: the value is already lossy from JSON.parse,\n // but promote to bigint so downstream encoding does not double-degrade.\n return BigInt(Math.trunc(v));\n }\n if (typeof v === \"string\") {\n try {\n return BigInt(v);\n } catch {\n return defaultValue;\n }\n }\n return defaultValue;\n}\n\nexport function parseAnchor(data: Record<string, unknown>): Anchor {\n return {\n version: (data.version as number) ?? 2,\n anchorId: ((data.anchor_id ?? data.anchorId) as string) ?? \"\",\n subject: subjectFrom(data),\n chainHash: ((data.chain_hash ?? data.chainHash) as string) ?? \"\",\n range: parseRange((data.range ?? {}) as Record<string, unknown>),\n entryCount: coerceInt64Field(data.entry_count ?? data.entryCount, 0),\n signature: (data.signature as string) ?? \"\",\n signingKeyId: ((data.signing_key_id ?? data.signingKeyId) as string) ?? \"\",\n createdAtMs: coerceInt64Field(data.created_at_ms ?? data.createdAtMs, 0),\n previousAnchorId:\n ((data.previous_anchor_id ?? data.previousAnchorId) as string) ?? \"\",\n verifiedThrough: coerceInt64Field(\n data.verified_through ?? data.verifiedThrough,\n 0,\n ),\n ...optionalString(\"previousAnchorHash\", data.previous_anchor_hash ?? data.previousAnchorHash),\n };\n}\n\nfunction optionalString(name: string, v: unknown): Record<string, string> {\n return typeof v === \"string\" ? { [name]: v } : {};\n}\n\n/** A v7 sequence number (a decimal string on the wire) as a bigint; absent stays absent. */\nfunction optionalSeq(name: string, v: unknown): Record<string, bigint | number> {\n if (v === undefined || v === null) return {};\n return { [name]: coerceInt64Field(v, -1) };\n}\n\nfunction parseRange(r: Record<string, unknown>): AnchorRange {\n return {\n startEntryId:\n ((r.start_entry_id ?? r.startEntryId) as string) ?? \"\",\n endEntryId:\n ((r.end_entry_id ?? r.endEntryId) as string) ?? \"\",\n ...optionalSeq(\"startSeq\", r.start_seq ?? r.startSeq),\n ...optionalSeq(\"endSeq\", r.end_seq ?? r.endSeq),\n };\n}\n\n/**\n * Parse exported entries from JSON array.\n *\n * # Description\n *\n * Parses an array of exported entry objects into ExportedEntry values.\n * Handles both camelCase and snake_case field names.\n *\n * # Inputs\n *\n * - data: Array of entry objects from a data export JSON file\n *\n * # Outputs\n *\n * - ExportedEntry[]: Array of parsed ExportedEntry objects\n *\n * # Example\n *\n * const entries = parseExportedEntries(rawArray);\n *\n * # Limitations\n *\n * - Does not validate hash formats or entry ordering\n * - LENIENT, and so not a reader for entries files: `data` has already been\n * through `JSON.parse` (last duplicate member kept, integers above 2^53\n * rounded), and a missing member becomes \"\" or 0 here. To read an entries\n * file's text, use `parseEntriesText` (which `loadExportedEntries` does).\n *\n * # Assumptions\n *\n * - Each element has at least entry_id or entryId present\n */\nfunction formatVersionFrom(e: Record<string, unknown>): { formatVersion?: number } {\n const v = e.format_version ?? e.formatVersion;\n return v === undefined || v === null ? {} : { formatVersion: v as number };\n}\n\nexport function parseExportedEntries(\n data: readonly Record<string, unknown>[]\n): ExportedEntry[] {\n return data.map((e) => ({\n entryId: ((e.entry_id ?? e.entryId) as string) ?? \"\",\n entryType: ((e.entry_type ?? e.entryType) as string) ?? \"\",\n timestamp: (e.timestamp as string) ?? \"\",\n runId: ((e.run_id ?? e.runId) as string) ?? \"\",\n sequenceNum: ((e.sequence_num ?? e.sequenceNum) as number) ?? 0,\n globalSeq: ((e.global_seq ?? e.globalSeq) as number) ?? 0,\n contentHash: ((e.content_hash ?? e.contentHash) as string) ?? \"\",\n chainHash: ((e.chain_hash ?? e.chainHash) as string) ?? \"\",\n // Which preimage produced chainHash. Dropping it would have every v3\n // entry recomputed as v2 and reported as a hash mismatch.\n ...formatVersionFrom(e),\n // Chain format v4 (format-spec §2.0). Lenient: absent members are not\n // recorded, so an empty string counts as absent (see `presentMembers`).\n ...optionalString(\"salt\", e.salt),\n ...optionalString(\"leafHash\", e.leaf_hash ?? e.leafHash),\n ...(typeof e.erased === \"boolean\" ? { erased: e.erased } : {}),\n }));\n}\n\n// Node-only filesystem loaders (`loadAnchor`, `loadExportedEntries`)\n// live in `./anchorLoaders.ts` and are re-exported only from the Node\n// entry point (`src/index.ts`), NOT from here, so the browser bundle\n// does not pull `await import(\"fs/promises\")` into its reachable graph.\n// See `dsar_js_browser_target_audit`.\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * A strict JSON parser for proof bundles and checkpoint text\n * (bundle-format §3).\n *\n * `JSON.parse` cannot be used: it silently keeps the LAST of two duplicate\n * member names, rounds numbers above 2⁵³, and accepts lone surrogates; and\n * `TextDecoder` replaces invalid UTF-8 unless told not to, and strips a BOM.\n * This parser works on the raw bytes and:\n *\n * - accepts only valid UTF-8 (no overlong forms, no encoded surrogates, nothing\n * above U+10FFFF), and refuses a byte-order mark (it is not a JSON token);\n * - refuses a lone surrogate, raw or as a `\\u` escape;\n * - limits nesting depth (the top-level value is depth 1; each array or object\n * inside another adds one);\n * - keeps numbers as their source text (never a JS number), so nothing rounds;\n * - REPORTS duplicate member names, compared after unescaping, instead of\n * choosing one, so the caller can apply §9.1's precedence (a grammar error\n * anywhere in the document outranks a duplicate).\n *\n * The lexical layer, {@link StrictJsonScanner}, is shared with the streaming\n * bundle reader (`proofBundleReader.ts`), which checks the bundle's structure\n * as it scans instead of building a tree.\n *\n * Its failures carry no position and no input: a parser error must never quote\n * the bundle (§10). Browser-safe.\n */\n\n/** A JSON number, kept as its exact source text (RFC 8259 grammar). */\nexport class JsonNumber {\n constructor(readonly text: string) {}\n}\n\n/** A JSON object. Member names are compared exactly, case-sensitively. */\nexport class JsonObject {\n readonly members = new Map<string, JsonValue>();\n}\n\n/** Any parsed JSON value. Arrays are plain arrays. */\nexport type JsonValue = string | boolean | null | JsonNumber | JsonObject | JsonValue[];\n\n/** The outcome of {@link parseStrictJson}. */\nexport type StrictJsonResult =\n | { readonly ok: true; readonly value: JsonValue; readonly duplicateKey: boolean }\n | { readonly ok: false };\n\n/** Signals a grammar violation. Deliberately carries no detail. */\nclass GrammarViolation {}\nconst VIOLATION = new GrammarViolation();\n\nconst QUOTE = 0x22;\nconst BACKSLASH = 0x5c;\n\nfunction isDigit(c: number | undefined): boolean {\n return c !== undefined && c >= 0x30 && c <= 0x39;\n}\n\n/**\n * The lexical layer of §3: whitespace, literals, numbers and strings, over raw\n * bytes. Every method throws an opaque violation on a grammar error; run the\n * scan inside {@link runStrict} to turn that into a result.\n *\n * Not safe for concurrent use: a scanner holds its position. Make one per\n * document.\n *\n * @internal\n */\nexport class StrictJsonScanner {\n protected pos = 0;\n private readonly decoder = new TextDecoder(\"utf-8\", { fatal: true, ignoreBOM: true });\n /** Reused output buffer for strings that hold escapes (grows by doubling). */\n private scratch = new Uint8Array(0);\n private scratchLength = 0;\n\n constructor(\n protected readonly b: Uint8Array,\n protected readonly maxDepth: number\n ) {}\n\n /** Throw the opaque grammar violation. */\n protected fail(): never {\n throw VIOLATION;\n }\n\n protected peek(): number | undefined {\n return this.b[this.pos];\n }\n\n protected skipWhitespace(): void {\n const b = this.b;\n while (this.pos < b.length) {\n const c = b[this.pos]!;\n if (c !== 0x20 && c !== 0x09 && c !== 0x0a && c !== 0x0d) return;\n this.pos++;\n }\n }\n\n protected expect(c: number): void {\n if (this.b[this.pos] !== c) this.fail();\n this.pos++;\n }\n\n /** The end of the document: only whitespace may follow the top-level value. */\n protected expectEnd(): void {\n this.skipWhitespace();\n if (this.pos !== this.b.length) this.fail();\n }\n\n protected literal(word: string): void {\n for (let i = 0; i < word.length; i++) {\n if (this.b[this.pos + i] !== word.charCodeAt(i)) this.fail();\n }\n this.pos += word.length;\n }\n\n /** Skip a number, holding it to RFC 8259's grammar exactly. */\n protected skipNumber(): void {\n const b = this.b;\n let p = this.pos;\n if (b[p] === 0x2d) p++;\n if (b[p] === 0x30) p++;\n else if (isDigit(b[p]) && b[p] !== 0x30) while (isDigit(b[p])) p++;\n else this.fail();\n if (b[p] === 0x2e) {\n p++;\n if (!isDigit(b[p])) this.fail();\n while (isDigit(b[p])) p++;\n }\n if (b[p] === 0x65 || b[p] === 0x45) {\n p++;\n if (b[p] === 0x2b || b[p] === 0x2d) p++;\n if (!isDigit(b[p])) this.fail();\n while (isDigit(b[p])) p++;\n }\n // A number character right after a complete number (`01`, `1-2`) is\n // refused by whatever reads next: it cannot follow a value.\n this.pos = p;\n }\n\n /** Read a number as its source text (ASCII, so UTF-8 decoding is exact). */\n protected readNumber(): string {\n const start = this.pos;\n this.skipNumber();\n return this.decoder.decode(this.b.subarray(start, this.pos));\n }\n\n /** Read a string (the cursor is on its opening quote) and decode it. */\n protected readString(): string {\n return this.scanString(true);\n }\n\n /** Check a string (the cursor is on its opening quote) without decoding it. */\n protected skipString(): void {\n this.scanString(false);\n }\n\n /**\n * Scan one string. Raw runs are validated in place; escapes are written,\n * with the runs around them, into one reused byte buffer, so a string full of\n * escapes costs one decode, not one allocation per escape.\n */\n private scanString(decode: boolean): string {\n const b = this.b;\n this.pos++; // opening quote\n const start = this.pos;\n let runStart = start;\n let escaped = false;\n this.scratchLength = 0;\n for (;;) {\n const c = b[this.pos];\n if (c === undefined) this.fail();\n if (c === QUOTE) {\n const end = this.pos;\n this.pos++;\n if (!decode) return \"\";\n if (!escaped)\n return end === start ? \"\" : this.decoder.decode(b.subarray(start, end));\n this.put(b.subarray(runStart, end));\n return this.decoder.decode(this.scratch.subarray(0, this.scratchLength));\n }\n if (c < 0x20) this.fail();\n if (c < 0x80 && c !== BACKSLASH) {\n this.pos++;\n continue;\n }\n if (c >= 0x80) {\n this.pos += this.utf8Length(this.pos);\n continue;\n }\n // An escape.\n if (decode) {\n escaped = true;\n this.put(b.subarray(runStart, this.pos));\n }\n const e = b[this.pos + 1];\n this.pos += 2;\n let cp: number;\n switch (e) {\n case 0x22:\n cp = 0x22;\n break;\n case 0x5c:\n cp = 0x5c;\n break;\n case 0x2f:\n cp = 0x2f;\n break;\n case 0x62:\n cp = 0x08;\n break;\n case 0x66:\n cp = 0x0c;\n break;\n case 0x6e:\n cp = 0x0a;\n break;\n case 0x72:\n cp = 0x0d;\n break;\n case 0x74:\n cp = 0x09;\n break;\n case 0x75: {\n const unit = this.hex4(this.pos);\n this.pos += 4;\n if (unit >= 0xdc00 && unit <= 0xdfff) this.fail(); // lone low surrogate\n if (unit >= 0xd800 && unit <= 0xdbff) {\n // A high surrogate must be followed at once by an escaped low one.\n if (b[this.pos] !== BACKSLASH || b[this.pos + 1] !== 0x75) this.fail();\n const low = this.hex4(this.pos + 2);\n if (low < 0xdc00 || low > 0xdfff) this.fail();\n this.pos += 6;\n cp = 0x10000 + ((unit - 0xd800) << 10) + (low - 0xdc00);\n } else {\n cp = unit;\n }\n break;\n }\n default:\n this.fail();\n }\n if (decode) this.putCodePoint(cp);\n runStart = this.pos;\n }\n }\n\n private reserve(n: number): void {\n const need = this.scratchLength + n;\n if (need <= this.scratch.length) return;\n const grown = new Uint8Array(Math.max(need, this.scratch.length * 2, 256));\n grown.set(this.scratch.subarray(0, this.scratchLength));\n this.scratch = grown;\n }\n\n private put(run: Uint8Array): void {\n if (run.length === 0) return;\n this.reserve(run.length);\n this.scratch.set(run, this.scratchLength);\n this.scratchLength += run.length;\n }\n\n /** Append one code point as UTF-8 (escapes never yield a lone surrogate). */\n private putCodePoint(cp: number): void {\n this.reserve(4);\n const s = this.scratch;\n let n = this.scratchLength;\n if (cp < 0x80) {\n s[n++] = cp;\n } else if (cp < 0x800) {\n s[n++] = 0xc0 | (cp >> 6);\n s[n++] = 0x80 | (cp & 0x3f);\n } else if (cp < 0x10000) {\n s[n++] = 0xe0 | (cp >> 12);\n s[n++] = 0x80 | ((cp >> 6) & 0x3f);\n s[n++] = 0x80 | (cp & 0x3f);\n } else {\n s[n++] = 0xf0 | (cp >> 18);\n s[n++] = 0x80 | ((cp >> 12) & 0x3f);\n s[n++] = 0x80 | ((cp >> 6) & 0x3f);\n s[n++] = 0x80 | (cp & 0x3f);\n }\n this.scratchLength = n;\n }\n\n private hex4(at: number): number {\n let v = 0;\n for (let i = 0; i < 4; i++) {\n const c = this.b[at + i];\n let d: number;\n if (c === undefined) this.fail();\n if (c >= 0x30 && c <= 0x39) d = c - 0x30;\n else if (c >= 0x61 && c <= 0x66) d = c - 0x61 + 10;\n else if (c >= 0x41 && c <= 0x46) d = c - 0x41 + 10;\n else this.fail();\n v = v * 16 + d;\n }\n return v;\n }\n\n /** Validate one UTF-8 sequence starting at `at`; return its length. */\n private utf8Length(at: number): number {\n const b = this.b;\n const c0 = b[at]!;\n const cont = (i: number, lo = 0x80, hi = 0xbf): void => {\n const c = b[at + i];\n if (c === undefined || c < lo || c > hi) this.fail();\n };\n if (c0 >= 0xc2 && c0 <= 0xdf) {\n cont(1);\n return 2;\n }\n if (c0 >= 0xe0 && c0 <= 0xef) {\n if (c0 === 0xe0) cont(1, 0xa0, 0xbf);\n else if (c0 === 0xed)\n cont(1, 0x80, 0x9f); // no encoded surrogates\n else cont(1);\n cont(2);\n return 3;\n }\n if (c0 >= 0xf0 && c0 <= 0xf4) {\n if (c0 === 0xf0) cont(1, 0x90, 0xbf);\n else if (c0 === 0xf4) cont(1, 0x80, 0x8f);\n else cont(1);\n cont(2);\n cont(3);\n return 4;\n }\n this.fail();\n }\n}\n\n/**\n * Run a scan, turning a grammar violation into `{ ok: false }`.\n *\n * @internal\n */\nexport function runStrict<T>(scan: () => T): { ok: true; value: T } | { ok: false } {\n try {\n return { ok: true, value: scan() };\n } catch (err) {\n if (err === VIOLATION) return { ok: false };\n // TextDecoder (fatal) on bytes this scanner already validated cannot fail;\n // if it ever does, the input is still not valid UTF-8 JSON.\n if (err instanceof TypeError) return { ok: false };\n throw new Error(\"strict JSON parser: internal error\");\n }\n}\n\n/** Builds the whole tree. Used for checkpoint text (at most 1 MiB). */\nclass TreeParser extends StrictJsonScanner {\n duplicateKey = false;\n\n parseDocument(): JsonValue {\n this.skipWhitespace();\n const v = this.parseValue(1);\n this.expectEnd();\n return v;\n }\n\n private parseValue(depth: number): JsonValue {\n const c = this.peek();\n switch (c) {\n case 0x7b: // {\n return this.parseObject(depth);\n case 0x5b: // [\n return this.parseArray(depth);\n case QUOTE:\n return this.readString();\n case 0x74: // t\n this.literal(\"true\");\n return true;\n case 0x66: // f\n this.literal(\"false\");\n return false;\n case 0x6e: // n\n this.literal(\"null\");\n return null;\n default:\n return new JsonNumber(this.readNumber());\n }\n }\n\n private parseArray(depth: number): JsonValue[] {\n if (depth > this.maxDepth) this.fail();\n this.pos++; // [\n const items: JsonValue[] = [];\n this.skipWhitespace();\n if (this.peek() === 0x5d) {\n this.pos++;\n return items;\n }\n for (;;) {\n this.skipWhitespace();\n items.push(this.parseValue(depth + 1));\n this.skipWhitespace();\n const c = this.peek();\n if (c === 0x2c) {\n this.pos++;\n continue;\n }\n if (c === 0x5d) {\n this.pos++;\n return items;\n }\n this.fail();\n }\n }\n\n private parseObject(depth: number): JsonObject {\n if (depth > this.maxDepth) this.fail();\n this.pos++; // {\n const obj = new JsonObject();\n this.skipWhitespace();\n if (this.peek() === 0x7d) {\n this.pos++;\n return obj;\n }\n for (;;) {\n this.skipWhitespace();\n if (this.peek() !== QUOTE) this.fail();\n const name = this.readString();\n this.skipWhitespace();\n this.expect(0x3a); // :\n this.skipWhitespace();\n const value = this.parseValue(depth + 1);\n if (obj.members.has(name)) this.duplicateKey = true;\n else obj.members.set(name, value);\n this.skipWhitespace();\n const c = this.peek();\n if (c === 0x2c) {\n this.pos++;\n continue;\n }\n if (c === 0x7d) {\n this.pos++;\n return obj;\n }\n this.fail();\n }\n }\n}\n\n/**\n * Parse bytes as JSON under bundle-format §3.\n *\n * # Description\n *\n * Returns `{ ok: false }` for anything that is not valid UTF-8 JSON under §3\n * (including a BOM, a lone surrogate, and depth beyond `maxDepth`). Otherwise\n * returns the value and whether any object repeated a member name (compared\n * after unescaping). For a repeated name, the first value is kept; a caller\n * that sees `duplicateKey` must not trust the tree.\n *\n * # Inputs\n *\n * - bytes: the document\n * - maxDepth: the nesting limit (8 in bundle-format §3)\n *\n * # Outputs\n *\n * - StrictJsonResult: never throws on any input\n *\n * # Example\n *\n * const r = parseStrictJson(bytes, 8);\n * if (!r.ok) return \"json\";\n * if (r.duplicateKey) return \"duplicate-key\";\n *\n * # Limitations\n *\n * - Builds the whole tree: memory grows with the number of values. The\n * bundle itself is read by the streaming `readProofBundle`; this parser\n * reads checkpoint text, which is at most 1 MiB.\n * - Numbers are checked against RFC 8259 only; a caller applies any stricter\n * rule (checkpoint text's `0|[1-9][0-9]*`, at most 2⁵³−1).\n *\n * # Assumptions\n *\n * - None.\n */\nexport function parseStrictJson(bytes: Uint8Array, maxDepth: number): StrictJsonResult {\n const parser = new TreeParser(bytes, maxDepth);\n const r = runStrict(() => parser.parseDocument());\n return r.ok ? { ok: true, value: r.value, duplicateKey: parser.duplicateKey } : r;\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Strict readers for the TEXT of an entries file and of an anchor\n * (format-spec §9.8 and §11).\n *\n * `JSON.parse` cannot be used for either. It silently keeps the LAST of two\n * members with one name, so two readers of one file can see two different\n * documents; it rounds integers above 2^53, so a `global_seq` beyond that is\n * not the one on the wire; and it has no opinion about a member spelled in\n * another case, which a case-insensitive reader elsewhere would accept as the\n * real one. These readers work on `strictJson.ts`, which reports duplicates\n * and keeps numbers as their source text.\n *\n * Their failures name a member, never a value: an error must not quote the\n * file it refuses. Browser-safe: no Node APIs.\n */\n\nimport { AnchorVerificationError, EntriesFormatError } from \"./errors.js\";\nimport { JsonNumber, JsonObject, parseStrictJson } from \"./strictJson.js\";\nimport type { JsonValue } from \"./strictJson.js\";\nimport type { Anchor, ExportedEntry } from \"./types.js\";\n\n// An entry is an object of scalars, and an anchor an object holding one more.\n// Unknown entry members are tolerated (below), so allow them some structure.\nconst MAX_ENTRIES_DEPTH = 32;\nconst MAX_ANCHOR_DEPTH = 2;\n\n// A JSON integer as these formats write one: no fraction, no exponent, no\n// leading zeros, and no \"-0\".\nconst INTEGER_TEXT = /^(0|-?[1-9][0-9]*)$/;\nconst MIN_INT64 = -(2n ** 63n);\nconst MAX_INT64 = 2n ** 63n - 1n;\n\nconst ENCODER = new TextEncoder();\n\nfunction toBytes(text: string | Uint8Array): Uint8Array {\n return typeof text === \"string\" ? ENCODER.encode(text) : text;\n}\n\n/** Read a JSON number as an exact 64-bit integer, or null when it is not one. */\nfunction int64Of(value: JsonValue | undefined): bigint | null {\n if (!(value instanceof JsonNumber) || !INTEGER_TEXT.test(value.text)) return null;\n // The pattern bounds nothing; 20 digits is past int64 and cheap to refuse.\n if (value.text.length > 20) return null;\n const n = BigInt(value.text);\n return n < MIN_INT64 || n > MAX_INT64 ? null : n;\n}\n\n/** A `number` while it is exact, a `bigint` beyond that: never a rounded value. */\nfunction narrow(n: bigint): number | bigint {\n return n >= BigInt(Number.MIN_SAFE_INTEGER) && n <= BigInt(Number.MAX_SAFE_INTEGER)\n ? Number(n)\n : n;\n}\n\n/**\n * A member name under Unicode simple case folding, as far as it can reach a\n * format member: the known names are ASCII, and the only other characters\n * that fold to an ASCII letter are U+017F LATIN SMALL LETTER LONG S (to `s`)\n * and U+212A KELVIN SIGN (to `k`). `toLowerCase` alone leaves both alone.\n */\nfunction foldName(name: string): string {\n return name.replace(/\\u017f/g, \"s\").replace(/\\u212a/g, \"k\").toLowerCase();\n}\n\n/**\n * Report a member whose name folds to a known snake_case name without being it\n * (`CHAIN_HASH`, or `ſalt` with U+017F). A case-folding reader takes it for the\n * real member, an exact one does not, and the two then verify different\n * documents.\n */\nfunction hasMiscasedMember(\n obj: JsonObject,\n snake: ReadonlySet<string>,\n aliases: ReadonlySet<string>\n): boolean {\n for (const name of obj.members.keys()) {\n if (!snake.has(name) && !aliases.has(name) && snake.has(foldName(name))) return true;\n }\n return false;\n}\n\n/** Thrown by {@link pick}; each reader turns it into its own error type. */\nclass BothSpellings {\n constructor(readonly snake: string) {}\n}\n\n/**\n * Read a member under its snake_case name or its camelCase alias. A document\n * carrying BOTH spellings of one member is refused: two readers that each\n * prefer a different one would see two different documents.\n */\nfunction pick(obj: JsonObject, snake: string, ...aliases: string[]): JsonValue | undefined {\n let found: JsonValue | undefined;\n let seen = 0;\n for (const name of [snake, ...aliases]) {\n if (obj.members.has(name)) {\n seen++;\n found = obj.members.get(name);\n }\n }\n if (seen > 1) throw new BothSpellings(snake);\n return found;\n}\n\n// =============================================================================\n// Entries\n// =============================================================================\n\n// snake_case name -> the camelCase alias `parseExportedEntries` also accepts.\nconst ENTRY_ALIASES: Readonly<Record<string, string>> = {\n entry_id: \"entryId\",\n entry_type: \"entryType\",\n timestamp: \"timestamp\",\n run_id: \"runId\",\n sequence_num: \"sequenceNum\",\n global_seq: \"globalSeq\",\n content_hash: \"contentHash\",\n chain_hash: \"chainHash\",\n format_version: \"formatVersion\",\n salt: \"salt\",\n leaf_hash: \"leafHash\",\n erased: \"erased\",\n};\nconst ENTRY_SNAKE: ReadonlySet<string> = new Set(Object.keys(ENTRY_ALIASES));\nconst ENTRY_CAMEL: ReadonlySet<string> = new Set(Object.values(ENTRY_ALIASES));\n// Without these four an object is not an entry at all.\nconst ENTRY_REQUIRED = [\"entry_id\", \"timestamp\", \"content_hash\", \"chain_hash\"] as const;\n\nfunction notEntries(detail: string): EntriesFormatError {\n return new EntriesFormatError(`not an entries file: ${detail}`);\n}\n\nfunction entryMember(obj: JsonObject, snake: string): JsonValue | undefined {\n const alias = ENTRY_ALIASES[snake]!;\n try {\n return alias === snake ? obj.members.get(snake) : pick(obj, snake, alias);\n } catch (err) {\n if (err instanceof BothSpellings) {\n throw notEntries(`an entry carries ${snake} under two spellings`);\n }\n throw err;\n }\n}\n\nfunction entryString(obj: JsonObject, snake: string, required: boolean): string {\n const v = entryMember(obj, snake);\n if (v === undefined) {\n if (required) throw notEntries(`an entry has no ${snake}`);\n return \"\";\n }\n if (typeof v !== \"string\") throw notEntries(`an entry's ${snake} is not a string`);\n return v;\n}\n\nfunction entryInteger(obj: JsonObject, snake: string): bigint | undefined {\n const v = entryMember(obj, snake);\n if (v === undefined) return undefined;\n const n = int64Of(v);\n if (n === null) throw notEntries(`an entry's ${snake} is not an integer`);\n return n;\n}\n\n/** `salt` and `leaf_hash` when present (strings), and `erased` (a boolean). */\nfunction v4Members(obj: JsonObject): Pick<ExportedEntry, \"salt\" | \"leafHash\" | \"erased\"> {\n const out: { salt?: string; leafHash?: string; erased?: boolean } = {};\n if (entryMember(obj, \"salt\") !== undefined) out.salt = entryString(obj, \"salt\", true);\n if (entryMember(obj, \"leaf_hash\") !== undefined) {\n out.leafHash = entryString(obj, \"leaf_hash\", true);\n }\n const erased = entryMember(obj, \"erased\");\n if (erased !== undefined) {\n if (typeof erased !== \"boolean\") throw notEntries(\"an entry's erased is not a boolean\");\n out.erased = erased;\n }\n return out;\n}\n\n/**\n * A v4 entry (format-spec §2.0). Its id, type and content hash are absent\n * from an erased entry, so only `timestamp` and `chain_hash` are required to\n * make it an entry; which members it carries is recorded, because v4 tells an\n * absent member from an empty one and the verifier judges the two shapes.\n */\nfunction entryV4From(value: JsonObject, formatVersion: bigint): ExportedEntry {\n const present = new Set<string>();\n for (const snake of ENTRY_SNAKE) {\n if (entryMember(value, snake) !== undefined) present.add(snake);\n }\n const sequenceNum = narrow(entryInteger(value, \"sequence_num\") ?? 0n);\n if (typeof sequenceNum !== \"number\") {\n throw notEntries(\"an entry's sequence_num is out of range\");\n }\n return {\n entryId: entryString(value, \"entry_id\", false),\n entryType: entryString(value, \"entry_type\", false),\n timestamp: entryString(value, \"timestamp\", true),\n runId: entryString(value, \"run_id\", false),\n sequenceNum,\n globalSeq: narrow(entryInteger(value, \"global_seq\") ?? 0n),\n contentHash: entryString(value, \"content_hash\", false),\n chainHash: entryString(value, \"chain_hash\", true),\n formatVersion: Number(formatVersion),\n ...v4Members(value),\n presentMembers: present,\n };\n}\n\nfunction entryFrom(value: JsonValue): ExportedEntry {\n if (!(value instanceof JsonObject)) {\n throw notEntries(\"an entry is not a JSON object\");\n }\n if (hasMiscasedMember(value, ENTRY_SNAKE, ENTRY_CAMEL)) {\n throw notEntries(\"an entry member is spelled in another case\");\n }\n // Dispatch on the declared format only (format-spec §2.2).\n const declared = entryInteger(value, \"format_version\");\n if (declared === 4n) return entryV4From(value, declared);\n\n const [entryId, timestamp, contentHash, chainHash] = ENTRY_REQUIRED.map((name) =>\n entryString(value, name, true)\n ) as [string, string, string, string];\n\n // Optional members default to \"\" / 0 / absent. v3 exports always write\n // `\"run_id\": \"\"` and `\"sequence_num\": 0`; leaving them out means the same.\n const sequenceNum = narrow(entryInteger(value, \"sequence_num\") ?? 0n);\n if (typeof sequenceNum !== \"number\") {\n throw notEntries(\"an entry's sequence_num is out of range\");\n }\n // Absent means v2 (format-spec §2.2). An unknown version is carried through\n // for the verifier to report; it is never guessed here.\n const formatVersion = entryInteger(value, \"format_version\");\n\n return {\n entryId,\n entryType: entryString(value, \"entry_type\", false),\n timestamp,\n runId: entryString(value, \"run_id\", false),\n sequenceNum,\n globalSeq: narrow(entryInteger(value, \"global_seq\") ?? 0n),\n contentHash,\n chainHash,\n ...(formatVersion === undefined ? {} : { formatVersion: Number(formatVersion) }),\n // A v4 member on a v2 or v3 entry is carried through for the verifier to\n // report as format_field_misuse (format-spec §2.2), never dropped.\n ...v4Members(value),\n };\n}\n\nfunction strictDocument(bytes: Uint8Array): JsonValue | undefined {\n const r = parseStrictJson(bytes, MAX_ENTRIES_DEPTH);\n if (!r.ok) return undefined;\n if (r.duplicateKey) throw notEntries(\"a member name is repeated\");\n return r.value;\n}\n\nfunction strictValue(bytes: Uint8Array, what: string): JsonValue {\n const v = strictDocument(bytes);\n if (v === undefined) throw notEntries(`${what} is not valid JSON`);\n return v;\n}\n\nfunction firstNonSpace(b: Uint8Array): number | undefined {\n for (const c of b) {\n if (c !== 0x20 && c !== 0x09 && c !== 0x0a && c !== 0x0d) return c;\n }\n return undefined;\n}\n\n/**\n * Decode the text of an entries file, refusing anything that is not entries.\n *\n * # Description\n *\n * Accepts the three forms an export takes:\n *\n * - one JSON array of entry objects;\n * - JSONL: one entry object per line (blank lines are skipped);\n * - the hosted platform's wrapper: one JSON object with an `entries` member\n * whose value is an array of entry objects. The wrapper's other members\n * are ignored. Any other top-level object is refused.\n *\n * Every v2 or v3 entry must carry `entry_id`, `timestamp`, `content_hash` and\n * `chain_hash` as strings. A v4 entry (`format_version: 4`, format-spec §2.0)\n * must carry `timestamp` and `chain_hash`: an erased one has no id, type or\n * content hash. `salt`, `leaf_hash` (strings) and `erased` (a boolean) are\n * read on every entry when present, and on a v4 entry the names of the\n * members it carried are returned in `presentMembers`, so the verifier can\n * judge its shape (absent is not empty in v4). `entry_type` and `run_id` (strings), and\n * `sequence_num`, `global_seq` and `format_version` (integers) are read when\n * present and are \"\" / 0 / absent otherwise. Each member may be spelled in\n * snake_case or in the camelCase alias `parseExportedEntries` accepts\n * (`entryId`, `chainHash`, ...). Members with other names are ignored.\n *\n * Refused, as an error and never as a broken chain: text that is not JSON, an\n * empty document or an empty array, `{}`, `null`, an export bundle, an anchor,\n * two objects on one line, a member name repeated in any object, an entry\n * carrying both spellings of one member, a name that case-folds to a known\n * snake_case name (`CHAIN_HASH`, `ſalt` with U+017F), a missing required\n * member, and a member that is null or of the wrong type (a `global_seq`\n * written as a string, a fraction, an exponent or `-0`). Text that is not\n * valid UTF-8, or escapes a lone surrogate, is refused and never repaired.\n *\n * This checks that the text IS entries. Whether the entries verify (hash\n * shapes, timestamps, the chain) is `verifyChainOffline`'s to report as breaks.\n *\n * # Inputs\n *\n * - text: The file's content. Pass the raw bytes when you have them: a\n * string has already had invalid UTF-8 replaced by whatever decoded it.\n *\n * # Outputs\n *\n * - ExportedEntry[]: At least one entry. `globalSeq` is a `number` up to\n * `Number.MAX_SAFE_INTEGER` and a `bigint` beyond it.\n * - EntriesFormatError: Thrown when the text is not entries. The message\n * names a member, never a value.\n *\n * # Example\n *\n * const entries = parseEntriesText(await response.text());\n * const result = await verifyChainOffline(entries);\n *\n * # Limitations\n *\n * - Builds every entry in memory.\n * - A single entry object spread over several lines is neither a wrapper nor\n * JSONL, and is refused.\n *\n * # Assumptions\n *\n * - None.\n */\nexport function parseEntriesText(text: string | Uint8Array): ExportedEntry[] {\n const bytes = toBytes(text);\n const first = firstNonSpace(bytes);\n if (first === undefined) throw notEntries(\"the document is empty\");\n\n let values: JsonValue[] | undefined;\n if (first === 0x5b) {\n // \"[\": one JSON array.\n const doc = strictValue(bytes, \"the document\");\n if (!Array.isArray(doc)) throw notEntries(\"the document is not an array of entries\");\n values = doc;\n } else if (first === 0x7b) {\n // \"{\": the wrapper, when the whole text is one object holding an\n // `entries` array. Anything else falls through to JSONL.\n const doc = strictDocument(bytes);\n if (doc instanceof JsonObject) {\n const wrapped = doc.members.get(\"entries\");\n if (Array.isArray(wrapped)) values = wrapped;\n }\n }\n if (values === undefined) {\n // JSONL: every non-blank line is exactly one JSON value.\n values = [];\n let start = 0;\n while (start < bytes.length) {\n let end = bytes.indexOf(0x0a, start);\n if (end === -1) end = bytes.length;\n const line = bytes.subarray(start, end);\n if (firstNonSpace(line) !== undefined) values.push(strictValue(line, \"a line\"));\n start = end + 1;\n }\n }\n if (values.length === 0) throw notEntries(\"it holds no entries\");\n return values.map(entryFrom);\n}\n\n// =============================================================================\n// Anchor\n// =============================================================================\n\n// format-spec §9.1: snake_case name -> the camelCase aliases `parseAnchor`\n// also accepts. Both subject names are listed so neither is \"unknown\"; which\n// one an anchor may carry is decided by its version, below.\nconst ANCHOR_ALIASES: Readonly<Record<string, readonly string[]>> = {\n version: [],\n anchor_id: [\"anchorId\"],\n subject: [\"subjectId\"],\n company_id: [\"companyId\"],\n chain_hash: [\"chainHash\"],\n range: [],\n entry_count: [\"entryCount\"],\n signature: [],\n signing_key_id: [\"signingKeyId\"],\n created_at_ms: [\"createdAtMs\"],\n previous_anchor_id: [\"previousAnchorId\"],\n previous_anchor_hash: [\"previousAnchorHash\"],\n verified_through: [\"verifiedThrough\"],\n};\nconst RANGE_ALIASES: Readonly<Record<string, readonly string[]>> = {\n start_entry_id: [\"startEntryId\"],\n end_entry_id: [\"endEntryId\"],\n start_seq: [\"startSeq\"],\n end_seq: [\"endSeq\"],\n};\n\n// format-spec §9.1 for v7: every member is required, signature included.\nconst V7_REQUIRED = [\n \"version\",\n \"anchor_id\",\n \"subject\",\n \"chain_hash\",\n \"range\",\n \"entry_count\",\n \"signature\",\n \"signing_key_id\",\n \"created_at_ms\",\n \"previous_anchor_id\",\n \"previous_anchor_hash\",\n] as const;\n// format-spec §2.1's decimal grammar: no sign, no leading zeros, 0 to 2^63 - 1.\nconst DECIMAL_TEXT = /^(0|[1-9][0-9]*)$/;\n\nfunction nameSets(table: Readonly<Record<string, readonly string[]>>) {\n return {\n table,\n snake: new Set(Object.keys(table)) as ReadonlySet<string>,\n aliases: new Set(Object.values(table).flat()) as ReadonlySet<string>,\n };\n}\nconst ANCHOR_NAMES = nameSets(ANCHOR_ALIASES);\nconst RANGE_NAMES = nameSets(RANGE_ALIASES);\ntype Names = typeof ANCHOR_NAMES;\n\nfunction refused(detail: string): AnchorVerificationError {\n return new AnchorVerificationError(`anchor refused: ${detail}`);\n}\n\nfunction onlyKnownMembers(obj: JsonObject, names: Names, where: string): void {\n if (hasMiscasedMember(obj, names.snake, names.aliases)) {\n throw refused(`${where} has a member spelled in another case`);\n }\n for (const name of obj.members.keys()) {\n if (!names.snake.has(name) && !names.aliases.has(name)) {\n throw refused(`${where} has an unknown member`);\n }\n }\n}\n\nfunction anchorMember(obj: JsonObject, names: Names, snake: string): JsonValue | undefined {\n try {\n return pick(obj, snake, ...names.table[snake]!);\n } catch (err) {\n if (err instanceof BothSpellings) throw refused(`${snake} is given under two spellings`);\n throw err;\n }\n}\n\n/** An absent string member reads as \"\"; `checkAnchorWellFormed` judges it. */\nfunction stringMember(obj: JsonObject, names: Names, snake: string): string {\n const v = anchorMember(obj, names, snake);\n if (v === undefined) return \"\";\n if (typeof v !== \"string\") throw refused(`${snake} is not a string`);\n return v;\n}\n\n/** An absent integer member reads as 0; `checkAnchorWellFormed` judges it. */\nfunction integerMember(obj: JsonObject, names: Names, snake: string): bigint {\n const v = anchorMember(obj, names, snake);\n if (v === undefined) return 0n;\n const n = int64Of(v);\n if (n === null) throw refused(`${snake} is not an integer`);\n return n;\n}\n\n/** A v7 decimal string member (`entry_count`, `start_seq`, `end_seq`) as a bigint. */\nfunction decimalMember(obj: JsonObject, names: Names, snake: string): bigint {\n const v = anchorMember(obj, names, snake);\n if (v === undefined) throw refused(`a v7 anchor has no ${snake}`);\n if (typeof v !== \"string\") throw refused(`${snake} is not a string`);\n if (!DECIMAL_TEXT.test(v) || v.length > 19 || BigInt(v) > MAX_INT64) {\n throw refused(`${snake} is not a decimal integer from 0 to 2^63 - 1`);\n }\n return BigInt(v);\n}\n\n/** A v7 anchor (format-spec §9.1, §9.8): every member required, each with its own JSON type. */\nfunction anchorV7From(doc: JsonObject, range: JsonObject | undefined): Anchor {\n for (const name of V7_REQUIRED) {\n if (anchorMember(doc, ANCHOR_NAMES, name) === undefined) {\n throw refused(`a v7 anchor has no ${name}`);\n }\n }\n if (anchorMember(doc, ANCHOR_NAMES, \"verified_through\") !== undefined) {\n throw refused(\"a v7 anchor has no verified_through\");\n }\n if (range === undefined) throw refused(\"a v7 anchor has no range\");\n for (const name of [\"start_entry_id\", \"end_entry_id\"]) {\n if (anchorMember(range, RANGE_NAMES, name) !== undefined) {\n throw refused(\"a v7 range names start_seq and end_seq, not entry ids\");\n }\n }\n return {\n version: 7,\n anchorId: stringMember(doc, ANCHOR_NAMES, \"anchor_id\"),\n subject: stringMember(doc, ANCHOR_NAMES, \"subject\"),\n chainHash: stringMember(doc, ANCHOR_NAMES, \"chain_hash\"),\n range: {\n startEntryId: \"\",\n endEntryId: \"\",\n startSeq: decimalMember(range, RANGE_NAMES, \"start_seq\"),\n endSeq: decimalMember(range, RANGE_NAMES, \"end_seq\"),\n },\n entryCount: decimalMember(doc, ANCHOR_NAMES, \"entry_count\"),\n signature: stringMember(doc, ANCHOR_NAMES, \"signature\"),\n signingKeyId: stringMember(doc, ANCHOR_NAMES, \"signing_key_id\"),\n createdAtMs: narrow(integerMember(doc, ANCHOR_NAMES, \"created_at_ms\")),\n previousAnchorId: stringMember(doc, ANCHOR_NAMES, \"previous_anchor_id\"),\n previousAnchorHash: stringMember(doc, ANCHOR_NAMES, \"previous_anchor_hash\"),\n };\n}\n\n/**\n * Parse the text of an anchor strictly (format-spec §9.8).\n *\n * # Description\n *\n * An anchor is read strictly: only the member names of §9.1, each at most\n * once, and `range` likewise. The subject is under the name its version uses\n * (`subject` from v6, `company_id` before); an anchor carrying the other name,\n * or both, is refused. A lenient parser accepts members the signature does not\n * cover and lets two readers see two different anchors.\n *\n * Each member may be spelled in snake_case or in the camelCase alias\n * `parseAnchor` accepts (`anchorId`, `chainHash`, `subjectId`, ...). An anchor\n * carrying BOTH spellings of one member is refused, and so is a known\n * snake_case name in another letter case (`ENTRY_COUNT`).\n *\n * A member of the wrong JSON type is refused; integers are JSON integers (no\n * quotes, no fraction, no exponent, no `-0`, within 64 bits) and are never\n * rounded. An ABSENT member is not refused here: it reads as \"\" or 0 (an\n * absent `range` as two empty ids), and `checkAnchorWellFormed` judges the\n * result. Nor is the version judged here.\n *\n * A v7 anchor is read more strictly (§9.8): every member of §9.1 is\n * required, `signature` included; `verified_through` and an entry-id range\n * are refused; `entry_count`, `range.start_seq` and `range.end_seq` must be\n * JSON STRINGS in §2.1's decimal grammar (a JSON number is refused: it would\n * round above 2^53) and are returned as bigints. A v1-v6 anchor carrying\n * `previous_anchor_hash` or a sequence range is refused.\n *\n * This is PARSING. The version, its invariants and the counts (§9.3, §9.8)\n * are checked by `checkAnchorWellFormed`, which `verifyAnchorLocally` and\n * `bindAnchorToEntries` both call.\n *\n * # Inputs\n *\n * - text: The anchor's JSON. Pass the raw bytes when you have them.\n *\n * # Outputs\n *\n * - Anchor: The parsed anchor. int64 fields are `number` while exact and\n * `bigint` beyond `Number.MAX_SAFE_INTEGER`.\n * - AnchorVerificationError: Thrown when the anchor is refused. The message\n * names a member, never a value.\n *\n * # Example\n *\n * const anchor = parseAnchorText(await response.text());\n * verifyAnchorLocally(anchor, publicKey);\n *\n * # Limitations\n *\n * - Does not verify the signature or bind the anchor to a chain.\n * - Returns an anchor that may be malformed (a missing member, a withdrawn\n * version): parse, then check.\n *\n * # Assumptions\n *\n * - None.\n */\nexport function parseAnchorText(text: string | Uint8Array): Anchor {\n const r = parseStrictJson(toBytes(text), MAX_ANCHOR_DEPTH);\n if (!r.ok) throw refused(\"not valid JSON for an anchor\");\n if (r.duplicateKey) throw refused(\"a member name is repeated\");\n const doc = r.value;\n if (!(doc instanceof JsonObject)) throw refused(\"not a JSON object\");\n onlyKnownMembers(doc, ANCHOR_NAMES, \"the anchor\");\n\n // Dispatch on the declared version only (§9.2). A version that is an\n // integer but not one this format defines is checkAnchorWellFormed's to\n // refuse; clamp it so `Number()` cannot round it into a known one.\n const declared = integerMember(doc, ANCHOR_NAMES, \"version\");\n const version = declared < 0n || declared > 1000n ? -1 : Number(declared);\n\n const subjectName = version === 6 || version === 7 ? \"subject\" : \"company_id\";\n const otherName = subjectName === \"subject\" ? \"company_id\" : \"subject\";\n if (anchorMember(doc, ANCHOR_NAMES, otherName) !== undefined) {\n throw refused(`this version names its subject ${subjectName}, not ${otherName}`);\n }\n\n const rangeValue = anchorMember(doc, ANCHOR_NAMES, \"range\");\n let range = new JsonObject();\n if (rangeValue !== undefined) {\n if (!(rangeValue instanceof JsonObject)) throw refused(\"range is not an object\");\n range = rangeValue;\n onlyKnownMembers(range, RANGE_NAMES, \"range\");\n }\n\n if (version === 7) return anchorV7From(doc, rangeValue === undefined ? undefined : range);\n // §9.8, the wrong range shape: v1-v6 name the range by entry id, and carry\n // no predecessor hash (the caller supplies it).\n if (\n anchorMember(range, RANGE_NAMES, \"start_seq\") !== undefined ||\n anchorMember(range, RANGE_NAMES, \"end_seq\") !== undefined\n ) {\n throw refused(\"a v1-v6 range names start_entry_id and end_entry_id, not sequence numbers\");\n }\n if (anchorMember(doc, ANCHOR_NAMES, \"previous_anchor_hash\") !== undefined) {\n throw refused(\"only a v7 anchor carries previous_anchor_hash\");\n }\n\n return {\n version,\n anchorId: stringMember(doc, ANCHOR_NAMES, \"anchor_id\"),\n subject: stringMember(doc, ANCHOR_NAMES, subjectName),\n chainHash: stringMember(doc, ANCHOR_NAMES, \"chain_hash\"),\n range: {\n startEntryId: stringMember(range, RANGE_NAMES, \"start_entry_id\"),\n endEntryId: stringMember(range, RANGE_NAMES, \"end_entry_id\"),\n },\n entryCount: narrow(integerMember(doc, ANCHOR_NAMES, \"entry_count\")),\n signature: stringMember(doc, ANCHOR_NAMES, \"signature\"),\n signingKeyId: stringMember(doc, ANCHOR_NAMES, \"signing_key_id\"),\n createdAtMs: narrow(integerMember(doc, ANCHOR_NAMES, \"created_at_ms\")),\n previousAnchorId: stringMember(doc, ANCHOR_NAMES, \"previous_anchor_id\"),\n verifiedThrough: narrow(integerMember(doc, ANCHOR_NAMES, \"verified_through\")),\n };\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Node-only filesystem loaders for anchor / exported-entries JSON files.\n *\n * Split out of `anchor.ts` as part of `dsar_js_browser_target_audit` so\n * the browser bundle (`src/index.browser.ts` → `dist/browser/`) does not\n * pull the dynamic `import(\"fs/promises\")` call into its reachable\n * graph. esbuild's tree-shaker cannot prove a dynamic import is dead,\n * so simply not re-exporting these from the browser entry was\n * insufficient — the loaders had to live in a different file the\n * browser entry never imports.\n *\n * The strict text readers (`parseAnchorText`, `parseEntriesText`) live in\n * `strictText.ts` and are the surface browsers use after `fetch()`-ing the\n * file themselves. The loaders here read the file's bytes and go through the\n * same two readers, so a file is refused or accepted alike in both places.\n */\n\nimport type { Anchor, ExportedEntry } from \"./types.js\";\nimport { parseAnchorText, parseEntriesText } from \"./strictText.js\";\n\n/**\n * Load anchor from JSON file (Node.js only).\n *\n * # Description\n *\n * Reads an anchor JSON file from disk and parses it STRICTLY with\n * parseAnchorText (format-spec §9.8): only the anchor's own member names,\n * spelled exactly, none repeated, the subject under its version's name.\n *\n * # Inputs\n *\n * - path: Filesystem path to the anchor JSON file\n *\n * # Outputs\n *\n * - Promise<Anchor>: Resolves to the parsed Anchor object\n * - Error: Rejects if the file cannot be read\n * - AnchorVerificationError: Rejects if the anchor is refused\n *\n * # Example\n *\n * const anchor = await loadAnchor('anchor-2026-01-20.json');\n *\n * # Limitations\n *\n * - Node.js only (uses fs/promises). Browser consumers should\n * `fetch(...)` the file themselves and pass its text (or bytes) to\n * `parseAnchorText` directly.\n *\n * # Assumptions\n *\n * - File is valid UTF-8 JSON in flat snake_case format\n */\nexport async function loadAnchor(path: string): Promise<Anchor> {\n const fs = await import(\"fs/promises\");\n // The bytes, not a decoded string: decoding would replace invalid UTF-8 and\n // strip a byte-order mark before the strict reader could refuse them.\n return parseAnchorText(new Uint8Array(await fs.readFile(path)));\n}\n\n/**\n * Load exported entries from JSON file (Node.js only).\n *\n * # Description\n *\n * Reads an entries file from disk and decodes it STRICTLY with\n * parseEntriesText: a JSON array of entries, JSONL, or the platform's\n * `{\"entries\": [...]}` wrapper. A file that is not\n * entries (an export bundle, an anchor, `{}`, an entry with a repeated or\n * missing member) is an error, never a broken chain.\n *\n * # Inputs\n *\n * - path: Filesystem path to the entries JSON file\n *\n * # Outputs\n *\n * - Promise<ExportedEntry[]>: Resolves to array of parsed ExportedEntry objects\n * - Error: Rejects if the file cannot be read\n * - EntriesFormatError: Rejects if the file is not entries\n *\n * # Example\n *\n * const entries = await loadExportedEntries('export-2026-01.json');\n *\n * # Limitations\n *\n * - Node.js only (uses fs/promises). Browser consumers should\n * `fetch(...)` the file themselves and pass its text (or bytes) to\n * `parseEntriesText` directly.\n * - The hosted platform's `{\"entries\": [...]}` wrapper is unwrapped; any\n * other top-level object is refused.\n *\n * # Assumptions\n *\n * - File is valid UTF-8: a JSON array of entries, JSONL, or the wrapper\n */\nexport async function loadExportedEntries(path: string): Promise<ExportedEntry[]> {\n const fs = await import(\"fs/promises\");\n return parseEntriesText(new Uint8Array(await fs.readFile(path)));\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Chain format v4 (format-spec §2.0): the leaf hash and the chain hash.\n *\n * ```\n * leaf_hash = SHA-512(\"aleutian.chain.leaf.v4:\"\n * ‖ len(entry_id) ‖ entry_id ‖ len(entry_type) ‖ entry_type\n * ‖ content_hash ‖ salt)\n * chain_hash = SHA-512(\"aleutian.chain.v4:\"\n * ‖ previous_hash ‖ \"|\" ‖ global_seq ‖ \"|\" ‖ timestamp ‖ \"|\" ‖ leaf_hash)\n * ```\n *\n * `len` is a 4-byte big-endian byte count. `entry_id` and `entry_type` are\n * hashed as their UTF-8 bytes EXACTLY AS STORED, never normalised: two\n * spellings that hashed alike would be a field an editor could change without\n * detection. `content_hash` and `salt` are hashed as their lowercase hex text.\n *\n * v4 separates what links the chain (the leaf hash) from what erasure removes\n * (the id, type, content hash and salt), so an erased entry is still\n * recomputed from its stored leaf hash (format-spec §5.0): no chain hash is\n * ever taken on trust.\n *\n * Written from the format spec alone. Hashing is synchronous\n * (`@noble/hashes`); the `compute*` functions return promises only so they\n * read like the v2/v3 functions. Browser-safe.\n */\n\nimport { sha512 } from \"@noble/hashes/sha2.js\";\nimport { bytesToHex, utf8ToBytes } from \"@noble/hashes/utils.js\";\n\n/** Chain format version 4 (format-spec §2.2). */\nexport const FORMAT_V4 = 4;\n\n/** The leaf hash's domain string (format-spec §2.0). */\nexport const CHAIN_LEAF_DOMAIN_V4 = \"aleutian.chain.leaf.v4:\";\n\n/** The v4 chain hash's domain string (format-spec §2.0). */\nexport const CHAIN_HASH_PREFIX_V4 = \"aleutian.chain.v4:\";\n\nconst HEX_128 = /^[0-9a-f]{128}$/;\nconst HEX_64 = /^[0-9a-f]{64}$/;\nconst DECIMAL = /^(0|[1-9][0-9]*)$/;\nconst TIMESTAMP =\n /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})\\.[0-9]{6}Z$/;\nconst MAX_INT64 = 2n ** 63n - 1n;\n// format-spec §2.0: U+0000 to U+001F and U+007F. Matching them is the point.\n// eslint-disable-next-line no-control-regex\nconst CONTROL = /[\\u0000-\\u001f\\u007f]/;\nconst LONE_SURROGATE =\n /[\\ud800-\\udbff](?![\\udc00-\\udfff])|(?<![\\ud800-\\udbff])[\\udc00-\\udfff]/;\n\nconst LEAF_DOMAIN_BYTES = utf8ToBytes(CHAIN_LEAF_DOMAIN_V4);\n\n/**\n * Whether a value is an `entry_id` or `entry_type` as v4 allows it\n * (format-spec §2.0, §5.5): a string of 1 to 256 UTF-8 bytes, valid UTF-8 (no\n * lone surrogate), with no control character (U+0000 to U+001F, U+007F).\n *\n * `|` and every other printable character are allowed: the field is\n * length-prefixed in the leaf hash.\n *\n * @param value - The stored value; anything but a string is refused\n * @returns True when the value may be hashed into a leaf\n */\nexport function isLeafText(value: unknown): value is string {\n if (typeof value !== \"string\" || value === \"\") return false;\n if (LONE_SURROGATE.test(value) || CONTROL.test(value)) return false;\n // At most 256 bytes; every UTF-16 unit encodes to at least one byte, so a\n // longer string is refused before encoding it.\n if (value.length > 256) return false;\n return utf8ToBytes(value).length <= 256;\n}\n\n/** Whether a string is a salt as v4 writes it: exactly 64 lowercase hex. */\nexport function isSalt(value: unknown): value is string {\n return typeof value === \"string\" && HEX_64.test(value);\n}\n\n/**\n * Whether a v4 entry carries the shape of a v2/v3 tombstone (format-spec §2.0):\n * `entry_type` `tombstone`, an `entry_id` starting `tomb_`, or a `content_hash`\n * starting `TOMBSTONE:`. Any ONE of them is `format_field_misuse` in v4.\n */\nexport function hasTombstoneShapeV4(\n entryId: string | undefined,\n entryType: string | undefined,\n contentHash: string | undefined\n): boolean {\n return (\n entryType === \"tombstone\" ||\n (entryId?.startsWith(\"tomb_\") ?? false) ||\n (contentHash?.startsWith(\"TOMBSTONE:\") ?? false)\n );\n}\n\nfunction u32(n: number): Uint8Array {\n return new Uint8Array([(n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff]);\n}\n\nfunction concat(parts: readonly Uint8Array[]): Uint8Array {\n let size = 0;\n for (const p of parts) size += p.length;\n const out = new Uint8Array(size);\n let at = 0;\n for (const p of parts) {\n out.set(p, at);\n at += p.length;\n }\n return out;\n}\n\n/**\n * The exact bytes the v4 leaf hash covers, WITHOUT validating anything.\n *\n * @internal Use {@link computeLeafHashV4}; this exists for callers that have\n * checked every field already (the bundle verifier) and for tests that pin\n * the preimage.\n */\nexport function leafPreimageV4(\n entryId: string,\n entryType: string,\n contentHash: string,\n salt: string\n): Uint8Array {\n const id = utf8ToBytes(entryId);\n const type = utf8ToBytes(entryType);\n return concat([\n LEAF_DOMAIN_BYTES,\n u32(id.length),\n id,\n u32(type.length),\n type,\n utf8ToBytes(contentHash),\n utf8ToBytes(salt),\n ]);\n}\n\n/**\n * The v4 leaf hash over fields already checked, synchronously.\n *\n * @internal Validates nothing; see {@link computeLeafHashV4}.\n */\nexport function leafHashV4Sync(\n entryId: string,\n entryType: string,\n contentHash: string,\n salt: string\n): string {\n return bytesToHex(sha512(leafPreimageV4(entryId, entryType, contentHash, salt)));\n}\n\n/**\n * The v4 chain hash over fields already checked, synchronously.\n *\n * @internal Validates nothing; see {@link computeChainHashV4}.\n */\nexport function chainHashV4Sync(\n previousHash: string,\n globalSeq: string,\n timestamp: string,\n leafHash: string\n): string {\n return bytesToHex(\n sha512(\n utf8ToBytes(\n CHAIN_HASH_PREFIX_V4 + previousHash + \"|\" + globalSeq + \"|\" + timestamp + \"|\" + leafHash\n )\n )\n );\n}\n\n/** A `global_seq` as base-10 text, or an Error naming the field. */\nfunction globalSeqText(globalSeq: number | bigint | string): string {\n if (typeof globalSeq === \"string\") {\n if (!DECIMAL.test(globalSeq) || globalSeq.length > 19 || BigInt(globalSeq) > MAX_INT64) {\n throw new Error(\n \"globalSeq must be base-10 with no sign or leading zeros, from 0 to 2^63 - 1\"\n );\n }\n return globalSeq;\n }\n if (typeof globalSeq === \"number\") {\n if (!Number.isSafeInteger(globalSeq)) {\n throw new Error(\n \"globalSeq is not a safe integer; pass a bigint or a decimal string beyond 2^53\"\n );\n }\n globalSeq = BigInt(globalSeq);\n }\n if (typeof globalSeq !== \"bigint\" || globalSeq < 0n || globalSeq > MAX_INT64) {\n throw new Error(\"globalSeq must be an integer from 0 to 2^63 - 1\");\n }\n return globalSeq.toString();\n}\n\n/** format-spec §4's form; the calendar is not judged here (§4 is about spelling). */\nfunction isTimestampForm(value: string): boolean {\n const m = TIMESTAMP.exec(value);\n if (!m) return false;\n const year = Number(m[1]);\n const month = Number(m[2]);\n const day = Number(m[3]);\n if (month < 1 || month > 12 || day < 1) return false;\n const leap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n if (day > days[month - 1]!) return false;\n return Number(m[4]) <= 23 && Number(m[5]) <= 59 && Number(m[6]) <= 59;\n}\n\n/**\n * Compute the v4 leaf hash of a live entry (format-spec §2.0).\n *\n * # Description\n *\n * Validates every field, then hashes the domain, the length-prefixed id and\n * type (UTF-8, as given), the content hash and the salt.\n *\n * # Inputs\n *\n * - entryId: 1 to 256 UTF-8 bytes, no control characters; not `tomb_…`\n * - entryType: as entryId; not `tombstone`\n * - contentHash: 128 lowercase hex (v4 has no tombstone value)\n * - salt: 64 lowercase hex\n *\n * # Outputs\n *\n * - Promise<string>: 128 lowercase hex\n * - Error: thrown (as a rejection) when a field is outside its shape. The\n * message names the field, never its value.\n *\n * # Example\n *\n * const leaf = await computeLeafHashV4(\"ent_0001\", \"event\", contentHash, salt);\n *\n * # Limitations\n *\n * - Does not mint salts: this SDK verifies, it never writes.\n *\n * # Assumptions\n *\n * - None: every field is validated.\n */\nexport function computeLeafHashV4(\n entryId: string,\n entryType: string,\n contentHash: string,\n salt: string\n): Promise<string> {\n // The executor's throw becomes the rejection.\n return new Promise((resolve) => resolve(leafHashV4Checked(entryId, entryType, contentHash, salt)));\n}\n\nfunction leafHashV4Checked(\n entryId: string,\n entryType: string,\n contentHash: string,\n salt: string\n): string {\n if (!isLeafText(entryId)) {\n throw new Error(\"entryId must be 1 to 256 UTF-8 bytes with no control character\");\n }\n if (!isLeafText(entryType)) {\n throw new Error(\"entryType must be 1 to 256 UTF-8 bytes with no control character\");\n }\n if (typeof contentHash !== \"string\" || !HEX_128.test(contentHash)) {\n throw new Error(\"contentHash must be exactly 128 lowercase hex characters\");\n }\n if (hasTombstoneShapeV4(entryId, entryType, contentHash)) {\n throw new Error(\"a v4 entry has no tombstone type or tomb_ id (format-spec §2.0)\");\n }\n if (!isSalt(salt)) {\n throw new Error(\"salt must be exactly 64 lowercase hex characters\");\n }\n return leafHashV4Sync(entryId, entryType, contentHash, salt);\n}\n\n/**\n * Compute the v4 chain hash of an entry (format-spec §2.0).\n *\n * # Description\n *\n * Validates the fields, including the first-entry rule (an empty\n * `previousHash` goes with `globalSeq` 0, a non-empty one with a `globalSeq`\n * above 0), then hashes the `|`-delimited preimage. For an erased entry, pass\n * its stored leaf hash: that is exactly what the verifier recomputes from.\n *\n * # Inputs\n *\n * - previousHash: \"\" for the chain's first entry, else 128 lowercase hex\n * - globalSeq: 0 to 2^63 - 1, as a bigint, a safe number, or base-10 text\n * - timestamp: exactly `YYYY-MM-DDTHH:MM:SS.ffffffZ` (format-spec §4)\n * - leafHash: 128 lowercase hex\n *\n * # Outputs\n *\n * - Promise<string>: 128 lowercase hex\n * - Error: thrown (as a rejection) when a field is malformed\n *\n * # Example\n *\n * const h = await computeChainHashV4(prev, 1n, \"2026-10-16T08:00:01.111111Z\", leaf);\n *\n * # Limitations\n *\n * - Checks one entry; linkage across entries is `verifyChainOffline`'s.\n *\n * # Assumptions\n *\n * - None: every field is validated.\n */\nexport function computeChainHashV4(\n previousHash: string,\n globalSeq: number | bigint | string,\n timestamp: string,\n leafHash: string\n): Promise<string> {\n // The executor's throw becomes the rejection.\n return new Promise((resolve) =>\n resolve(chainHashV4Checked(previousHash, globalSeq, timestamp, leafHash))\n );\n}\n\nfunction chainHashV4Checked(\n previousHash: string,\n globalSeq: number | bigint | string,\n timestamp: string,\n leafHash: string\n): string {\n if (typeof previousHash !== \"string\" || (previousHash !== \"\" && !HEX_128.test(previousHash))) {\n throw new Error(\"previousHash must be empty or exactly 128 lowercase hex characters\");\n }\n const seq = globalSeqText(globalSeq);\n if ((previousHash === \"\") !== (seq === \"0\")) {\n throw new Error(\n \"an entry with an empty previousHash has globalSeq 0, and only it (format-spec §2.0)\"\n );\n }\n if (typeof timestamp !== \"string\" || !isTimestampForm(timestamp)) {\n throw new Error(\"timestamp must be YYYY-MM-DDTHH:MM:SS.ffffffZ (UTC, six digits)\");\n }\n if (typeof leafHash !== \"string\" || !HEX_128.test(leafHash)) {\n throw new Error(\"leafHash must be exactly 128 lowercase hex characters\");\n }\n return chainHashV4Sync(previousHash, seq, timestamp, leafHash);\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Cross-runtime constant-time byte-array equality.\n *\n * Prefers the runtime's built-in constant-time comparator when one is\n * available (Node ≥ 16's `crypto.timingSafeEqual`, implemented at C\n * level), and falls back to a pure-JS implementation in browsers and\n * other runtimes that do not ship a built-in.\n *\n * This module is the single source of truth for constant-time\n * comparison across the SDK. Both `verifyV3.ts` and `consent.ts`\n * depend on it; `webhook.ts` is Node-only and continues to use the\n * Node `crypto` API directly.\n *\n * # Why it exists as a separate module\n *\n * `verifyV3.ts` shipped this logic first in the chain_f track. When\n * the browser-target audit revealed that `consent.ts` was still using\n * a top-level static `import { timingSafeEqual } from \"crypto\"` (a\n * module-load blocker in browsers), the cleanest fix was to lift the\n * dynamic-require pattern into a shared internal module rather than\n * duplicate it inline. See `dsar_js_browser_target_audit` Unit A.\n *\n * # Runtime caveat (browsers)\n *\n * The JS fallback iterates `max(a.length, b.length)` bytes and ORs\n * into an accumulator without short-circuiting — but JIT\n * optimizations and timer resolution on browser hosts can still\n * leak residual timing signal in adversarial conditions. The caveat\n * is documented in `sdk_threat_model_doc`; for high-assurance\n * deployments, prefer the Node runtime (which uses the built-in).\n */\n\nlet _nodeTimingSafeEqual:\n | ((a: Uint8Array, b: Uint8Array) => boolean)\n | null = null;\n\ntry {\n // Dynamic require so the module loads cleanly in browsers (where\n // `node:crypto` doesn't resolve). The bundler tree-shakes this\n // path out of browser builds.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const nodeCrypto = require(\"node:crypto\") as {\n timingSafeEqual?: (a: Uint8Array, b: Uint8Array) => boolean;\n };\n if (typeof nodeCrypto.timingSafeEqual === \"function\") {\n _nodeTimingSafeEqual = nodeCrypto.timingSafeEqual;\n }\n} catch {\n // Browser / Deno / other runtimes — fall through to the pure-JS\n // fallback. No exception is propagated; the absence is the\n // expected detection signal.\n}\n\n/**\n * Constant-time byte-array equality. Returns `true` iff `a` and `b`\n * are byte-identical.\n *\n * # Why constant-time matters here\n *\n * A short-circuiting compare leaks the position of the first\n * differing byte via timing, which on a hash-comparison gate\n * becomes a forgery oracle: an attacker can brute-force the hash\n * one byte at a time.\n *\n * # Implementation\n *\n * Under Node 16+ this delegates to `crypto.timingSafeEqual` (the\n * built-in C implementation). Under browsers it uses a pure-JS\n * fallback that iterates the longer of the two inputs and ORs\n * into an accumulator.\n */\nexport function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {\n // Length mismatch: Node's built-in throws RangeError on length\n // mismatch (it requires equal-length inputs), so we handle that\n // gate ourselves before delegating. The XOR-of-lengths variant\n // ensures the constant-time property survives the gate.\n if (a.length !== b.length) {\n // Still iterate over max length to avoid a length-leaking\n // early return that could be timeable. Then return false.\n let acc = 1; // non-zero baseline so result is always false\n const n = Math.max(a.length, b.length);\n for (let i = 0; i < n; i++) {\n const ai = i < a.length ? a[i]! : 0;\n const bi = i < b.length ? b[i]! : 0;\n acc |= ai ^ bi;\n }\n return acc === 0; // unreachable true given the seeded 1, but\n // structured for property clarity\n }\n if (_nodeTimingSafeEqual !== null) {\n return _nodeTimingSafeEqual(a, b);\n }\n // Pure-JS fallback (browsers / non-Node runtimes).\n let diff = 0;\n for (let i = 0; i < a.length; i++) {\n diff |= a[i]! ^ b[i]!;\n }\n return diff === 0;\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Chain verification for the Aleutian verification SDK.\n *\n * This module provides functions to verify chain integrity using exported\n * entries without requiring network access to Aleutian APIs.\n */\n\nimport { AnchorVerificationError, ChainVerificationError } from \"./errors.js\";\nimport {\n computeChainHash,\n computeChainHashV3,\n isChainDigest,\n isChainTimestamp,\n normalizeFormatVersion,\n FORMAT_V2,\n FORMAT_V3,\n} from \"./chain.js\";\nimport {\n chainHashV4Sync,\n FORMAT_V4,\n hasTombstoneShapeV4,\n isLeafText,\n isSalt,\n leafHashV4Sync,\n} from \"./chainV4.js\";\nimport { checkAnchorWellFormed } from \"./anchorCanonical.js\";\nimport {\n SEED_ANCHOR_HASH,\n SEED_ANCHOR_ID,\n anchorChainHashV7Sync,\n computeAnchorChainHash,\n} from \"./anchorChainHash.js\";\nimport { constantTimeEqual } from \"./internal/constantTime.js\";\nimport { isTombstone, validateTombstoneContentHash } from \"./tombstone.js\";\nimport type {\n Anchor,\n AnchorBindExpectations,\n AnchorBindOutcome,\n AnchorBindResult,\n BreakType,\n ExportedEntry,\n OfflineVerificationResult,\n OfflineBreak,\n ChainVerifyOptions,\n} from \"./types.js\";\n\n// Reuse a single TextEncoder for hex-string → byte encoding; the encoder\n// is stateless and safe to share. Used only to feed the shared\n// constant-time comparator (which operates on Uint8Array).\nconst HEX_ENCODER = new TextEncoder();\n\n/**\n * Constant-time equality of two ASCII/hex strings.\n *\n * Delegates to the shared `internal/constantTime.ts` byte comparator\n * (which prefers Node's C-level `crypto.timingSafeEqual` when\n * available and uses a non-short-circuiting pure-JS fallback\n * elsewhere). Hex hashes encode 1:1 ASCII so byte-length matches\n * char-length and the comparator's length-mismatch handling stays\n * constant-time. Replaces the local string-XOR variant that used\n * to live here; see dsar_js_verify_consolidate_constant_time.\n */\nfunction chainHashEqual(a: string, b: string): boolean {\n return constantTimeEqual(HEX_ENCODER.encode(a), HEX_ENCODER.encode(b));\n}\n\n// global_seq is a signed 64-bit integer in every implementation (format-spec §2.1).\nconst MAX_INT64 = 2n ** 63n - 1n;\n\n/**\n * Read a global_seq as an exact integer, or null when it is not one.\n *\n * A `number` that is not a safe integer has already been rounded (or was never\n * an integer), so it is not the value on the wire and is not compared.\n */\nfunction exactInteger(value: unknown): bigint | null {\n if (typeof value === \"bigint\") return value;\n if (typeof value === \"number\" && Number.isSafeInteger(value)) return BigInt(value);\n return null;\n}\n\n/**\n * The ONE rule that decides whether an entry is a tombstone (format-spec §5,\n * §5.5): `entryType === \"tombstone\"` AND `entryId` starts with `tomb_`. A\n * `TOMBSTONE:` content hash on any other entry does not make it one.\n */\nfunction isTombstoneEntry(entry: ExportedEntry): boolean {\n return (\n typeof entry.entryType === \"string\" &&\n typeof entry.entryId === \"string\" &&\n isTombstone(entry.entryType, entry.entryId)\n );\n}\n\n/** What a walk of the entries found. */\ninterface ChainWalk {\n readonly breaks: OfflineBreak[];\n readonly tombstonesFound: number;\n readonly lastTombstone: number;\n /** Every position read as a tombstone, ascending. */\n readonly tombstonePositions: readonly number[];\n readonly erasedFound: number;\n}\n\n/**\n * Whether an entry carried a member (format-spec §2.0 tells absent from\n * empty). Exact for entries `parseEntriesText` read (`presentMembers`); for an\n * entry built in code, an empty string or a zero `sequenceNum` counts as\n * absent, as does an undefined optional field.\n */\nfunction carries(entry: ExportedEntry, snake: string): boolean {\n const present = entry.presentMembers;\n if (present !== undefined) return present.has(snake);\n const e = entry as unknown as Record<string, unknown>;\n switch (snake) {\n case \"entry_id\":\n return e.entryId !== undefined && e.entryId !== \"\";\n case \"entry_type\":\n return e.entryType !== undefined && e.entryType !== \"\";\n case \"content_hash\":\n return e.contentHash !== undefined && e.contentHash !== \"\";\n case \"run_id\":\n return e.runId !== undefined && e.runId !== \"\";\n case \"sequence_num\":\n return e.sequenceNum !== undefined && e.sequenceNum !== 0;\n case \"salt\":\n return e.salt !== undefined;\n case \"leaf_hash\":\n return e.leafHash !== undefined;\n case \"erased\":\n return e.erased !== undefined;\n case \"global_seq\":\n return e.globalSeq !== undefined;\n default:\n return true;\n }\n}\n\n/** The two v4 entry shapes of format-spec §2.0, beyond the members every entry has. */\nconst V4_LIVE_ONLY = [\"entry_id\", \"entry_type\", \"content_hash\", \"salt\"] as const;\n\n/**\n * The first §2.0 / §5.5 shape rule a v4 entry breaks (step 7), or null.\n * `linkedFrom` is the hash the entry links from: \"\" for a chain's first entry.\n */\nfunction v4ShapeProblem(\n entry: ExportedEntry,\n seq: bigint | null,\n hasPredecessor: boolean\n): { field: string; detail: string } | null {\n if (!carries(entry, \"global_seq\") || !carries(entry, \"leaf_hash\")) {\n return { field: \"shape\", detail: \"a v4 entry carries global_seq and leaf_hash\" };\n }\n if (entry.erased !== undefined || carries(entry, \"erased\")) {\n if (entry.erased !== true) {\n return { field: \"erased\", detail: \"a live v4 entry carries no erased member\" };\n }\n for (const name of V4_LIVE_ONLY) {\n if (carries(entry, name)) {\n return {\n field: \"shape\",\n detail: \"an erased v4 entry carries no entry_id, entry_type, content_hash or salt\",\n };\n }\n }\n } else {\n for (const name of V4_LIVE_ONLY) {\n if (!carries(entry, name)) {\n return {\n field: \"shape\",\n detail: \"a live v4 entry carries entry_id, entry_type, content_hash and salt\",\n };\n }\n }\n if (!isLeafText(entry.entryId)) {\n return {\n field: \"entryId\",\n detail: \"entryId must be 1 to 256 UTF-8 bytes with no control character\",\n };\n }\n if (!isLeafText(entry.entryType)) {\n return {\n field: \"entryType\",\n detail: \"entryType must be 1 to 256 UTF-8 bytes with no control character\",\n };\n }\n if (!isChainDigest(entry.contentHash)) {\n return {\n field: \"contentHash\",\n detail: \"a v4 contentHash must be exactly 128 lowercase hex characters\",\n };\n }\n if (!isSalt(entry.salt)) {\n return { field: \"salt\", detail: \"salt must be exactly 64 lowercase hex characters\" };\n }\n }\n if (!isChainDigest(entry.leafHash)) {\n return { field: \"leafHash\", detail: \"leafHash must be exactly 128 lowercase hex characters\" };\n }\n if (seq === null || seq < 0n || seq > MAX_INT64) {\n return {\n field: \"globalSeq\",\n detail: \"globalSeq must be an integer from 0 to 2^63 - 1 (a bigint beyond 2^53)\",\n };\n }\n // §2.0, the first entry: an empty previous hash goes with global_seq 0, and\n // a previous hash with a global_seq above 0.\n if (hasPredecessor !== seq > 0n) {\n return {\n field: \"globalSeq\",\n detail: hasPredecessor\n ? \"an entry with a predecessor has a globalSeq above 0\"\n : \"a v4 entry with no predecessor has globalSeq 0: walk a segment from its predecessor hash\",\n };\n }\n return null;\n}\n\n/**\n * Walk entries and collect every break (format-spec §2, §4, §5.0, §5.5).\n *\n * The order of checks is fixed (§5.5), so every implementation names the same\n * FIRST break for an entry with several defects:\n *\n * 1. `sequence_gap`: `globalSeq` is not the previous entry's plus one\n * (recorded, and the entry is still checked)\n * 2. `invalid_field`: `chainHash` is not a digest, on every entry\n * 3. `format_field_misuse`: a v2 or v3 entry after a v4 entry (§2.5), a v4\n * member (`salt`, `leaf_hash`, `erased`) on a v2 or v3 entry (§2.2), or a\n * v4 entry with run fields or a tombstone shape (§2.0)\n * 4. (v2 and v3) a tombstone's own checks, and then nothing else\n * 5. `invalid_timestamp`\n * 6. the declared format: `unknown_format`, or a v3 entry with run fields\n * 7. `invalid_field`: field shapes; for v4 the two entry shapes and the\n * first-entry rule of §2.0\n * 8. `hash_mismatch`: for v4 the leaf hash first, then the chain hash\n *\n * After a break in steps 2 to 7 the walk continues from the entry's stored\n * chain hash. After a v4 leaf mismatch it continues from the chain hash the\n * RECOMPUTED leaf gives (§5.0); after a chain mismatch, from the expected one.\n *\n * Counts (§5.5): `tombstonesFound` counts entries read as tombstones and not\n * refused at step 3; `erasedFound` counts v4 entries with `erased: true`,\n * whatever else is wrong with them. Neither counts an entry whose chain_hash\n * is out of shape (step 2). Both count every entry walked.\n *\n * The shape is checked on its own because a hash recomputed over malformed\n * fields can equal the stored one (§5.5).\n */\nasync function walkChain(\n entries: readonly ExportedEntry[],\n startHash: string,\n maxBreaks: number\n): Promise<ChainWalk> {\n const breaks: OfflineBreak[] = [];\n // format-spec §3, §5.5: the supplied predecessor hash is a digest too. It\n // is the one unvalidated field that could shift a preimage boundary.\n const startMalformed = startHash !== \"\" && !isChainDigest(startHash);\n // null: the hash to link from is not known (a malformed predecessor), so the\n // next entry cannot be recomputed. Its own break has been reported.\n let previousHash: string | null = startMalformed ? null : startHash;\n let previousSeq: bigint | null = null;\n let tombstonesFound = 0;\n let lastTombstone = -1;\n const tombstonePositions: number[] = [];\n let erasedFound = 0;\n // §2.5: from the first v4 entry on, every entry is v4.\n let seenV4 = false;\n\n const report = (\n position: number,\n entry: ExportedEntry,\n breakType: BreakType,\n context: Record<string, string>,\n expectedHash = \"\"\n ): void => {\n breaks.push({\n position,\n entryId: typeof entry.entryId === \"string\" ? entry.entryId : \"\",\n expectedHash,\n actualHash: isChainDigest(entry.chainHash) ? entry.chainHash : \"\",\n breakType,\n context,\n });\n };\n\n for (let i = 0; i < entries.length; i++) {\n // M-10: Stop early if too many breaks found\n if (maxBreaks > 0 && breaks.length >= maxBreaks) {\n break;\n }\n\n const entry = entries[i]!;\n const seq = exactInteger(entry.globalSeq);\n\n // The formats cannot be told apart by looking at a digest, so the entry\n // has to say which preimage produced it (§2.2). Absent means v2.\n const declared: unknown = entry.formatVersion;\n const entryFormat =\n declared === undefined || typeof declared === \"number\"\n ? normalizeFormatVersion(declared)\n : Number.NaN;\n const isV4 = entryFormat === FORMAT_V4;\n const isV2orV3 = entryFormat === FORMAT_V2 || entryFormat === FORMAT_V3;\n const formatKnown = isV2orV3 || isV4;\n\n // Step 3's condition, decided before anything is reported: it also\n // decides whether a tombstone is counted.\n let crossFormat: string | null = null;\n if (isV2orV3 && seenV4) {\n crossFormat = \"a v2 or v3 entry after a v4 entry: a chain never goes back from v4\";\n } else if (isV2orV3 && (carries(entry, \"salt\") || carries(entry, \"leaf_hash\") || carries(entry, \"erased\"))) {\n crossFormat = \"a v2 or v3 entry must not carry salt, leaf_hash or erased\";\n } else if (isV4 && (carries(entry, \"run_id\") || carries(entry, \"sequence_num\"))) {\n crossFormat = \"a v4 entry carries no run_id and no sequence_num\";\n } else if (\n isV4 &&\n hasTombstoneShapeV4(\n carries(entry, \"entry_id\") ? entry.entryId : undefined,\n carries(entry, \"entry_type\") ? entry.entryType : undefined,\n carries(entry, \"content_hash\") ? entry.contentHash : undefined\n )\n ) {\n crossFormat = \"a v4 entry has no tombstone type, tomb_ id or TOMBSTONE: content hash\";\n }\n if (isV4) seenV4 = true;\n\n // 1. Sequence continuity. The FIRST global_seq is not constrained here\n // (§5.5; v4's first-entry rule is step 7). From there it rises by one.\n if (previousSeq !== null && seq !== null && seq !== previousSeq + 1n) {\n report(i, entry, \"sequence_gap\", {\n expectedSeq: (previousSeq + 1n).toString(),\n actualSeq: seq.toString(),\n });\n }\n previousSeq = seq;\n\n // 2. chain_hash is a digest on EVERY entry. A tombstone's is taken as\n // stored, so an unchecked one would flow straight into the next preimage.\n if (!isChainDigest(entry.chainHash)) {\n report(i, entry, \"invalid_field\", {\n field: \"chainHash\",\n detail: \"chainHash must be exactly 128 lowercase hex characters\",\n });\n previousHash = null;\n continue;\n }\n // Counted once step 2 passes, whatever else is wrong with it (§5.5).\n if (isV4 && entry.erased === true) erasedFound++;\n\n // Every break below leaves the stored hash as the one to link from: it is\n // a digest (checked above), and the entry itself cannot be recomputed.\n const stop = (breakType: BreakType, context: Record<string, string>): void => {\n report(i, entry, breakType, context);\n previousHash = entry.chainHash;\n };\n\n // 3.\n if (crossFormat !== null) {\n stop(\"format_field_misuse\", { detail: crossFormat });\n continue;\n }\n\n const unknownFormat = (): void => {\n // A format this build cannot recompute is NOT evidence of tampering.\n const shown =\n typeof declared === \"number\" && Number.isSafeInteger(declared)\n ? String(declared)\n : \"(not an integer)\";\n stop(\"unknown_format\", {\n detail: `chain hash format version ${shown} is not implemented by this build`,\n });\n };\n // v3 binds NEITHER run field.\n const runFieldMisuse = entryFormat === FORMAT_V3 && Boolean(entry.runId || entry.sequenceNum);\n const fieldMisuse = (): void =>\n stop(\"format_field_misuse\", {\n detail:\n \"a v3 entry must not carry runId or sequenceNum; neither is bound into its hash\",\n });\n const seqInvalid = seq === null || seq < 0n || seq > MAX_INT64;\n const invalidSeq = (): void =>\n stop(\"invalid_field\", {\n field: \"globalSeq\",\n detail: \"globalSeq must be an integer from 0 to 2^63 - 1 (a bigint beyond 2^53)\",\n });\n const invalidStart = (): void =>\n stop(\"invalid_field\", {\n field: \"previousHash\",\n detail: \"previousHash must be empty or exactly 128 lowercase hex characters\",\n });\n\n // 4. Tombstones (v2 and v3): validate, then advance on the stored hash.\n //\n // A tombstone retains the ORIGINAL entry's chainHash, computed from that\n // entry's real contentHash before erasure. Its chain hash is therefore NOT\n // reproducible from its own fields, and recomputing it here reports\n // hash_mismatch on every lawfully erased entry — telling a customer their\n // chain is broken precisely when they are demonstrating that they honoured a\n // deletion request (sdk_verify_01).\n //\n // The preservation is deliberate: anchors sign the chain hash. Recomputing on\n // erasure would invalidate every anchor covering that range, so exercising a\n // right to erasure would destroy the proof the data ever existed. Preserving\n // it keeps erasure and provability compatible.\n //\n // What a tombstone DECLARES is still checked (§5.5): its content-hash\n // format, its format version, and its sequence. Its timestamp form and the\n // v2 runId / sequenceNum rules are not. v4 has no tombstones (step 3).\n if (!isV4 && isTombstoneEntry(entry)) {\n tombstonesFound++;\n lastTombstone = i;\n tombstonePositions.push(i);\n if (!validateTombstoneContentHash(entry.contentHash)) {\n stop(\"invalid_tombstone\", {\n detail: 'a tombstone contentHash must be \"TOMBSTONE:\" + 64 lowercase hex',\n });\n } else if (!formatKnown) {\n unknownFormat();\n } else if (runFieldMisuse) {\n fieldMisuse();\n } else if (seqInvalid) {\n invalidSeq();\n } else if (i === 0 && startMalformed) {\n // Not needed to carry a tombstone forward, but a malformed supplied\n // predecessor hash is a break at position 0 whatever sits there.\n invalidStart();\n } else {\n // Subsequent entries were chained against the stored value, so that\n // is what the next iteration must link from.\n previousHash = entry.chainHash;\n }\n continue;\n }\n\n // 5. The timestamp is stored as exactly the string that was hashed.\n if (!isChainTimestamp(entry.timestamp)) {\n stop(\"invalid_timestamp\", {\n detail: \"timestamp must be YYYY-MM-DDTHH:MM:SS.ffffffZ (UTC, six digits)\",\n });\n continue;\n }\n // 6.\n if (!formatKnown) {\n unknownFormat();\n continue;\n }\n if (runFieldMisuse) {\n fieldMisuse();\n continue;\n }\n // 7. Field shapes.\n if (i === 0 && startMalformed) {\n invalidStart();\n continue;\n }\n\n if (isV4) {\n const problem = v4ShapeProblem(entry, seq, i > 0 || startHash !== \"\");\n if (problem !== null) {\n stop(\"invalid_field\", problem);\n continue;\n }\n if (previousHash === null) {\n // Nothing to link from: the entry before had no usable hash, and said so.\n previousHash = entry.chainHash;\n continue;\n }\n // 8. The leaf hash first (live entries; an erased one keeps its stored\n // leaf hash, checked for shape only), then the chain hash. No stored\n // chain hash is taken on trust (§5.0).\n const storedLeaf = entry.leafHash!;\n const leaf =\n entry.erased === true\n ? storedLeaf\n : leafHashV4Sync(entry.entryId, entry.entryType, entry.contentHash, entry.salt!);\n const expectedHash = chainHashV4Sync(previousHash, seq!.toString(), entry.timestamp, leaf);\n if (!chainHashEqual(leaf, storedLeaf)) {\n report(i, entry, \"hash_mismatch\", { field: \"leafHash\" }, expectedHash);\n } else if (!chainHashEqual(entry.chainHash, expectedHash)) {\n report(i, entry, \"hash_mismatch\", {}, expectedHash);\n }\n // As v3 does after a mismatch: continue from the RECOMPUTED hash, so one\n // altered entry does not cascade into false breaks after it.\n previousHash = expectedHash;\n continue;\n }\n\n if (\n !isChainDigest(entry.contentHash) &&\n !(typeof entry.contentHash === \"string\" && validateTombstoneContentHash(entry.contentHash))\n ) {\n // A well-formed TOMBSTONE: value on an ordinary entry passes the shape\n // and then fails the recompute: the content hash alone does not make a\n // tombstone (§5.5).\n stop(\"invalid_field\", {\n field: \"contentHash\",\n detail:\n 'contentHash must be 128 lowercase hex characters, or a tombstone value (\"TOMBSTONE:\" + 64 lowercase hex)',\n });\n continue;\n }\n if (seqInvalid) {\n invalidSeq();\n continue;\n }\n if (entryFormat === FORMAT_V2) {\n if (typeof entry.runId !== \"string\" || entry.runId === \"\") {\n stop(\"invalid_field\", {\n field: \"runId\",\n detail: \"a v2 entry's runId must not be empty\",\n });\n continue;\n }\n const sequenceNum: unknown = entry.sequenceNum;\n if (\n typeof sequenceNum !== \"number\" ||\n !Number.isSafeInteger(sequenceNum) ||\n sequenceNum < 0\n ) {\n stop(\"invalid_field\", {\n field: \"sequenceNum\",\n detail: \"a v2 entry's sequenceNum must be a non-negative integer\",\n });\n continue;\n }\n }\n\n if (previousHash === null) {\n // Nothing to link from: the entry before had no usable hash, and said so.\n previousHash = entry.chainHash;\n continue;\n }\n\n // 8.\n const expectedHash =\n entryFormat === FORMAT_V2\n ? await computeChainHash(\n previousHash,\n entry.runId,\n entry.sequenceNum,\n entry.timestamp,\n entry.contentHash\n )\n : await computeChainHashV3(previousHash, seq, entry.timestamp, entry.contentHash);\n\n if (!chainHashEqual(entry.chainHash, expectedHash)) {\n report(i, entry, \"hash_mismatch\", {}, expectedHash);\n }\n\n // Advance using the computed hash, not the stored one. If entry.chainHash\n // was tampered, using it would cause every subsequent entry to fail\n // (cascade false positives). Using expectedHash keeps the chain on the\n // correct trajectory so only genuinely broken entries produce breaks.\n previousHash = expectedHash;\n }\n\n return { breaks, tombstonesFound, lastTombstone, tombstonePositions, erasedFound };\n}\n\nfunction walkResult(\n walk: ChainWalk,\n processed: number,\n durationMs: number,\n anchorOutcome?: AnchorBindOutcome\n): OfflineVerificationResult {\n const entriesNotVerified = walk.lastTombstone + 1;\n return {\n valid: walk.breaks.length === 0,\n entriesVerified: processed - entriesNotVerified,\n entriesProcessed: processed,\n tombstonesFound: walk.tombstonesFound,\n erasedFound: walk.erasedFound,\n lastTombstone: walk.lastTombstone,\n entriesNotVerified,\n breaks: walk.breaks,\n durationMs,\n ...(anchorOutcome === undefined ? {} : { anchorOutcome }),\n };\n}\n\n/**\n * Decide what an anchor binds to, given entries that have been walked from the\n * chain's first entry (format-spec §9.4, §9.7, §9.8).\n *\n * EXACTLY the entries given: the first is the range start, the last is the\n * range end, and their number is the height. The order of checks is fixed so\n * every implementation names the same outcome.\n */\nasync function bindOutcome(\n anchor: Anchor,\n entries: readonly ExportedEntry[],\n chainValid: boolean,\n previousAnchorHash: string\n): Promise<AnchorBindOutcome> {\n if (!chainValid) return \"chain_broken\";\n\n const tip = entries[entries.length - 1]!;\n if (entries[0]!.entryId !== anchor.range.startEntryId) return \"range_start_mismatch\";\n if (tip.entryId !== anchor.range.endEntryId) return \"range_end_mismatch\";\n if (BigInt(anchor.entryCount) !== BigInt(entries.length)) return \"height_mismatch\";\n\n // §9.8: the predecessor is named twice, by id and by hash. The seed id goes\n // with the seed hash and with nothing else.\n const namesSeed = anchor.previousAnchorId === SEED_ANCHOR_ID;\n const usesSeed = previousAnchorHash === SEED_ANCHOR_HASH;\n if (namesSeed !== usesSeed) return \"predecessor_mismatch\";\n\n // The chain verified, so the stored hash of the tip IS its chain hash\n // (recomputed, or for a tombstone carried as stored).\n const expected = await computeAnchorChainHash(\n previousAnchorHash,\n anchor.subject,\n anchor.range.startEntryId,\n anchor.range.endEntryId,\n tip.chainHash\n );\n return chainHashEqual(expected, anchor.chainHash) ? \"bound\" : \"head_mismatch\";\n}\n\n/**\n * Bind an anchor to the entries it covers, without a key.\n *\n * # Description\n *\n * Verifies the entries as a WHOLE chain (from its first entry: a segment\n * cannot be bound, format-spec §9.8), then checks that the anchor describes\n * EXACTLY those entries, in this order: the chain verifies, the first entry is\n * `range.startEntryId`, the last is `range.endEntryId`, their number is\n * `entryCount`, the predecessor is named consistently (§9.8), and the anchor\n * chain hash recomputes (§9.4).\n *\n * A v7 anchor names its range by sequence and carries its predecessor's hash:\n * it is bound by `bindAnchorV7ToEntries`, to which this delegates, with\n * `previousAnchorHash` as the EXPECTED predecessor (§9.7 step 4) and no\n * expected subject (`subjectChecked` false). What follows is v1-v6.\n *\n * PASS THE COVERED PREFIX. An anchor is bound against the entries it covered,\n * as the chain was when it was signed (§9.7): entries `0 … entryCount - 1`.\n * This function does not slice. Given a chain that has grown since the anchor,\n * it reports `range_end_mismatch`.\n *\n * KEYLESS: the signature is NOT checked. Use `verifyAnchorLocally` for that; a\n * bind without a signature check says only that the anchor's fields describe\n * these entries, not who wrote them.\n *\n * WHAT A TOMBSTONE LEAVES UNBOUND (§5.5). A tombstone's chain hash is taken as\n * stored, so nothing links the entries before it to the anchored tip. Whoever\n * can write the store can replace every entry up to a tombstone and the bind\n * still succeeds. `entriesNotBound` counts those entries. Never describe them\n * as verified or as bound.\n *\n * # Inputs\n *\n * - anchor: The anchor, as `parseAnchorText` returns it\n * - entries: The entries the anchor covers, from the chain's first entry\n * - previousAnchorHash: The previous anchor's `chainHash`, or\n * `SEED_ANCHOR_HASH` for the first anchor. Never guessed.\n *\n * # Outputs\n *\n * - Promise<AnchorBindResult>: the outcome; `bound` is true only for\n * `\"bound\"`. `tombstones` and `entriesNotBound` are what the walk found,\n * in every outcome.\n * - AnchorVerificationError: the anchor is malformed (§9.3, §9.8 counts and\n * key id), or `previousAnchorHash` is not a digest. An error, not an outcome.\n * - ChainVerificationError: `entries` is empty\n *\n * # Example\n *\n * const anchor = parseAnchorText(anchorText);\n * const entries = parseEntriesText(entriesText);\n * const covered = entries.slice(0, Number(anchor.entryCount));\n * const r = await bindAnchorToEntries(anchor, covered, SEED_ANCHOR_HASH);\n * if (r.bound && r.entriesNotBound > 0) {\n * console.log(`bound, except the first ${r.entriesNotBound} entries`);\n * }\n *\n * # Limitations\n *\n * - Does not verify the signature, and does not check a series of anchors\n * against each other.\n * - Cannot detect a rewrite of the entries before a tombstone.\n *\n * # Assumptions\n *\n * - `entries[0]` is the chain's first entry.\n */\nexport async function bindAnchorToEntries(\n anchor: Anchor,\n entries: readonly ExportedEntry[],\n previousAnchorHash: string\n): Promise<AnchorBindResult> {\n if (anchor.version === 7) {\n // A v7 anchor carries its predecessor's hash; the one given is checked\n // against it (format-spec §9.7 step 4).\n return bindAnchorV7ToEntries(anchor, entries, { previousAnchorHash });\n }\n checkAnchorWellFormed(anchor);\n if (!isChainDigest(previousAnchorHash)) {\n throw new AnchorVerificationError(\n \"previousAnchorHash must be exactly 128 lowercase hex characters \" +\n \"(SEED_ANCHOR_HASH for the first anchor)\"\n );\n }\n if (entries.length === 0) {\n throw new ChainVerificationError(\"entries array cannot be empty\");\n }\n\n const startTime = performance.now();\n const walk = await walkChain(entries, \"\", 0);\n const outcome = await bindOutcome(\n anchor,\n entries,\n walk.breaks.length === 0,\n previousAnchorHash\n );\n const chain = walkResult(walk, entries.length, performance.now() - startTime, outcome);\n return {\n outcome,\n bound: outcome === \"bound\",\n tombstones: chain.tombstonesFound,\n entriesNotBound: chain.entriesNotVerified,\n chain,\n };\n}\n\n/** A v7 bind's outcome, and the index of its tip entry (-1 when there is none). */\ninterface V7Bind {\n readonly outcome: AnchorBindOutcome;\n readonly tipIndex: number;\n}\n\n/**\n * Decide what a v7 anchor binds to (format-spec §9.7), given entries walked\n * from the chain's first entry. The first check that fails is the outcome.\n */\nfunction bindOutcomeV7(\n anchor: Anchor,\n entries: readonly ExportedEntry[],\n chainValid: boolean,\n expect: AnchorBindExpectations\n): V7Bind {\n // 1. The chain.\n if (!chainValid) return { outcome: \"chain_broken\", tipIndex: -1 };\n // checkAnchorWellFormed has established both are integers in range.\n const startSeq = BigInt(anchor.range.startSeq!);\n const endSeq = BigInt(anchor.range.endSeq!);\n // 2. The start: the first entry of a walk that is not a segment is the\n // chain's first entry.\n const firstSeq = exactInteger(entries[0]!.globalSeq);\n if (firstSeq === null || firstSeq !== startSeq) {\n return { outcome: \"range_start_mismatch\", tipIndex: -1 };\n }\n // 3. The end. The chain verified, so global_seq rises by one from the first\n // entry: the entry at end_seq, if given, is at index end_seq - start_seq.\n const offset = endSeq - startSeq;\n const tipIndex = offset < BigInt(entries.length) ? Number(offset) : -1;\n if (tipIndex < 0 || exactInteger(entries[tipIndex]!.globalSeq) !== endSeq) {\n return { outcome: \"height_mismatch\", tipIndex: -1 };\n }\n // 4. The predecessor, when the caller expected one.\n const expectedPrev = expect.previousAnchorHash ?? \"\";\n if (expectedPrev !== \"\" && !chainHashEqual(expectedPrev, anchor.previousAnchorHash!)) {\n return { outcome: \"predecessor_mismatch\", tipIndex };\n }\n // 5. The subject, byte for byte, when the caller expected one.\n const expectedSubject = expect.subject ?? \"\";\n if (expectedSubject !== \"\" && expectedSubject !== anchor.subject) {\n return { outcome: \"tenant_mismatch\", tipIndex };\n }\n // 6. The head, over the anchor's own predecessor hash. The chain verified,\n // so the tip's stored hash IS its chain hash (recomputed; an erased v4\n // entry's too, §5.0).\n const expected = anchorChainHashV7Sync(\n anchor.previousAnchorHash!,\n anchor.subject,\n startSeq.toString(),\n endSeq.toString(),\n entries[tipIndex]!.chainHash\n );\n return {\n outcome: chainHashEqual(expected, anchor.chainHash) ? \"bound\" : \"head_mismatch\",\n tipIndex,\n };\n}\n\n/** Entries up to and including the last tombstone at or before `tipIndex`. */\nfunction notBoundThrough(walk: ChainWalk, tipIndex: number): number {\n let last = -1;\n for (const p of walk.tombstonePositions) if (p <= tipIndex) last = p;\n return last + 1;\n}\n\n/**\n * Bind a v7 anchor to the entries it covers, without a key (format-spec §9.7).\n *\n * # Description\n *\n * Refuses, as errors with no outcome, an anchor that breaks format-spec §9.3\n * or §9.8 and entries given as a segment (`expect.previousHash`). Then walks\n * the entries from the chain's first entry and checks, in this order, the\n * first failure being the outcome:\n *\n * 1. the chain verifies (§5.5): otherwise `chain_broken`;\n * 2. the first entry's `globalSeq` is `range.startSeq`: otherwise\n * `range_start_mismatch`;\n * 3. an entry has `globalSeq` `range.endSeq`: otherwise `height_mismatch`\n * (the anchor covers entries not given). Entries after it are not the\n * anchor's concern: a chain that has grown since still binds;\n * 4. `expect.previousAnchorHash`, if given, equals the anchor's\n * `previousAnchorHash`: otherwise `predecessor_mismatch`;\n * 5. `expect.subject`, if given, equals the anchor's `subject` byte for\n * byte: otherwise `tenant_mismatch`;\n * 6. the v7 anchor chain hash (§9.4) recomputes to `chainHash`: otherwise\n * `head_mismatch`. All six: `bound`.\n *\n * A v7 anchor carries its predecessor's hash in its signed bytes, so no\n * predecessor hash is needed to bind it; `expect.previousAnchorHash` only\n * CHECKS it against the one the caller holds.\n *\n * KEYLESS: the signature is NOT checked. Use `verifyAnchorLocally`.\n *\n * WHAT IS NOT CHECKED, SAID SO. Without `expect.subject`, `subjectChecked` is\n * false: the anchor may be about another chain. `entriesNotBound` counts the\n * entries up to and including the last v2/v3 tombstone at or before the tip\n * (a v3 prefix continued in v4 keeps exactly its guarantee, §2.5). Never\n * describe those entries as bound.\n *\n * # Inputs\n *\n * - anchor: a v7 anchor, as `parseAnchorText` returns it\n * - entries: the chain from its first entry (it may have grown since)\n * - expect: the subject and predecessor hash the caller expects; empty or\n * omitted means not given\n *\n * # Outputs\n *\n * - Promise<AnchorBindResult>: `bound` only for `\"bound\"`; `subjectChecked`\n * always set\n * - AnchorVerificationError: the anchor is not v7 or is malformed,\n * `expect.previousHash` is given, or `expect.previousAnchorHash` is not a\n * digest\n * - ChainVerificationError: `entries` is empty\n *\n * # Example\n *\n * const r = await bindAnchorV7ToEntries(parseAnchorText(text), entries, {\n * subject: \"orders\",\n * });\n *\n * # Limitations\n *\n * - Does not verify the signature, and does not check a series of anchors.\n *\n * # Assumptions\n *\n * - `entries[0]` is the chain's first entry.\n */\nexport async function bindAnchorV7ToEntries(\n anchor: Anchor,\n entries: readonly ExportedEntry[],\n expect: AnchorBindExpectations = {}\n): Promise<AnchorBindResult> {\n if (anchor.version !== 7) {\n throw new AnchorVerificationError(\n \"bindAnchorV7ToEntries binds a v7 anchor; bind v1-v6 with bindAnchorToEntries\"\n );\n }\n checkAnchorWellFormed(anchor);\n if ((expect.previousHash ?? \"\") !== \"\") {\n // §9.8: entry_count is counted from the chain's first entry.\n throw new AnchorVerificationError(\n \"an anchor cannot be bound to a segment: pass the chain from its first entry\"\n );\n }\n const expectedPrev = expect.previousAnchorHash ?? \"\";\n if (expectedPrev !== \"\" && !isChainDigest(expectedPrev)) {\n throw new AnchorVerificationError(\n \"the expected previousAnchorHash must be exactly 128 lowercase hex characters\"\n );\n }\n if (entries.length === 0) {\n throw new ChainVerificationError(\"entries array cannot be empty\");\n }\n\n const startTime = performance.now();\n const walk = await walkChain(entries, \"\", 0);\n const { outcome, tipIndex } = bindOutcomeV7(anchor, entries, walk.breaks.length === 0, expect);\n const chain = walkResult(walk, entries.length, performance.now() - startTime, outcome);\n return {\n outcome,\n bound: outcome === \"bound\",\n tombstones: chain.tombstonesFound,\n entriesNotBound: notBoundThrough(walk, tipIndex < 0 ? entries.length - 1 : tipIndex),\n chain,\n subjectChecked: (expect.subject ?? \"\") !== \"\",\n };\n}\n\n/**\n * Verify a complete chain from exported data.\n *\n * Performs full chain verification using exported entries without\n * requiring network access to Aleutian APIs. Verifies field shapes, chain hash\n * continuity and tombstone format validity (format-spec §2, §4, §5), and\n * optionally binds the result to an anchor.\n *\n * The first `globalSeq` is not constrained: a chain may start at 0, at 1, or\n * (for a segment, with `options.previousHash`) anywhere.\n *\n * WHAT A TOMBSTONE LEAVES UNVERIFIED (format-spec §5.5). `valid` says the\n * entries are consistent with each other. It does NOT say the entries before a\n * tombstone are the ones originally written: a tombstone's chain hash is taken\n * as stored, so whoever can write the store can replace every entry up to it.\n * `entriesNotVerified` (and `lastTombstone`) report how many entries that is.\n * Never describe them as verified.\n *\n * WARNING (M-4): OfflineBreak contains entryId and hashes that may correlate\n * to PII. Consider truncating hashes before logging: hash.slice(0, 8) is sufficient.\n *\n * @param entries - Array of entries in globalSeq order\n * @param options - Verification options (anchor, previousHash, maxEntries, maxBreaks)\n * @returns Verification result with validity, breaks, and statistics\n *\n * @throws ChainVerificationError for unrecoverable errors (empty entries, or\n * an anchor together with `previousHash`)\n * @throws AnchorVerificationError when `options.anchor` is malformed\n * (format-spec §9.3, §9.8): an error, not a break\n *\n * @example\n * ```typescript\n * import {\n * loadExportedEntries,\n * loadAnchor,\n * verifyChainOffline\n * } from '@aleutian/verification';\n *\n * const entries = await loadExportedEntries('export-2026-01.json');\n * const anchor = await loadAnchor('anchor-2026-01-20.json');\n *\n * const result = await verifyChainOffline(entries, {\n * anchor,\n * previousAnchorHash: SEED_ANCHOR_HASH, // genesis; else prior anchor's chainHash\n * maxBreaks: 100, // Stop early if chain is severely corrupted\n * });\n *\n * if (result.valid) {\n * console.log(\n * `Chain consistent: ${result.entriesVerified} entries verified, ` +\n * `${result.entriesNotVerified} not verified (up to the last tombstone)`\n * );\n * } else {\n * console.log(`Chain invalid: ${result.breaks.length} breaks`);\n * }\n * ```\n */\nexport async function verifyChainOffline(\n entries: readonly ExportedEntry[],\n options: ChainVerifyOptions = {}\n): Promise<OfflineVerificationResult> {\n if (entries.length === 0) {\n throw new ChainVerificationError(\"entries array cannot be empty\");\n }\n const startHash = options.previousHash ?? \"\";\n if (options.anchor && startHash !== \"\") {\n // format-spec §9.8: entry_count is counted from the chain's first entry,\n // so an anchor is never bound to entries verified from a predecessor hash.\n throw new ChainVerificationError(\n \"an anchor cannot be bound to a segment: omit previousHash and pass the chain from its first entry\"\n );\n }\n if (options.anchor) {\n checkAnchorWellFormed(options.anchor);\n }\n\n // M-10: Resource bounds - limit entries processed\n const maxEntries = options.maxEntries ?? 0;\n const entriesToProcess =\n maxEntries > 0 && entries.length > maxEntries\n ? entries.slice(0, maxEntries)\n : entries;\n\n const startTime = performance.now();\n const walk = await walkChain(entriesToProcess, startHash, options.maxBreaks ?? 0);\n const breaks = walk.breaks;\n const lastEntry = entriesToProcess[entriesToProcess.length - 1]!;\n let anchorOutcome: AnchorBindOutcome | undefined;\n\n // Anchor binding: when caller supplied an Anchor, bind it exactly as\n // `bindAnchorToEntries` does. The legacy expectedLastHash path below\n // cannot bind to real anchors because anchor.chain_hash and the tip\n // entry's chain_hash live in different SHA-512 domain separators.\n if (options.anchor) {\n const anchor = options.anchor;\n let prevAnchorHash = options.previousAnchorHash ?? \"\";\n if (prevAnchorHash === \"\" && anchor.previousAnchorId === SEED_ANCHOR_ID) {\n prevAnchorHash = SEED_ANCHOR_HASH;\n }\n if (anchor.version === 7) {\n // v7 carries its predecessor hash; a given one is the expected one.\n const expectedPrev = options.previousAnchorHash ?? \"\";\n anchorOutcome =\n expectedPrev !== \"\" && !isChainDigest(expectedPrev)\n ? breaks.length === 0\n ? \"predecessor_mismatch\"\n : \"chain_broken\"\n : bindOutcomeV7(anchor, entriesToProcess, breaks.length === 0, {\n previousAnchorHash: expectedPrev,\n }).outcome;\n } else if (!isChainDigest(prevAnchorHash)) {\n // No usable predecessor hash: no trust can be established.\n anchorOutcome = breaks.length === 0 ? \"predecessor_mismatch\" : \"chain_broken\";\n } else {\n anchorOutcome = await bindOutcome(\n anchor,\n entriesToProcess,\n breaks.length === 0,\n prevAnchorHash\n );\n }\n if (anchorOutcome !== \"bound\" && anchorOutcome !== \"chain_broken\") {\n breaks.push({\n position: entriesToProcess.length - 1,\n entryId: typeof lastEntry.entryId === \"string\" ? lastEntry.entryId : \"\",\n expectedHash: \"\",\n actualHash: \"\",\n breakType: \"anchor_mismatch\",\n context: { outcome: anchorOutcome },\n });\n }\n } else {\n // Deprecated legacy path; will be removed in the next minor release.\n const expectedLastHash = options.expectedLastHash ?? \"\";\n const tipHash = isChainDigest(lastEntry.chainHash) ? lastEntry.chainHash : \"\";\n if (expectedLastHash && !chainHashEqual(tipHash, expectedLastHash)) {\n breaks.push({\n position: entriesToProcess.length - 1,\n entryId: typeof lastEntry.entryId === \"string\" ? lastEntry.entryId : \"\",\n expectedHash: expectedLastHash,\n actualHash: tipHash,\n breakType: \"anchor_mismatch\",\n context: {},\n });\n }\n }\n\n return walkResult(walk, entriesToProcess.length, performance.now() - startTime, anchorOutcome);\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Trust-manifest freshness verdicts (chainlinker_modernization_12f_e).\n *\n * A verifier holding a trust manifest can only reflect revocations known\n * AT the manifest's generation date: a key revoked afterwards is invisible\n * (\"the CRL problem\" for offline verification). This module makes that\n * limitation explicit rather than emitting a bare \"valid\".\n *\n * v1 semantics (ADR-029 §D5): advisory report + warn, never hard-fail.\n * Byte-identical to the Go (`EvaluateManifestFreshness`) and Python\n * (`evaluate_manifest_freshness`) SDK helpers via the shared golden\n * vectors in `sdk/testdata/manifest_freshness_golden.json`.\n *\n * Browser-safe: depends only on `Date` + string ops (no Node built-ins).\n */\n\n/**\n * Soft-warn threshold (ADR-029 §D5). A manifest older than this many days\n * is reported STALE — advisory only; never changes validity, never fails.\n */\nexport const MANIFEST_FRESHNESS_MAX_AGE_DAYS = 30;\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\n/**\n * Structured, advisory freshness verdict for a trust manifest. All fields\n * are advisory in v1: they inform the verdict string and let a STATEFUL\n * caller act on `rollbackDetected`, but the SDK never converts any of them\n * into a hard verification failure.\n */\nexport interface ManifestFreshness {\n /** The manifest's monotonic version integer. */\n readonly version: number;\n /** The manifest's generation wall-clock time (UnixMilli, UTC). */\n readonly generatedAtMs: number;\n /**\n * floor((now - generatedAtMs) / 1 day), clamped to 0 for a manifest\n * whose generation stamp is in the future relative to `now`.\n */\n readonly ageDays: number;\n /** True when `ageDays > MANIFEST_FRESHNESS_MAX_AGE_DAYS`. Advisory. */\n readonly stale: boolean;\n /**\n * True only for a STATEFUL evaluation (a non-negative `lastSeenVersion`\n * was supplied) where `version` is LOWER than the last version this\n * verifier saw — a suppressed/rolled-back update that could hide a\n * revocation. A stateless one-shot verifier cannot detect this and\n * always reports false; its only defense is the reported date.\n */\n readonly rollbackDetected: boolean;\n}\n\n/**\n * Compute the advisory freshness verdict for a trust manifest.\n *\n * Pure function over the manifest's signed `version` + `generatedAtMs` and\n * a caller-supplied reference clock. Never fetches, never mutates, never\n * throws.\n *\n * @param version - the manifest's monotonic version integer.\n * @param generatedAtMs - the manifest's generation time (UnixMilli, UTC).\n * @param nowMs - reference clock (UnixMilli, UTC).\n * @param lastSeenVersion - the highest manifest version this verifier has\n * previously observed, for anti-rollback. Pass a NEGATIVE value (e.g.\n * `-1`) for a STATELESS verifier — rollback detection is then disabled.\n */\nexport function evaluateManifestFreshness(\n version: number,\n generatedAtMs: number,\n nowMs: number,\n lastSeenVersion: number,\n): ManifestFreshness {\n const ageMs = nowMs - generatedAtMs;\n const ageDays = ageMs > 0 ? Math.floor(ageMs / MS_PER_DAY) : 0;\n return {\n version,\n generatedAtMs,\n ageDays,\n stale: ageDays > MANIFEST_FRESHNESS_MAX_AGE_DAYS,\n rollbackDetected: lastSeenVersion >= 0 && version < lastSeenVersion,\n };\n}\n\n/**\n * Return the manifest generation date as a UTC `YYYY-MM-DD` string. This is\n * the exact date form embedded in the verdict line and is byte-identical\n * across the Go/Python/JS SDKs.\n */\nexport function manifestGeneratedDate(f: ManifestFreshness): string {\n return new Date(f.generatedAtMs).toISOString().slice(0, 10);\n}\n\n/**\n * Return the freshness caveat WITHOUT asserting signature validity. Use in\n * a context that reports manifest freshness but does not itself establish\n * that a signature verified — e.g. the offline chain CLI, which checks\n * chain continuity + anchor binding, not signatures against the manifest.\n */\nexport function manifestRevocationNote(f: ManifestFreshness): string {\n let note =\n `Revocation checked against trust manifest v${f.version} ` +\n `dated ${manifestGeneratedDate(f)} — a key revoked after that date ` +\n `is not reflected.`;\n if (f.stale) {\n note += ` [WARNING: manifest is ${f.ageDays} days old]`;\n }\n return note;\n}\n\n/**\n * Return the exact ADR-029 §D5 verdict line for a VALID signature:\n *\n * Signature valid. Revocation checked against trust manifest v{N} dated\n * {YYYY-MM-DD} — a key revoked after that date is not reflected.\n *\n * with ` [WARNING: manifest is {age} days old]` appended when stale. Never\n * a bare \"valid\". Only emit this where signature validity has already been\n * established; otherwise use {@link manifestRevocationNote}.\n */\nexport function manifestVerdictLine(f: ManifestFreshness): string {\n return \"Signature valid. \" + manifestRevocationNote(f);\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Key ids, as proof computes them (format-spec §9.6).\n *\n * A key id only NAMES a key: whether to trust that key is the verifier's\n * decision. A verifier that checks a signature row naming key id K must make\n * sure the public key it verifies with really has id K\n * (`await keyIdMLDSA65(pk) === K`); otherwise a row could name one key and be\n * checked with another.\n *\n * - ML-DSA-65: the first 16 bytes of\n * `SHA-512(\"proof.keyid.v1:\" || SubjectPublicKeyInfo DER)`, as 32 lowercase\n * hex. The SPKI follows RFC 9881: the AlgorithmIdentifier is the ML-DSA-65\n * OID with parameters ABSENT, and the BIT STRING holds the raw public key.\n * - X-Wing, a legacy rule: the first 16 bytes of `SHA-512(raw public key)`, no\n * domain string.\n *\n * Vectors: `testdata/keyid_vectors.json` (computed independently, in Python,\n * from the spec).\n */\n\nimport { hexToUint8Array, sha512HexRaw } from \"./hash.js\";\n\n/** The domain string hashed before an ML-DSA SubjectPublicKeyInfo. */\nexport const KEYID_DOMAIN = \"proof.keyid.v1:\";\n\n/** ML-DSA-65 public key size (FIPS 204). */\nexport const MLDSA65_PUBLIC_KEY_SIZE = 1952;\n\n// RFC 9881: id-ml-dsa-65 = 2.16.840.1.101.3.4.3.18, parameters absent.\nconst MLDSA65_ALGORITHM_IDENTIFIER = hexToUint8Array(\"300b0609608648016503040312\");\n\nfunction derLength(n: number): Uint8Array {\n if (n < 0x80) return Uint8Array.of(n);\n const body: number[] = [];\n for (let v = n; v > 0; v = Math.floor(v / 256)) body.unshift(v % 256);\n return Uint8Array.of(0x80 | body.length, ...body);\n}\n\nfunction concat(...parts: Uint8Array[]): Uint8Array {\n const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));\n let at = 0;\n for (const p of parts) {\n out.set(p, at);\n at += p.length;\n }\n return out;\n}\n\n/**\n * The SubjectPublicKeyInfo DER of a raw ML-DSA-65 public key.\n *\n * @throws Error when the key is not exactly 1952 bytes.\n */\nexport function mldsa65Spki(publicKey: Uint8Array): Uint8Array {\n if (publicKey.length !== MLDSA65_PUBLIC_KEY_SIZE) {\n throw new Error(\n `an ML-DSA-65 public key is ${MLDSA65_PUBLIC_KEY_SIZE} bytes, got ${publicKey.length}`\n );\n }\n const bitString = concat(\n Uint8Array.of(0x03),\n derLength(publicKey.length + 1),\n Uint8Array.of(0x00),\n publicKey\n );\n const body = concat(MLDSA65_ALGORITHM_IDENTIFIER, bitString);\n return concat(Uint8Array.of(0x30), derLength(body.length), body);\n}\n\n/**\n * The key id of a raw ML-DSA-65 public key: 32 lowercase hex.\n *\n * @throws Error when the key is not exactly 1952 bytes.\n */\nexport async function keyIdMLDSA65(publicKey: Uint8Array): Promise<string> {\n const input = concat(new TextEncoder().encode(KEYID_DOMAIN), mldsa65Spki(publicKey));\n return (await sha512HexRaw(input)).slice(0, 32);\n}\n\n/**\n * The key id of a raw X-Wing public key (the legacy rule, no domain).\n *\n * @throws Error when the key is empty.\n */\nexport async function keyIdXWing(publicKey: Uint8Array): Promise<string> {\n if (publicKey.length === 0) throw new Error(\"an X-Wing public key cannot be empty\");\n return (await sha512HexRaw(publicKey)).slice(0, 32);\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * SAR (Data Subject Access Request) v3 chain entry types — TS verifier port.\n *\n * Cross-language reference\n * ========================\n * Mirror of {@link \"../../verification-go/sar_entries_v3.go\"} and\n * {@link \"../../verification-python/src/aleutian_verification/sar_entries.py\"}.\n * Field order in each interface MUST match the alphabetical body-field order\n * from `pqc_05c v3 §4.5–4.9`. The canonical encoder in `canonicalV3.ts`\n * (ticket dsar_chain_f_02) relies on declaration ordering — silent reorder\n * is a wire-format break.\n *\n * Sealed discriminated union\n * ==========================\n * TypeScript cannot enforce protocol sealing at the type-system level the\n * way Go can (no unexported parameter types). Instead this module defines\n * `CONCRETE_SAR_ENTRY_TYPE_TAGS` — an authoritative set of `entryType`\n * literal values — and the public encoder / verifier dispatch chain\n * (canonicalV3.chainCanonicalV3 in `_02`, verifyV3.verifyChainEntryV3\n * in `_04`) checks the tag at runtime before any work. Structural-typing\n * impostors that duck-type `ChainEntryV3` are refused at that boundary.\n * The `ChainEntryV3` discriminated union remains the static type for\n * annotation purposes; it is NOT the security boundary — the tag set is.\n *\n * Privacy posture (OQ-11, locked)\n * ================================\n * SAR entries are systematically actor-anonymous on chain. NONE of these\n * interfaces carry actor pseudonyms or email-derived hashes. Verifiers\n * cannot identify the data subject from the chain entry alone.\n *\n * Field naming\n * ============\n * camelCase per TS convention. The on-the-wire JSON form is snake_case;\n * the canonical encoder operates on these typed objects directly, NOT\n * on the JSON. Callers loading from chain rows should convert via the\n * snake-case→camel-case helper in `chainRowDecode.ts` (future ticket)\n * before passing entries into the encoder/verifier.\n *\n * @module\n */\n\n// =============================================================================\n// Enums (string literal unions)\n// =============================================================================\n\n/** Chain entry discriminating tag (pqc_05c v3 §3.2). */\nexport type EventTypeV3 =\n | \"sar_intent\"\n | \"sar_acknowledged\"\n | \"sar_fulfilled\"\n | \"sar_rejected\"\n | \"sar_extended\";\n\n/** Surface that originated a SAR intent (canonical on chain, only on intent). */\nexport type SARSourceChannelV3 = \"portal\" | \"api\";\n\n/** GDPR right being exercised. */\nexport type SARTypeV3 = \"access\" | \"erasure\" | \"both\";\n\n/** What the controller actually did at fulfillment time. */\nexport type SARFulfillmentKindV3 = \"access\" | \"erasure\" | \"both\";\n\n// =============================================================================\n// TenantHMACDigestV3\n// =============================================================================\n\nconst _HMAC_DIGEST_LEN = 64 as const;\n\n/**\n * Internal brand for nominal-typing on TenantHMACDigestV3.\n *\n * The brand is TYPE-ONLY — there is no runtime property of this name on\n * the value. `declare const ... unique symbol` is erased at runtime, so\n * the constructed object has only `hex` at runtime. The compile-time\n * brand prevents external code from forging a digest via plain object\n * literal: `{ hex: \"...\" } as TenantHMACDigestV3` fails type-check\n * because the synthetic brand property is unsatisfiable outside this\n * module.\n */\ndeclare const _digestBrand: unique symbol;\n\n/**\n * HMAC-SHA-512 digest under a per-tenant PII subkey (pqc_05c v3 §4.0).\n *\n * Stored as a hex string (or empty string for the zero / unset sentinel) —\n * matches Go SDK's `TenantHMACDigestV3` byte-for-byte so the canonical\n * encoder produces parity output. The encoder calls `.hex`; empty\n * string emits a 0-length TLV (sentinel for \"caller did not supply\n * cleartext\"), and 128-hex emits a 128-byte string.\n *\n * Construct via {@link tenantHMACDigestFromHex}, {@link tenantHMACDigestFromRaw},\n * or {@link tenantHMACDigestZero}. The type-only brand prevents\n * external code from forging a digest via `{} as TenantHMACDigestV3` —\n * the brand property is unsatisfiable outside this module.\n */\nexport interface TenantHMACDigestV3 {\n readonly hex: string;\n // Phase 3 review M1: brand is `: never` (NOT `?: never`). The\n // optional form `?:` was bypassable via `{ hex } as TenantHMACDigestV3`\n // because TS treats an absent optional property as satisfying\n // `never`. With the required form, the cast fails compilation —\n // the brand actually carries weight beyond documentation.\n readonly [_digestBrand]: never;\n}\n\n/**\n * Compile-time-only attached \"brand\" so the constructor functions\n * can satisfy the required `[_digestBrand]: never` slot without\n * actually creating that property at runtime. Type-erased at emit.\n */\nconst _digestBrandStamp = {} as { [_digestBrand]: never };\n\n/**\n * H4 redaction methods (Phase 3 review pre-emptive ticket): every\n * TenantHMACDigestV3 instance carries non-enumerable methods that\n * redact the full HMAC hex when the value is logged or serialized\n * by accident. The methods cover all four JS surfaces a developer\n * might hit:\n *\n * - `toString()` — used by template literals, `String(d)`, `d + \"\"`\n * - `toJSON()` — used by `JSON.stringify(d)`\n * - `[Symbol.toPrimitive]` — used by coercion and runtime introspection\n * - `[Symbol.for(\"nodejs.util.inspect.custom\")]` — used by Node's\n * `util.inspect` (and `console.log` under Node)\n *\n * The redacted form shows only the first 8 hex chars + \"...\". A zero\n * digest renders as `TenantHMACDigestV3(unset)`. The raw `.hex`\n * property remains accessible for verifier code that legitimately\n * needs the bytes (the encoder calls `.hex` directly).\n *\n * Methods are non-enumerable and non-writable so they don't leak\n * into `Object.keys(d)` or `JSON.stringify(...{...d})` spreads, and\n * can't be deleted to bypass the redaction.\n */\nfunction _stampRedactionMethods(d: TenantHMACDigestV3): TenantHMACDigestV3 {\n const redacted = (): string =>\n d.hex === \"\"\n ? \"TenantHMACDigestV3(unset)\"\n : `TenantHMACDigestV3(${d.hex.slice(0, 8)}…)`;\n const define = (key: PropertyKey, value: unknown): void => {\n Object.defineProperty(d, key, {\n value,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n };\n define(\"toString\", redacted);\n define(\"toJSON\", redacted);\n define(Symbol.toPrimitive, redacted);\n define(Symbol.for(\"nodejs.util.inspect.custom\"), redacted);\n return d;\n}\n\n/** Construct from a 128-char lowercase hex string. Empty string → zero digest. */\nexport function tenantHMACDigestFromHex(hex: string): TenantHMACDigestV3 {\n // Combined length + charset check via a single anchored regex\n // (Phase 3 review LOW: collapses the two prior conditions).\n if (hex !== \"\" && !/^[0-9a-f]{128}$/.test(hex)) {\n throw new Error(\n `TenantHMACDigestV3 hex must be empty OR exactly ${_HMAC_DIGEST_LEN * 2} lowercase hex chars`,\n );\n }\n return _stampRedactionMethods({ hex, ..._digestBrandStamp });\n}\n\n/** Construct from 64 raw bytes. */\nexport function tenantHMACDigestFromRaw(raw: Uint8Array): TenantHMACDigestV3 {\n if (!(raw instanceof Uint8Array)) {\n throw new TypeError(\"TenantHMACDigestV3.fromRaw expects Uint8Array\");\n }\n if (raw.length !== _HMAC_DIGEST_LEN) {\n throw new Error(`TenantHMACDigestV3.fromRaw expects ${_HMAC_DIGEST_LEN} bytes`);\n }\n // Phase 3 review LOW: idiomatic Array.from(...).join instead of\n // per-byte string concatenation.\n const hex = Array.from(raw, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return _stampRedactionMethods({ hex, ..._digestBrandStamp });\n}\n\n/** Zero / unset digest — encodes as empty string on chain. */\nexport function tenantHMACDigestZero(): TenantHMACDigestV3 {\n return _stampRedactionMethods({ hex: \"\", ..._digestBrandStamp });\n}\n\n/** True iff the digest is the zero / unset sentinel. */\nexport function tenantHMACDigestIsZero(d: TenantHMACDigestV3): boolean {\n return d.hex === \"\";\n}\n\n// =============================================================================\n// V3 SAR chain entry interfaces — 5 discriminated-union members\n//\n// Header (alphabetical):\n// 1. companyId — comp_<26-char ULID>\n// 2. entryType — discriminating tag (EventTypeV3)\n// 3. signingKeyId — KMS key identifier\n// 4. timestampMs — Unix milliseconds\n//\n// Body order per type follows pqc_05c v3 §4.5–4.9 alphabetical.\n// =============================================================================\n\n/**\n * Common header — present on every v3 chain entry.\n *\n * # Number vs BigInt typing (Phase 3 review H1)\n *\n * Int64 fields (`timestampMs`, `tombstoneCount`, `extendedDueAtMs`)\n * accept `bigint | number`. JS `Number` is double-precision IEEE-754,\n * so values above `Number.MAX_SAFE_INTEGER` (2^53 - 1) silently lose\n * precision. Realistic v3 values fit comfortably (e.g., year-3000\n * UnixMilli is ~3.3 × 10^13, well under 2^53 ≈ 9 × 10^15), but a\n * future caller pulling row data from BigQuery — where int64 may\n * surface as `bigint` — should be able to pass it through without a\n * cast or precision-loss risk.\n *\n * The encoder (`canonicalV3.appendU64`) accepts either form and\n * routes through `DataView.setBigUint64` for byte-identical BE\n * encoding regardless of the source representation.\n */\ninterface _ChainEntryHeaderV3<T extends EventTypeV3> {\n readonly companyId: string;\n readonly entryType: T;\n readonly signingKeyId: string;\n readonly timestampMs: bigint | number;\n}\n\n/**\n * Filed-SAR entry. Header + 5 body fields (pqc_05c v3 §4.5).\n *\n * `piiDigestKeyVersion` (pii_hmac_key_rotation_R4): source-namespaced\n * PII-HMAC key version (\"sm:v1\") under which `reasonHash` was computed.\n * OPTIONAL on intent (reason_hash itself is optional). Empty string is\n * the legacy / pre-rotation sentinel — encoded ONLY when non-empty so a\n * legacy leaf hashes byte-identically to its original signing. Matches\n * the Go SDK's `SARIntentEntryV3.PIIDigestKeyVersion` (json\n * `pii_digest_key_version`).\n */\nexport interface SARIntentEntryV3 extends _ChainEntryHeaderV3<\"sar_intent\"> {\n readonly piiDigestKeyVersion: string;\n readonly reasonHash: TenantHMACDigestV3;\n readonly requestId: string;\n readonly sarType: SARTypeV3;\n readonly scope: string;\n readonly sourceChannel: SARSourceChannelV3;\n}\n\n/** Acknowledged-SAR entry. Header + 2 body fields (pqc_05c v3 §4.6). */\nexport interface SARAcknowledgedEntryV3\n extends _ChainEntryHeaderV3<\"sar_acknowledged\"> {\n readonly intentEntryId: string;\n readonly requestId: string;\n}\n\n/**\n * Fulfilled-SAR entry. Header + 7 body fields (pqc_05c v3 §4.7).\n *\n * `certificateId` was added 2026-05-16 by `dsar_fulfill_b_pre_02e` as the\n * alphabetical-first body field. Per-kind shape rules:\n *\n * - fulfillmentKind=access → certificateId MUST be empty\n * - fulfillmentKind=erasure → certificateId MUST match cert_<32-hex>\n * - fulfillmentKind=both → certificateId MUST match cert_<32-hex>\n */\nexport interface SARFulfilledEntryV3\n extends _ChainEntryHeaderV3<\"sar_fulfilled\"> {\n readonly certificateId: string;\n readonly fulfillmentKind: SARFulfillmentKindV3;\n readonly intentEntryId: string;\n readonly legalBasis: string;\n readonly manifestRoot: string;\n readonly requestId: string;\n readonly tombstoneCount: bigint | number;\n}\n\n/**\n * Rejected-SAR entry. Header + 4 body fields (pqc_05c v3 §4.8).\n *\n * `piiDigestKeyVersion` (pii_hmac_key_rotation_R4): PII-HMAC key version\n * (\"sm:v1\") under which `rationaleHash` was computed. REQUIRED in the\n * sense that rationale_hash is required on rejection, so a non-empty\n * version always has a digest to apply it to. Empty string is the legacy\n * sentinel — encoded ONLY when non-empty. Matches Go\n * `SARRejectedEntryV3.PIIDigestKeyVersion`.\n */\nexport interface SARRejectedEntryV3 extends _ChainEntryHeaderV3<\"sar_rejected\"> {\n readonly intentEntryId: string;\n readonly legalBasis: string;\n readonly piiDigestKeyVersion: string;\n readonly rationaleHash: TenantHMACDigestV3;\n readonly requestId: string;\n}\n\n/**\n * Extended-SAR entry. Header + 4 body fields (pqc_05c v3 §4.9).\n *\n * Body alphabetical: extendedDueAtMs, intentEntryId, piiDigestKeyVersion\n * (R4, iff non-empty), reasonHash, requestId.\n * `originalDueAtMs` is NOT bound — derivable from the intent entry.\n */\nexport interface SARExtendedEntryV3 extends _ChainEntryHeaderV3<\"sar_extended\"> {\n readonly extendedDueAtMs: bigint | number;\n readonly intentEntryId: string;\n /**\n * `piiDigestKeyVersion` (pii_hmac_key_rotation_R4): PII-HMAC key\n * version (\"sm:v1\") under which `reasonHash` was computed. reason_hash\n * is required on extension, so a non-empty version always has a digest\n * to apply it to. Empty string is the legacy sentinel — encoded ONLY\n * when non-empty. Matches Go `SARExtendedEntryV3.PIIDigestKeyVersion`.\n */\n readonly piiDigestKeyVersion: string;\n readonly reasonHash: TenantHMACDigestV3;\n readonly requestId: string;\n}\n\n/**\n * Discriminated union of all 5 v3 SAR chain entry types.\n *\n * The `entryType` literal field is the discriminant — TypeScript narrows\n * to a specific interface when you switch on it:\n *\n * ```ts\n * function describe(e: ChainEntryV3): string {\n * switch (e.entryType) {\n * case \"sar_intent\": return `intent ${e.requestId}`;\n * case \"sar_fulfilled\": return `fulfilled ${e.manifestRoot.slice(0, 8)}…`;\n * // ... compiler errors if you forget a case\n * }\n * }\n * ```\n */\nexport type ChainEntryV3 =\n | SARIntentEntryV3\n | SARAcknowledgedEntryV3\n | SARFulfilledEntryV3\n | SARRejectedEntryV3\n | SARExtendedEntryV3;\n\n// =============================================================================\n// Concrete-tag set for runtime dispatch (the actual security boundary).\n//\n// Used by canonicalV3.chainCanonicalV3 (in _02) and verifyV3.verifyChainEntryV3\n// (in _04) as the allowlist that refuses structural-typing impostors.\n// Mirrors Python's CONCRETE_SAR_ENTRY_TYPES dispatch.\n// =============================================================================\n\n/**\n * Phase 3 review M3: exhaustiveness pin between the `ChainEntryV3`\n * union and the runtime tag allowlist. Adding a new entry variant\n * to `EventTypeV3` without updating the Set below now FAILS\n * COMPILATION on this `Record<EventTypeV3, true>` literal — the\n * compiler reports the missing key. Older versions of this code\n * relied on a runtime `.size === 5` test that would silently lag\n * behind a new variant addition.\n */\nconst _CONCRETE_TAG_EXHAUSTIVE_PIN: Record<EventTypeV3, true> = {\n sar_intent: true,\n sar_acknowledged: true,\n sar_fulfilled: true,\n sar_rejected: true,\n sar_extended: true,\n};\n\n/**\n * Phase 3 review M2: a transitively-loaded module cannot corrupt\n * the security boundary by calling `.add(\"evil_tag\")` etc. Note:\n * `Object.freeze` alone is INSUFFICIENT here — `Set.prototype.add`\n * is a prototype method that mutates internal slots, not a property\n * assignment the freeze can block. So the mutating methods are\n * explicitly overridden on the instance to throw, AND the instance\n * is frozen so the overrides themselves can't be deleted.\n *\n * `ReadonlySet` at the type level just suppresses TS access to the\n * mutating method names; runtime callers casting to `Set` would\n * otherwise bypass it. This wrapper makes the runtime match the\n * type-level contract.\n */\nfunction _buildImmutableTagSet(tags: EventTypeV3[]): ReadonlySet<EventTypeV3> {\n const s = new Set<EventTypeV3>(tags);\n const throwMutation = (op: string): never => {\n throw new TypeError(\n `CONCRETE_SAR_ENTRY_TYPE_TAGS is immutable — refusing ${op}()`,\n );\n };\n Object.defineProperty(s, \"add\", {\n value: () => throwMutation(\"add\"),\n writable: false,\n configurable: false,\n });\n Object.defineProperty(s, \"delete\", {\n value: () => throwMutation(\"delete\"),\n writable: false,\n configurable: false,\n });\n Object.defineProperty(s, \"clear\", {\n value: () => throwMutation(\"clear\"),\n writable: false,\n configurable: false,\n });\n return Object.freeze(s);\n}\n\nexport const CONCRETE_SAR_ENTRY_TYPE_TAGS: ReadonlySet<EventTypeV3> =\n _buildImmutableTagSet(\n Object.keys(_CONCRETE_TAG_EXHAUSTIVE_PIN) as EventTypeV3[],\n );\n\n/**\n * Runtime check that an unknown value carries a valid v3 SAR chain\n * entry TAG. Verifies the `entryType` discriminant is in the\n * concrete-tag allowlist; does NOT shape-check body fields — that\n * happens in `validateV3Entry` (see `_03`).\n *\n * Phase 3 review M4: renamed from the previous `isChainEntryV3` to\n * accurately reflect what it does. Code paths that need full shape\n * validation should call `validateV3Entry` from `canonicalV3.ts`.\n */\nexport function hasValidChainEntryTag(value: unknown): value is ChainEntryV3 {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const tag = (value as { entryType?: unknown }).entryType;\n return (\n typeof tag === \"string\" &&\n CONCRETE_SAR_ENTRY_TYPE_TAGS.has(tag as EventTypeV3)\n );\n}\n\n/**\n * @deprecated Renamed to `hasValidChainEntryTag` (Phase 3 review M4)\n * to accurately describe the tag-only check. Will be removed in a\n * future minor version; switch call sites to the new name.\n */\nexport const isChainEntryV3 = hasValidChainEntryTag;\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Canonical V3 encoder — TS port of `sdk/verification-go/canonical_v3.go`.\n *\n * Produces byte-identical canonical bytes for the 5 SAR entry types so\n * cross-language signature verification works. The load-bearing test\n * (`canonicalV3.goldenVectors.test.ts` in _05) drives this against the\n * Go-baked golden fixtures.\n *\n * # Encoding (per pqc_05c v3 §3 + §4 + §7)\n *\n * - 4-field common header, alphabetical: company_id, entry_type,\n * signing_key_id, timestamp_ms (NO schema_version per OQ-13)\n * - Per-event-type body, alphabetical within the body\n * - Strings: NFC-normalize via `.normalize(\"NFC\")`, then u32 BE\n * length prefix, then UTF-8 bytes (post-NFC byte length per §7)\n * - int64 / uint64: u64 BE encoding; v3 fields are non-negative\n * - String length cap: 256 bytes post-NFC per spec §7\n *\n * # BigInt vs Number\n *\n * `appendU64` accepts `bigint | number` and routes through\n * `DataView.setBigUint64` to dodge JS `Number` precision loss above\n * 2^53. Current v3 fields (`timestampMs`, `tombstoneCount`,\n * `extendedDueAtMs`) are all comfortably under 2^53 for realistic\n * inputs, but we route via BigInt for safety + future-proofing.\n *\n * # Privacy Invariant 4 (no caller-input echo)\n *\n * Per `sdk_privacy_invariants_spec`, error messages NEVER echo the\n * caller-supplied value — operators have it in their producer-side\n * logs. Mirrors Go SDK posture (chain_d_go_review_followup 2026-05-28).\n *\n * # Does NOT validate\n *\n * Encoder assumes pre-validated inputs. Validators ship in `_03`.\n * The encoder still enforces the 256-byte post-NFC cap and rejects\n * negative integers because those are encoder-internal invariants\n * (silently truncating or wrapping would produce wrong bytes).\n */\n\nimport { RE_PII_DIGEST_KEY_VERSION } from \"./captureEntryV3.js\";\nimport {\n CONCRETE_SAR_ENTRY_TYPE_TAGS,\n type ChainEntryV3,\n type EventTypeV3,\n type SARAcknowledgedEntryV3,\n type SARExtendedEntryV3,\n type SARFulfilledEntryV3,\n type SARFulfillmentKindV3,\n type SARIntentEntryV3,\n type SARRejectedEntryV3,\n type SARSourceChannelV3,\n type SARTypeV3,\n type TenantHMACDigestV3,\n tenantHMACDigestIsZero,\n} from \"./sarEntries.js\";\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/**\n * Locked V3 domain prefix used for content-hash and signature\n * derivation. See Go SDK `DomainPrefixV3` for the producer-side\n * counterpart.\n *\n * # WARNING — load-bearing constant\n *\n * Changing this byte sequence invalidates every signed v3 chain\n * entry across all language ports.\n */\nexport const DOMAIN_PREFIX_V3 = \"aleutian.chain.entry.v3:\";\n\n/** Pre-computed `Uint8Array` form to avoid per-hash allocation. */\nexport const DOMAIN_PREFIX_V3_BYTES: Uint8Array = new TextEncoder().encode(\n DOMAIN_PREFIX_V3,\n);\n\n/**\n * v3 spec §7 byte cap on string fields post-NFC. Cross-language\n * locked value; matches Go's `maxV3StringFieldBytesSDK` and Python's\n * `_MAX_V3_STRING_FIELD_BYTES`.\n */\nexport const MAX_V3_STRING_FIELD_BYTES = 256;\n\n/** SHA-512 hex digest length (cross-language constant). */\nexport const V3_SHA512_HEX_LEN = 128;\n\n/**\n * Maximum canonical-byte sum per entry (cross-language locked\n * value; matches Go's `MaxCanonicalBytesV3` and Python's\n * `MAX_CANONICAL_BYTES_V3`). The widest current v3 SAR entry fits\n * comfortably under 1 KiB; 4× headroom absorbs future field\n * additions without forcing a SemVer-breaking bound bump.\n *\n * # Cross-language consistency is load-bearing\n *\n * A divergent value in any one SDK becomes a per-tenant DoS vector\n * against customers using the laxer SDK — they'd do unbounded work\n * on adversarial inputs. Pinned in\n * `verifyV3.test.ts::MAX_CANONICAL_BYTES_V3_LockedAtCrossLanguageValue`.\n */\nexport const MAX_CANONICAL_BYTES_V3 = 4096;\n\n/**\n * 14-month sanity bound for `extendedDueAtMs` past `timestampMs`.\n * Mirror of Go's `420 * 24 * 60 * 60 * 1000` literal.\n */\nexport const EXTENDED_SANITY_BOUND_MS = 420 * 24 * 60 * 60 * 1000;\n\n// =============================================================================\n// Validation regexes (precompiled at module load, mirror of Go SDK patterns)\n// =============================================================================\n\n/**\n * Cross-SDK regex parity note: JS regex literal uses `^...$` because\n * the JS regex engine treats `$` as strict end-of-string in default\n * mode (no `m` flag). This matches Go's default behavior. Python\n * uses `\\A...\\Z` to force strict end-of-string because Python's `$`\n * accepts trailing `\\n` (the chain_d H8 finding). All three SDKs\n * reject the same input set.\n */\nconst RE_COMPANY_ID = /^comp_[0-9A-HJKMNP-TV-Z]{26}$/;\nconst RE_REQUEST_ID = /^[0-9A-HJKMNP-TV-Z]{26}$/;\nconst RE_INTENT_ENTRY_ID =\n /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;\nconst RE_LEGAL_BASIS = /^[a-z0-9_+]{1,64}$/;\nconst RE_SOURCE_CHANNEL = /^[a-z0-9_+]{1,64}$/;\nconst RE_SCOPE = /^(all|grant_[A-Za-z0-9_-]{1,64})$/;\nconst RE_SIGNING_KEY_ID = /^[A-Za-z0-9_./-]{1,128}$/;\nconst RE_SHA512_HEX = /^[0-9a-f]{128}$/;\nconst RE_CERTIFICATE_ID = /^cert_[0-9a-f]{32}$/;\n\nconst SAR_TYPE_ALLOWED: ReadonlySet<SARTypeV3> = new Set<SARTypeV3>([\n \"access\",\n \"erasure\",\n \"both\",\n]);\n\nconst SAR_FULFILLMENT_KIND_ALLOWED: ReadonlySet<SARFulfillmentKindV3> =\n new Set<SARFulfillmentKindV3>([\"access\", \"erasure\", \"both\"]);\n\n// =============================================================================\n// Error types\n// =============================================================================\n\n/**\n * Wrapped sentinel for encoder validation failures. Customer code\n * can `err instanceof ErrInvalidEntryV3` to distinguish encoder\n * rejections from signature/content-hash failures (which use\n * distinct sentinels; see verifyV3.ts).\n *\n * Per `sdk_error_hierarchy_spec`, this is the V3 entry-shape error.\n */\nexport class ErrInvalidEntryV3 extends Error {\n // Typed as `string` (not the literal `\"ErrInvalidEntryV3\"`) so\n // subclasses (`ErrUnknownSigningKeyV3`, etc. in verifyV3.ts) can\n // override the name without a TS2416 mismatch.\n override readonly name: string = \"ErrInvalidEntryV3\";\n constructor(message: string) {\n super(`CanonicalBytesV3: ${message}`);\n if ((Error as { captureStackTrace?: unknown }).captureStackTrace) {\n (\n Error as unknown as {\n captureStackTrace: (target: object, ctor: unknown) => void;\n }\n ).captureStackTrace(this, ErrInvalidEntryV3);\n }\n }\n}\n\n// =============================================================================\n// Validators (mirror of Go's `validateV3*` family)\n// =============================================================================\n\n/**\n * Strict UTF-8 string field validator. Checks NFC byte cap, rejects\n * disallowed control bytes (< 0x20 or 0x7F), AND rejects lone\n * surrogates (H10).\n *\n * Mirror of Go's `validateV3StringFieldSDK`. Privacy Inv 4: errors\n * do NOT echo the value or the post-NFC byte length.\n *\n * # H10 — lone-surrogate detection (Phase 3 review pre-emptive)\n *\n * JS strings are UTF-16; a \"string\" containing a lone high\n * (U+D800-U+DBFF) or low (U+DC00-U+DFFF) surrogate is technically\n * ill-formed UTF-16. `TextEncoder.encode` silently substitutes\n * U+FFFD for such code units, which would produce canonical bytes\n * different from what the caller's source actually contains —\n * breaking cross-language byte parity. We detect and reject these\n * explicitly rather than letting TextEncoder absorb them. Equivalent\n * to Go's `utf8.ValidString` gate on the source side.\n *\n * `String.prototype.isWellFormed` is ECMAScript 2024+ and not yet\n * universally available in browsers / older Node; the manual\n * surrogate scan below is the portable fallback.\n */\n// Exported for intra-package reuse by the capture-entry mirror\n// (captureEntryV3.ts). NOT re-exported from index.ts, so it stays internal to\n// the package — the capture mirror shares this load-bearing surrogate/NFC/\n// control-byte validator rather than duplicating it (drift hazard).\nexport function validateV3StringField(name: string, value: string): void {\n // H10: scan UTF-16 code units for lone surrogates BEFORE any other\n // processing. A well-formed pair is (high, low) adjacent; anything\n // else (high without low, low without preceding high, low first)\n // is ill-formed.\n for (let i = 0; i < value.length; i++) {\n const u = value.charCodeAt(i);\n if (u >= 0xd800 && u <= 0xdbff) {\n // High surrogate — must be followed by a low surrogate\n const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;\n if (next < 0xdc00 || next > 0xdfff) {\n throw new ErrInvalidEntryV3(\n `${name} contains a lone surrogate (ill-formed UTF-16)`,\n );\n }\n i++; // skip the low surrogate we just validated\n } else if (u >= 0xdc00 && u <= 0xdfff) {\n // Low surrogate without preceding high\n throw new ErrInvalidEntryV3(\n `${name} contains a lone surrogate (ill-formed UTF-16)`,\n );\n }\n }\n const nfc = value.normalize(\"NFC\");\n // M6 (2026-05-29): require inputs to already be in NFC form so the\n // canonical-bytes pipeline can skip the redundant per-field\n // re-normalization in `V3Encoder.appendStr`. NFC is what every\n // mainstream OS / browser / editor produces by default, so this\n // tightens the contract without affecting realistic callers. Cross-\n // language note: Go's encoder normalizes opaquely; differing on this\n // gate is intentional — both pipelines emit byte-identical canonical\n // bytes for NFC inputs, which is the only contract that matters for\n // cross-language verification.\n if (value !== nfc) {\n throw new ErrInvalidEntryV3(\n `${name} is not in Unicode NFC form; normalize with .normalize(\"NFC\") before passing to the SDK`,\n );\n }\n const utf8Len = new TextEncoder().encode(nfc).length;\n if (utf8Len > MAX_V3_STRING_FIELD_BYTES) {\n throw new ErrInvalidEntryV3(\n `${name} exceeds ${MAX_V3_STRING_FIELD_BYTES} bytes after NFC`,\n );\n }\n // Disallowed control bytes: any byte < 0x20 (C0 controls + NUL) or\n // 0x7F (DEL). Iterate code points rather than UTF-16 units so a\n // surrogate pair (4 UTF-8 bytes for U+10000+) isn't misread.\n for (const ch of nfc) {\n const cp = ch.codePointAt(0)!;\n if (cp < 0x20 || cp === 0x7f) {\n throw new ErrInvalidEntryV3(\n `${name} contains a disallowed control byte`,\n );\n }\n }\n}\n\n// Exported for intra-package reuse by captureEntryV3.ts (see note on\n// validateV3StringField). Not part of the public API (index.ts is selective).\nexport function validateV3SigningKeyId(s: string): void {\n if (s === \"\") {\n throw new ErrInvalidEntryV3(\"signing_key_id empty\");\n }\n if (!RE_SIGNING_KEY_ID.test(s)) {\n throw new ErrInvalidEntryV3(\n \"signing_key_id must match ^[A-Za-z0-9_./-]{1,128}$\",\n );\n }\n validateV3StringField(\"signing_key_id\", s);\n}\n\nfunction validateV3CommonHeader(\n companyId: string,\n signingKeyId: string,\n timestampMs: bigint | number,\n entryType: EventTypeV3,\n expected: EventTypeV3,\n): void {\n if (companyId === \"\") {\n throw new ErrInvalidEntryV3(\"company_id empty\");\n }\n if (!RE_COMPANY_ID.test(companyId)) {\n throw new ErrInvalidEntryV3(\n \"company_id must match comp_<26-char Crockford-base32 ULID>\",\n );\n }\n validateV3StringField(\"company_id\", companyId);\n if (entryType !== expected) {\n // Privacy Inv 4: do NOT echo the caller-supplied entry_type value.\n throw new ErrInvalidEntryV3(\n \"entry_type does not match expected for this variant\",\n );\n }\n validateV3SigningKeyId(signingKeyId);\n const ts =\n typeof timestampMs === \"bigint\" ? timestampMs : BigInt(timestampMs);\n if (ts <= 0n) {\n // Privacy Inv 4: do NOT echo the value.\n throw new ErrInvalidEntryV3(\"timestamp_ms must be positive\");\n }\n}\n\nfunction validateV3RequestId(s: string): void {\n if (!RE_REQUEST_ID.test(s)) {\n throw new ErrInvalidEntryV3(\n \"request_id must match ULID regex (Crockford-base32, 26 chars)\",\n );\n }\n}\n\nfunction validateV3IntentEntryId(s: string): void {\n if (!RE_INTENT_ENTRY_ID.test(s)) {\n throw new ErrInvalidEntryV3(\"intent_entry_id must match UUIDv7 regex\");\n }\n}\n\nfunction validateV3LegalBasis(s: string): void {\n if (s === \"\") {\n throw new ErrInvalidEntryV3(\"legal_basis empty\");\n }\n if (!RE_LEGAL_BASIS.test(s)) {\n throw new ErrInvalidEntryV3(\n \"legal_basis must match ^[a-z0-9_+]{1,64}$ (spec §6.0 charset)\",\n );\n }\n}\n\nfunction validateV3ManifestRoot(s: string): void {\n if (!RE_SHA512_HEX.test(s)) {\n throw new ErrInvalidEntryV3(\n `manifest_root must be exactly ${V3_SHA512_HEX_LEN} lowercase hex chars (SHA-512)`,\n );\n }\n}\n\nfunction validateV3OptionalDigest(\n name: string,\n d: TenantHMACDigestV3,\n): void {\n if (tenantHMACDigestIsZero(d)) {\n return;\n }\n if (!RE_SHA512_HEX.test(d.hex)) {\n throw new ErrInvalidEntryV3(\n `${name} digest violates shape invariant (constructor regression?)`,\n );\n }\n}\n\nfunction validateV3RequiredDigest(\n name: string,\n d: TenantHMACDigestV3,\n): void {\n if (tenantHMACDigestIsZero(d)) {\n // Phase 3 review HIGH: prior wording said \"rejection without\n // rationale is invalid\" — misleading on the sar_extended path\n // where the same helper is used for `reason_hash` (extension\n // without reason). Generic wording covers both call sites.\n throw new ErrInvalidEntryV3(`${name} required (must be non-zero)`);\n }\n validateV3OptionalDigest(name, d);\n}\n\n/**\n * Validates `pii_digest_key_version` on a SAR entry\n * (pii_hmac_key_rotation_R4). RELAXED invariant — mirror of Go's\n * `validateV3PIIDigestKeyVersionSDK`: charset (empty allowed) + strict\n * UTF-8 string-field checks + the ONLY hard rule\n * `version !== \"\" ⇒ digestPresent`.\n *\n * A non-empty digest with an EMPTY version is a LEGAL pre-rotation legacy\n * leaf, NOT an error — do not reject it (that would break verification of\n * every historical SAR row). This is the deliberate asymmetry vs the\n * STRICT capture-leaf (R3) contract, which rejects both directions of\n * mismatch.\n *\n * Privacy Inv 4: the error does NOT echo the offending version value.\n *\n * @param version - The `piiDigestKeyVersion` field value (\"\" allowed).\n * @param digestPresent - Whether the entry's PII digest is non-zero\n * (`reason_hash` for intent/extended; `rationale_hash` for rejected).\n */\nfunction validateV3PIIDigestKeyVersion(\n version: string,\n digestPresent: boolean,\n): void {\n if (!RE_PII_DIGEST_KEY_VERSION.test(version)) {\n // Privacy Inv 4: do NOT echo the offending value.\n throw new ErrInvalidEntryV3(\n \"pii_digest_key_version must match ^[a-z0-9:_.-]{0,64}$\",\n );\n }\n validateV3StringField(\"pii_digest_key_version\", version);\n if (version !== \"\" && !digestPresent) {\n throw new ErrInvalidEntryV3(\n \"pii_digest_key_version present but no PII digest to apply it to\",\n );\n }\n}\n\n/**\n * Per-kind `certificate_id` matrix (chain_writer_certificate_id mirror):\n * - access → certificate_id MUST be empty\n * - erasure → certificate_id MUST match cert_<32-hex>\n * - both → certificate_id MUST match cert_<32-hex>\n *\n * Mirror of Go's `validateV3SARFulfilledCertificateIDSDK`.\n */\nfunction validateV3SARFulfilledCertificateId(\n kind: SARFulfillmentKindV3,\n certId: string,\n): void {\n switch (kind) {\n case \"access\":\n if (certId !== \"\") {\n throw new ErrInvalidEntryV3(\n \"certificate_id must be empty when fulfillment_kind=access\",\n );\n }\n return;\n case \"erasure\":\n case \"both\":\n if (certId === \"\") {\n throw new ErrInvalidEntryV3(\n `certificate_id is required when fulfillment_kind=${kind}`,\n );\n }\n if (!RE_CERTIFICATE_ID.test(certId)) {\n throw new ErrInvalidEntryV3(\"certificate_id must match cert_<32-hex>\");\n }\n return;\n default: {\n // Defense-in-depth: a future SARFulfillmentKindV3 addition\n // without updating this switch would silently accept any\n // cert_id. The vocabulary check upstream catches this today\n // but pinning here too.\n const _exhaustive: never = kind;\n throw new ErrInvalidEntryV3(\n `unknown fulfillment_kind in certificate_id validator: ${String(_exhaustive)}`,\n );\n }\n }\n}\n\n// =============================================================================\n// Per-entry validators\n// =============================================================================\n\nfunction validateSarIntent(e: SARIntentEntryV3): void {\n validateV3CommonHeader(\n e.companyId,\n e.signingKeyId,\n e.timestampMs,\n e.entryType,\n \"sar_intent\",\n );\n validateV3OptionalDigest(\"reason_hash\", e.reasonHash);\n // R4: relaxed pii_digest_key_version contract — digest is reason_hash.\n validateV3PIIDigestKeyVersion(\n e.piiDigestKeyVersion,\n !tenantHMACDigestIsZero(e.reasonHash),\n );\n validateV3RequestId(e.requestId);\n if (!SAR_TYPE_ALLOWED.has(e.sarType)) {\n throw new ErrInvalidEntryV3(\"sar_type must be access|erasure|both\");\n }\n if (!RE_SCOPE.test(e.scope)) {\n // Privacy Inv 4: do NOT echo the offending caller value.\n throw new ErrInvalidEntryV3(\n \"scope must match ^(all|grant_[A-Za-z0-9_-]{1,64})$\",\n );\n }\n // Phase 3 review LOW: dropped gratuitous `as string` cast — the\n // SARSourceChannelV3 union is already string-typed so direct\n // equality + RE_SOURCE_CHANNEL.test() are fine without bypass.\n if (e.sourceChannel === (\"\" as SARSourceChannelV3)) {\n throw new ErrInvalidEntryV3(\"source_channel empty\");\n }\n if (!RE_SOURCE_CHANNEL.test(e.sourceChannel)) {\n throw new ErrInvalidEntryV3(\n \"source_channel must match ^[a-z0-9_+]{1,64}$ (spec §6.0 charset)\",\n );\n }\n}\n\nfunction validateSarAcknowledged(e: SARAcknowledgedEntryV3): void {\n validateV3CommonHeader(\n e.companyId,\n e.signingKeyId,\n e.timestampMs,\n e.entryType,\n \"sar_acknowledged\",\n );\n validateV3IntentEntryId(e.intentEntryId);\n validateV3RequestId(e.requestId);\n}\n\nfunction validateSarFulfilled(e: SARFulfilledEntryV3): void {\n validateV3CommonHeader(\n e.companyId,\n e.signingKeyId,\n e.timestampMs,\n e.entryType,\n \"sar_fulfilled\",\n );\n if (!SAR_FULFILLMENT_KIND_ALLOWED.has(e.fulfillmentKind)) {\n throw new ErrInvalidEntryV3(\n \"fulfillment_kind must be access|erasure|both\",\n );\n }\n validateV3SARFulfilledCertificateId(e.fulfillmentKind, e.certificateId);\n validateV3IntentEntryId(e.intentEntryId);\n validateV3LegalBasis(e.legalBasis);\n validateV3ManifestRoot(e.manifestRoot);\n validateV3RequestId(e.requestId);\n if (e.tombstoneCount < 0) {\n throw new ErrInvalidEntryV3(\"tombstone_count must be >= 0\");\n }\n}\n\nfunction validateSarRejected(e: SARRejectedEntryV3): void {\n validateV3CommonHeader(\n e.companyId,\n e.signingKeyId,\n e.timestampMs,\n e.entryType,\n \"sar_rejected\",\n );\n validateV3IntentEntryId(e.intentEntryId);\n validateV3LegalBasis(e.legalBasis);\n validateV3RequiredDigest(\"rationale_hash\", e.rationaleHash);\n // R4: relaxed pii_digest_key_version contract — digest is rationale_hash.\n validateV3PIIDigestKeyVersion(\n e.piiDigestKeyVersion,\n !tenantHMACDigestIsZero(e.rationaleHash),\n );\n validateV3RequestId(e.requestId);\n}\n\nfunction validateSarExtended(e: SARExtendedEntryV3): void {\n validateV3CommonHeader(\n e.companyId,\n e.signingKeyId,\n e.timestampMs,\n e.entryType,\n \"sar_extended\",\n );\n validateV3IntentEntryId(e.intentEntryId);\n validateV3RequestId(e.requestId);\n // Phase 3 review H1 follow-up: timestampMs and extendedDueAtMs\n // are `bigint | number`. Mixed-type arithmetic throws TypeError\n // in JS, so normalize both to bigint for the sanity-bound check.\n // Relational mixed comparison (`<= 0`) is permitted by JS for\n // both number AND bigint with a plain `0`, so that check is fine\n // as-is.\n if (e.extendedDueAtMs <= 0) {\n throw new ErrInvalidEntryV3(\"extended_due_at_ms must be > 0\");\n }\n const dueAt =\n typeof e.extendedDueAtMs === \"bigint\"\n ? e.extendedDueAtMs\n : BigInt(e.extendedDueAtMs);\n const ts =\n typeof e.timestampMs === \"bigint\" ? e.timestampMs : BigInt(e.timestampMs);\n if (dueAt > ts + BigInt(EXTENDED_SANITY_BOUND_MS)) {\n throw new ErrInvalidEntryV3(\n \"extended_due_at_ms exceeds 14-month sanity bound from timestamp\",\n );\n }\n validateV3RequiredDigest(\"reason_hash\", e.reasonHash);\n // R4: relaxed pii_digest_key_version contract — digest is reason_hash.\n validateV3PIIDigestKeyVersion(\n e.piiDigestKeyVersion,\n !tenantHMACDigestIsZero(e.reasonHash),\n );\n}\n\n/**\n * Validates a V3 chain entry by dispatching to the per-type\n * validator. Throws `ErrInvalidEntryV3` on any failure. Called\n * automatically by `chainCanonicalV3` before encoding.\n *\n * Exported so customers can validate without encoding.\n */\nexport function validateV3Entry(entry: ChainEntryV3): void {\n if (entry == null) {\n throw new ErrInvalidEntryV3(\"entry is null/undefined\");\n }\n if (!CONCRETE_SAR_ENTRY_TYPE_TAGS.has(entry.entryType)) {\n throw new ErrInvalidEntryV3(\n \"unrecognised entry_type; only the 5 concrete SAR entry types are accepted\",\n );\n }\n switch (entry.entryType) {\n case \"sar_intent\":\n validateSarIntent(entry);\n return;\n case \"sar_acknowledged\":\n validateSarAcknowledged(entry);\n return;\n case \"sar_fulfilled\":\n validateSarFulfilled(entry);\n return;\n case \"sar_rejected\":\n validateSarRejected(entry);\n return;\n case \"sar_extended\":\n validateSarExtended(entry);\n return;\n default: {\n const _exhaustive: never = entry;\n throw new ErrInvalidEntryV3(\n `dispatch: unhandled entry variant ${String((_exhaustive as { entryType?: string }).entryType ?? \"unknown\")}`,\n );\n }\n }\n}\n\n// =============================================================================\n// Encoder helper\n// =============================================================================\n\n/**\n * `V3Encoder` bundles a growing `Uint8Array` buffer. Per-event-type\n * body encoders append fields without explicit error plumbing — the\n * encoder throws synchronously on invariant violations (256-byte\n * cap, negative u64).\n *\n * Mirror of Go's `v3EncoderSDK`.\n *\n * Exported for the explicit purpose of unit-testing the encoder\n * mechanics (NFC normalization, BE encoding, length cap) without\n * routing through the full `chainCanonicalV3` pipeline (which\n * validates regex/vocabulary constraints first). Customers writing\n * normal verification code should call `chainCanonicalV3`.\n */\nexport class V3Encoder {\n private buf: Uint8Array;\n private pos: number;\n // Phase 3 review LOW: cache the DataView so we don't allocate one\n // per appendStr/appendU64 call. The view is invalidated + rebuilt\n // inside `grow()` whenever the underlying buffer is reallocated.\n private view: DataView;\n // Phase 3 review LOW: reuse a single TextEncoder to avoid the\n // per-call allocation in `appendStr`.\n private readonly textEncoder = new TextEncoder();\n // M6 (post-review follow-up 2026-05-29): when true, `appendStr`\n // SKIPS the `s.normalize(\"NFC\")` call on the assumption that the\n // caller (typically the internal `chainCanonicalV3` pipeline) has\n // already run `validateV3Entry`, which calls `s.normalize(\"NFC\")`\n // on every string field. NFC is idempotent so the result is\n // identical byte-for-byte; this saves one `String.normalize` call\n // per field on the hot path. Defaults to `false` so the\n // exported-for-unit-tests surface remains safe.\n private readonly assumeNormalized: boolean;\n\n constructor(initialCapacity = 640, options?: { assumeNormalized?: boolean }) {\n this.buf = new Uint8Array(initialCapacity);\n this.pos = 0;\n this.view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength);\n this.assumeNormalized = options?.assumeNormalized ?? false;\n }\n\n /** Final byte slice (a fresh allocation; safe to share with callers). */\n bytes(): Uint8Array {\n return this.buf.slice(0, this.pos);\n }\n\n private grow(want: number): void {\n if (this.pos + want <= this.buf.length) {\n return;\n }\n let cap = this.buf.length;\n while (this.pos + want > cap) {\n cap *= 2;\n }\n const next = new Uint8Array(cap);\n next.set(this.buf);\n this.buf = next;\n this.view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength);\n }\n\n /**\n * Writes a length-prefixed UTF-8 string with the spec's \"post-NFC,\n * post-UTF-8 byte length\" semantics (pqc_05c v3 §7).\n *\n * Privacy Inv 4: errors do NOT echo the offending field length.\n *\n * # Double-NFC posture (M6, 2026-05-29)\n *\n * When called via `chainCanonicalV3`, `validateV3Entry` has\n * already NFC-normalized this field. NFC is idempotent so the\n * re-normalization here is a no-op semantically, but it does pay\n * one `String.normalize(\"NFC\")` call per field. Construct the\n * encoder with `{ assumeNormalized: true }` to skip the redundant\n * call when the caller has already validated. Defaults to `false`\n * so direct unit-test use of `V3Encoder` remains safe.\n */\n appendStr(s: string): void {\n const nfc = this.assumeNormalized ? s : s.normalize(\"NFC\");\n const utf8 = this.textEncoder.encode(nfc);\n if (utf8.length > MAX_V3_STRING_FIELD_BYTES) {\n throw new ErrInvalidEntryV3(\n `appendStr: field exceeds ${MAX_V3_STRING_FIELD_BYTES} bytes after NFC`,\n );\n }\n this.grow(4 + utf8.length);\n // u32 BE length prefix (cached DataView, rebuilt by grow on realloc)\n this.view.setUint32(this.pos, utf8.length, false);\n this.pos += 4;\n this.buf.set(utf8, this.pos);\n this.pos += utf8.length;\n }\n\n /**\n * Writes a u64 BE non-negative integer. v3 has no signed-int\n * fields; callers attempting to emit negative values indicate a\n * validator bug — the encoder traps it as a distinct invariant\n * violation.\n *\n * Accepts `bigint` or `number`. `number` inputs are checked for\n * `Number.isSafeInteger`; if you have a value above 2^53, pass it\n * as `bigint` (e.g. `BigInt(value)`).\n */\n appendU64(v: bigint | number): void {\n let big: bigint;\n if (typeof v === \"bigint\") {\n big = v;\n } else {\n if (!Number.isFinite(v) || !Number.isInteger(v)) {\n throw new ErrInvalidEntryV3(\n \"appendU64: non-integer number reached encoder (validator bug)\",\n );\n }\n if (!Number.isSafeInteger(v)) {\n throw new ErrInvalidEntryV3(\n \"appendU64: number exceeds Number.MAX_SAFE_INTEGER; pass as bigint\",\n );\n }\n big = BigInt(v);\n }\n if (big < 0n) {\n throw new ErrInvalidEntryV3(\n \"appendU64: encoder invariant violated (negative value reached encoder; validator must have rejected)\",\n );\n }\n if (big > 0xffffffffffffffffn) {\n throw new ErrInvalidEntryV3(\n \"appendU64: value exceeds u64 max\",\n );\n }\n this.grow(8);\n this.view.setBigUint64(this.pos, big, false);\n this.pos += 8;\n }\n\n /**\n * Writes the 4-field common header in alphabetical order:\n * company_id, entry_type, signing_key_id, timestamp_ms.\n */\n appendV3Header(\n companyId: string,\n entryType: string,\n signingKeyId: string,\n timestampMs: bigint | number,\n ): void {\n this.appendStr(companyId);\n this.appendStr(entryType);\n this.appendStr(signingKeyId);\n this.appendU64(timestampMs);\n }\n}\n\n// =============================================================================\n// Per-entry encode functions (mirror of Go's `encodeCanonicalV3` methods)\n// =============================================================================\n\nfunction encodeSARIntentV3(enc: V3Encoder, e: SARIntentEntryV3): void {\n enc.appendV3Header(e.companyId, e.entryType, e.signingKeyId, e.timestampMs);\n // Alphabetical body: pii_digest_key_version (R4, iff non-empty),\n // reason_hash, request_id, sar_type, scope, source_channel.\n // pii_digest_key_version is alphabetical-first; emitted IFF non-empty so a\n // pre-rotation legacy leaf (empty version) hashes byte-identically to its\n // original signing.\n if (e.piiDigestKeyVersion !== \"\") {\n enc.appendStr(e.piiDigestKeyVersion);\n }\n enc.appendStr(e.reasonHash.hex);\n enc.appendStr(e.requestId);\n enc.appendStr(e.sarType);\n enc.appendStr(e.scope);\n enc.appendStr(e.sourceChannel);\n}\n\nfunction encodeSARAcknowledgedV3(\n enc: V3Encoder,\n e: SARAcknowledgedEntryV3,\n): void {\n enc.appendV3Header(e.companyId, e.entryType, e.signingKeyId, e.timestampMs);\n // Alphabetical body: intent_entry_id, request_id\n enc.appendStr(e.intentEntryId);\n enc.appendStr(e.requestId);\n}\n\nfunction encodeSARFulfilledV3(enc: V3Encoder, e: SARFulfilledEntryV3): void {\n enc.appendV3Header(e.companyId, e.entryType, e.signingKeyId, e.timestampMs);\n // Alphabetical body (7 fields):\n // certificate_id, fulfillment_kind, intent_entry_id, legal_basis,\n // manifest_root, request_id, tombstone_count\n enc.appendStr(e.certificateId); // 1 (alphabetical-first; dsar_fulfill_b_pre_02e 2026-05-16)\n enc.appendStr(e.fulfillmentKind); // 2\n enc.appendStr(e.intentEntryId); // 3\n enc.appendStr(e.legalBasis); // 4\n enc.appendStr(e.manifestRoot); // 5\n enc.appendStr(e.requestId); // 6\n enc.appendU64(e.tombstoneCount); // 7\n}\n\nfunction encodeSARRejectedV3(enc: V3Encoder, e: SARRejectedEntryV3): void {\n enc.appendV3Header(e.companyId, e.entryType, e.signingKeyId, e.timestampMs);\n // Alphabetical body: intent_entry_id, legal_basis,\n // pii_digest_key_version (R4, iff non-empty), rationale_hash, request_id\n enc.appendStr(e.intentEntryId);\n enc.appendStr(e.legalBasis);\n if (e.piiDigestKeyVersion !== \"\") {\n enc.appendStr(e.piiDigestKeyVersion);\n }\n enc.appendStr(e.rationaleHash.hex);\n enc.appendStr(e.requestId);\n}\n\nfunction encodeSARExtendedV3(enc: V3Encoder, e: SARExtendedEntryV3): void {\n enc.appendV3Header(e.companyId, e.entryType, e.signingKeyId, e.timestampMs);\n // Alphabetical body: extended_due_at_ms, intent_entry_id,\n // pii_digest_key_version (R4, iff non-empty), reason_hash, request_id\n enc.appendU64(e.extendedDueAtMs);\n enc.appendStr(e.intentEntryId);\n if (e.piiDigestKeyVersion !== \"\") {\n enc.appendStr(e.piiDigestKeyVersion);\n }\n enc.appendStr(e.reasonHash.hex);\n enc.appendStr(e.requestId);\n}\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Encode a typed V3 chain entry to canonical bytes per pqc_05c v3\n * §3 + §4. The single entry-point for cross-language byte-identical\n * encoding.\n *\n * Mirror of Go's `CanonicalBytesV3`.\n *\n * @param entry - A typed v3 chain entry (one of the 5 SAR variants).\n * @returns Canonical TLV bytes.\n * @throws {ErrInvalidEntryV3} On encoder invariant violation.\n */\nexport function chainCanonicalV3(entry: ChainEntryV3): Uint8Array {\n // Validate FIRST (mirror of Go SDK ordering): a malformed entry\n // returning an encoder-side TLV error instead of a typed\n // ErrInvalidEntryV3 would be confusing. `validateV3Entry` covers\n // the null/undefined guard and the entry_type allowlist.\n validateV3Entry(entry);\n // M6 (2026-05-29): validateV3Entry has already NFC-normalized every\n // string field; skip the redundant per-field re-normalization in\n // `appendStr` on this hot path.\n const enc = new V3Encoder(640, { assumeNormalized: true });\n switch (entry.entryType) {\n case \"sar_intent\":\n encodeSARIntentV3(enc, entry);\n break;\n case \"sar_acknowledged\":\n encodeSARAcknowledgedV3(enc, entry);\n break;\n case \"sar_fulfilled\":\n encodeSARFulfilledV3(enc, entry);\n break;\n case \"sar_rejected\":\n encodeSARRejectedV3(enc, entry);\n break;\n case \"sar_extended\":\n encodeSARExtendedV3(enc, entry);\n break;\n default: {\n // Exhaustiveness check — adding a new variant without a case\n // becomes a compile error.\n const _exhaustive: never = entry;\n throw new ErrInvalidEntryV3(\n `dispatch: unhandled entry variant ${String((_exhaustive as { entryType?: string }).entryType ?? \"unknown\")}`,\n );\n }\n }\n return enc.bytes();\n}\n\n/**\n * Compute the V3 content hash: SHA-512(DOMAIN_PREFIX_V3_BYTES || canonical).\n *\n * Mirror of Go's `ContentHashV3` (which returns hex). This JS version\n * returns the raw 64-byte digest; hex encoding is the caller's job\n * via `bytesToHex` (caller-side utility).\n *\n * Uses `crypto.subtle.digest(\"SHA-512\", ...)` from the Web Crypto API,\n * which is available in Node ≥16 (via `globalThis.crypto`) and all\n * modern browsers.\n *\n * @param canonical - Canonical bytes from `chainCanonicalV3`.\n * @returns The 64-byte SHA-512 digest.\n */\nexport async function computeV3ContentHash(\n canonical: Uint8Array,\n): Promise<Uint8Array> {\n const preimage = new Uint8Array(\n DOMAIN_PREFIX_V3_BYTES.length + canonical.length,\n );\n preimage.set(DOMAIN_PREFIX_V3_BYTES, 0);\n preimage.set(canonical, DOMAIN_PREFIX_V3_BYTES.length);\n const digest = await crypto.subtle.digest(\"SHA-512\", preimage);\n return new Uint8Array(digest);\n}\n\n/**\n * Convenience: encode + hash in one call. Mirror of Go's\n * `EncodeAndHashV3`.\n */\nexport async function encodeAndHashV3(\n entry: ChainEntryV3,\n): Promise<{ canonical: Uint8Array; contentHash: Uint8Array }> {\n const canonical = chainCanonicalV3(entry);\n const contentHash = await computeV3ContentHash(canonical);\n return { canonical, contentHash };\n}\n\n/**\n * Lowercase hex encoder for digests. Mirror of Go's\n * `hex.EncodeToString`. Useful for cross-language hash comparison\n * tests (golden vectors carry hex strings).\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n // Phase 3 review LOW: array-join instead of per-byte string\n // concatenation. Negligible for 64-byte SHA-512 digests but\n // idiomatic and protects future callers that hand larger inputs.\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The streaming bundle reader: one pass over the bytes that checks §3's\n * grammar, §5's limits and §4's structure as it goes, and builds only what a\n * readable bundle needs (bundle-format revision 3.2).\n *\n * Why not parse a tree first: a tree of tiny values costs far more memory than\n * the bytes that encode them (16 MiB of `{}` is about a gigabyte of objects).\n * This reader knows each value's §4 position as it begins, so it can:\n *\n * - count every JSON value as it begins (§5's value limit, §9.1 position 3).\n * Past it, it keeps neither values nor member names, and only checks the rest\n * of the input against §3 (position 2 can still apply);\n * - detect a structure violation at once: an unknown member or a wrong type\n * when the value begins, missing members when an object closes, an empty\n * `entries` when it closes. After the first one it builds nothing, but keeps\n * tracking member names (duplicate-key outranks structure) and the top-level\n * `format` value (format outranks it too);\n * - count chains, entries and checkpoints as they stream, and stop building\n * past a count limit (structure still outranks it).\n *\n * Once the outcome is unreadable, nothing more is built and what was built is\n * dropped, so memory on hostile input stays below that of the largest\n * readable bundle. The §9.1 reason is chosen only after the whole input has\n * been scanned, so a grammar error anywhere outranks everything but the size.\n *\n * NO-LEAK RULE (§10): the outcome is a reason code, never a value or position.\n * Browser-safe.\n */\n\nimport type { ProofBundleLimits, ProofBundleUnreadableReason } from \"./proofBundle.js\";\nimport { runStrict, StrictJsonScanner } from \"./strictJson.js\";\n\n/** The bundle format string (§4.1). */\nexport const BUNDLE_FORMAT_V1 = \"aleutian.proof.bundle.v1\";\n\n/** The v2 bundle format string (§16): chain format v4, v7 checkpoints, record.v2. */\nexport const BUNDLE_FORMAT_V2 = \"aleutian.proof.bundle.v2\";\n\n/** Which bundle format a readable bundle declared. */\nexport type BundleFormatVersion = 1 | 2;\n\n/** Nesting depth limit (§3, §5). */\nexport const BUNDLE_MAX_DEPTH = 8;\n\n/** One entry, as §4.3 requires it (shapes are judged later, §7.1). */\nexport interface BundleEntry {\n readonly entryId: string;\n readonly entryType: string;\n readonly globalSeq: string;\n readonly previousHash: string;\n readonly timestamp: string;\n readonly contentHash: string;\n readonly chainHash: string;\n /** v2 only (§16 §4.3): 64 lowercase hex, judged in §7.1. */\n readonly salt?: string;\n /** v2 only (§16 §4.3): 128 lowercase hex, judged in §7.1. */\n readonly leafHash?: string;\n readonly recordSignature?: { readonly keyId: string; readonly signature: string };\n readonly disclosed?: { readonly content: string; readonly nonce: string };\n}\n\n/** One chain, as §4.2 requires it. */\nexport interface BundleChain {\n readonly chainId: string;\n readonly entries: BundleEntry[];\n readonly checkpoints: string[];\n}\n\n/** The outcome of {@link readProofBundle}. */\nexport type BundleReadOutcome =\n | { readonly ok: true; readonly format: BundleFormatVersion; readonly chains: BundleChain[] }\n | { readonly ok: false; readonly reason: ProofBundleUnreadableReason };\n\nconst LBRACE = 0x7b;\nconst RBRACE = 0x7d;\nconst LBRACKET = 0x5b;\nconst RBRACKET = 0x5d;\nconst QUOTE = 0x22;\nconst COMMA = 0x2c;\nconst COLON = 0x3a;\n\n/** §4.3's required entry members, in BundleEntry order; bit i is member i. */\nconst ENTRY_MEMBERS = [\n \"entry_id\",\n \"entry_type\",\n \"global_seq\",\n \"previous_hash\",\n \"timestamp\",\n \"content_hash\",\n \"chain_hash\",\n] as const;\nconst ENTRY_INDEX = new Map<string, number>(ENTRY_MEMBERS.map((name, i) => [name, i]));\nconst ENTRY_ALL = (1 << ENTRY_MEMBERS.length) - 1;\n\n/**\n * The longest raw text a format string can have: every character as a\n * six-byte `\\u` escape, plus the quotes. Anything longer is neither, unread.\n */\nconst FORMAT_MAX_RAW = 6 * Math.max(BUNDLE_FORMAT_V1.length, BUNDLE_FORMAT_V2.length) + 2;\n\nclass BundleReader extends StrictJsonScanner {\n private values = 0;\n private valueLimitHit = false;\n private duplicateKey = false;\n private topIsObject = false;\n private formatOk = false;\n private formatVersion: BundleFormatVersion = 1;\n /**\n * Whether an entry carried a v2-only member (`salt`, `leaf_hash`), and\n * whether one lacked either. Members may come in any order, `format` last,\n * so which of the two is a structure violation is decided at the end.\n */\n private sawV2Member = false;\n private missedV2Member = false;\n private structureBad = false;\n private countExceeded = false;\n private chainCount = 0;\n private entryCount = 0;\n private checkpointCount = 0;\n /** False once the outcome cannot be readable: nothing more is built. */\n private building = true;\n\n private readonly anyMember = (_name: string, depth: number): void => this.any(depth);\n private readonly anyElement = (depth: number): void => this.any(depth);\n\n constructor(\n bytes: Uint8Array,\n private readonly limits: ProofBundleLimits\n ) {\n super(bytes, BUNDLE_MAX_DEPTH);\n }\n\n /** Scan the whole document; the chains, while still building. */\n document(): BundleChain[] | undefined {\n this.skipWhitespace();\n const chains = this.root();\n this.expectEnd();\n return chains;\n }\n\n /** The lowest-numbered §9.1 reason after positions 1 and 2, or the chains. */\n outcome(chains: BundleChain[] | undefined): BundleReadOutcome {\n // §5 / §16 §5: the value limit is the declared format's (v2 entries have\n // two more values). A bundle declaring neither format is held to v1's.\n const v2 = this.formatOk && this.formatVersion === 2;\n if (this.valueLimitHit || this.values > (v2 ? this.v2ValueLimit : this.limits.values)) {\n return { ok: false, reason: \"too-large\" };\n }\n if (this.duplicateKey) return { ok: false, reason: \"duplicate-key\" };\n if (this.topIsObject && !this.formatOk) return { ok: false, reason: \"format\" };\n if (this.structureBad) return { ok: false, reason: \"structure\" };\n // §4.3 / §16 §4.3: a v1 entry has no salt or leaf_hash; a v2 entry has both.\n if (v2 ? this.missedV2Member : this.sawV2Member) return { ok: false, reason: \"structure\" };\n if (this.countExceeded || chains === undefined)\n return { ok: false, reason: \"too-large\" };\n return { ok: true, format: this.formatVersion, chains };\n }\n\n /** §16 §5's value limit (17,000,000); v1's when none is given. */\n private get v2ValueLimit(): number {\n return this.limits.valuesV2 ?? this.limits.values;\n }\n\n /**\n * Past this many values no outcome can be readable under either format, so\n * nothing more is built or kept (the format may come last).\n */\n private get valueCutoff(): number {\n return Math.max(this.limits.values, this.v2ValueLimit);\n }\n\n /** Whether §4 is still being checked: no structure violation, under the value limit. */\n private get checking(): boolean {\n return !this.structureBad && !this.valueLimitHit;\n }\n\n private violate(): void {\n this.structureBad = true;\n this.building = false;\n }\n\n /** A value begins: count it (§5). Past the higher of the two formats' limits, stop building. */\n private begin(): void {\n this.values++;\n if (!this.valueLimitHit && this.values > this.valueCutoff) {\n this.valueLimitHit = true;\n this.building = false;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Grammar only\n // ---------------------------------------------------------------------------\n\n /** Any value, checked against §3 only (its names still tracked). */\n private any(depth: number): void {\n this.begin();\n this.skipBody(depth);\n }\n\n /** The value at the cursor, already counted, checked against §3 only. */\n private skipBody(depth: number): void {\n const c = this.peek();\n if (c === LBRACE) this.object(depth, this.anyMember);\n else if (c === LBRACKET) this.array(depth, this.anyElement);\n else if (c === QUOTE) this.skipString();\n else if (c === 0x74) this.literal(\"true\");\n else if (c === 0x66) this.literal(\"false\");\n else if (c === 0x6e) this.literal(\"null\");\n else this.skipNumber();\n }\n\n /**\n * An object: grammar, depth and duplicate names (until the value limit).\n * `member` reads each first-seen member's value; a repeated name's value is\n * only scanned, since the outcome is already duplicate-key or worse.\n */\n private object(depth: number, member: (name: string, depth: number) => void): void {\n if (depth > this.maxDepth) this.fail();\n this.pos++; // {\n this.skipWhitespace();\n if (this.peek() === RBRACE) {\n this.pos++;\n return;\n }\n let names: Set<string> | undefined;\n for (;;) {\n this.skipWhitespace();\n if (this.peek() !== QUOTE) this.fail();\n if (this.valueLimitHit) {\n // Past the value limit only §3 can still matter: no names kept.\n names = undefined;\n this.skipString();\n this.colon();\n this.any(depth + 1);\n } else {\n const name = this.readString();\n names ??= new Set<string>();\n const fresh = !names.has(name);\n if (fresh) {\n names.add(name);\n } else {\n this.duplicateKey = true;\n this.building = false;\n }\n this.colon();\n if (fresh) member(name, depth + 1);\n else this.any(depth + 1);\n }\n this.skipWhitespace();\n const c = this.peek();\n if (c === COMMA) {\n this.pos++;\n continue;\n }\n if (c === RBRACE) {\n this.pos++;\n return;\n }\n this.fail();\n }\n }\n\n /** The colon after a member name, with the whitespace around it. */\n private colon(): void {\n this.skipWhitespace();\n this.expect(COLON);\n this.skipWhitespace();\n }\n\n /** An array: grammar and depth; `element` reads each element. Returns the length. */\n private array(depth: number, element: (depth: number) => void): number {\n if (depth > this.maxDepth) this.fail();\n this.pos++; // [\n this.skipWhitespace();\n if (this.peek() === RBRACKET) {\n this.pos++;\n return 0;\n }\n let n = 0;\n for (;;) {\n this.skipWhitespace();\n element(depth + 1);\n n++;\n this.skipWhitespace();\n const c = this.peek();\n if (c === COMMA) {\n this.pos++;\n continue;\n }\n if (c === RBRACKET) {\n this.pos++;\n return n;\n }\n this.fail();\n }\n }\n\n // ---------------------------------------------------------------------------\n // §4 positions. Each begins by counting its value; when §4 is no longer\n // checked, it only scans. A wrong JSON type is a structure violation.\n // ---------------------------------------------------------------------------\n\n /** Scan a value of the wrong type for its position. */\n private wrongType(depth: number): void {\n this.violate();\n this.skipBody(depth);\n }\n\n /** §4.1: the top-level object. */\n private root(): BundleChain[] | undefined {\n this.begin();\n if (this.peek() !== LBRACE) {\n this.wrongType(1);\n return undefined;\n }\n this.topIsObject = true;\n let chains: BundleChain[] | undefined;\n let hasChains = false;\n this.object(1, (name, depth) => {\n if (name === \"format\") this.format(depth);\n else if (!this.checking) this.any(depth);\n else if (name === \"chains\") {\n hasChains = true;\n chains = this.chains(depth);\n } else {\n this.violate();\n this.any(depth);\n }\n });\n if (this.checking && !hasChains) this.violate();\n return this.building ? chains : undefined;\n }\n\n /** `format`: judged even after a structure violation (position 5 outranks 6). */\n private format(depth: number): void {\n this.begin();\n if (this.valueLimitHit || this.peek() !== QUOTE) {\n this.building = false;\n this.skipBody(depth);\n return;\n }\n const start = this.pos;\n this.skipString();\n if (this.pos - start <= FORMAT_MAX_RAW) {\n this.pos = start;\n const format = this.readString();\n if (format === BUNDLE_FORMAT_V1) {\n this.formatOk = true;\n this.formatVersion = 1;\n } else if (format === BUNDLE_FORMAT_V2) {\n this.formatOk = true;\n this.formatVersion = 2;\n }\n }\n if (!this.formatOk) this.building = false;\n }\n\n /** A string member or checkpoint text; undefined unless building. */\n private str(depth: number): string | undefined {\n this.begin();\n if (!this.checking) {\n this.skipBody(depth);\n return undefined;\n }\n if (this.peek() !== QUOTE) {\n this.wrongType(depth);\n return undefined;\n }\n if (!this.building) {\n this.skipString();\n return undefined;\n }\n return this.readString();\n }\n\n /** §4.1 `chains`. */\n private chains(depth: number): BundleChain[] | undefined {\n this.begin();\n if (!this.checking) {\n this.skipBody(depth);\n return undefined;\n }\n if (this.peek() !== LBRACKET) {\n this.wrongType(depth);\n return undefined;\n }\n let out: BundleChain[] | undefined = this.building ? [] : undefined;\n this.array(depth, (d) => {\n if (!this.checking) return this.any(d);\n if (++this.chainCount > this.limits.chains) this.overCount();\n const chain = this.chain(d);\n if (this.building && out !== undefined && chain !== undefined) out.push(chain);\n else out = undefined;\n });\n return this.building ? out : undefined;\n }\n\n private overCount(): void {\n this.countExceeded = true;\n this.building = false;\n }\n\n /** §4.2 a chain. */\n private chain(depth: number): BundleChain | undefined {\n this.begin();\n if (!this.checking) {\n this.skipBody(depth);\n return undefined;\n }\n if (this.peek() !== LBRACE) {\n this.wrongType(depth);\n return undefined;\n }\n let chainId: string | undefined;\n let entries: BundleEntry[] | undefined;\n let checkpoints: string[] | undefined;\n let seen = 0;\n this.object(depth, (name, d) => {\n if (!this.checking) return this.any(d);\n if (name === \"chain_id\") {\n seen |= 1;\n chainId = this.str(d);\n } else if (name === \"entries\") {\n seen |= 2;\n entries = this.entries(d);\n } else if (name === \"checkpoints\") {\n seen |= 4;\n checkpoints = this.checkpoints(d);\n } else {\n this.violate();\n this.any(d);\n }\n });\n if (this.checking && seen !== 7) this.violate();\n if (\n !this.building ||\n chainId === undefined ||\n entries === undefined ||\n checkpoints === undefined\n ) {\n return undefined;\n }\n return { chainId, entries, checkpoints };\n }\n\n /** §4.2 `entries`: not empty. */\n private entries(depth: number): BundleEntry[] | undefined {\n this.begin();\n if (!this.checking) {\n this.skipBody(depth);\n return undefined;\n }\n if (this.peek() !== LBRACKET) {\n this.wrongType(depth);\n return undefined;\n }\n let out: BundleEntry[] | undefined = this.building ? [] : undefined;\n const n = this.array(depth, (d) => {\n if (!this.checking) return this.any(d);\n if (++this.entryCount > this.limits.entries) this.overCount();\n const entry = this.entry(d);\n if (this.building && out !== undefined && entry !== undefined) out.push(entry);\n else out = undefined;\n });\n if (this.checking && n === 0) this.violate();\n return this.building ? out : undefined;\n }\n\n /** §4.2 `checkpoints`: strings. */\n private checkpoints(depth: number): string[] | undefined {\n this.begin();\n if (!this.checking) {\n this.skipBody(depth);\n return undefined;\n }\n if (this.peek() !== LBRACKET) {\n this.wrongType(depth);\n return undefined;\n }\n let out: string[] | undefined = this.building ? [] : undefined;\n this.array(depth, (d) => {\n if (!this.checking) return this.any(d);\n if (++this.checkpointCount > this.limits.checkpoints) this.overCount();\n const text = this.str(d);\n if (this.building && out !== undefined && text !== undefined) out.push(text);\n else out = undefined;\n });\n return this.building ? out : undefined;\n }\n\n /** §4.3 an entry. */\n private entry(depth: number): BundleEntry | undefined {\n this.begin();\n if (!this.checking) {\n this.skipBody(depth);\n return undefined;\n }\n if (this.peek() !== LBRACE) {\n this.wrongType(depth);\n return undefined;\n }\n const fields: (string | undefined)[] = [];\n let seen = 0;\n let recordSignature: BundleEntry[\"recordSignature\"];\n let disclosed: BundleEntry[\"disclosed\"];\n let salt: string | undefined;\n let leafHash: string | undefined;\n let v2Seen = 0;\n this.object(depth, (name, d) => {\n if (!this.checking) return this.any(d);\n const i = ENTRY_INDEX.get(name);\n if (i !== undefined) {\n seen |= 1 << i;\n fields[i] = this.str(d);\n } else if (name === \"salt\") {\n v2Seen |= 1;\n salt = this.str(d);\n } else if (name === \"leaf_hash\") {\n v2Seen |= 2;\n leafHash = this.str(d);\n } else if (name === \"record_signature\") {\n const p = this.pair(d, \"key_id\", \"signature\");\n if (p !== undefined) recordSignature = { keyId: p[0], signature: p[1] };\n } else if (name === \"disclosed\") {\n const p = this.pair(d, \"content\", \"nonce\");\n if (p !== undefined) disclosed = { content: p[0], nonce: p[1] };\n } else {\n this.violate();\n this.any(d);\n }\n });\n if (this.checking && seen !== ENTRY_ALL) this.violate();\n if (v2Seen !== 0) this.sawV2Member = true;\n if (v2Seen !== 3) this.missedV2Member = true;\n if (!this.building) return undefined;\n const [\n entryId,\n entryType,\n globalSeq,\n previousHash,\n timestamp,\n contentHash,\n chainHash,\n ] = fields as [string, string, string, string, string, string, string];\n return {\n entryId,\n entryType,\n globalSeq,\n previousHash,\n timestamp,\n contentHash,\n chainHash,\n ...(salt === undefined ? {} : { salt }),\n ...(leafHash === undefined ? {} : { leafHash }),\n recordSignature,\n disclosed,\n };\n }\n\n /** `record_signature` or `disclosed`: exactly its two string members (§4.3). */\n private pair(depth: number, a: string, b: string): [string, string] | undefined {\n this.begin();\n if (!this.checking) {\n this.skipBody(depth);\n return undefined;\n }\n if (this.peek() !== LBRACE) {\n this.wrongType(depth);\n return undefined;\n }\n let x: string | undefined;\n let y: string | undefined;\n let seen = 0;\n this.object(depth, (name, d) => {\n if (!this.checking) return this.any(d);\n if (name === a) {\n seen |= 1;\n x = this.str(d);\n } else if (name === b) {\n seen |= 2;\n y = this.str(d);\n } else {\n this.violate();\n this.any(d);\n }\n });\n if (this.checking && seen !== 3) this.violate();\n return this.building && x !== undefined && y !== undefined ? [x, y] : undefined;\n }\n}\n\n/**\n * Read a bundle under bundle-format §3–§5 and §9.1.\n *\n * # Description\n *\n * Scans the bundle once. Returns its chains when it is readable, or the\n * lowest-numbered §9.1 reason that applies (format `aleutian.proof.bundle.v1`\n * or `.v2`, §16): 1 too-large (size), 2 json,\n * 3 too-large (values), 4 duplicate-key, 5 format, 6 structure, 7 too-large\n * (counts). Every reason is determined over the whole input before one is\n * chosen.\n *\n * # Inputs\n *\n * - bytes: the bundle file's exact bytes\n * - limits: the §5 limits (tests may lower them)\n *\n * # Outputs\n *\n * - BundleReadOutcome: never throws on any input\n *\n * # Example\n *\n * const read = readProofBundle(bytes, PROOF_BUNDLE_LIMITS);\n * if (!read.ok) return read.reason;\n *\n * # Limitations\n *\n * - Holds the input and the built chains in memory; building stops as soon\n * as the outcome cannot be readable.\n *\n * # Assumptions\n *\n * - None.\n */\nexport function readProofBundle(\n bytes: Uint8Array,\n limits: ProofBundleLimits\n): BundleReadOutcome {\n if (bytes.length > limits.bundleBytes) return { ok: false, reason: \"too-large\" };\n const reader = new BundleReader(bytes, limits);\n const scanned = runStrict(() => reader.document());\n if (!scanned.ok) return { ok: false, reason: \"json\" };\n return reader.outcome(scanned.value);\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Salted commitments (format-spec §8).\n *\n * ```\n * commitment = SHA-512( \"aleutian.commit.v1:\" ‖ nonce ‖ SHA-512(content) )\n * ```\n *\n * The nonce is exactly 32 bytes; any other length is refused, never hashed.\n * The content is hashed first, so the outer input is always 115 bytes. The\n * result is 128 lowercase hex and compares exactly: an uppercase commitment\n * does not match.\n *\n * Vectors: `testdata/commitment_vectors.json` (computed independently, in\n * Python, from the spec). Browser-safe: WebCrypto only.\n */\n\nimport { sha512HexRaw } from \"./hash.js\";\n\n/** The commitment domain string (format-spec §8). */\nexport const COMMITMENT_DOMAIN = \"aleutian.commit.v1:\";\n\n/** The only nonce length a commitment accepts, in bytes. */\nexport const COMMITMENT_NONCE_SIZE = 32;\n\nconst DOMAIN_BYTES = new TextEncoder().encode(COMMITMENT_DOMAIN);\n\n/**\n * Compute a salted commitment.\n *\n * # Description\n *\n * Returns `hex(SHA-512(\"aleutian.commit.v1:\" ‖ nonce ‖ SHA-512(content)))`.\n *\n * # Inputs\n *\n * - nonce: exactly 32 bytes\n * - content: the committed bytes, any length\n *\n * # Outputs\n *\n * - string: 128 lowercase hex characters\n * - Error: thrown when the nonce is not exactly 32 bytes\n *\n * # Example\n *\n * const c = await computeCommitment(nonce, new TextEncoder().encode(\"consent: yes\"));\n *\n * # Limitations\n *\n * - Imposes no content size limit; a caller that has one enforces it.\n *\n * # Assumptions\n *\n * - WebCrypto (`crypto.subtle`) is available.\n */\nexport async function computeCommitment(\n nonce: Uint8Array,\n content: Uint8Array\n): Promise<string> {\n if (nonce.length !== COMMITMENT_NONCE_SIZE) {\n throw new Error(`a commitment nonce is exactly ${COMMITMENT_NONCE_SIZE} bytes`);\n }\n const inner = new Uint8Array(await crypto.subtle.digest(\"SHA-512\", content));\n const outer = new Uint8Array(DOMAIN_BYTES.length + nonce.length + inner.length);\n outer.set(DOMAIN_BYTES, 0);\n outer.set(nonce, DOMAIN_BYTES.length);\n outer.set(inner, DOMAIN_BYTES.length + nonce.length);\n return sha512HexRaw(outer);\n}\n\n/**\n * Check whether a nonce and content open a commitment.\n *\n * # Description\n *\n * True exactly when the nonce is 32 bytes and the recomputed commitment equals\n * `commitment` character for character. A nonce of any other length is a\n * refusal (false), not an error.\n *\n * # Inputs\n *\n * - nonce: the disclosed nonce\n * - content: the disclosed content\n * - commitment: the expected commitment (an entry's `content_hash`)\n *\n * # Outputs\n *\n * - boolean: whether the commitment opens\n *\n * # Example\n *\n * if (!(await openCommitment(nonce, content, entry.content_hash))) { ... }\n *\n * # Limitations\n *\n * - Not constant-time; commitments and disclosures are public values.\n *\n * # Assumptions\n *\n * - WebCrypto (`crypto.subtle`) is available.\n */\nexport async function openCommitment(\n nonce: Uint8Array,\n content: Uint8Array,\n commitment: string\n): Promise<boolean> {\n if (nonce.length !== COMMITMENT_NONCE_SIZE) return false;\n return (await computeCommitment(nonce, content)) === commitment;\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Synchronous SHA-512 hashes for the proof bundle verifier.\n *\n * The SDK's general primitives (`computeChainHashV3`, `computeAnchorChainHash`,\n * `openCommitment`) use WebCrypto, which is always async. The bundle verifier\n * hashes several times per entry over up to a million entries, and awaiting\n * WebCrypto each time dominates its run time. These are the same preimages,\n * hashed with `@noble/hashes`' synchronous SHA-512, and used only by the\n * bundle verifier. They take inputs already checked for shape (§7.1), so they\n * validate nothing; the domain strings are imported from the general\n * primitives so the two cannot drift.\n *\n * Browser-safe.\n */\n\nimport { sha512 } from \"@noble/hashes/sha2.js\";\nimport { bytesToHex, utf8ToBytes } from \"@noble/hashes/utils.js\";\n\nimport { ANCHOR_CHAIN_DOMAIN_V2 } from \"./anchorChainHash.js\";\nimport { CHAIN_HASH_PREFIX_V3 } from \"./chain.js\";\nimport { COMMITMENT_DOMAIN, COMMITMENT_NONCE_SIZE } from \"./commitment.js\";\n\nconst COMMITMENT_DOMAIN_BYTES = utf8ToBytes(COMMITMENT_DOMAIN);\n\n/**\n * SHA-512 of a string's UTF-8 bytes, as 128 lowercase hex.\n *\n * # Description\n *\n * Synchronous counterpart of `sha512Hex` (`hash.ts`).\n *\n * # Inputs\n *\n * - text: the string to hash (UTF-8 encoded)\n *\n * # Outputs\n *\n * - string: 128 lowercase hex characters\n *\n * # Example\n *\n * const h = sha512HexSync(\"aleutian.sink.erasure.v1:\" + record);\n *\n * # Limitations\n *\n * - Holds the whole input in memory.\n *\n * # Assumptions\n *\n * - None.\n */\nexport function sha512HexSync(text: string): string {\n return bytesToHex(sha512(utf8ToBytes(text)));\n}\n\n/**\n * The v3 chain hash (format-spec §2.1), synchronously.\n *\n * # Description\n *\n * `SHA-512(\"aleutian.chain.v3:\" ‖ previous ‖ \"|\" ‖ globalSeq ‖ \"|\" ‖ timestamp\n * ‖ \"|\" ‖ contentHash)`, the preimage `computeChainHashV3` hashes.\n *\n * # Inputs\n *\n * - previousHash: empty, or 128 lowercase hex\n * - globalSeq: the stored base-10 sequence (no sign or leading zeros)\n * - timestamp: `YYYY-MM-DDTHH:MM:SS.ffffffZ`\n * - contentHash: 128 lowercase hex\n *\n * # Outputs\n *\n * - string: 128 lowercase hex characters\n *\n * # Example\n *\n * if (chainHashV3Sync(e.previousHash, e.globalSeq, e.timestamp, e.contentHash) !== e.chainHash) ...\n *\n * # Limitations\n *\n * - Validates nothing: a malformed field would shift a \"|\" boundary.\n *\n * # Assumptions\n *\n * - Every field is already in its §4.3 shape (the caller checked §7.1).\n */\nexport function chainHashV3Sync(\n previousHash: string,\n globalSeq: string,\n timestamp: string,\n contentHash: string\n): string {\n return sha512HexSync(\n CHAIN_HASH_PREFIX_V3 +\n previousHash +\n \"|\" +\n globalSeq +\n \"|\" +\n timestamp +\n \"|\" +\n contentHash\n );\n}\n\n/**\n * The anchor-of-anchors chain hash, synchronously.\n *\n * # Description\n *\n * `SHA-512(\"aleutian.anchor.v2:\" ‖ previousAnchorHash ‖ \"|\" ‖ subject ‖ \"|\" ‖\n * startEntryId ‖ \"|\" ‖ endEntryId ‖ \"|\" ‖ tipChainHash)`, the preimage\n * `computeAnchorChainHash` hashes.\n *\n * # Inputs\n *\n * - previousAnchorHash: the previous checkpoint's chain hash, or the seed\n * - subject: the chain id\n * - startEntryId, endEntryId: the range\n * - tipChainHash: the chain hash of the range's last entry\n *\n * # Outputs\n *\n * - string: 128 lowercase hex characters\n *\n * # Example\n *\n * const h = anchorChainHashSync(SEED_ANCHOR_HASH, chainId, first, last, tip);\n *\n * # Limitations\n *\n * - Validates nothing.\n *\n * # Assumptions\n *\n * - The inputs hold no \"|\" (sink ids and hex never do).\n */\nexport function anchorChainHashSync(\n previousAnchorHash: string,\n subject: string,\n startEntryId: string,\n endEntryId: string,\n tipChainHash: string\n): string {\n return sha512HexSync(\n ANCHOR_CHAIN_DOMAIN_V2 +\n previousAnchorHash +\n \"|\" +\n subject +\n \"|\" +\n startEntryId +\n \"|\" +\n endEntryId +\n \"|\" +\n tipChainHash\n );\n}\n\n/**\n * Whether a nonce and content open a salted commitment (format-spec §8),\n * synchronously.\n *\n * # Description\n *\n * True exactly when the nonce is 32 bytes and\n * `hex(SHA-512(\"aleutian.commit.v1:\" ‖ nonce ‖ SHA-512(content)))` equals\n * `commitment`, as `openCommitment` decides.\n *\n * # Inputs\n *\n * - nonce: the disclosed nonce\n * - content: the disclosed content\n * - commitment: the entry's `content_hash`\n *\n * # Outputs\n *\n * - boolean: whether the commitment opens\n *\n * # Example\n *\n * if (!openCommitmentSync(nonce, content, e.contentHash)) problems.add(\"modified\", i);\n *\n * # Limitations\n *\n * - Not constant-time; commitments and disclosures are public values.\n *\n * # Assumptions\n *\n * - None.\n */\nexport function openCommitmentSync(\n nonce: Uint8Array,\n content: Uint8Array,\n commitment: string\n): boolean {\n if (nonce.length !== COMMITMENT_NONCE_SIZE) return false;\n const inner = sha512(content);\n const outer = new Uint8Array(\n COMMITMENT_DOMAIN_BYTES.length + nonce.length + inner.length\n );\n outer.set(COMMITMENT_DOMAIN_BYTES, 0);\n outer.set(nonce, COMMITMENT_DOMAIN_BYTES.length);\n outer.set(inner, COMMITMENT_DOMAIN_BYTES.length + nonce.length);\n return bytesToHex(sha512(outer)) === commitment;\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Value shapes of proof's sink format (sink-format §1, format-spec §2.1, §4).\n *\n * Shared by the record envelope (sink-format §9.1) and the bundle verifier\n * (bundle-format §4.3), which hold the same values to the same shapes.\n *\n * Every pattern is anchored at both ends. JavaScript's `$` (without the `m`\n * flag) matches only at the end of input, never before a trailing newline, and\n * `[0-9]` is ASCII only. Browser-safe.\n */\n\n/** A sink chain id: `<class>.<32 lowercase hex>` (sink-format §1). */\nexport const SINK_CHAIN_ID = /^[a-z0-9][a-z0-9_-]{0,30}\\.[0-9a-f]{32}$/;\n\n/** A sink entry id: `sink-` and 32 lowercase hex (sink-format §1). */\nexport const SINK_ENTRY_ID = /^sink-[0-9a-f]{32}$/;\n\n/** A SHA-512 digest as hex: exactly 128 lowercase hex characters. */\nexport const HEX_128 = /^[0-9a-f]{128}$/;\n\n/** A 32-byte value as hex (a nonce): exactly 64 lowercase hex characters. */\nexport const HEX_64 = /^[0-9a-f]{64}$/;\n\n/** A key id (format-spec §9.6): exactly 32 lowercase hex characters. */\nexport const HEX_32 = /^[0-9a-f]{32}$/;\n\nconst DECIMAL = /^(0|[1-9][0-9]*)$/;\nconst MAX_GLOBAL_SEQ = 2n ** 63n - 1n;\nconst TIMESTAMP =\n /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})\\.[0-9]{6}Z$/;\n\n/**\n * Whether a string is a `global_seq`: base-10, no sign, no leading zeros,\n * 0 ≤ n ≤ 2⁶³−1 (format-spec §2.1). Compared as a BigInt, never a Number.\n */\nexport function isGlobalSeq(s: string): boolean {\n if (!DECIMAL.test(s)) return false;\n // 2^63-1 has 19 digits: a longer string is out of range without parsing it.\n return s.length <= 19 && BigInt(s) <= MAX_GLOBAL_SEQ;\n}\n\nfunction daysInMonth(year: number, month: number): number {\n if (month === 2) {\n const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);\n return leap ? 29 : 28;\n }\n return month === 4 || month === 6 || month === 9 || month === 11 ? 30 : 31;\n}\n\n/**\n * Whether a string is a sink timestamp: exactly `YYYY-MM-DDTHH:MM:SS.ffffffZ`\n * (format-spec §4) AND a real UTC instant: year 0001–9999, a valid month and\n * day (leap years included), hour ≤ 23, minute ≤ 59, second ≤ 59\n * (bundle-format §4.3, sink-format §9.1).\n */\nexport function isSinkTimestamp(s: string): boolean {\n const m = TIMESTAMP.exec(s);\n if (!m) return false;\n const year = Number(m[1]);\n const month = Number(m[2]);\n const day = Number(m[3]);\n const hour = Number(m[4]);\n const minute = Number(m[5]);\n const second = Number(m[6]);\n if (year < 1 || month < 1 || month > 12) return false;\n if (day < 1 || day > daysInMonth(year, month)) return false;\n return hour <= 23 && minute <= 59 && second <= 59;\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The record-signature envelopes `aleutian.proof.record.v1` and `.v2`\n * (sink-format §9.1), and their ML-DSA-65 signature checks.\n *\n * record.v2 (over a chain-format-v4 entry) adds field 0x09, the entry's leaf\n * hash, and is signed with the ML-DSA context `aleutian.proof.record.v2`;\n * record.v1 below uses the empty context.\n *\n * ```\n * envelope = \"aleutian.proof.record.v1\" 0x00\n * ‖ field(0x01, chain_id) ‖ field(0x02, entry_id)\n * ‖ field(0x03, entry_type) ‖ field(0x04, global_seq)\n * ‖ field(0x05, previous_hash) ‖ field(0x06, timestamp)\n * ‖ field(0x07, content_hash) ‖ field(0x08, signing_key_id)\n * field(tag, v) = tag (1 byte) ‖ uint32 big-endian length of v ‖ v\n * ```\n *\n * The signature is pure ML-DSA-65 with an EMPTY context: the domain is in the\n * message. `record.v1` is ML-DSA-65 only.\n *\n * Vectors: `testdata/record_v1_vectors.json`. Browser-safe.\n */\n\nimport { ml_dsa65 } from \"@noble/post-quantum/ml-dsa.js\";\n\nimport {\n HEX_128,\n HEX_32,\n isGlobalSeq,\n isSinkTimestamp,\n SINK_CHAIN_ID,\n SINK_ENTRY_ID,\n} from \"./sinkShapes.js\";\n\n/** The envelope's domain string; a 0x00 byte follows it. */\nexport const RECORD_ENVELOPE_DOMAIN = \"aleutian.proof.record.v1\";\n\n/** ML-DSA-65 public key size in bytes (FIPS 204). */\nconst MLDSA65_PUBLIC_KEY_SIZE = 1952;\n\n/** ML-DSA-65 signature size in bytes (FIPS 204). */\nconst MLDSA65_SIGNATURE_SIZE = 3309;\n\nconst EMPTY_CONTEXT = new Uint8Array(0);\n\n/** The eight values a record signature covers, as stored strings. */\nexport interface RecordEnvelopeFields {\n /** A sink chain id (sink-format §1). */\n readonly chainId: string;\n /** `sink-` and 32 lowercase hex. */\n readonly entryId: string;\n /** `sink.event` or `sink.erasure`. */\n readonly entryType: string;\n /** Base-10, no sign or leading zeros, 0 ≤ n ≤ 2⁶³−1. */\n readonly globalSeq: string;\n /** 128 lowercase hex; empty exactly when `globalSeq` is \"0\". */\n readonly previousHash: string;\n /** `YYYY-MM-DDTHH:MM:SS.ffffffZ`, a real instant, year 0001–9999. */\n readonly timestamp: string;\n /** 128 lowercase hex. */\n readonly contentHash: string;\n /** The signing key's id: 32 lowercase hex. */\n readonly signingKeyId: string;\n}\n\n/**\n * Whether every value is inside sink-format §9.1's table, so an envelope may\n * be built from it.\n */\nexport function isValidRecordEnvelopeFields(f: RecordEnvelopeFields): boolean {\n if (!SINK_CHAIN_ID.test(f.chainId)) return false;\n if (!SINK_ENTRY_ID.test(f.entryId)) return false;\n if (f.entryType !== \"sink.event\" && f.entryType !== \"sink.erasure\") return false;\n if (!isGlobalSeq(f.globalSeq)) return false;\n if (f.globalSeq === \"0\") {\n if (f.previousHash !== \"\") return false;\n } else if (!HEX_128.test(f.previousHash)) {\n return false;\n }\n if (!isSinkTimestamp(f.timestamp)) return false;\n if (!HEX_128.test(f.contentHash)) return false;\n return HEX_32.test(f.signingKeyId);\n}\n\n/**\n * Build the exact bytes a record signature covers.\n *\n * # Description\n *\n * Writes the domain, a 0x00 byte, then the eight tagged, length-prefixed\n * fields in order. Values are the stored strings, never re-formatted.\n *\n * # Inputs\n *\n * - fields: the eight envelope values\n *\n * # Outputs\n *\n * - Uint8Array: the envelope bytes\n * - Error: thrown, with a fixed message that quotes no value, when any value\n * is outside sink-format §9.1's table (no envelope may be built)\n *\n * # Example\n *\n * const envelope = buildRecordEnvelopeV1({ chainId, entryId, ... });\n *\n * # Limitations\n *\n * - Builds bytes only; {@link verifyRecordSignatureV1} checks a signature.\n *\n * # Assumptions\n *\n * - None: every value is validated here.\n */\nexport function buildRecordEnvelopeV1(fields: RecordEnvelopeFields): Uint8Array {\n if (!isValidRecordEnvelopeFields(fields)) {\n throw new Error(\"record envelope: a field is outside sink-format §9.1\");\n }\n return encodeEnvelope(RECORD_ENVELOPE_DOMAIN, [\n fields.chainId,\n fields.entryId,\n fields.entryType,\n fields.globalSeq,\n fields.previousHash,\n fields.timestamp,\n fields.contentHash,\n fields.signingKeyId,\n ]);\n}\n\n/** domain ‖ 0x00 ‖ field(1, v1) ‖ field(2, v2) ‖ … with field(t, v) = t ‖ u32be(len v) ‖ v. */\nfunction encodeEnvelope(domainText: string, fieldValues: readonly string[]): Uint8Array {\n const enc = new TextEncoder();\n const values = fieldValues.map((v) => enc.encode(v));\n const domain = enc.encode(domainText);\n\n let size = domain.length + 1;\n for (const v of values) size += 5 + v.length;\n const out = new Uint8Array(size);\n const view = new DataView(out.buffer);\n out.set(domain, 0);\n let at = domain.length;\n out[at++] = 0x00;\n values.forEach((v, i) => {\n out[at++] = i + 1;\n view.setUint32(at, v.length, false);\n at += 4;\n out.set(v, at);\n at += v.length;\n });\n return out;\n}\n\n/**\n * Verify a pure ML-DSA-65 signature with an EMPTY context.\n *\n * # Description\n *\n * FIPS 204 pure mode (not HashML-DSA), context of zero bytes, as proof signs\n * checkpoints (format-spec §9.5) and records (sink-format §9.1). A signature\n * made with a non-empty context, or with HashML-DSA, does not verify.\n *\n * # Inputs\n *\n * - publicKey: raw 1952-byte ML-DSA-65 public key\n * - message: the exact signed bytes\n * - signature: raw 3309-byte signature\n *\n * # Outputs\n *\n * - boolean: true only when the signature verifies. Never throws: a wrong\n * size or a library error is false.\n *\n * # Example\n *\n * if (!verifyMLDSA65Pure(pk, envelope, sig)) { ... }\n *\n * # Limitations\n *\n * - Does not resolve key ids; the caller matches the key to its id.\n *\n * # Assumptions\n *\n * - `@noble/post-quantum` 0.5: `verify(sig, msg, publicKey, { context })`\n * builds the pure-mode message `0x00 ‖ len(ctx) ‖ ctx ‖ msg`.\n */\nexport function verifyMLDSA65Pure(\n publicKey: Uint8Array,\n message: Uint8Array,\n signature: Uint8Array\n): boolean {\n return verifyMLDSA65PureWithContext(publicKey, message, signature, EMPTY_CONTEXT);\n}\n\n/**\n * Verify a pure ML-DSA-65 signature made with a given FIPS 204 context.\n *\n * # Description\n *\n * FIPS 204 pure mode (not HashML-DSA) with context `ctx` (0 to 255 bytes):\n * the signed message is `0x00 ‖ len(ctx) ‖ ctx ‖ message`. A signature made\n * with any other context, or none, does not verify. proof uses\n * `aleutian.proof.anchor.v7` for v7 anchors (format-spec §9.5) and\n * `aleutian.proof.record.v2` for record.v2 signatures (sink-format §9.1).\n *\n * # Inputs\n *\n * - publicKey: raw 1952-byte ML-DSA-65 public key\n * - message: the exact signed bytes\n * - signature: raw 3309-byte signature\n * - context: the context bytes (the caller chooses it from the declared\n * version, never from the signature)\n *\n * # Outputs\n *\n * - boolean: true only when the signature verifies. Never throws.\n *\n * # Example\n *\n * verifyMLDSA65PureWithContext(pk, envelope, sig, utf8(\"aleutian.proof.record.v2\"));\n *\n * # Limitations\n *\n * - Does not resolve key ids.\n *\n * # Assumptions\n *\n * - `@noble/post-quantum` 0.5's `{ context }` option.\n */\nexport function verifyMLDSA65PureWithContext(\n publicKey: Uint8Array,\n message: Uint8Array,\n signature: Uint8Array,\n context: Uint8Array\n): boolean {\n if (publicKey.length !== MLDSA65_PUBLIC_KEY_SIZE) return false;\n if (signature.length !== MLDSA65_SIGNATURE_SIZE) return false;\n if (!(context instanceof Uint8Array) || context.length > 255) return false;\n try {\n return ml_dsa65.verify(signature, message, publicKey, { context });\n } catch {\n return false;\n }\n}\n\n/**\n * Verify a record signature over the `record.v1` envelope of `fields`.\n *\n * # Description\n *\n * Builds the envelope from the stored values and verifies the signature (pure\n * ML-DSA-65, empty context). False when no envelope can be built.\n *\n * # Inputs\n *\n * - publicKey: raw 1952-byte ML-DSA-65 public key, whose key id the caller\n * has checked equals `fields.signingKeyId`\n * - fields: the eight envelope values\n * - signature: raw 3309-byte signature\n *\n * # Outputs\n *\n * - boolean: whether the signature verifies. Never throws.\n *\n * # Example\n *\n * const ok = verifyRecordSignatureV1(pk, fields, sig);\n *\n * # Limitations\n *\n * - Does not check that `publicKey` has id `fields.signingKeyId`.\n *\n * # Assumptions\n *\n * - The caller decided the key is trusted for records.\n */\nexport function verifyRecordSignatureV1(\n publicKey: Uint8Array,\n fields: RecordEnvelopeFields,\n signature: Uint8Array\n): boolean {\n if (!isValidRecordEnvelopeFields(fields)) return false;\n return verifyMLDSA65Pure(publicKey, buildRecordEnvelopeV1(fields), signature);\n}\n\n// =============================================================================\n// record.v2 (sink-format §9.1): a record signature over a chain-format-v4 entry\n// =============================================================================\n\n/** The record.v2 envelope's domain string; a 0x00 byte follows it. */\nexport const RECORD_ENVELOPE_DOMAIN_V2 = \"aleutian.proof.record.v2\";\n\n/**\n * The ML-DSA context a record.v2 signature is made with (sink-format §9.1).\n * record.v1 uses the empty context.\n */\nexport const RECORD_SIGNATURE_CONTEXT_V2 = \"aleutian.proof.record.v2\";\n\nconst CONTEXT_V2 = new TextEncoder().encode(RECORD_SIGNATURE_CONTEXT_V2);\n\n/** The nine values a record.v2 signature covers: record.v1's eight and the leaf hash. */\nexport interface RecordEnvelopeFieldsV2 extends RecordEnvelopeFields {\n /** The entry's leaf hash (format-spec §2.0): 128 lowercase hex. */\n readonly leafHash: string;\n}\n\n/** Whether every value is inside sink-format §9.1's table, leaf hash included. */\nexport function isValidRecordEnvelopeFieldsV2(f: RecordEnvelopeFieldsV2): boolean {\n return isValidRecordEnvelopeFields(f) && typeof f.leafHash === \"string\" && HEX_128.test(f.leafHash);\n}\n\n/**\n * Build the exact bytes a record.v2 signature covers (sink-format §9.1).\n *\n * # Description\n *\n * `\"aleutian.proof.record.v2\" 0x00`, then fields 0x01-0x08 as record.v1\n * (chain id, entry id, entry type, global seq, previous hash, timestamp,\n * content hash, signing key id), then 0x09 the leaf hash. Signing the leaf\n * hash binds the salt, which the content hash alone does not. Values are the\n * stored strings, never re-formatted.\n *\n * # Inputs\n *\n * - fields: the nine envelope values\n *\n * # Outputs\n *\n * - Uint8Array: the envelope bytes\n * - Error: thrown, with a fixed message, when a value is outside the table\n *\n * # Example\n *\n * const envelope = buildRecordEnvelopeV2({ ...fieldsV1, leafHash });\n *\n * # Limitations\n *\n * - Builds bytes only; {@link verifyRecordSignatureV2} checks a signature.\n *\n * # Assumptions\n *\n * - None: every value is validated here.\n */\nexport function buildRecordEnvelopeV2(fields: RecordEnvelopeFieldsV2): Uint8Array {\n if (!isValidRecordEnvelopeFieldsV2(fields)) {\n throw new Error(\"record envelope: a field is outside sink-format §9.1\");\n }\n return encodeEnvelope(RECORD_ENVELOPE_DOMAIN_V2, [\n fields.chainId,\n fields.entryId,\n fields.entryType,\n fields.globalSeq,\n fields.previousHash,\n fields.timestamp,\n fields.contentHash,\n fields.signingKeyId,\n fields.leafHash,\n ]);\n}\n\n/**\n * Verify a record signature over the record.v2 envelope of `fields`.\n *\n * # Description\n *\n * Builds the v2 envelope and verifies the signature as pure ML-DSA-65 with the\n * context `aleutian.proof.record.v2`. A record.v1 signature, or one made with\n * the empty or another context, does not verify. False when no envelope can\n * be built.\n *\n * # Inputs\n *\n * - publicKey: raw 1952-byte ML-DSA-65 public key, whose key id the caller\n * has checked equals `fields.signingKeyId`\n * - fields: the nine envelope values\n * - signature: raw 3309-byte signature\n *\n * # Outputs\n *\n * - boolean: whether the signature verifies. Never throws.\n *\n * # Example\n *\n * const ok = verifyRecordSignatureV2(pk, fields, sig);\n *\n * # Limitations\n *\n * - Does not check that `publicKey` has id `fields.signingKeyId`.\n *\n * # Assumptions\n *\n * - The caller decided the key is trusted for records.\n */\nexport function verifyRecordSignatureV2(\n publicKey: Uint8Array,\n fields: RecordEnvelopeFieldsV2,\n signature: Uint8Array\n): boolean {\n if (!isValidRecordEnvelopeFieldsV2(fields)) return false;\n return verifyMLDSA65PureWithContext(publicKey, buildRecordEnvelopeV2(fields), signature, CONTEXT_V2);\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Verifier for proof's sink export bundles, `aleutian.proof.bundle.v1` and\n * `aleutian.proof.bundle.v2`.\n *\n * Written from `proof/docs/bundle-format.md` (normative, revision 4: §1-§15 for\n * v1, §16's deltas for v2) and what it references (format-spec §2.0, §2.1, §3,\n * §4, §8, §9; sink-format §1, §2, §4.1, §9), independently of proof's code.\n * Section numbers below are bundle-format's unless stated otherwise.\n *\n * Dispatch is on the bundle's declared `format` only. v1: chain hash v3, v6\n * checkpoints, record.v1 (empty ML-DSA context). v2: chain format v4 (leaf\n * hash, then chain hash), v7 checkpoints (context `aleutian.proof.anchor.v7`),\n * record.v2 (context `aleutian.proof.record.v2`). Both give the same result.\n *\n * Trust is the verifier's (§6): the caller supplies checkpoint keys and record\n * keys; a bundle never adds a key. The result is §9's, a closed set that every\n * implementation produces identically.\n *\n * NO-LEAK RULE (§10): nothing here puts a bundle value into an error message.\n * The parser reports no positions and no input; every error this module throws\n * has a fixed message.\n *\n * The bundle is read in one streaming pass (`proofBundleReader.ts`), so memory\n * on hostile input stays bounded by the largest readable bundle (§5's value\n * limit). Hashing is synchronous (`proofBundleHashes.ts`).\n *\n * Browser-safe: WebCrypto, `@noble/hashes` and `@noble/post-quantum` only, no\n * Node APIs, and no embedded key fixtures (`keys.ts` is not imported).\n */\n\nimport {\n ANCHOR_SIGNATURE_CONTEXT_V7,\n canonicalizeAnchorV6,\n canonicalizeAnchorV7,\n} from \"./anchorCanonical.js\";\nimport {\n anchorChainHashV7Sync,\n SEED_ANCHOR_HASH,\n SEED_ANCHOR_ID,\n} from \"./anchorChainHash.js\";\nimport { chainHashV4Sync, leafHashV4Sync } from \"./chainV4.js\";\nimport { decodeCanonicalBase64 } from \"./canonicalBase64.js\";\nimport { hexToUint8Array } from \"./hash.js\";\nimport { keyIdMLDSA65, MLDSA65_PUBLIC_KEY_SIZE } from \"./keyId.js\";\nimport {\n BUNDLE_FORMAT_V1,\n BUNDLE_FORMAT_V2,\n BUNDLE_MAX_DEPTH,\n readProofBundle,\n type BundleChain,\n type BundleEntry,\n type BundleFormatVersion,\n} from \"./proofBundleReader.js\";\nimport {\n anchorChainHashSync,\n chainHashV3Sync,\n openCommitmentSync,\n sha512HexSync,\n} from \"./proofBundleHashes.js\";\nimport {\n buildRecordEnvelopeV1,\n buildRecordEnvelopeV2,\n RECORD_SIGNATURE_CONTEXT_V2,\n verifyMLDSA65Pure,\n verifyMLDSA65PureWithContext,\n} from \"./recordEnvelope.js\";\nimport {\n HEX_128,\n HEX_32,\n HEX_64,\n isGlobalSeq,\n isSinkTimestamp,\n SINK_CHAIN_ID,\n SINK_ENTRY_ID,\n} from \"./sinkShapes.js\";\nimport { JsonNumber, JsonObject, parseStrictJson, type JsonValue } from \"./strictJson.js\";\n\n// =============================================================================\n// Result types (§9)\n// =============================================================================\n\n/** The result id. A consumer MUST refuse any other (§9.4). */\nexport const PROOF_BUNDLE_RESULT_ID = \"aleutian.proof.bundle-result.v1\";\n\n/** The v1 bundle format string (§4.1). */\nexport const PROOF_BUNDLE_FORMAT = BUNDLE_FORMAT_V1;\n\n/**\n * The v2 bundle format string (§16): chain format v4 entries, v7 checkpoints,\n * record.v2 signatures. Verified with the same result as v1.\n */\nexport const PROOF_BUNDLE_FORMAT_V2 = BUNDLE_FORMAT_V2;\n\n/**\n * Why a bundle is unreadable (§9.1). Precedence: too-large (size), json,\n * too-large (values), duplicate-key, format, structure, too-large (counts).\n */\nexport type ProofBundleUnreadableReason =\n | \"too-large\"\n | \"json\"\n | \"duplicate-key\"\n | \"format\"\n | \"structure\";\n\n/** A verdict (§1). */\nexport type ProofBundleVerdict = \"ok\" | \"unauthenticated\" | \"failed\";\n\n/** Whether a trust dimension was checked (§6). */\nexport type ProofBundleTrustState = \"checked\" | \"not_checked\";\n\n/** A chain's erasure state (§7.9). */\nexport type ProofBundleErasureState = \"none\" | \"recorded\" | \"anchored\" | \"signed\";\n\n/** The complete v1 list of problem codes (§12). */\nexport type ProofBundleProblemCode =\n | \"duplicate-chain\"\n | \"invalid-chain-id\"\n | \"field-shape\"\n | \"duplicate-entry-id\"\n | \"first-entry\"\n | \"sequence\"\n | \"link\"\n | \"chain-hash\"\n | \"entry-type\"\n | \"erasure-invalid\"\n | \"after-erasure\"\n | \"erased-event-disclosed\"\n | \"modified\"\n | \"checkpoint-malformed\"\n | \"checkpoint-subject\"\n | \"checkpoint-sequence\"\n | \"checkpoint-overreach\"\n | \"checkpoint-binding\"\n | \"checkpoint-unknown-key\"\n | \"checkpoint-bad-signature\"\n | \"unsigned\"\n | \"malformed-signature\"\n | \"unknown-key\"\n | \"bad-signature\";\n\n/** One problem code with its count and lowest index (§9.2). */\nexport interface ProofBundleProblem {\n readonly code: ProofBundleProblemCode;\n readonly count: number;\n /** The lowest index; null only for `invalid-chain-id`. */\n readonly first: number | null;\n}\n\n/** A chain's counts (§9.2). Every count is always present. */\nexport interface ProofBundleChainCounts {\n readonly entries: number;\n readonly events: number;\n readonly erasures: number;\n readonly opened: number;\n readonly committed: number;\n readonly erased: number;\n readonly checkpoints: number;\n readonly unanchored: number;\n readonly authenticated: number;\n readonly unauthenticated: number;\n readonly checkpoint_authenticated: number;\n readonly record_authenticated: number;\n readonly record_signatures_present: number;\n}\n\n/** One chain's result (§9.2). */\nexport interface ProofBundleChainResult {\n readonly verdict: ProofBundleVerdict;\n readonly erasure: ProofBundleErasureState;\n readonly counts: ProofBundleChainCounts;\n /** Sorted by `code` in byte order. */\n readonly problems: ProofBundleProblem[];\n}\n\n/** An unreadable bundle (§9.1). */\nexport interface ProofBundleUnreadableResult {\n readonly result: typeof PROOF_BUNDLE_RESULT_ID;\n readonly readable: false;\n readonly reason: ProofBundleUnreadableReason;\n}\n\n/** A readable bundle (§9.2). */\nexport interface ProofBundleReadableResult {\n readonly result: typeof PROOF_BUNDLE_RESULT_ID;\n readonly readable: true;\n readonly checkpoint_trust: ProofBundleTrustState;\n readonly record_trust: ProofBundleTrustState;\n readonly verdict: ProofBundleVerdict;\n /** Sorted by `code` in byte order. */\n readonly bundle_problems: ProofBundleProblem[];\n /** Keyed by chain id, or `#<i>` for an invalid or duplicated id (§9.3). */\n readonly chains: Record<string, ProofBundleChainResult>;\n}\n\n/** The §9 result. */\nexport type ProofBundleResult = ProofBundleUnreadableResult | ProofBundleReadableResult;\n\n/** The verifier's trust (§6): raw 1952-byte ML-DSA-65 public keys. */\nexport interface ProofBundleTrust {\n /** Keys trusted for checkpoints. Empty: the dimension is not checked. */\n readonly checkpointKeys: readonly Uint8Array[];\n /** Keys trusted for record signatures. Empty: the dimension is not checked. */\n readonly recordKeys: readonly Uint8Array[];\n}\n\n/** The §5 limits. */\nexport interface ProofBundleLimits {\n readonly bundleBytes: number;\n /** JSON values in a v1 bundle, at every depth, the top-level value included. */\n readonly values: number;\n /**\n * JSON values in a v2 bundle (§16 §5: 17,000,000). When absent, `values`\n * applies to both formats.\n */\n readonly valuesV2?: number;\n readonly chains: number;\n readonly entries: number;\n readonly checkpoints: number;\n readonly checkpointTextBytes: number;\n}\n\n/** The normative limits (§5). Every implementation MUST accept a bundle within them. */\nexport const PROOF_BUNDLE_LIMITS: ProofBundleLimits = Object.freeze({\n bundleBytes: 256 * 1024 * 1024,\n values: 15_000_000,\n valuesV2: 17_000_000,\n chains: 100_000,\n entries: 1_000_000,\n checkpoints: 100_000,\n checkpointTextBytes: 1024 * 1024,\n});\n\n/** Nesting depth limit (§3, §5). */\nconst MAX_DEPTH = BUNDLE_MAX_DEPTH;\n\n/** Thrown only for a caller error (bad trust keys) or a bug; never names a bundle value. */\nexport class ProofBundleVerifierError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ProofBundleVerifierError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// =============================================================================\n// Checkpoint text (§4.4)\n// =============================================================================\n\ninterface Checkpoint {\n readonly anchorId: string;\n readonly chainHash: string;\n readonly createdAtMs: bigint;\n readonly entryCount: number;\n readonly previousAnchorId: string;\n readonly startEntryId: string;\n readonly endEntryId: string;\n readonly signature: Uint8Array;\n readonly signingKeyId: string;\n readonly subject: string;\n readonly verifiedThrough: bigint;\n}\n\n/** Whether an object has exactly the required members. */\nfunction hasExactMembers(obj: JsonObject, required: readonly string[]): boolean {\n if (obj.members.size !== required.length) return false;\n for (const name of required) if (!obj.members.has(name)) return false;\n return true;\n}\n\n/** A member that must be a string; undefined when it is not. */\nfunction str(obj: JsonObject, name: string): string | undefined {\n const v = obj.members.get(name);\n return typeof v === \"string\" ? v : undefined;\n}\n\n/** A two-string object (`range`), or null on any violation. */\nfunction stringPair(\n v: JsonValue | undefined,\n a: string,\n b: string\n): [string, string] | null {\n if (!(v instanceof JsonObject) || !hasExactMembers(v, [a, b])) return null;\n const x = str(v, a);\n const y = str(v, b);\n return x === undefined || y === undefined ? null : [x, y];\n}\n\nconst CHECKPOINT_MEMBERS = [\n \"version\",\n \"anchor_id\",\n \"chain_hash\",\n \"created_at_ms\",\n \"entry_count\",\n \"previous_anchor_id\",\n \"range\",\n \"signature\",\n \"signing_key_id\",\n \"subject\",\n \"verified_through\",\n] as const;\nconst CHECKPOINT_NUMBER = /^(0|[1-9][0-9]*)$/;\nconst MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);\nconst MLDSA65_SIGNATURE_SIZE = 3309;\n\n/** A checkpoint number (§3): `0|[1-9][0-9]*`, at most 2⁵³−1; null otherwise. */\nfunction checkpointNumber(v: JsonValue | undefined): bigint | null {\n if (!(v instanceof JsonNumber) || !CHECKPOINT_NUMBER.test(v.text)) return null;\n const n = BigInt(v.text);\n return n <= MAX_SAFE ? n : null;\n}\n\n/** A non-empty string without `|` (anchor ids, subject). */\nfunction pipeFree(s: string | undefined): s is string {\n return s !== undefined && s !== \"\" && !s.includes(\"|\");\n}\n\n/** Step a of §7.6: the text satisfies §3 and §4.4, or null. */\nfunction parseCheckpoint(text: string, limits: ProofBundleLimits): Checkpoint | null {\n // The text came out of the strict parser, so it holds no lone surrogate and\n // encodes to UTF-8 exactly.\n const bytes = new TextEncoder().encode(text);\n if (bytes.length > limits.checkpointTextBytes) return null;\n const parsed = parseStrictJson(bytes, MAX_DEPTH);\n if (!parsed.ok || parsed.duplicateKey) return null;\n const obj = parsed.value;\n if (!(obj instanceof JsonObject) || !hasExactMembers(obj, CHECKPOINT_MEMBERS))\n return null;\n\n const version = checkpointNumber(obj.members.get(\"version\"));\n const createdAtMs = checkpointNumber(obj.members.get(\"created_at_ms\"));\n const entryCount = checkpointNumber(obj.members.get(\"entry_count\"));\n const verifiedThrough = checkpointNumber(obj.members.get(\"verified_through\"));\n if (version !== 6n || createdAtMs === null) return null;\n if (entryCount === null || entryCount < 1n) return null;\n if (verifiedThrough === null || verifiedThrough < 1n) return null;\n\n const anchorId = str(obj, \"anchor_id\");\n const previousAnchorId = str(obj, \"previous_anchor_id\");\n const subject = str(obj, \"subject\");\n if (!pipeFree(anchorId) || !pipeFree(previousAnchorId) || !pipeFree(subject))\n return null;\n\n const chainHash = str(obj, \"chain_hash\");\n const signingKeyId = str(obj, \"signing_key_id\");\n if (chainHash === undefined || !HEX_128.test(chainHash)) return null;\n if (signingKeyId === undefined || !HEX_32.test(signingKeyId)) return null;\n\n const signatureText = str(obj, \"signature\");\n const signature =\n signatureText === undefined ? null : decodeCanonicalBase64(signatureText);\n if (signature === null || signature.length !== MLDSA65_SIGNATURE_SIZE) return null;\n\n const range = stringPair(obj.members.get(\"range\"), \"start_entry_id\", \"end_entry_id\");\n if (range === null || !SINK_ENTRY_ID.test(range[0]) || !SINK_ENTRY_ID.test(range[1]))\n return null;\n\n return {\n anchorId,\n chainHash,\n createdAtMs,\n entryCount: Number(entryCount),\n previousAnchorId,\n startEntryId: range[0],\n endEntryId: range[1],\n signature,\n signingKeyId,\n subject,\n verifiedThrough,\n };\n}\n\n/** The v6 canonical bytes a checkpoint signature covers (format-spec §9.2). */\nfunction checkpointCanonicalBytes(cp: Checkpoint): Uint8Array {\n const canonical = canonicalizeAnchorV6({\n version: 6,\n anchorId: cp.anchorId,\n subject: cp.subject,\n chainHash: cp.chainHash,\n range: { startEntryId: cp.startEntryId, endEntryId: cp.endEntryId },\n entryCount: BigInt(cp.entryCount),\n signature: \"\",\n signingKeyId: cp.signingKeyId,\n createdAtMs: cp.createdAtMs,\n previousAnchorId: cp.previousAnchorId,\n verifiedThrough: cp.verifiedThrough,\n });\n return new TextEncoder().encode(canonical);\n}\n\n// =============================================================================\n// v2 checkpoint text (§16 §4.4): a v7 anchor\n// =============================================================================\n\ninterface CheckpointV7 {\n readonly anchorId: string;\n readonly chainHash: string;\n readonly createdAtMs: bigint;\n readonly entryCount: bigint;\n readonly endSeq: string;\n readonly previousAnchorHash: string;\n readonly previousAnchorId: string;\n readonly signature: Uint8Array;\n readonly signingKeyId: string;\n readonly subject: string;\n}\n\nconst CHECKPOINT_V7_MEMBERS = [\n \"version\",\n \"anchor_id\",\n \"chain_hash\",\n \"created_at_ms\",\n \"entry_count\",\n \"previous_anchor_hash\",\n \"previous_anchor_id\",\n \"range\",\n \"signature\",\n \"signing_key_id\",\n \"subject\",\n] as const;\n\nconst ANCHOR_CONTEXT_V7 = new TextEncoder().encode(ANCHOR_SIGNATURE_CONTEXT_V7);\nconst RECORD_CONTEXT_V2 = new TextEncoder().encode(RECORD_SIGNATURE_CONTEXT_V2);\n\n/** Step a of §7.6 for v2: the text satisfies §3 and §16 §4.4, or null. */\nfunction parseCheckpointV7(text: string, limits: ProofBundleLimits): CheckpointV7 | null {\n const bytes = new TextEncoder().encode(text);\n if (bytes.length > limits.checkpointTextBytes) return null;\n const parsed = parseStrictJson(bytes, MAX_DEPTH);\n if (!parsed.ok || parsed.duplicateKey) return null;\n const obj = parsed.value;\n if (!(obj instanceof JsonObject) || !hasExactMembers(obj, CHECKPOINT_V7_MEMBERS))\n return null;\n\n // Numbers in v7 checkpoint text are only version and created_at_ms (§16 §3).\n const version = checkpointNumber(obj.members.get(\"version\"));\n const createdAtMs = checkpointNumber(obj.members.get(\"created_at_ms\"));\n if (version !== 7n || createdAtMs === null) return null;\n\n // entry_count and the range are decimal STRINGS (format-spec §2.1's grammar),\n // compared as integers.\n const entryCountText = str(obj, \"entry_count\");\n if (entryCountText === undefined || !isGlobalSeq(entryCountText)) return null;\n const entryCount = BigInt(entryCountText);\n if (entryCount < 1n) return null;\n const range = stringPair(obj.members.get(\"range\"), \"start_seq\", \"end_seq\");\n if (range === null || !isGlobalSeq(range[0]) || !isGlobalSeq(range[1])) return null;\n if (range[0] !== \"0\" || entryCount !== BigInt(range[1]) + 1n) return null;\n\n const anchorId = str(obj, \"anchor_id\");\n const previousAnchorId = str(obj, \"previous_anchor_id\");\n const subject = str(obj, \"subject\");\n if (!pipeFree(anchorId) || !pipeFree(previousAnchorId) || !pipeFree(subject))\n return null;\n\n const chainHash = str(obj, \"chain_hash\");\n const previousAnchorHash = str(obj, \"previous_anchor_hash\");\n const signingKeyId = str(obj, \"signing_key_id\");\n if (chainHash === undefined || !HEX_128.test(chainHash)) return null;\n if (previousAnchorHash === undefined || !HEX_128.test(previousAnchorHash)) return null;\n if (signingKeyId === undefined || !HEX_32.test(signingKeyId)) return null;\n // format-spec §9.3: the seed id exactly when the seed hash.\n if ((previousAnchorId === SEED_ANCHOR_ID) !== (previousAnchorHash === SEED_ANCHOR_HASH))\n return null;\n\n const signatureText = str(obj, \"signature\");\n const signature =\n signatureText === undefined ? null : decodeCanonicalBase64(signatureText);\n if (signature === null || signature.length !== MLDSA65_SIGNATURE_SIZE) return null;\n\n return {\n anchorId,\n chainHash,\n createdAtMs,\n entryCount,\n endSeq: range[1],\n previousAnchorHash,\n previousAnchorId,\n signature,\n signingKeyId,\n subject,\n };\n}\n\n/** The v7 canonical bytes a v2 checkpoint signature covers (format-spec §9.2). */\nfunction checkpointCanonicalBytesV7(cp: CheckpointV7): Uint8Array {\n const canonical = canonicalizeAnchorV7({\n version: 7,\n anchorId: cp.anchorId,\n subject: cp.subject,\n chainHash: cp.chainHash,\n range: { startEntryId: \"\", endEntryId: \"\", startSeq: 0n, endSeq: BigInt(cp.endSeq) },\n entryCount: cp.entryCount,\n signature: \"\",\n signingKeyId: cp.signingKeyId,\n createdAtMs: cp.createdAtMs,\n previousAnchorId: cp.previousAnchorId,\n previousAnchorHash: cp.previousAnchorHash,\n });\n return new TextEncoder().encode(canonical);\n}\n\n// =============================================================================\n// Chain checks (§7)\n// =============================================================================\n\n/** Problem codes with counts and lowest indexes. */\nclass ProblemSet {\n private readonly byCode = new Map<\n ProofBundleProblemCode,\n { count: number; first: number | null }\n >();\n\n add(code: ProofBundleProblemCode, index: number | null): void {\n const p = this.byCode.get(code);\n if (p === undefined) {\n this.byCode.set(code, { count: 1, first: index });\n } else {\n p.count++;\n if (index !== null && (p.first === null || index < p.first)) p.first = index;\n }\n }\n\n get empty(): boolean {\n return this.byCode.size === 0;\n }\n\n /** Sorted by code in byte order (codes are ASCII, so UTF-16 order is byte order). */\n list(): ProofBundleProblem[] {\n return [...this.byCode.entries()]\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([code, p]) => ({ code, count: p.count, first: p.first }));\n }\n}\n\nconst ERASURE_DOMAIN = \"aleutian.sink.erasure.v1:\";\n\n/** EH (§7.3): the erasure hash for the position after an entry of `globalSeq`. */\nfunction erasureHash(previousGlobalSeq: string): string {\n // sink-format §4.1: the record, built (never parsed) from the stored string.\n const record =\n '{\"erased\":\"every earlier event on this chain\",\"through_global_seq\":\"' +\n previousGlobalSeq +\n '\"}';\n return sha512HexSync(ERASURE_DOMAIN + record);\n}\n\n/** §4.3's `disclosed` shape: canonical base64 of 1–65,536 bytes, and a 64-hex nonce. */\nfunction disclosedInShape(d: NonNullable<BundleEntry[\"disclosed\"]>): boolean {\n if (!HEX_64.test(d.nonce)) return false;\n // 65,536 bytes is 87,384 base64 characters; refuse longer text unread.\n if (d.content.length > 87_384) return false;\n const content = decodeCanonicalBase64(d.content);\n return content !== null && content.length >= 1 && content.length <= 65_536;\n}\n\n/**\n * The well-formedness of §7.1.3: the six hashed members in shape, and in v2\n * (§16 §4.3) `salt` and `leaf_hash` too.\n */\nfunction isWellFormed(e: BundleEntry, format: BundleFormatVersion): boolean {\n if (format === 2 && !(HEX_64.test(e.salt ?? \"\") && HEX_128.test(e.leafHash ?? \"\"))) {\n return false;\n }\n return (\n SINK_ENTRY_ID.test(e.entryId) &&\n isGlobalSeq(e.globalSeq) &&\n (e.previousHash === \"\" || HEX_128.test(e.previousHash)) &&\n isSinkTimestamp(e.timestamp) &&\n HEX_128.test(e.contentHash) &&\n HEX_128.test(e.chainHash)\n );\n}\n\ninterface TrustKeys {\n readonly checkpoint: ReadonlyMap<string, Uint8Array>;\n readonly record: ReadonlyMap<string, Uint8Array>;\n}\n\n/**\n * §7.2 step 3: whether a well-formed entry's hashes recompute. v1: chain hash\n * v3. v2 (§16 §7.2): the leaf hash v4 over the stored id, type, content hash\n * and salt, then chain hash v4 over the stored leaf hash.\n */\nfunction hashesRecompute(e: BundleEntry, format: BundleFormatVersion): boolean {\n if (format === 1) {\n return chainHashV3Sync(e.previousHash, e.globalSeq, e.timestamp, e.contentHash) === e.chainHash;\n }\n const leafHash = e.leafHash!;\n if (leafHashV4Sync(e.entryId, e.entryType, e.contentHash, e.salt!) !== leafHash) return false;\n return chainHashV4Sync(e.previousHash, e.globalSeq, e.timestamp, leafHash) === e.chainHash;\n}\n\n/** One step of §7.6 failed: its problem code. */\ntype CheckpointStep =\n | \"checkpoint-malformed\"\n | \"checkpoint-subject\"\n | \"checkpoint-sequence\"\n | \"checkpoint-overreach\"\n | \"checkpoint-binding\"\n | \"checkpoint-unknown-key\"\n | \"checkpoint-bad-signature\";\n\n/** The state the next checkpoint of a series is judged against (§7.6). */\ninterface SeriesHead {\n readonly anchorId: string;\n readonly anchorHash: string;\n readonly count: bigint;\n}\n\n/** §16 §7.6: one v7 checkpoint's first failing step, or the head it establishes. */\nfunction checkCheckpointV7(\n text: string,\n head: SeriesHead,\n ctx: {\n readonly chainId: string;\n readonly chainIdValid: boolean;\n readonly entries: readonly BundleEntry[];\n readonly firstMalformed: number;\n readonly trust: TrustKeys;\n readonly limits: ProofBundleLimits;\n }\n): CheckpointStep | SeriesHead {\n const n = BigInt(ctx.entries.length);\n const cp = parseCheckpointV7(text, ctx.limits);\n if (cp === null) return \"checkpoint-malformed\"; // a\n if (!ctx.chainIdValid || cp.subject !== ctx.chainId) return \"checkpoint-subject\"; // b\n if (\n cp.previousAnchorId !== head.anchorId ||\n cp.previousAnchorHash !== head.anchorHash ||\n cp.entryCount <= head.count\n ) {\n return \"checkpoint-sequence\"; // c\n }\n if (cp.entryCount > n) return \"checkpoint-overreach\"; // d\n // e: entries 0 … entry_count−1 all well-formed, and the v7 anchor chain hash\n // over previous_anchor_hash, the chain id, \"0\", end_seq, and the stored chain\n // hash of entry end_seq (= entry_count − 1: §7.5 covers by index).\n if (cp.entryCount > BigInt(ctx.firstMalformed)) return \"checkpoint-binding\";\n const tip = ctx.entries[Number(cp.entryCount) - 1]!;\n const expected = anchorChainHashV7Sync(\n cp.previousAnchorHash,\n ctx.chainId,\n \"0\",\n cp.endSeq,\n tip.chainHash\n );\n if (cp.chainHash !== expected) return \"checkpoint-binding\";\n if (ctx.trust.checkpoint.size > 0) {\n const key = ctx.trust.checkpoint.get(cp.signingKeyId);\n if (key === undefined) return \"checkpoint-unknown-key\"; // f\n // g: pure ML-DSA-65, context aleutian.proof.anchor.v7, v7 canonical bytes.\n if (\n !verifyMLDSA65PureWithContext(\n key,\n checkpointCanonicalBytesV7(cp),\n cp.signature,\n ANCHOR_CONTEXT_V7\n )\n ) {\n return \"checkpoint-bad-signature\";\n }\n }\n return { anchorId: cp.anchorId, anchorHash: cp.chainHash, count: cp.entryCount };\n}\n\nfunction verifyChain(\n chain: BundleChain,\n trust: TrustKeys,\n limits: ProofBundleLimits,\n format: BundleFormatVersion\n): ProofBundleChainResult {\n const { chainId, entries } = chain;\n const n = entries.length;\n const problems = new ProblemSet();\n const checkpointTrust = trust.checkpoint.size > 0;\n const recordTrust = trust.record.size > 0;\n\n // §7.1 Shape.\n const chainIdValid = SINK_CHAIN_ID.test(chainId);\n if (!chainIdValid) problems.add(\"invalid-chain-id\", null);\n\n const wellFormed: boolean[] = [];\n const disclosedBad: boolean[] = [];\n const seenIds = new Set<string>();\n for (let i = 0; i < n; i++) {\n const e = entries[i]!;\n const wf = isWellFormed(e, format);\n const dBad =\n e.disclosed !== undefined &&\n (e.entryType !== \"sink.event\" || !disclosedInShape(e.disclosed));\n wellFormed.push(wf);\n disclosedBad.push(dBad);\n if (!wf || dBad) problems.add(\"field-shape\", i);\n if (seenIds.has(e.entryId)) problems.add(\"duplicate-entry-id\", i);\n if (wf) seenIds.add(e.entryId);\n }\n\n // §7.2 Links, and §7.3 erasure positions.\n const holdsErasureHash: boolean[] = new Array<boolean>(n).fill(false);\n let lastErasure = -1;\n for (let i = 0; i < n; i++) {\n if (!wellFormed[i]) continue;\n const e = entries[i]!;\n if (i === 0) {\n if (e.globalSeq !== \"0\" || e.previousHash !== \"\") problems.add(\"first-entry\", i);\n } else if (wellFormed[i - 1]) {\n const prev = entries[i - 1]!;\n if (BigInt(e.globalSeq) !== BigInt(prev.globalSeq) + 1n)\n problems.add(\"sequence\", i);\n if (e.previousHash !== prev.chainHash) problems.add(\"link\", i);\n if (e.contentHash === erasureHash(prev.globalSeq)) {\n holdsErasureHash[i] = true;\n lastErasure = i;\n }\n }\n if (!hashesRecompute(e, format)) problems.add(\"chain-hash\", i);\n }\n\n // §7.4 Entries.\n const E = lastErasure;\n let events = 0;\n let erasures = 0;\n let opened = 0;\n let committed = 0;\n let erased = 0;\n const genuineErasure: boolean[] = new Array<boolean>(n).fill(false);\n for (let i = 0; i < n; i++) {\n const e = entries[i]!;\n if (e.entryType === \"sink.event\") events++;\n if (!wellFormed[i]) continue;\n if (E >= 0 && i > E) {\n problems.add(\"after-erasure\", i);\n continue;\n }\n if (disclosedBad[i]) continue; // its field-shape is its outcome (§7.1.3)\n if (holdsErasureHash[i]) {\n if (e.entryType === \"sink.erasure\") {\n genuineErasure[i] = true;\n erasures++;\n } else {\n problems.add(\"erasure-invalid\", i);\n }\n } else if (e.entryType === \"sink.erasure\") {\n problems.add(\"erasure-invalid\", i);\n } else if (e.entryType === \"sink.event\") {\n if (i < E) {\n if (e.disclosed === undefined) erased++;\n else problems.add(\"erased-event-disclosed\", i);\n } else if (e.disclosed === undefined) {\n committed++;\n } else {\n const nonce = hexToUint8Array(e.disclosed.nonce);\n const content = decodeCanonicalBase64(e.disclosed.content)!;\n if (openCommitmentSync(nonce, content, e.contentHash)) opened++;\n else problems.add(\"modified\", i);\n }\n } else {\n problems.add(\"entry-type\", i);\n }\n }\n\n // §7.6 Checkpoints. The first failing step ends the series. Step e needs\n // entries 0..count-1 well-formed: count <= the first malformed index.\n const malformedAt = wellFormed.indexOf(false);\n const firstMalformed = malformedAt === -1 ? n : malformedAt;\n let passedCheckpoints = 0;\n let covered = 0;\n let prevAnchorId = SEED_ANCHOR_ID;\n let prevAnchorHash = SEED_ANCHOR_HASH;\n let prevCount = 0;\n if (format === 2) {\n let head: SeriesHead = { anchorId: SEED_ANCHOR_ID, anchorHash: SEED_ANCHOR_HASH, count: 0n };\n for (let k = 0; k < chain.checkpoints.length; k++) {\n const step = checkCheckpointV7(chain.checkpoints[k]!, head, {\n chainId,\n chainIdValid,\n entries,\n firstMalformed,\n trust,\n limits,\n });\n if (typeof step === \"string\") {\n problems.add(step, k);\n break;\n }\n head = step;\n passedCheckpoints++;\n covered = Number(step.count);\n }\n }\n for (let k = 0; format === 1 && k < chain.checkpoints.length; k++) {\n const cp = parseCheckpoint(chain.checkpoints[k]!, limits);\n if (cp === null) {\n problems.add(\"checkpoint-malformed\", k);\n break;\n }\n if (!chainIdValid || cp.subject !== chainId) {\n problems.add(\"checkpoint-subject\", k);\n break;\n }\n if (\n cp.previousAnchorId !== prevAnchorId ||\n cp.entryCount < 1 ||\n cp.entryCount <= prevCount\n ) {\n problems.add(\"checkpoint-sequence\", k);\n break;\n }\n if (cp.entryCount > n) {\n problems.add(\"checkpoint-overreach\", k);\n break;\n }\n const count = cp.entryCount;\n let bound = count <= firstMalformed;\n if (bound) {\n const first = entries[0]!;\n const tip = entries[count - 1]!;\n bound =\n cp.startEntryId === first.entryId &&\n cp.endEntryId === tip.entryId &&\n cp.chainHash ===\n anchorChainHashSync(\n prevAnchorHash,\n chainId,\n cp.startEntryId,\n cp.endEntryId,\n tip.chainHash\n );\n }\n if (!bound) {\n problems.add(\"checkpoint-binding\", k);\n break;\n }\n if (checkpointTrust) {\n const key = trust.checkpoint.get(cp.signingKeyId);\n if (key === undefined) {\n problems.add(\"checkpoint-unknown-key\", k);\n break;\n }\n if (!verifyMLDSA65Pure(key, checkpointCanonicalBytes(cp), cp.signature)) {\n problems.add(\"checkpoint-bad-signature\", k);\n break;\n }\n }\n passedCheckpoints++;\n covered = count;\n prevAnchorId = cp.anchorId;\n prevAnchorHash = cp.chainHash;\n prevCount = count;\n }\n\n // §7.7 Record signatures, and §7.8 authentication.\n let recordSignaturesPresent = 0;\n const recordAuthenticated: boolean[] = new Array<boolean>(n).fill(false);\n for (let i = 0; i < n; i++) {\n const e = entries[i]!;\n const rs = e.recordSignature;\n if (rs !== undefined) recordSignaturesPresent++;\n if (!recordTrust) continue;\n if (rs === undefined) {\n problems.add(\"unsigned\", i);\n continue;\n }\n const signature = HEX_32.test(rs.keyId) ? decodeCanonicalBase64(rs.signature) : null;\n if (signature === null || signature.length !== MLDSA65_SIGNATURE_SIZE) {\n problems.add(\"malformed-signature\", i);\n continue;\n }\n const key = trust.record.get(rs.keyId);\n if (key === undefined) {\n problems.add(\"unknown-key\", i);\n continue;\n }\n const envelopeBuildable =\n wellFormed[i] &&\n chainIdValid &&\n (e.entryType === \"sink.event\" || e.entryType === \"sink.erasure\") &&\n (e.previousHash === \"\") === (e.globalSeq === \"0\");\n if (!envelopeBuildable) {\n problems.add(\"bad-signature\", i);\n continue;\n }\n const fields = {\n chainId,\n entryId: e.entryId,\n entryType: e.entryType,\n globalSeq: e.globalSeq,\n previousHash: e.previousHash,\n timestamp: e.timestamp,\n contentHash: e.contentHash,\n signingKeyId: rs.keyId,\n };\n // v1: record.v1, empty context. v2 (§16 §7.7): record.v2 with the stored\n // leaf_hash as field 0x09, context aleutian.proof.record.v2.\n const verified =\n format === 1\n ? verifyMLDSA65Pure(key, buildRecordEnvelopeV1(fields), signature)\n : verifyMLDSA65PureWithContext(\n key,\n buildRecordEnvelopeV2({ ...fields, leafHash: e.leafHash! }),\n signature,\n RECORD_CONTEXT_V2\n );\n if (verified) recordAuthenticated[i] = true;\n else problems.add(\"bad-signature\", i);\n }\n\n let authenticated = 0;\n let checkpointAuthenticated = 0;\n let recordAuthenticatedCount = 0;\n const checkpointAuthenticatedAt = (i: number): boolean =>\n checkpointTrust && wellFormed[i] === true && i < covered;\n for (let i = 0; i < n; i++) {\n const byCheckpoint = checkpointAuthenticatedAt(i);\n const byRecord = recordAuthenticated[i] === true;\n if (byCheckpoint) checkpointAuthenticated++;\n if (byRecord) recordAuthenticatedCount++;\n if (byCheckpoint || byRecord) authenticated++;\n }\n\n // §7.9 Erasure state.\n let erasure: ProofBundleErasureState = \"none\";\n if (E >= 0 && genuineErasure[E]) {\n if (problems.empty && checkpointAuthenticatedAt(E)) erasure = \"anchored\";\n else if (problems.empty && recordAuthenticated[E]) erasure = \"signed\";\n else erasure = \"recorded\";\n }\n\n // §7.10 Verdict.\n const unauthenticated = n - authenticated;\n const verdict: ProofBundleVerdict = !problems.empty\n ? \"failed\"\n : unauthenticated > 0\n ? \"unauthenticated\"\n : \"ok\";\n\n return {\n verdict,\n erasure,\n counts: {\n entries: n,\n events,\n erasures,\n opened,\n committed,\n erased,\n checkpoints: passedCheckpoints,\n unanchored: n - covered,\n authenticated,\n unauthenticated,\n checkpoint_authenticated: checkpointAuthenticated,\n record_authenticated: recordAuthenticatedCount,\n record_signatures_present: recordSignaturesPresent,\n },\n problems: problems.list(),\n };\n}\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/** The caller's trust, held to its declared shape (the API boundary). */\nfunction checkTrustShape(trust: ProofBundleTrust): void {\n const t = trust as unknown;\n if (\n typeof t !== \"object\" ||\n t === null ||\n !Array.isArray((t as ProofBundleTrust).checkpointKeys) ||\n !Array.isArray((t as ProofBundleTrust).recordKeys)\n ) {\n throw new ProofBundleVerifierError(\n \"trust must be an object with checkpointKeys and recordKeys arrays of Uint8Array\"\n );\n }\n}\n\nasync function keyMap(\n keys: readonly Uint8Array[],\n role: string\n): Promise<Map<string, Uint8Array>> {\n const map = new Map<string, Uint8Array>();\n for (const key of keys) {\n if (!(key instanceof Uint8Array) || key.length !== MLDSA65_PUBLIC_KEY_SIZE) {\n throw new ProofBundleVerifierError(\n `${role} trust: every key must be a raw ${MLDSA65_PUBLIC_KEY_SIZE}-byte ML-DSA-65 public key`\n );\n }\n map.set(await keyIdMLDSA65(key), key);\n }\n return map;\n}\n\n/**\n * Verify a bundle under limits other than §5's. For tests only: a verifier\n * MUST accept every bundle within §5's limits, so production code calls\n * {@link verifyProofBundle}.\n *\n * @internal\n */\nexport async function verifyProofBundleWithLimits(\n bundle: Uint8Array,\n trust: ProofBundleTrust,\n limits: ProofBundleLimits\n): Promise<ProofBundleResult> {\n if (!(bundle instanceof Uint8Array)) {\n throw new ProofBundleVerifierError(\"bundle must be a Uint8Array\");\n }\n checkTrustShape(trust);\n const keys: TrustKeys = {\n checkpoint: await keyMap(trust.checkpointKeys, \"checkpoint\"),\n record: await keyMap(trust.recordKeys, \"record\"),\n };\n\n const read = readProofBundle(bundle, limits);\n if (!read.ok)\n return { result: PROOF_BUNDLE_RESULT_ID, readable: false, reason: read.reason };\n const chains = read.chains;\n\n // §8 Bundle-level checks: duplicate chain ids, compared as strings.\n const occurrences = new Map<string, number>();\n for (const c of chains)\n occurrences.set(c.chainId, (occurrences.get(c.chainId) ?? 0) + 1);\n const bundleProblems = new ProblemSet();\n const seen = new Set<string>();\n chains.forEach((c, i) => {\n if (seen.has(c.chainId)) bundleProblems.add(\"duplicate-chain\", i);\n seen.add(c.chainId);\n });\n\n const results: Record<string, ProofBundleChainResult> = {};\n let anyFailed = false;\n let anyUnauthenticated = false;\n for (let i = 0; i < chains.length; i++) {\n const c = chains[i]!;\n const r = verifyChain(c, keys, limits, read.format);\n const keyedById = SINK_CHAIN_ID.test(c.chainId) && occurrences.get(c.chainId) === 1;\n results[keyedById ? c.chainId : `#${i}`] = r;\n if (r.verdict === \"failed\") anyFailed = true;\n if (r.verdict === \"unauthenticated\") anyUnauthenticated = true;\n }\n\n const verdict: ProofBundleVerdict =\n anyFailed || !bundleProblems.empty\n ? \"failed\"\n : anyUnauthenticated || chains.length === 0\n ? \"unauthenticated\"\n : \"ok\";\n\n return {\n result: PROOF_BUNDLE_RESULT_ID,\n readable: true,\n checkpoint_trust: keys.checkpoint.size > 0 ? \"checked\" : \"not_checked\",\n record_trust: keys.record.size > 0 ? \"checked\" : \"not_checked\",\n verdict,\n bundle_problems: bundleProblems.list(),\n chains: results,\n };\n}\n\n/**\n * Verify an `aleutian.proof.bundle.v1` or `aleutian.proof.bundle.v2` bundle.\n *\n * # Description\n *\n * Applies bundle-format §3–§9 to the bundle bytes under the caller's trust and\n * returns the §9 result: either unreadable with its lowest-numbered reason, or\n * readable with both trust dimensions, the bundle verdict, bundle problems and\n * a result per chain. A dimension is checked exactly when its key set is\n * non-empty.\n *\n * # Inputs\n *\n * - bundle: the bundle file's exact bytes\n * - trust: raw 1952-byte ML-DSA-65 public keys trusted for checkpoints and\n * for record signatures (see `parseProofPublicKeyFile` for key files)\n *\n * # Outputs\n *\n * - ProofBundleResult: the §9 result. An unreadable or failing bundle is a\n * result, never an exception.\n * - ProofBundleVerifierError: thrown only when `bundle` is not a Uint8Array,\n * `trust` is not an object with two arrays, or a trust key is not a\n * 1952-byte Uint8Array. The message names no bundle value.\n *\n * # Example\n *\n * const result = await verifyProofBundle(bytes, {\n * checkpointKeys: [checkpointKey],\n * recordKeys: [],\n * });\n * if (result.readable && result.verdict === \"ok\") { ... }\n *\n * # Limitations\n *\n * - Holds the bundle and its parsed chains in memory (at most 256 MiB of\n * input and 15,000,000 JSON values for v1, 17,000,000 for v2, §5, §16);\n * hostile input is refused without\n * building more than a readable bundle would.\n * - A passing bundle proves only what §1 says: not that it holds every\n * chain, not that a chain is complete to its end, and nothing against a\n * writer that controls every key the verifier trusts.\n *\n * # Assumptions\n *\n * - WebCrypto (`crypto.subtle`) is available (Node ≥ 19, modern browsers).\n * - The caller chose the trust keys out of band; a bundle never adds a key.\n */\nexport function verifyProofBundle(\n bundle: Uint8Array,\n trust: ProofBundleTrust\n): Promise<ProofBundleResult> {\n return verifyProofBundleWithLimits(bundle, trust, PROOF_BUNDLE_LIMITS);\n}\n\n/**\n * The key ids present in both trust sets (§6: allowed, but one key for both\n * roles means one compromise forges both, so a verifier SHOULD warn).\n *\n * # Description\n *\n * Computes each key's id (format-spec §9.6) and returns those in both sets,\n * sorted.\n *\n * # Inputs\n *\n * - trust: the two key sets\n *\n * # Outputs\n *\n * - string[]: key ids trusted for both checkpoints and records\n * - ProofBundleVerifierError: thrown when `trust` is not an object with two\n * arrays, or a key is not a 1952-byte Uint8Array\n *\n * # Example\n *\n * for (const id of await keysTrustedForBothRoles(trust)) warn(id);\n *\n * # Limitations\n *\n * - Compares key ids, which name keys exactly (SHA-512 based).\n *\n * # Assumptions\n *\n * - None.\n */\nexport async function keysTrustedForBothRoles(\n trust: ProofBundleTrust\n): Promise<string[]> {\n checkTrustShape(trust);\n const checkpoint = await keyMap(trust.checkpointKeys, \"checkpoint\");\n const record = await keyMap(trust.recordKeys, \"record\");\n return [...checkpoint.keys()].filter((id) => record.has(id)).sort();\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Trust key files for proof bundles (bundle-format §6).\n *\n * A key file is PEM: EXACTLY one block, label `PUBLIC KEY`, no headers, a\n * canonical base64 body, and nothing but whitespace after it. The block holds\n * exactly the RFC 9881 SubjectPublicKeyInfo DER of a 1952-byte ML-DSA-65 key:\n * the same bytes its key id hashes (format-spec §9.6). That is what\n * `proof keygen` and `proof sink init` write. Anything else is refused.\n *\n * Browser-safe: this parses bytes; reading the file is the caller's job.\n */\n\nimport { decodeCanonicalBase64 } from \"./canonicalBase64.js\";\nimport { mldsa65Spki, MLDSA65_PUBLIC_KEY_SIZE } from \"./keyId.js\";\n\n/** Thrown for any key file that is not exactly what §6 allows. */\nexport class ProofKeyFileError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ProofKeyFileError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nconst BEGIN = \"-----BEGIN PUBLIC KEY-----\";\nconst END = \"-----END PUBLIC KEY-----\";\n// RFC 9881 SPKI of a 1952-byte key: 4-byte SEQUENCE header, 13-byte\n// AlgorithmIdentifier, 5-byte BIT STRING header, the key.\nconst SPKI_SIZE = 4 + 13 + 5 + MLDSA65_PUBLIC_KEY_SIZE;\nconst WHITESPACE_ONLY = /^[ \\t\\r\\n]*$/;\nconst BODY_LINE = /^[A-Za-z0-9+/=]+$/;\n\nfunction isAscii(bytes: Uint8Array): boolean {\n for (const b of bytes) if (b > 0x7f) return false;\n return true;\n}\n\n/**\n * Parse a trust key file into a raw ML-DSA-65 public key.\n *\n * # Description\n *\n * Accepts one PEM block labelled `PUBLIC KEY`, optionally surrounded by\n * whitespace, whose body lines (ending in LF or CRLF) join to canonical base64\n * of exactly the RFC 9881 SPKI DER of a 1952-byte ML-DSA-65 key. Returns the\n * raw 1952-byte key.\n *\n * # Inputs\n *\n * - bytes: the whole key file\n *\n * # Outputs\n *\n * - Uint8Array: the raw 1952-byte public key\n * - ProofKeyFileError: thrown, with a fixed message that quotes nothing from\n * the file, for any other file\n *\n * # Example\n *\n * const pk = parseProofPublicKeyFile(await readFile(\"checkpoint.pub\"));\n *\n * # Limitations\n *\n * - ML-DSA-65 only. Text before the block is refused (only whitespace may\n * surround it).\n *\n * # Assumptions\n *\n * - None.\n */\nexport function parseProofPublicKeyFile(bytes: Uint8Array): Uint8Array {\n if (!isAscii(bytes)) throw new ProofKeyFileError(\"key file: not an ASCII PEM file\");\n let text = \"\";\n for (const b of bytes) text += String.fromCharCode(b);\n\n const begin = text.indexOf(BEGIN);\n if (begin < 0 || !WHITESPACE_ONLY.test(text.slice(0, begin))) {\n throw new ProofKeyFileError(\n \"key file: not exactly one PEM block labelled PUBLIC KEY\"\n );\n }\n const afterBegin = begin + BEGIN.length;\n const end = text.indexOf(END, afterBegin);\n if (end < 0) throw new ProofKeyFileError(\"key file: PEM block not terminated\");\n if (!WHITESPACE_ONLY.test(text.slice(end + END.length))) {\n throw new ProofKeyFileError(\n \"key file: something other than whitespace after the PEM block\"\n );\n }\n\n // Between the markers: a line break, then body lines each ending in a line\n // break. Anything else (a header, a blank line, stray spaces) is refused.\n const inner = text.slice(afterBegin, end);\n const lines = inner.split(\"\\n\");\n if (\n lines.length < 3 ||\n (lines[0] !== \"\" && lines[0] !== \"\\r\") ||\n lines[lines.length - 1] !== \"\"\n ) {\n throw new ProofKeyFileError(\"key file: malformed PEM body\");\n }\n let body = \"\";\n for (const raw of lines.slice(1, -1)) {\n const line = raw.endsWith(\"\\r\") ? raw.slice(0, -1) : raw;\n if (!BODY_LINE.test(line))\n throw new ProofKeyFileError(\"key file: malformed PEM body\");\n body += line;\n }\n\n const der = decodeCanonicalBase64(body);\n if (der === null) throw new ProofKeyFileError(\"key file: body is not canonical base64\");\n if (der.length !== SPKI_SIZE) {\n throw new ProofKeyFileError(\"key file: not the SPKI of an ML-DSA-65 public key\");\n }\n const key = der.slice(SPKI_SIZE - MLDSA65_PUBLIC_KEY_SIZE);\n const expected = mldsa65Spki(key);\n for (let i = 0; i < SPKI_SIZE; i++) {\n if (der[i] !== expected[i]) {\n throw new ProofKeyFileError(\"key file: not the SPKI of an ML-DSA-65 public key\");\n }\n }\n return key;\n}\n","{\"public_key_b64\": \"R+dFhtvIZmQtyLr2S3xal9jvJAcfihEtBBuEclDzwxsIPWO1N3mkxAPIr/NUnVQllItEDs1Rtp3idRUT/qDULpnQr37XYivMrPbv35tjM9BELAQ17B1TPk//sacNZQ/6Utfp7YzawCEfnvMnqdQNJuWxgxGSIce+wzh5WsgPWDDGmCHgBrxDQKx0D9/AyTcbWq2E+qhe8kxVXm9Nitsz59vO4N/Ru6H3WrZAIhFFAiLpDYi0Sth8jPuwMr8kLHcbPwVkMbxlTbd+dUQYUL5URm/COlMWxogKSkpLhkEQdlS+ibamwdV8sSydSricaDkezeCCuzKZEHd5k09GBTN+UMmwo1RzB+Aq5G+9FhSvm9rj4r8zyu7zEVA4iBwM9vofVQ14+SDgcMbUBtQkqqsKri7IPeQ8QAyybztBIMA4DeUtYWmI1d65mqPH2EqoxAqVno/q6oQdPrrBo0zBeR71S420AXULV3rZymVjYFxTz5gv4A1myVsIbjEoh3k5Zv6Akp7fvjkhgYOyg37JSJn193chl9nCkUSWMr8oh/psY6u++oHycOkSe+HZgbZ4iFoCnh5KeOGrbs5v9iuuaEaesB1woJArCGI/OC6w7cvHITUw805YxNaW4xOCGWyZHp0IBUUYsUtJkm95qF07poIlXpVOOxDhAUtyaTShqGEcD65TN+V6+uYmF/oAtB8c1W+SCHwE5NWIeTN6GS4fNPD9pjRJ/BoxywGec+1CgMSamje/8gNI9HHGACTT8gc5rIQzeGJeHbA+M7eCUU7S9PPmIM+b0nTPdT3U8UV71NfiKxI5kz2wwRF9+DQiTchqZDW1YZtLWKZil91lu49Vl/OQLj1N28epsb+8xdCNW2nge+0Mf7T5NuQlJbDGkCltKM00lMLHqxvUwZK3Wm/25ih6CiEPJ1WMN53Ng8V7AbpmTIWUi4cosjsnffIKinEYO/ncuUrIfHgFPweZu1U/kZpgCfO8QxsneG7ro1dqpSa5/AHQi1/GuOe1NngaQefvz07sReR4DIEiUcbG77/Z923uVPBuEta5fYZFBEsQTc8zWfTg581tMW6Qog1Nn2pVr4PqSbHx7PUWgoegCfs0aRAEe1VR3yvuagPJwjMZ9UrwjAqW+7MIGZYtGVzn7Wx1Xlr/M0hLH/rATyPBTPESQNRFEuZUqIcyzuVr3vkNtaZnZC8xbKaOKt3S55BxQeUsprESq/T7CiVRU5IqpyzfpSp6fhRJiC+J+lDzw5jU3xyUb85FFLbOHPAyBMjVSeKXj2Pmfq89yaMxeGVS6ntdrgeD8WBd+echHhLtyuLSIgBtaD6I02IhT5YubpQ69MUsvaSZe1gpvRJ4sQUSjiy4kVbEbt8AYmzvWv7oheVA5N7kJPg0clFhDWvR7fgHA9W+L9tyUi8NAro02+n6hSnJQx9EtWbtLyYGP9pZJeqwjgxtpdtZDTnWTpMxwTqFHbebElUS1YyRHOkr/94kpFB4FxdrujPFNCv/udvJh1fWLTloEiJgX853WHUzQLbMCddeFjELaZgZIYZlVylW+h3jB6S0pGrb+RYmeJY4GNHcGpz7oz0DzV7zZVh4UMKQiQTQE/P04iysJo0Y7p01na+evgNxX3rQamzP5V2P40TfCJhdM+A/DiTsJ0C2B2PhMz46DdzuRngFWF831fg16lgqaIl00jK5UR4iIxNLdGmwlwxpWO5K5KXE/ETcVdKcqPI6IX8alvHbJJhNXUmV7znA2fRIeXY1w1VLMxTdgVgCa4e7+saXrcdIxSK5B7LcAHaV2/vX/6aFO29Kd2lxjlO7qHGjgOAw3rxz2EqA9m06VH4MsOvhNOgme1nPAH2aICN8ZphN2RSE0GqbCccKi8uTfZL943ZcZApgPXNImEMneiXr2gw62Z7zAs7rYXRE1bRby/VugLmR1G95SH6Zyy0n2nXoG0JFyNkMIWGIByoFTjodx1Jw5Pq1xheHi+14UIqHHWwVEj7mpREpBAOcAC0Ul2L1OJtmVq826WJaBzBf+zfoUr7upW4ZK1uUa2f2XFoKUxsxIBF8FosKiMRnqM6MBHveLJnQD2bQXwd4EYCPSc8m5aPBYDfNIwjqLmtIn1taFYJ6V7S78WTgzT5q+Uhj/rLA7g33JYSiD8YS2ahoKFJpNpNEDv9Xl/cQRfkbvikNVNfXy/MG9S7jgGrwnx6epnTFZJMKRXpOqmx+7ImrhEk9Xmji0QR9Roo3AY0u4x4ZhNxJJVjoD3nHlzuFAy3+kpatHdC2l1HOe7fR0QygIrG1Tg44vXMi4igxA2hwK+7MKwldLsQ/bgMO1FMkYkhnH+N3tFj2rEXBhsXLiU3+Diwz44U8mjoegYu7GDQwLSsOtWTkILUJgmdnQcWOwbepy1/2qikglXWmNZj0ekLaOIO+bUq3hn9LP6nBWf4jmMZP1jUI/XvBKw1bCvbCb0dzxFdwLsoiHyAEqVdzdeyhjDdQyAYYzy0V6ASyzHg9lMZXgYdwY0ao+lJaR+mNcmGpQ7YNugIC/cpcZ2lGCN/4sZCcDM6zguWhkjuy9sVwLNGbvoFZQuEwZpcMxeKteQzKFZokXE5j/naVBlLaH4K+hBaAxbI=\"}","{\"public_key_b64\": \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"}","{\"public_key_b64\": \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"}","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Customer SDK live-manifest fetcher (15n_H1.3).\n *\n * # Description\n *\n * `loadTrustManifest` fetches the current trust-store manifest from the\n * audit-api endpoint, verifies its ML-DSA-65 signature against the\n * SDK-pinned `TRUST_ROOT_PUBLIC_KEY`, and returns a snapshot indexed by\n * `key_id`. A per-process in-memory cache absorbs repeated calls until\n * the TTL expires.\n *\n * # Trust model\n *\n * - The audit-api endpoint is an UNTRUSTED transport. Whatever bytes\n * it returns are verified against the SDK-pinned root pubkey before\n * any leaf key is exposed.\n * - The SDK never trusts a server-provided root claim. The fixture is\n * the trust anchor.\n *\n * # Pinning strategy\n *\n * Mirrors the Python SDK pattern (runtime env selection — JS doesn't\n * have build tags). At module load the env is selected from\n * `process.env.ALEUTIAN_ENV`, defaulting to `dev`. Production\n * deployments MUST set `ALEUTIAN_ENV=prod` BEFORE this module is\n * imported.\n *\n * # Ticket\n *\n * - tickets/planned/15n_H1_3_sdk_manifest_js.md\n * - docs/technical_specifications/audit_details/21_trust_store_sdk_consumer_design.md\n */\n\nimport { ml_dsa65 } from \"@noble/post-quantum/ml-dsa.js\";\n\nimport devRoot from \"./fixtures/trust-root-dev.json\" with { type: \"json\" };\nimport stagingRoot from \"./fixtures/trust-root-staging.json\" with { type: \"json\" };\nimport prodRoot from \"./fixtures/trust-root-prod.json\" with { type: \"json\" };\n\n/** Raw ML-DSA-65 public key size per FIPS 204. */\nexport const MLDSA65_PUBLIC_KEY_SIZE = 1952;\n\n/** Canonical root key identifier used in manifest audit markers. */\nexport const TRUST_ROOT_KEY_ID = \"trust-root-mldsa65\";\n\nfunction selectTrustRootEnv(): string {\n const env =\n typeof process !== \"undefined\" && process.env && process.env.ALEUTIAN_ENV\n ? process.env.ALEUTIAN_ENV\n : \"dev\";\n if (env === \"prod\" || env === \"staging\" || env === \"dev\") {\n return env;\n }\n return \"dev\";\n}\n\nfunction loadTrustRootFixture(env: string): Uint8Array {\n const fixture =\n env === \"prod\" ? prodRoot : env === \"staging\" ? stagingRoot : devRoot;\n const b64 = (fixture as { public_key_b64: string }).public_key_b64;\n const raw = base64ToUint8(b64);\n if (raw.length !== MLDSA65_PUBLIC_KEY_SIZE) {\n throw new Error(\n `verification: fixtures/trust-root-${env}.json yielded ${raw.length} bytes; ` +\n `want ${MLDSA65_PUBLIC_KEY_SIZE}. Re-run 15n_fix_A4 Step 2 for ${env}.`,\n );\n }\n return raw;\n}\n\n/** Env label selected at module load (\"dev\" / \"staging\" / \"prod\"). */\nexport const ACTIVE_TRUST_ENV: string = selectTrustRootEnv();\n\n/** Pinned ML-DSA-65 root public key for the selected env (raw 1952 bytes). */\nexport const TRUST_ROOT_PUBLIC_KEY: Uint8Array = loadTrustRootFixture(\n ACTIVE_TRUST_ENV,\n);\n\n/**\n * Return true if TRUST_ROOT_PUBLIC_KEY is the all-zero placeholder\n * shipped before the 15n_fix_A4 ceremony populates the env fixture.\n *\n * Use `loadTrustManifest` checks this before any verify; placeholder\n * root cannot validate anything.\n */\nexport function isTrustRootPlaceholder(): boolean {\n for (let i = 0; i < TRUST_ROOT_PUBLIC_KEY.length; i++) {\n if (TRUST_ROOT_PUBLIC_KEY[i] !== 0) {\n return false;\n }\n }\n return true;\n}\n\n// ─── Errors ─────────────────────────────────────────────────────────────────\n\nexport class TrustManifestError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n ) {\n super(message);\n this.name = \"TrustManifestError\";\n }\n}\n\nexport class ManifestUnavailableError extends TrustManifestError {\n constructor(message: string) {\n super(message, \"manifest_unavailable\");\n this.name = \"ManifestUnavailableError\";\n }\n}\nexport class ManifestMalformedError extends TrustManifestError {\n constructor(message: string) {\n super(message, \"manifest_malformed\");\n this.name = \"ManifestMalformedError\";\n }\n}\nexport class ManifestRootSignatureError extends TrustManifestError {\n constructor(message: string) {\n super(message, \"manifest_root_signature\");\n this.name = \"ManifestRootSignatureError\";\n }\n}\nexport class TrustRootPlaceholderError extends TrustManifestError {\n constructor(message: string) {\n super(message, \"trust_root_placeholder\");\n this.name = \"TrustRootPlaceholderError\";\n }\n}\nexport class OfflineOnlyError extends TrustManifestError {\n constructor(message: string) {\n super(message, \"offline_only\");\n this.name = \"OfflineOnlyError\";\n }\n}\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface TrustManifestEntry {\n readonly keyId: string;\n readonly kmsKeyVersion: string;\n readonly publicKeyB64: string;\n readonly algorithm: string;\n readonly addedAtMs: number;\n readonly revokedAtMs: number | null;\n readonly notAfterMs: number | null;\n readonly tenantId: string;\n}\n\nexport interface TrustManifest {\n readonly version: number;\n readonly generatedAt: Date;\n readonly env: string;\n readonly approvedBy: string;\n readonly rootKeyId: string;\n readonly schemaNote: string;\n readonly platformKeys: ReadonlyArray<TrustManifestEntry>;\n readonly tenantKeys: ReadonlyArray<TrustManifestEntry>;\n publicKey(keyId: string): Uint8Array | undefined;\n keyIds(): string[];\n}\n\nexport interface LoadTrustManifestOptions {\n /** Override the default audit-api endpoint. */\n baseUrl?: string;\n /** Cache TTL in milliseconds. Default 3,600,000 (1 hour). 0 disables. */\n cacheTtlMs?: number;\n /** Injectable fetch (for tests or Cloudflare Workers). Default: global fetch. */\n fetch?: typeof fetch;\n /** Use cached manifest on fetch failure. Default false (strict). */\n allowStale?: boolean;\n /** Skip network; return cache or throw OfflineOnlyError. Default false. */\n offlineOnly?: boolean;\n /** Per-request timeout in ms (default fetch only). Default 30,000. */\n timeoutMs?: number;\n}\n\n// ─── Implementation ─────────────────────────────────────────────────────────\n\nfunction defaultBaseUrl(): string {\n if (ACTIVE_TRUST_ENV === \"prod\") return \"https://audit-api.aleutian.ai\";\n if (ACTIVE_TRUST_ENV === \"staging\")\n return \"https://audit-api.staging.aleutian.ai\";\n return \"https://audit-api.dev.aleutian.ai\";\n}\n\nlet cachedManifest: TrustManifest | null = null;\nlet cachedAt = 0;\n\n/**\n * Wipe the per-process cache. Intended for tests; production callers\n * should not need this.\n */\nexport function clearTrustManifestCache(): void {\n cachedManifest = null;\n cachedAt = 0;\n}\n\n/**\n * Fetch, verify, and return the current trust manifest.\n *\n * # Inputs\n * - opts: see LoadTrustManifestOptions.\n *\n * # Returns\n * A read-only TrustManifest snapshot.\n *\n * # Throws\n * - TrustRootPlaceholderError when the SDK build ships with the\n * all-zero placeholder root.\n * - OfflineOnlyError when offlineOnly=true and no cached manifest.\n * - ManifestUnavailableError on transport / non-200 failure when\n * allowStale didn't yield a cached snapshot.\n * - ManifestMalformedError when the body doesn't parse.\n * - ManifestRootSignatureError when signature verification fails.\n */\nexport async function loadTrustManifest(\n opts: LoadTrustManifestOptions = {},\n): Promise<TrustManifest> {\n const cacheTtlMs = opts.cacheTtlMs ?? 3_600_000; // 1 hour default per H1.0\n const allowStale = opts.allowStale ?? false;\n const offlineOnly = opts.offlineOnly ?? false;\n\n if (isTrustRootPlaceholder() && !offlineOnly) {\n throw new TrustRootPlaceholderError(\n `env=${ACTIVE_TRUST_ENV}; SDK build is missing the post-ceremony ` +\n `root fixture. Re-bundle the SDK with the real trust-root-${ACTIVE_TRUST_ENV}.json.`,\n );\n }\n\n if (offlineOnly) {\n if (cachedManifest) return cachedManifest;\n throw new OfflineOnlyError(\n \"offlineOnly=true and no cached manifest available\",\n );\n }\n\n if (cacheTtlMs > 0 && cachedManifest && Date.now() - cachedAt < cacheTtlMs) {\n return cachedManifest;\n }\n\n const baseUrl = (opts.baseUrl ?? defaultBaseUrl()).replace(/\\/+$/, \"\");\n const url = `${baseUrl}/v1/trust/manifest`;\n const fetchFn = opts.fetch ?? globalThis.fetch;\n if (!fetchFn) {\n throw new ManifestUnavailableError(\n \"no fetch available; pass opts.fetch or run on a fetch-capable runtime\",\n );\n }\n\n let raw: string;\n try {\n const ac = new AbortController();\n const timeout = setTimeout(\n () => ac.abort(),\n opts.timeoutMs ?? 30_000,\n );\n let resp: Response;\n try {\n resp = await fetchFn(url, {\n method: \"GET\",\n headers: {\n \"User-Agent\": \"aleutian-verification-js/1.0\",\n Accept: \"application/json\",\n },\n signal: ac.signal,\n });\n } finally {\n clearTimeout(timeout);\n }\n if (!resp.ok) {\n throw new ManifestUnavailableError(\n `GET ${url} returned ${resp.status}`,\n );\n }\n raw = await resp.text();\n if (raw.length > 8 * 1024 * 1024) {\n throw new ManifestMalformedError(\n `GET ${url} body exceeded 8 MiB`,\n );\n }\n } catch (e) {\n if (e instanceof ManifestMalformedError) throw e;\n const wrapped =\n e instanceof ManifestUnavailableError\n ? e\n : new ManifestUnavailableError(\n `GET ${url}: ${(e as Error).message ?? e}`,\n );\n if (allowStale && cachedManifest) return cachedManifest;\n throw wrapped;\n }\n\n const manifest = parseVerifyAndIndex(raw);\n cachedManifest = manifest;\n cachedAt = Date.now();\n return manifest;\n}\n\n/**\n * Parse, signature-verify against the SDK-pinned root, and index\n * non-revoked leaves by key_id. Returns a frozen, read-only snapshot.\n */\n/**\n * Parse + root-signature-verify a manifest from text/bytes, no network.\n *\n * Offline entry point for the CISO \"verify against published keys\" motion\n * (chainlinker_modernization_12f_e): a customer downloads the published\n * manifest once and verifies exported chains against it with zero egress.\n * Shares the exact parse -> verify-root-signature -> index invariant as\n * {@link loadTrustManifest}; only the transport differs. The returned\n * snapshot carries `version` + `generatedAt`, which callers feed to\n * `evaluateManifestFreshness` (see `manifestFreshness.ts`).\n *\n * @throws ManifestMalformedError / ManifestRootSignatureError on failure.\n */\nexport function parseAndVerifyTrustManifest(\n raw: string | Uint8Array,\n): TrustManifest {\n const text =\n typeof raw === \"string\" ? raw : new TextDecoder().decode(raw);\n return parseVerifyAndIndex(text);\n}\n\nfunction parseVerifyAndIndex(rawText: string): TrustManifest {\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawText);\n } catch (e) {\n throw new ManifestMalformedError(\n `JSON parse: ${(e as Error).message}`,\n );\n }\n if (\n !parsed ||\n typeof parsed !== \"object\" ||\n Array.isArray(parsed)\n ) {\n throw new ManifestMalformedError(\"manifest root is not a JSON object\");\n }\n const body = parsed as Record<string, unknown>;\n\n const sigB64 = body.root_signature_b64;\n if (!sigB64 || typeof sigB64 !== \"string\") {\n throw new ManifestMalformedError(\n \"missing or non-string root_signature_b64\",\n );\n }\n let sig: Uint8Array;\n try {\n sig = base64ToUint8(sigB64);\n } catch (e) {\n throw new ManifestMalformedError(\n `root_signature_b64 not base64: ${(e as Error).message}`,\n );\n }\n\n // Canonical JSON over body sans root_signature_b64.\n const bodySansSig: Record<string, unknown> = { ...body };\n delete bodySansSig.root_signature_b64;\n const canonical = canonicalJson(bodySansSig);\n const canonicalBytes = new TextEncoder().encode(canonical);\n\n try {\n // noble signature: ml_dsa65.verify(sig, msg, pubKey)\n const ok = ml_dsa65.verify(sig, canonicalBytes, TRUST_ROOT_PUBLIC_KEY);\n if (!ok) {\n throw new Error(\"ml_dsa65.verify returned false\");\n }\n } catch (e) {\n throw new ManifestRootSignatureError(\n `verify against pinned root: ${(e as Error).message ?? e}`,\n );\n }\n\n const platformKeys = ((body.platform_keys as unknown[]) ?? [])\n .map(parseEntry);\n const tenantKeys = ((body.tenant_keys as unknown[]) ?? [])\n .map(parseEntry);\n\n const keys = new Map<string, Uint8Array>();\n for (const e of [...platformKeys, ...tenantKeys]) {\n if (e.revokedAtMs !== null) continue;\n if (!e.publicKeyB64) continue;\n try {\n keys.set(e.keyId, base64ToUint8(e.publicKeyB64));\n } catch (err) {\n throw new ManifestMalformedError(\n `entry ${e.keyId}: public_key_b64 not base64: ${(err as Error).message}`,\n );\n }\n }\n\n const generatedAtMs = numberFromBody(body.generated_at_ms);\n const manifest: TrustManifest = Object.freeze({\n version: numberFromBody(body.version),\n generatedAt: new Date(generatedAtMs),\n env: stringFromBody(body.env),\n approvedBy: stringFromBody(body.approved_by),\n rootKeyId: stringFromBody(body.root_key_id),\n schemaNote: stringFromBody(body.schema_note),\n platformKeys: Object.freeze(platformKeys),\n tenantKeys: Object.freeze(tenantKeys),\n publicKey(keyId: string): Uint8Array | undefined {\n // Defensive copy: callers must not be able to mutate the cached\n // public key bytes. Mirrors V3 H6 (trust manifest immutability).\n // Ticket: dsar_js_trust_manifest_key_mutability.\n const k = keys.get(keyId);\n return k ? new Uint8Array(k) : undefined;\n },\n keyIds(): string[] {\n return Array.from(keys.keys()).sort();\n },\n });\n return manifest;\n}\n\nfunction parseEntry(raw: unknown): TrustManifestEntry {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n throw new ManifestMalformedError(\"entry is not a JSON object\");\n }\n const e = raw as Record<string, unknown>;\n return Object.freeze({\n keyId: stringFromBody(e.key_id),\n kmsKeyVersion: stringFromBody(e.kms_key_version),\n publicKeyB64: stringFromBody(e.public_key_b64),\n algorithm: stringFromBody(e.algorithm),\n addedAtMs: numberFromBody(e.added_at_ms),\n revokedAtMs: e.revoked_at_ms == null ? null : numberFromBody(e.revoked_at_ms),\n notAfterMs: e.not_after_ms == null ? null : numberFromBody(e.not_after_ms),\n tenantId: stringFromBody(e.tenant_id),\n });\n}\n\nfunction stringFromBody(v: unknown): string {\n if (typeof v === \"string\") return v;\n if (v == null) return \"\";\n return String(v);\n}\n\nfunction numberFromBody(v: unknown): number {\n if (typeof v === \"number\") return v;\n if (typeof v === \"string\") {\n const n = Number(v);\n if (Number.isFinite(n)) return n;\n }\n return 0;\n}\n\n/**\n * Byte-for-byte mirror of internal/compliance/trust_store_loader.go\n * canonicalJSON():\n * - object keys recursively sorted lexicographically\n * - no insignificant whitespace\n * - strings NOT HTML-escaped\n * - UTF-8 output, non-ASCII inline (NOT \\uXXXX escaped)\n * - numbers preserved as JSON.stringify renders them\n *\n * Exported for the cross-language parity test (H1.4).\n */\nexport function canonicalJson(value: unknown): string {\n return writeCanonical(value);\n}\n\nfunction writeCanonical(v: unknown): string {\n if (v === null) return \"null\";\n if (typeof v === \"boolean\") return v ? \"true\" : \"false\";\n if (typeof v === \"number\") {\n if (!Number.isFinite(v)) {\n throw new ManifestMalformedError(\n `canonicalJson: non-finite number ${v}`,\n );\n }\n return JSON.stringify(v);\n }\n if (typeof v === \"string\") {\n return JSON.stringify(v);\n }\n if (Array.isArray(v)) {\n return \"[\" + v.map(writeCanonical).join(\",\") + \"]\";\n }\n if (typeof v === \"object\") {\n const obj = v as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const parts = keys.map(\n (k) => JSON.stringify(k) + \":\" + writeCanonical(obj[k]),\n );\n return \"{\" + parts.join(\",\") + \"}\";\n }\n throw new ManifestMalformedError(\n `canonicalJson: unsupported type ${typeof v}`,\n );\n}\n\n// Local base64 decoder — Uint8Array helper. Mirrors hash.ts's\n// base64ToUint8Array but kept inline so trustManifest.ts has no internal\n// import dependencies (clean public surface).\nfunction base64ToUint8(b64: string): Uint8Array {\n if (typeof atob === \"function\") {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n }\n // Node fallback\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const buf = (globalThis as any).Buffer.from(b64, \"base64\");\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * `aleutian-verify verify-proof-bundle`: verify a proof sink export bundle\n * (`aleutian.proof.bundle.v1` or `.v2`) under trust the operator supplies.\n *\n * ```\n * aleutian-verify verify-proof-bundle <bundle.json>\n * [--checkpoint-key F]... [--record-key F]... [--json]\n * ```\n *\n * The verb is distinct from `verify`, which checks platform bundles that carry\n * their own trust manifest: here trust is the verifier's (bundle-format §6).\n *\n * Exit codes (bundle-format §11):\n *\n * 0 ok\n * 1 failed\n * 2 usage: bad arguments; a missing or unreadable bundle or key file; an\n * invalid key file\n * 3 an unreadable bundle (§9.1)\n * 4 unauthenticated\n * 5 an internal error in the verifier: never a verdict on the bundle\n *\n * NO-LEAK RULE (§10): on every channel, nothing from the bundle is printed\n * except valid chain ids (result keys are valid ids or `#<i>`), problem codes\n * and indexes. Internal errors print a fixed message, never the error's text\n * or stack.\n */\n\nimport { constants } from \"node:fs\";\nimport { open, readFile, stat, type FileHandle } from \"node:fs/promises\";\n\nimport {\n keysTrustedForBothRoles,\n PROOF_BUNDLE_LIMITS,\n PROOF_BUNDLE_RESULT_ID,\n verifyProofBundle,\n type ProofBundleChainResult,\n type ProofBundleProblem,\n type ProofBundleReadableResult,\n type ProofBundleResult,\n type ProofBundleTrust,\n} from \"../proofBundle.js\";\nimport { parseProofPublicKeyFile, ProofKeyFileError } from \"../proofKeyFile.js\";\n\n/** Exit codes, bundle-format §11. */\nexport const PROOF_BUNDLE_EXIT = Object.freeze({\n ok: 0,\n failed: 1,\n usage: 2,\n unreadable: 3,\n unauthenticated: 4,\n internal: 5,\n});\n\n/** Where the command writes. Injectable so tests can capture both channels. */\nexport interface ProofBundleCliIO {\n readonly stdout: (text: string) => void;\n readonly stderr: (text: string) => void;\n}\n\nconst PROCESS_IO: ProofBundleCliIO = {\n stdout: (text) => void process.stdout.write(text),\n stderr: (text) => void process.stderr.write(text),\n};\n\nconst USAGE = [\n \"usage: aleutian-verify verify-proof-bundle <bundle.json> [--checkpoint-key F]... [--record-key F]... [--json]\",\n \"\",\n \"Verify a proof sink export bundle (aleutian.proof.bundle.v1 or .v2) under the keys you trust.\",\n \" --checkpoint-key F a PEM public key trusted for checkpoints (repeatable)\",\n \" --record-key F a PEM public key trusted for record signatures (repeatable)\",\n \" --json print exactly the aleutian.proof.bundle-result.v1 JSON\",\n \"Exit 0 ok, 1 failed, 2 usage, 3 unreadable bundle, 4 unauthenticated, 5 internal error.\",\n \"\",\n].join(\"\\n\");\n\nconst LIMITS_LINE =\n \"Limits (bundle-format §1): a pass does not prove that the bundle holds every chain, that a chain \" +\n \"is complete to its end, that erased content is gone anywhere, that timestamps are true time, or \" +\n \"which sink a chain came from; it proves nothing against a writer who controls the evidence and \" +\n \"every key you trust, and nothing about what happened after the export.\";\n\ninterface ParsedArgs {\n readonly bundlePath: string;\n readonly checkpointKeyPaths: string[];\n readonly recordKeyPaths: string[];\n readonly json: boolean;\n}\n\nclass UsageError extends Error {}\n\n/**\n * The largest key file read. A valid one is about 2.7 KB (one PEM block of a\n * 1974-byte SPKI); the rest of the room is for surrounding whitespace.\n */\nconst MAX_KEY_FILE_BYTES = 16 * 1024;\n\nfunction parseArgs(args: readonly string[]): ParsedArgs {\n let bundlePath: string | undefined;\n const checkpointKeyPaths: string[] = [];\n const recordKeyPaths: string[] = [];\n let json = false;\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!;\n const value = (): string => {\n const v = args[i + 1];\n if (v === undefined) throw new UsageError(`${arg} requires a file`);\n i++;\n return v;\n };\n if (arg === \"--checkpoint-key\") checkpointKeyPaths.push(value());\n else if (arg === \"--record-key\") recordKeyPaths.push(value());\n else if (arg === \"--json\") json = true;\n else if (arg.startsWith(\"-\")) throw new UsageError(`unknown flag: ${arg}`);\n else if (bundlePath === undefined) bundlePath = arg;\n else throw new UsageError(\"exactly one bundle file is required\");\n }\n if (bundlePath === undefined) throw new UsageError(\"a bundle file is required\");\n return { bundlePath, checkpointKeyPaths, recordKeyPaths, json };\n}\n\nasync function loadKey(path: string): Promise<Uint8Array> {\n let bytes: Uint8Array;\n try {\n // stat first: never open a FIFO or device (it could block or never end).\n const info = await stat(path);\n if (!info.isFile()) throw new UsageError(`key file is not a regular file: ${path}`);\n if (info.size > MAX_KEY_FILE_BYTES) {\n throw new UsageError(\n `key file is larger than ${MAX_KEY_FILE_BYTES} bytes: ${path}`\n );\n }\n bytes = await readFile(path);\n } catch (err) {\n if (err instanceof UsageError) throw err;\n throw new UsageError(`cannot read key file ${path}`);\n }\n if (bytes.length > MAX_KEY_FILE_BYTES) {\n throw new UsageError(`key file is larger than ${MAX_KEY_FILE_BYTES} bytes: ${path}`);\n }\n try {\n return parseProofPublicKeyFile(bytes);\n } catch (err) {\n if (err instanceof ProofKeyFileError)\n throw new UsageError(`invalid key file ${path}: ${err.message}`);\n throw err;\n }\n}\n\n/**\n * The bundle bytes, or null when the file is over the §5 size limit.\n *\n * Opens the file once and reads at most limit + 1 bytes, so a file that grows\n * after it is opened is still judged by what was read. O_NONBLOCK keeps the\n * open from waiting on a FIFO, which is then refused as not a regular file.\n */\nasync function loadBundle(path: string): Promise<Uint8Array | null> {\n const limit = PROOF_BUNDLE_LIMITS.bundleBytes;\n let handle: FileHandle;\n try {\n handle = await open(path, constants.O_RDONLY | (constants.O_NONBLOCK ?? 0));\n } catch {\n throw new UsageError(`cannot read bundle file ${path}`);\n }\n try {\n const info = await handle.stat();\n if (!info.isFile()) throw new UsageError(`not a regular file: ${path}`);\n if (info.size > limit) return null;\n const cap = limit + 1;\n let buf = new Uint8Array(Math.min(info.size + 1, cap));\n let n = 0;\n for (;;) {\n if (n === buf.length) {\n if (buf.length >= cap) break;\n const grown = new Uint8Array(Math.min(buf.length * 2, cap));\n grown.set(buf);\n buf = grown;\n }\n const { bytesRead } = await handle.read(buf, n, buf.length - n, null);\n if (bytesRead === 0) break;\n n += bytesRead;\n }\n return n > limit ? null : buf.subarray(0, n);\n } catch (err) {\n if (err instanceof UsageError) throw err;\n throw new UsageError(`cannot read bundle file ${path}`);\n } finally {\n await handle.close().catch(() => undefined);\n }\n}\n\nfunction exitCode(result: ProofBundleResult): number {\n if (!result.readable) return PROOF_BUNDLE_EXIT.unreadable;\n if (result.verdict === \"failed\") return PROOF_BUNDLE_EXIT.failed;\n if (result.verdict === \"unauthenticated\") return PROOF_BUNDLE_EXIT.unauthenticated;\n return PROOF_BUNDLE_EXIT.ok;\n}\n\nfunction problemsText(\n problems: readonly ProofBundleProblem[],\n indexLabel: string\n): string {\n return problems\n .map(\n (p) =>\n `${p.code} x${p.count}${p.first === null ? \"\" : ` (first at ${indexLabel} ${p.first})`}`\n )\n .join(\", \");\n}\n\nfunction chainLine(key: string, r: ProofBundleChainResult): string[] {\n const c = r.counts;\n const lines = [\n ` ${key}: ${r.verdict.toUpperCase()}, erasure ${r.erasure}; ${c.entries} entries ` +\n `(${c.authenticated} authenticated, ${c.unauthenticated} unauthenticated), ` +\n `${c.checkpoints} checkpoints, ${c.unanchored} unanchored`,\n ];\n if (r.problems.length > 0) {\n lines.push(` problems: ${problemsText(r.problems, \"index\")}`);\n }\n return lines;\n}\n\n/** §10 for an unreadable bundle: the reason, both trust dimensions, the limits. */\nfunction unreadableText(reason: string, trust: ProofBundleTrust): string {\n return [\n `Proof bundle: UNREADABLE (${reason})`,\n `Checkpoint trust: NOT CHECKED (the bundle is unreadable; ${trust.checkpointKeys.length} key(s) supplied)`,\n `Record trust: NOT CHECKED (the bundle is unreadable; ${trust.recordKeys.length} key(s) supplied)`,\n LIMITS_LINE,\n \"\",\n ].join(\"\\n\");\n}\n\nfunction humanReadable(\n result: ProofBundleReadableResult,\n trust: ProofBundleTrust\n): string {\n const chains = Object.entries(result.chains);\n const signaturesPresent = chains.reduce(\n (n, [, r]) => n + r.counts.record_signatures_present,\n 0\n );\n const tally = { ok: 0, unauthenticated: 0, failed: 0 };\n for (const [, r] of chains) tally[r.verdict]++;\n\n const lines = [`Proof bundle: ${result.verdict.toUpperCase()}`];\n lines.push(\n result.checkpoint_trust === \"checked\"\n ? `Checkpoint trust: CHECKED (${trust.checkpointKeys.length} key(s))`\n : \"Checkpoint trust: NOT CHECKED (checkpoints checked for structure only; they authenticate nothing)\"\n );\n lines.push(\n result.record_trust === \"checked\"\n ? `Record trust: CHECKED (${trust.recordKeys.length} key(s))`\n : `Record trust: NOT CHECKED (${signaturesPresent} entries carry record signatures; none were verified)`\n );\n if (result.bundle_problems.length > 0) {\n lines.push(`Bundle problems: ${problemsText(result.bundle_problems, \"chain\")}`);\n }\n lines.push(\n `Chains: ${chains.length} (ok ${tally.ok}, unauthenticated ${tally.unauthenticated}, failed ${tally.failed})`\n );\n if (chains.length === 0) lines.push(\" (no chains: an empty bundle proves nothing)\");\n for (const [key, r] of chains) lines.push(...chainLine(key, r));\n lines.push(LIMITS_LINE);\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Run `verify-proof-bundle`.\n *\n * # Description\n *\n * Parses the arguments, loads the key files and the bundle, verifies it, and\n * prints §10's human output or, with `--json`, exactly the §9 JSON on stdout.\n * Warns on stderr when a key is trusted for both roles.\n *\n * # Inputs\n *\n * - argv: the arguments after `verify-proof-bundle`\n * - io: output channels (defaults to the process's)\n *\n * # Outputs\n *\n * - number: the §11 exit code. Never throws.\n *\n * # Example\n *\n * const code = await runVerifyProofBundle([\"bundle.json\", \"--checkpoint-key\", \"cp.pub\"]);\n *\n * # Limitations\n *\n * - Reads the whole bundle into memory (at most 256 MiB; a larger file is\n * reported too-large after reading at most one byte past the limit).\n * - Key files must be regular files of at most 16 KiB.\n *\n * # Assumptions\n *\n * - Node.js ≥ 19 (WebCrypto).\n */\nexport async function runVerifyProofBundle(\n argv: readonly string[],\n io: ProofBundleCliIO = PROCESS_IO\n): Promise<number> {\n if (argv.includes(\"--help\") || argv.includes(\"-h\")) {\n io.stdout(USAGE);\n return PROOF_BUNDLE_EXIT.ok;\n }\n try {\n const args = parseArgs(argv);\n const trust: ProofBundleTrust = {\n checkpointKeys: await Promise.all(args.checkpointKeyPaths.map(loadKey)),\n recordKeys: await Promise.all(args.recordKeyPaths.map(loadKey)),\n };\n const bytes = await loadBundle(args.bundlePath);\n\n for (const id of await keysTrustedForBothRoles(trust)) {\n io.stderr(\n `warning: key ${id} is trusted for both checkpoints and records; ` +\n \"one key for both roles means one compromise forges both\\n\"\n );\n }\n\n const result: ProofBundleResult =\n bytes === null\n ? { result: PROOF_BUNDLE_RESULT_ID, readable: false, reason: \"too-large\" }\n : await verifyProofBundle(bytes, trust);\n\n if (args.json) {\n io.stdout(JSON.stringify(result) + \"\\n\");\n } else if (!result.readable) {\n io.stdout(unreadableText(result.reason, trust));\n } else {\n io.stdout(humanReadable(result, trust));\n }\n return exitCode(result);\n } catch (err) {\n if (err instanceof UsageError) {\n io.stderr(`${err.message}\\n${USAGE}`);\n return PROOF_BUNDLE_EXIT.usage;\n }\n // Never the error's message or stack: either could carry input (§10).\n io.stderr(\"internal error in the verifier: no verdict on the bundle\\n\");\n return PROOF_BUNDLE_EXIT.internal;\n }\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Command-line entry point for the JS verification SDK.\n *\n * Invoked via the `aleutian-verify` bin entry in package.json. Mirrors\n * the Python SDK's `aleutian-verify verify --anchor PATH --entries PATH`\n * surface byte-for-byte on the locked stdout JSON contract so a Phase F\n * cross-language smoke can diff results.\n *\n * Output schema (single line on stdout):\n *\n * {\n * \"status\": \"valid\" | \"invalid\",\n * \"chain_length\": number, // entries read, NOT entries verified\n * \"interface\": \"js-sdk\",\n * \"bundle_sha256\": string,\n * \"reason\"?: string,\n * \"breaks\"?: Array<{position, entry_id, break_type}>,\n * \"tombstones\"?: number, // present only when the chain has one\n * \"entries_not_bound\"?: number, // present only when the chain has one\n * \"note\"?: string // present only when the chain has one\n * }\n *\n * WHAT \"valid\" COVERS (format-spec §5.5). When the chain holds a tombstone,\n * the entries up to and including the last one are neither verified nor bound\n * by the anchor: a tombstone's chain hash is taken as stored, so nothing links\n * them to what follows. \"status\":\"valid\" then speaks only for the entries\n * after it; `entries_not_bound` says how many it does NOT speak for, and\n * `note` says so in words. The three members are absent, meaning 0, when the\n * chain has no tombstone.\n *\n * Exit codes (stable across releases; scripts depend on these):\n *\n * 0 valid\n * 1 invalid (chain verify returned valid=false)\n * 2 usage error\n * 3 IO / parse error (including an entries file that is not entries, and\n * an anchor that is refused as malformed: neither is a verdict on a chain)\n *\n * KEYLESS: the anchor's signature is not checked here, only that its fields\n * describe the entries.\n *\n * No new crypto here — wraps the existing library `verifyChainOffline`\n * + `loadAnchor` + `loadExportedEntries` shipped in this SDK.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\n\nimport {\n evaluateManifestFreshness,\n loadAnchor,\n loadExportedEntries,\n manifestGeneratedDate,\n manifestRevocationNote,\n verifyChainOffline,\n} from \"../index.js\";\nimport { parseAndVerifyTrustManifest } from \"../trustManifest.js\";\nimport { runVerifyProofBundle } from \"./verifyProofBundle.js\";\n\nconst INTERFACE_NAME = \"js-sdk\";\n\n// Stable exit codes.\nconst EXIT_VALID = 0;\nconst EXIT_INVALID = 1;\nconst EXIT_USAGE = 2;\nconst EXIT_IO_OR_PARSE = 3;\n\ninterface ParsedArgs {\n anchorPath: string;\n entriesPath: string;\n previousAnchorHash: string;\n maxEntries: number;\n manifestPath?: string;\n}\n\n/**\n * Offline trust-manifest freshness advisory (12f_e / ADR-029 §D5). Present\n * only when --manifest is supplied. Fields mirror the Go + Python SDK CLIs.\n * On a load/verify failure only `error` is populated; the chain verdict and\n * exit code are unaffected (freshness is advisory).\n */\ninterface ManifestOut {\n version?: number;\n generated_at?: string;\n age_days?: number;\n stale?: boolean;\n revocation_note?: string;\n error?: string;\n}\n\n/**\n * Entry point. Returns the exit code (does not call process.exit so it\n * can be tested in-process).\n */\nexport async function main(argv: readonly string[]): Promise<number> {\n // Minimal arg parser. Subcommand \"verify\" is required; everything\n // after is --flag value pairs. Mirrors the Python argparse surface.\n if (argv.length === 0 || argv[0] === \"--help\" || argv[0] === \"-h\") {\n printUsage();\n return argv[0] ? EXIT_VALID : EXIT_USAGE;\n }\n\n // proof sink export bundles (bundle-format §11): trust is the verifier's,\n // the opposite of `verify`, so it is a separate verb with its own exit codes.\n if (argv[0] === \"verify-proof-bundle\") {\n return runVerifyProofBundle(argv.slice(1));\n }\n\n if (argv[0] !== \"verify\") {\n process.stderr.write(`unknown command: ${argv[0]}\\n`);\n printUsage();\n return EXIT_USAGE;\n }\n\n let parsed: ParsedArgs;\n try {\n parsed = parseArgs(argv.slice(1));\n } catch (err) {\n process.stderr.write(`${(err as Error).message}\\n`);\n printUsage();\n return EXIT_USAGE;\n }\n\n return runVerify(parsed);\n}\n\nasync function runVerify(args: ParsedArgs): Promise<number> {\n const bundleSha = await safeSha256(args.entriesPath);\n\n // Optional offline manifest freshness advisory. Computed once and\n // attached to EVERY output path. Advisory only: a manifest failure is\n // surfaced in the manifest block but NEVER changes the exit code.\n const manifestBlock = await loadManifestAdvisory(args.manifestPath);\n\n let anchor;\n let entries;\n try {\n anchor = await loadAnchor(args.anchorPath);\n entries = await loadExportedEntries(args.entriesPath);\n } catch (err) {\n emitResult({\n status: \"invalid\",\n chain_length: 0,\n bundle_sha256: bundleSha,\n reason: `load: ${(err as Error).message}`,\n manifest: manifestBlock,\n });\n return EXIT_IO_OR_PARSE;\n }\n\n let result;\n try {\n result = await verifyChainOffline(entries, {\n anchor,\n previousAnchorHash: args.previousAnchorHash,\n maxEntries: args.maxEntries,\n maxBreaks: 100,\n });\n } catch (err) {\n // A malformed anchor (format-spec §9.3, §9.8) is an error, not a verdict.\n emitResult({\n status: \"invalid\",\n chain_length: 0,\n bundle_sha256: bundleSha,\n reason: `verify: ${(err as Error).message}`,\n manifest: manifestBlock,\n });\n return EXIT_IO_OR_PARSE;\n }\n\n // format-spec §5.5: say how many entries the result leaves exposed, and\n // never call them verified or bound.\n const exposed =\n result.tombstonesFound > 0\n ? {\n tombstones: result.tombstonesFound,\n entries_not_bound: result.entriesNotVerified,\n note: notVerifiedNote(result.entriesNotVerified, result.valid),\n }\n : {};\n\n if (result.valid) {\n emitResult({\n status: \"valid\",\n chain_length: result.entriesProcessed,\n bundle_sha256: bundleSha,\n manifest: manifestBlock,\n ...exposed,\n });\n return EXIT_VALID;\n }\n\n const firstBreak = result.breaks[0];\n const reason = firstBreak\n ? `${firstBreak.breakType} at position ${firstBreak.position}`\n : \"unspecified verification failure\";\n\n emitResult({\n status: \"invalid\",\n chain_length: result.entriesProcessed,\n bundle_sha256: bundleSha,\n reason,\n breaks: result.breaks.map((b) => ({\n position: b.position,\n entry_id: b.entryId,\n break_type: b.breakType,\n })),\n manifest: manifestBlock,\n ...exposed,\n });\n return EXIT_INVALID;\n}\n\n/**\n * The §5.5 wording for a chain that holds a tombstone. Exported for tests.\n *\n * @param entriesNotVerified - Entries up to and including the last tombstone\n * @param valid - Whether the rest of the result is a pass\n * @returns One sentence that never calls those entries verified or bound\n */\nexport function notVerifiedNote(entriesNotVerified: number, valid: boolean): string {\n const which =\n entriesNotVerified === 1\n ? \"entry 0 (the last tombstone)\"\n : `entries 0 to ${entriesNotVerified - 1} (up to and including the last tombstone)`;\n const are = entriesNotVerified === 1 ? \"is\" : \"are\";\n return valid\n ? `${which} ${are} NOT verified and NOT bound by the anchor; status covers only the entries after`\n : `${which} ${are} NOT verified and NOT bound by the anchor`;\n}\n\n/**\n * Read + root-signature-verify a published trust manifest offline (no\n * network) and return its freshness advisory, or undefined when no path is\n * given. A failure is captured in the `error` field rather than thrown —\n * freshness is advisory and must never change the exit code.\n *\n * The CLI is a one-shot stateless verifier, so lastSeenVersion is -1\n * (rollback detection disabled).\n */\nasync function loadManifestAdvisory(\n manifestPath: string | undefined,\n): Promise<ManifestOut | undefined> {\n if (manifestPath === undefined) return undefined;\n let raw: string;\n try {\n raw = await readFile(manifestPath, \"utf-8\");\n } catch (err) {\n return { error: `read manifest: ${(err as Error).message}` };\n }\n try {\n const manifest = parseAndVerifyTrustManifest(raw);\n const f = evaluateManifestFreshness(\n manifest.version,\n manifest.generatedAt.getTime(),\n Date.now(),\n -1,\n );\n return {\n version: f.version,\n generated_at: manifestGeneratedDate(f),\n age_days: f.ageDays,\n stale: f.stale,\n revocation_note: manifestRevocationNote(f),\n };\n } catch (err) {\n return { error: `verify manifest: ${(err as Error).message}` };\n }\n}\n\ninterface ResultOut {\n status: \"valid\" | \"invalid\";\n chain_length: number;\n bundle_sha256: string;\n reason?: string;\n breaks?: Array<{ position: number; entry_id: string; break_type: string }>;\n manifest?: ManifestOut;\n tombstones?: number;\n entries_not_bound?: number;\n note?: string;\n}\n\n/**\n * Emit the JSON contract. Keys sorted alphabetically + serialized on a\n * single line so the cross-SDK smoke can `diff` outputs.\n */\nfunction emitResult(r: ResultOut): void {\n const out: Record<string, unknown> = {\n bundle_sha256: r.bundle_sha256,\n chain_length: r.chain_length,\n interface: INTERFACE_NAME,\n status: r.status,\n };\n if (r.reason !== undefined) out.reason = r.reason;\n if (r.breaks && r.breaks.length > 0) out.breaks = r.breaks;\n if (r.manifest !== undefined) out.manifest = r.manifest;\n if (r.tombstones !== undefined) out.tombstones = r.tombstones;\n if (r.entries_not_bound !== undefined) out.entries_not_bound = r.entries_not_bound;\n if (r.note !== undefined) out.note = r.note;\n // Sort top-level keys for deterministic cross-SDK comparison.\n const sortedKeys = Object.keys(out).sort();\n const sorted: Record<string, unknown> = {};\n for (const k of sortedKeys) sorted[k] = out[k];\n process.stdout.write(`${JSON.stringify(sorted)}\\n`);\n}\n\nfunction parseArgs(args: readonly string[]): ParsedArgs {\n let anchorPath: string | undefined;\n let entriesPath: string | undefined;\n let previousAnchorHash = \"\";\n let maxEntries = 0;\n let manifestPath: string | undefined;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n const next = (): string => {\n const v = args[i + 1];\n if (v === undefined) throw new Error(`${arg} requires a value`);\n i++;\n return v;\n };\n switch (arg) {\n case \"--anchor\":\n anchorPath = next();\n break;\n case \"--entries\":\n entriesPath = next();\n break;\n case \"--previous-anchor-hash\":\n previousAnchorHash = next();\n break;\n case \"--max-entries\":\n maxEntries = Number.parseInt(next(), 10);\n if (Number.isNaN(maxEntries) || maxEntries < 0) {\n throw new Error(\"--max-entries must be a non-negative integer\");\n }\n break;\n case \"--manifest\":\n manifestPath = next();\n break;\n default:\n throw new Error(`unknown flag: ${arg}`);\n }\n }\n\n if (!anchorPath) throw new Error(\"--anchor is required\");\n if (!entriesPath) throw new Error(\"--entries is required\");\n\n return {\n anchorPath,\n entriesPath,\n previousAnchorHash,\n maxEntries,\n manifestPath,\n };\n}\n\nfunction printUsage(): void {\n process.stderr.write(\n [\n \"usage: aleutian-verify verify --anchor PATH --entries PATH [--max-entries N]\",\n \"\",\n \"Verify an extracted chain export (anchor + entries JSON/JSONL).\",\n \"Emits a single JSON line to stdout matching the locked contract.\",\n \"Exit 0 = valid, 1 = invalid, 2 = usage error, 3 = IO/parse error.\",\n \"\",\n \"usage: aleutian-verify verify-proof-bundle <bundle.json> [--checkpoint-key F]... [--record-key F]... [--json]\",\n \"\",\n \"Verify a proof sink export bundle under the keys you trust (see --help on the verb).\",\n \"\",\n ].join(\"\\n\"),\n );\n}\n\n/**\n * SHA-256 of the entries file. Empty string on read failure — hashing\n * is never the failure mode of the CLI.\n */\nasync function safeSha256(path: string): Promise<string> {\n try {\n const h = createHash(\"sha256\");\n await new Promise<void>((resolve, reject) => {\n const stream = createReadStream(path);\n stream.on(\"data\", (chunk) => h.update(chunk));\n stream.on(\"end\", () => resolve());\n stream.on(\"error\", (err) => reject(err));\n });\n return h.digest(\"hex\");\n } catch {\n return \"\";\n }\n}\n","// Copyright 2026 Aleutian AI\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Bin entry stub for the `aleutian-verify` CLI. Thin process-level\n * shim: parse argv, call main(), set the exit code. All real logic lives\n * in `verifyBundle.ts` so it stays testable in-process.\n *\n * It sets `process.exitCode` and lets Node exit on its own instead of\n * calling `process.exit()`: on a pipe, stdout writes are asynchronous, and\n * exiting at once cuts the output short (at 64 KiB on macOS), so\n * `--json | jq` would read invalid JSON.\n *\n * An error that escapes `main` prints a fixed message, never its text or\n * stack (either could quote input: bundle-format §10), and exits 5, an\n * internal error (§11).\n */\n\nimport { main } from \"./verifyBundle.js\";\n\nmain(process.argv.slice(2)).then(\n (code) => {\n process.exitCode = code;\n },\n () => {\n process.stderr.write(\"internal error in the verifier\\n\");\n process.exitCode = 5;\n }\n);\n"]}
|