@svta/cml-c2pa 1.2.0 → 1.3.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/dist/index.d.ts CHANGED
@@ -56,7 +56,7 @@ declare const C2paStatusCode: {
56
56
  /** An action requiring an ingredient reference does not have one (§18.15.4.7) */
57
57
  readonly ASSERTION_ACTION_INGREDIENT_MISMATCH: "assertion.action.ingredientMismatch";
58
58
  /** Claim signature verification failed, or the signature carries no certificate (§15.7) */
59
- readonly CLAIM_SIGNATURE_MISMATCH: "claim.signature.mismatch";
59
+ readonly CLAIM_SIGNATURE_MISMATCH: "claimSignature.mismatch";
60
60
  /** The manifest has no `c2pa.signature` box, so the claim signature cannot be found (§15.7) */
61
61
  readonly CLAIM_SIGNATURE_MISSING: "claimSignature.missing";
62
62
  /** The manifest has no claim box (§15.6.1) */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/C2paAssertion.ts","../src/C2paSignatureInfo.ts","../src/C2paManifest.ts","../src/C2paStatusCode.ts","../src/cose/CoseKeyJwk.ts","../src/LiveVideoStatusCode.ts","../src/bmff/BmffHashExclusion.ts","../src/merkle/MerkleSegmentValidation.ts","../src/init/InitSegmentValidation.ts","../src/init/validateC2paInitSegment.ts","../src/vsi/SequenceState.ts","../src/segment/SegmentValidation.ts","../src/segment/validateC2paSegment.ts","../src/manifestbox/ManifestBoxValidation.ts","../src/manifestbox/validateC2paManifestBoxSegment.ts","../src/merkle/validateC2paMerkleSegment.ts"],"sourcesContent":[],"mappings":";;;;;;;AAKA;;KAAY,aAAA;;ECAZ,SAAY,IAAA,EAAA,OAAA;;;;;;;ADAZ;;KCAY,iBAAA;;EAAZ,SAAY,aAAA,EAAA,MAAA,GAAA,IAAA;;;;;ADAZ;;;;ACAY,KCGA,YAAA,GDHA;;;;ECGZ,SAAY,aAAA,EAIa,iBAAA;gCACM;;;;;;AFR/B;;;;ACAA;;;;ACGY,cCIC,cDAY,EAAA;;;;ECAzB,SAAa,iBAAA,EAAA,mBAAA;EAwBb;;;;EC9BA;;;;ECMA;EA0BA,SAAY,4BAAqC,EAAA,8BAAf;;;;AChClC;AAcA;;;;ACXY,KJ2BA,cAAA,GAAiB,OI3BjB,CAAA,OJ2BgC,cI3BhC,CAAA;;;;;;APJZ;;;KICY,UAAA;EHDZ,SAAY,GAAA,EAAA,MAAA;;;;ACGZ,CAAA;;;;;AFHA;;;;ACAA;;;;ACGY,cGIC,mBHAY,EAAA;;;;ECAzB,SAAa,gBAAA,EAAA,4BAAA;EAwBb;;;;AC9BA;;;;ECMA;EA0BA,SAAY,yBAAA,EAAA,oCAAsB;;;;EChClC,SAAY,kBAAA,EAAA,8BAEK;AAYjB,CAAA;;;;ACXA;;AAKoB,KFwBR,mBAAA,GAAsB,OExBd,CAAA,OFwB6B,mBExB7B,CAAA;;;;;;APTpB;;;KMCY,kBAAA;ELDZ,SAAY,MAAA,EAAA,MAAA;kBKGK;;;AJAjB;;;;ACIA;AAwBA;;;KGhBY,iBAAA;EFdZ,SAAY,KAAA,EAAA,MAAA;2BEgBc;;;;ANjB1B;;;;ACAA;KMIY,SAAA;;;ELDZ,SAAY,KAAA,EAAA,MAAA;4BKKe;qBACP;;EJFpB,SAAa,UAAA,EAAA,SIIkB,iBJJlB,EAAA;EAwBb,SAAY,gBAAA,EAAA,MAAgC;;;;AC9B5C;;;;ACMA;AA0BA;;;;AChCY,KCyBA,kBAAA,GDzBA;EAcZ,SAAY,aAAA,ECYa,WDVC,CAAA,MAAA,EAAA,MAAA,CAAA;;;;ACb1B;;;AAO+B,KAwBnB,uBAAA,GAxBmB;EAAA,SAAA,QAAA,EAAA,MAAA,GAAA,IAAA;EAe/B,SAAY,WAAA,EAAA,MAAA,GAAA,IAAA;EASZ,SAAY,OAAA,EAAA,OAAA;iCAIoB,sBAAsB;;;;;;ANvCtD;;;;ACGA;;KMMY,mBAAA;;ELFZ,SAAa,GAAA,EKIE,ULJF;EAwBb,SAAY,iBAAA,EAAA,MAAgC;;;;AC9B5C;;;;ACMA;AA0BA;;KGTY,qBAAA;qBACQ;EFxBpB,SAAY,WAAA,EEyBW,UFzBX,GAEK,IAAA;EAYjB,SAAY,UAAA,EAAA,MAAA,GAAA,IAAA;iCEaoB;gCACD;;EDzB/B,SAAY,UAAA,EAAA,SAAA,CC2BoB,mBD3BpB,GC2B0C,cD3B1C,CAAA,EAAA;CAIe;;;;;APR3B;;;;ACAA;;;;ACGA;;;;ACIA;AAwBA;;;;AC9BY,iBK0MU,uBAAA,CL1MV,KAAA,EK0MyC,UL1MzC,CAAA,EK0MsD,OL1MtD,CK0M8D,qBL1M9D,CAAA;;;;;AJDZ;;;;ACAA;;;;ACGA;;;KQQY,aAAA;EPJZ,SAAa,kBAAA,EAAA,MAAA,GAAA,IAAA;EAwBb,SAAY,aAAA,EOlBa,WPkBmB,CAAA,MAAA,CAAA;;;;AC9B5C;;;;ACMA;AA0BA;;cKRa;;EJxBb,SAAY,KAAA,EAAA,OAAA;EAcZ;;;;ECXA;EAI2B,SAAA,YAAA,EAAA,cAAA;EACP;EAEW,SAAA,6BAAA,EAAA,+BAAA;CAAA;AAe/B;AASA;;;;AC1BY,KEkCA,wBAAA,GAA2B,OFhCxB,CAAA,OEgCuC,wBFhCvC,CAAA;AAaf;;;;;;;;KE6BY,wBAAA;;0BACyC,wBAAA,CAAyB;ADqJ9E,CAAA,GAAsB;EAA+B,SAAA,OAAA,EAAA,KAAA;EAAqB,SAAA,MAAA,EAAA,OCjJ7D,wBAAA,CAAyB,6BDiJoC,GAAA,OChJ7D,wBAAA,CAAyB,SDgJoC,GAAA,OC/I7D,wBAAA,CAAyB,YD+IoC;CAAR,GAAA;EAAA,SAAA,OAAA,EAAA,KAAA;0BC3IvC,wBAAA,CAAyB;;;AArDpD,CAAA;;;;AVXA;;;;ACAA;;KUKY,uBAAA;;ETFZ,SAAY,UAAA,EAAA,MAAA;;;2BSOc;ERH1B,SAAa,OAAA,EAAA,OAAA;EAwBb,SAAY,UAAA,EAAA,SQnBmB,mBRmBF,EAAA;;;;AH/B7B;;;;ACAA;;;;ACGA;;;;ACIA;AAwBA;;;;AC9BA;;iBQgCsB,mBAAA,eACP,kCACQ,uCACP,gBACb;mBAA2B;EP9B9B,SAAa,iBAAA,EO8BsE,aP9BtE;AA0Bb,CAAA,GAAY,IAAA,CAAA;;;ALjCZ;;;;ACAA;;;KYMY,2BAAA;EXHZ,SAAY,QAAA,EWIQ,YXAK,GAAA,IAAA;;;wBWGF;EVHvB,SAAa,cAAA,EAAA,MAAA,GAAA,IAAA;EAwBb,SAAY,kBAAA,EAAA,MAAgC,GAAA,IAAA;;;;EC9B5C,SAAY,OAAA,EAAA,OAAA;iCSgBoB,sBAAsB;;;ARVtD;AA0BA;;;KQRY,8BAAA,wBACS,SAAS,oCACnB,2BACI;AP3Bf;AAcA;;;;ACXY,KM+BA,4BAAA,GN/BA;EAIe,SAAA,mBAAA,CAAA,EAAA;IACP,SAAA,MAAA,EAAA,MAAA;IAEW,SAAA,QAAA,EM2BV,8BN3BU;EAAA,CAAA;AAe/B,CAAA;AASA;;;;AC1BA;AAeA;;;AAIgC,KKsBpB,0BAAA,GLtBoB;EACD,SAAA,YAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAEC,SAAA,kBAAA,CAAA,EAAA,MAAA,GAAA,IAAA;CAAsB;;;;;AR/BtD;;;;ACAA;;;;ACGA;;;;ACIA;AAwBA;;;;AC9BA;;;;ACMA;AA0BA;iBSuJsB,8BAAA,QACd,mDAEC,sCACE,+BACR;mBACe;;ER7LlB,SAAY,SAAA,EQ+LS,0BR7LJ;AAYjB,CAAA,CAAA;;;;;ANfA;;;;ACAA;;;;ACGA;;;;ACIa,iBYmNS,yBAAA,CZnNT,YAAA,EYoNE,UZpNF,EAAA,UAAA,EAAA,SYqNS,SZrNT,EAAA,EAAA,KAAA,CAAA,EYsNJ,kBZtNI,CAAA,EYuNV,OZvNU,CAAA;EAwBb,SAAY,MAAA,EYgMM,uBZhM0B;sBYiMvB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/C2paAssertion.ts","../src/C2paSignatureInfo.ts","../src/C2paManifest.ts","../src/C2paStatusCode.ts","../src/cose/CoseKeyJwk.ts","../src/LiveVideoStatusCode.ts","../src/bmff/BmffHashExclusion.ts","../src/merkle/MerkleSegmentValidation.ts","../src/init/InitSegmentValidation.ts","../src/init/validateC2paInitSegment.ts","../src/vsi/SequenceState.ts","../src/segment/SegmentValidation.ts","../src/segment/validateC2paSegment.ts","../src/manifestbox/ManifestBoxValidation.ts","../src/manifestbox/validateC2paManifestBoxSegment.ts","../src/merkle/validateC2paMerkleSegment.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -761,7 +761,7 @@ const C2paStatusCode = {
761
761
  ASSERTION_HASHEDURI_MISMATCH: "assertion.hashedURI.mismatch",
762
762
  ASSERTION_MISSING: "assertion.missing",
763
763
  ASSERTION_ACTION_INGREDIENT_MISMATCH: "assertion.action.ingredientMismatch",
764
- CLAIM_SIGNATURE_MISMATCH: "claim.signature.mismatch",
764
+ CLAIM_SIGNATURE_MISMATCH: "claimSignature.mismatch",
765
765
  CLAIM_SIGNATURE_MISSING: "claimSignature.missing",
766
766
  CLAIM_MISSING: "claim.missing",
767
767
  ASSERTION_BMFFHASH_MALFORMED: "assertion.bmffHash.malformed",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["coseGet","toUint8Array","protectedHeader: CoseHeader","TEXT_DECODER","HEX_TABLE: readonly string[]","C2PA_MANIFEST_UUID: readonly number[]","JUMBF_UUID: readonly number[]","TEXT_DECODER","TEXT_DECODER","notBefore: string | null","assertions: InternalAssertionData[]","data: unknown","refs: ClaimAssertionRef[]","claimData: Record<string, unknown> | null","claimCborBytes: Uint8Array | null","internalAssertions: InternalAssertionData[]","signatureBytes: Uint8Array | null","assertions: C2paAssertion[]","codes: C2paStatusCode[]","codes: C2paStatusCode[]","CURVE_COMPONENT_BYTES: Record<string, number>","RSA_PSS_SALT_LENGTH: Record<string, number>","Code","codes: C2paStatusCode[]","EC_CURVE_NAMES: Record<number, string>","OKP_CURVE_NAMES: Record<number, string>","constraints: BmffHashConstraint[]","exclusions: BmffHashExclusion[]","row: Uint8Array[]","maps: MerkleMap[]","BMFF_HASH_ASSERTION_LABEL","EMPTY_BMFF_HASH: BmffHashFields","integrityCodes: readonly C2paStatusCode[]","errorCodes: (LiveVideoStatusCode | C2paStatusCode)[]","payloads: Uint8Array[]","first: unknown","hashes: (Uint8Array | null)[]","leafHashCache: LeafHashCache","location: number | null","bmffHashHex: string | null"],"sources":["../src/LiveVideoStatusCode.ts","../src/cose/decodeCoseSign1.ts","../src/jumbf/parseJumbfBoxes.ts","../src/jumbf/parseJumbfLabel.ts","../src/utils.ts","../src/x509/asn1.ts","../src/x509/extractCertificateInfo.ts","../src/readC2paManifest.ts","../src/bmff/shouldExcludeBox.ts","../src/bmff/computeBmffHash.ts","../src/C2paStatusCode.ts","../src/extractManifestCertificate.ts","../src/claim/validateActionIngredients.ts","../src/claim/validateAssertionHashes.ts","../src/cose/constants.ts","../src/cose/resolveAlgorithmFromCoseAlg.ts","../src/cose/buildSigStructure.ts","../src/cose/verifyCoseSign1.ts","../src/x509/extractCertificateSpki.ts","../src/x509/normalizeRsaPssSpki.ts","../src/claim/verifyClaimSignature.ts","../src/claim/validateManifestIntegrity.ts","../src/cose/convertCoseKeyToJwk.ts","../src/cose/resolveImportAlgorithm.ts","../src/cose/verifySignerBinding.ts","../src/bmff/parseExclusions.ts","../src/merkle/validateMerkleMaps.ts","../src/init/validateC2paInitSegment.ts","../src/emsg/extractVsiEmsgBox.ts","../src/vsi/decodeVsiMap.ts","../src/vsi/createSequenceState.ts","../src/vsi/SequenceState.ts","../src/vsi/validateSequenceNumber.ts","../src/bmff/validateBmffHash.ts","../src/segment/validateC2paSegment.ts","../src/manifestbox/validateC2paManifestBoxSegment.ts","../src/merkle/validateC2paMerkleSegment.ts"],"sourcesContent":["import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Standard C2PA failure status codes for live video validation,\n * as defined in the C2PA specification section 19.7.\n *\n * @see {@link https://c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_live_video_validation_process | C2PA Spec §19.7}\n *\n * @enum\n *\n * @public\n */\nexport const LiveVideoStatusCode = {\n\t/** Init segment contains an `mdat` box (§19.7.1) */\n\tINIT_INVALID: 'livevideo.init.invalid',\n\t/** C2PA Manifest Box failed standard validation (§19.7.1) */\n\tMANIFEST_INVALID: 'livevideo.manifest.invalid',\n\t/** Segment structure invalid: missing Manifest Box/emsg, signature/hash/key failure (§19.7) */\n\tSEGMENT_INVALID: 'livevideo.segment.invalid',\n\t/**\n\t * Live video assertion field invalid: sequenceNumber or streamId mismatch\n\t * (§19.7.2). Also reused for VOD Merkle per-track location discontinuity\n\t * (§15.12.2), which has no dedicated code.\n\t */\n\tASSERTION_INVALID: 'livevideo.assertion.invalid',\n\t/** continuityMethod absent, unsupported, or companion fields incorrect (§19.7.2) */\n\tCONTINUITY_METHOD_INVALID: 'livevideo.continuityMethod.invalid',\n\t/** Custom continuityMethod with no registered validator (§19.7.2) */\n\tCONTINUITY_METHOD_UNSUPPORTED: 'livevideo.continuityMethod.unsupported',\n\t/** Session key invalid: signerBinding failed or required fields absent (§19.7.3) */\n\tSESSIONKEY_INVALID: 'livevideo.sessionkey.invalid',\n} as const\n\n/**\n * Union type of all {@link (LiveVideoStatusCode:variable)} values.\n *\n * @public\n */\nexport type LiveVideoStatusCode = ValueOf<typeof LiveVideoStatusCode>\n","import { decode } from 'cbor-x/decode'\nimport type { CoseSign1 } from './CoseSign1.ts'\n\nconst COSE_SIGN1_TAG_SINGLE_BYTE = 0xd2\nconst COSE_SIGN1_TAG_TWO_BYTE_FIRST = 0xd8\nconst COSE_SIGN1_TAG_TWO_BYTE_SECOND = 0x12\nconst COSE_SIGN1_ARRAY_LENGTH = 4\nconst COSE_KEY_KID = 4\nconst COSE_KEY_ALG = 1\n\ntype CoseHeader = Map<number, unknown> | Record<number | string, unknown>\n\nfunction coseGet(header: CoseHeader, key: number): unknown {\n\tif (header instanceof Map) return header.get(key)\n\treturn (header as Record<number | string, unknown>)[key]\n}\n\nfunction stripCoseTag(bytes: Uint8Array): Uint8Array {\n\tif (bytes[0] === COSE_SIGN1_TAG_SINGLE_BYTE) return bytes.subarray(1)\n\tif (bytes[0] === COSE_SIGN1_TAG_TWO_BYTE_FIRST && bytes[1] === COSE_SIGN1_TAG_TWO_BYTE_SECOND) return bytes.subarray(2)\n\treturn bytes\n}\n\nfunction toUint8Array(value: unknown): Uint8Array {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\tthrow new Error(`Expected Uint8Array or number[], got ${typeof value}`)\n}\n\n/**\n * Decodes a `COSE_Sign1` structure from raw bytes (RFC 9052).\n *\n * Handles CBOR tag 18 in both single-byte (0xD2) and two-byte (0xD8 0x12) form.\n *\n * @param coseBytes - Raw COSE_Sign1 bytes, optionally prefixed with CBOR tag 18\n * @returns The decoded COSE_Sign1 structure\n * @throws If the bytes do not represent a valid COSE_Sign1 structure\n *\n * @example\n * {@includeCode ../../test/cose/decodeCoseSign1.test.ts#example}\n *\n * @internal\n */\nexport function decodeCoseSign1(coseBytes: Uint8Array): CoseSign1 {\n\ttry {\n\t\tconst stripped = stripCoseTag(coseBytes)\n\t\tconst coseArray = decode(stripped) as unknown\n\n\t\tif (!Array.isArray(coseArray) || coseArray.length !== COSE_SIGN1_ARRAY_LENGTH) {\n\t\t\tthrow new Error('Invalid COSE_Sign1 structure: expected array with 4 elements')\n\t\t}\n\n\t\tconst [protectedRaw, unprotectedRaw, payloadRaw, signatureRaw] = coseArray as unknown[]\n\n\t\tconst protectedBytes = toUint8Array(protectedRaw)\n\t\tlet protectedHeader: CoseHeader = {}\n\t\tif (protectedBytes.length > 0) {\n\t\t\tprotectedHeader = decode(protectedBytes) as CoseHeader\n\t\t}\n\n\t\tconst unprotectedHeader = (unprotectedRaw ?? {}) as CoseHeader\n\t\tconst kidRaw = coseGet(protectedHeader, COSE_KEY_KID) ?? coseGet(unprotectedHeader, COSE_KEY_KID) ?? null\n\t\tconst kid = kidRaw != null ? toUint8Array(kidRaw) : null\n\t\tconst alg = (coseGet(protectedHeader, COSE_KEY_ALG) ?? coseGet(unprotectedHeader, COSE_KEY_ALG) ?? null) as number | null\n\n\t\treturn {\n\t\t\tprotectedBytes,\n\t\t\tprotectedHeader: protectedHeader as Readonly<Record<number, unknown>>,\n\t\t\tunprotectedHeader: unprotectedHeader as Readonly<Record<number, unknown>>,\n\t\t\tpayload: payloadRaw == null ? null : toUint8Array(payloadRaw),\n\t\t\tsignature: toUint8Array(signatureRaw),\n\t\t\tkid,\n\t\t\talg,\n\t\t}\n\t}\n\tcatch (error) {\n\t\tthrow new Error(`Failed to decode COSE_Sign1: ${(error as Error).message}`)\n\t}\n}\n","import { readIsoBoxes } from '@svta/cml-iso-bmff'\nimport type { JumbfBox } from './JumbfBox.ts'\n\n/**\n * Parses JUMBF boxes (ISO 19566-5) from raw bytes.\n *\n * JUMBF boxes share the same 4-byte size + 4-byte type structure as ISO BMFF boxes,\n * so they can be parsed with the same reader.\n *\n * @param bytes - Raw bytes containing JUMBF box content\n * @returns Array of parsed JUMBF boxes with their payloads\n *\n * @example\n * {@includeCode ../../test/jumbf/parseJumbfBoxes.test.ts#example}\n *\n * @internal\n */\nexport function parseJumbfBoxes(bytes: Uint8Array): JumbfBox[] {\n\treturn readIsoBoxes(bytes).map(box => ({\n\t\ttype: box.type,\n\t\tdata: box.view.readData(box.view.bytesRemaining),\n\t}))\n}\n","const TEXT_DECODER = /* @__PURE__ */ new TextDecoder()\nconst JUMD_UUID_SIZE = 16\nconst JUMD_TOGGLES_OFFSET = 16\nconst JUMD_LABEL_START = 17\nconst LABEL_FLAG_MASK = 0x03\nconst LABEL_FLAG_EXPECTED = 0x03\n\n/**\n * Extracts the label from a JUMBF Description Box (`jumd`) data payload.\n *\n * The `jumd` format is: 16-byte UUID + 1-byte toggles + null-terminated label string.\n * A label is only present when bits 0 and 1 of the toggles byte are both set.\n *\n * @param jumdData - Raw bytes of the `jumd` box data (payload after the box header)\n * @returns The label string, or `null` if no label is present\n *\n * @example\n * {@includeCode ../../test/jumbf/parseJumbfLabel.test.ts#example}\n *\n * @internal\n */\nexport function parseJumbfLabel(jumdData: Uint8Array): string | null {\n\tif (jumdData.length < JUMD_UUID_SIZE + 1) return null\n\n\tconst toggles = jumdData[JUMD_TOGGLES_OFFSET]\n\tif ((toggles & LABEL_FLAG_MASK) !== LABEL_FLAG_EXPECTED) return null\n\n\tlet end = JUMD_LABEL_START\n\twhile (end < jumdData.length && jumdData[end] !== 0) end++\n\tif (end >= jumdData.length) return null\n\n\treturn TEXT_DECODER.decode(jumdData.subarray(JUMD_LABEL_START, end))\n}\n","import type { IsoBoxReadView, ParsedIsoBox } from '@svta/cml-iso-bmff'\n\nconst MILLISECONDS_PER_SECOND = 1000\nconst SHA_ALGORITHM_PATTERN = /^sha(\\d+)$/i\n\n/**\n * Normalizes hash algorithm names to WebCrypto format (e.g. `sha256` → `SHA-256`).\n *\n * Defaults to `'SHA-256'` when no algorithm is provided.\n *\n * @internal\n */\nexport function normalizeAlgorithmName(rawAlg?: string): string {\n\treturn (rawAlg ?? 'SHA-256').replace(SHA_ALGORITHM_PATTERN, 'SHA-$1')\n}\n\nconst HEX_TABLE: readonly string[] = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'))\n\n/**\n * Converts a Uint8Array to a lowercase hex string.\n *\n * @internal\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n\tlet hex = ''\n\tfor (const byte of bytes) hex += HEX_TABLE[byte]\n\treturn hex\n}\n\n/**\n * Checks whether a session key has expired based on its creation time\n * and validity period.\n *\n * @param createdAt - ISO 8601 date string when the key was created\n * @param validityPeriodSeconds - Validity duration in seconds\n * @param now - Current time (defaults to `new Date()`, injectable for testing)\n * @returns `true` if the key has expired\n *\n * @internal\n */\nexport function isKeyExpired(createdAt: string, validityPeriodSeconds: number, now: Date = new Date()): boolean {\n\tconst createdAtMs = new Date(createdAt).getTime()\n\tif (Number.isNaN(createdAtMs)) return true\n\tconst validityEnd = new Date(createdAtMs + validityPeriodSeconds * MILLISECONDS_PER_SECOND)\n\treturn now > validityEnd\n}\n\n/**\n * Constant-time comparison of two hash byte arrays.\n *\n * @internal\n */\nexport function hashesEqual(a: Uint8Array, b: Uint8Array): boolean {\n\tif (a.length !== b.length) return false\n\tlet diff = 0\n\tfor (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i]\n\treturn diff === 0\n}\n\n// C2PA manifest store UUID per C2PA specification\nconst C2PA_MANIFEST_UUID: readonly number[] = [\n\t0xd8, 0xfe, 0xc3, 0xd6, 0x1a, 0x96, 0x4f, 0x32,\n\t0xa0, 0xf6, 0xf3, 0xec, 0xf9, 0x6c, 0x10, 0xea,\n]\n\n// JUMBF UUID per ISO 19566-5 (used by c2pa-rs and other JUMBF-compliant tools)\n/** @internal */\nexport const JUMBF_UUID: readonly number[] = [\n\t0xd8, 0xfe, 0xc3, 0xd6, 0x1b, 0x0e, 0x48, 0x3c,\n\t0x92, 0x97, 0x58, 0x28, 0x87, 0x7e, 0xc4, 0x81,\n]\n\n// Compares a uuid box usertype against an expected 16-byte extended type.\n/** @internal */\nexport function matchesUuid(usertype: readonly number[], expected: readonly number[]): boolean {\n\treturn usertype.length === expected.length && expected.every((b, i) => b === usertype[i])\n}\n\n// Converts CBOR-decoded bytes (Uint8Array or number[]) to Uint8Array, or null.\n/** @internal */\nexport function toUint8Array(value: unknown): Uint8Array | null {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\treturn null\n}\n\n/** @internal */\nexport function asInteger(value: unknown): number | null {\n\treturn typeof value === 'number' && Number.isInteger(value) ? value : null\n}\n\nfunction isC2paUuid(usertype: readonly number[]): boolean {\n\treturn matchesUuid(usertype, C2PA_MANIFEST_UUID) || matchesUuid(usertype, JUMBF_UUID)\n}\n\n/**\n * A parsed ISO BMFF box with a UUID type.\n *\n * `ParsedIsoBox` does not include 'uuid' in its type union because UUID boxes\n * are not part of the standard `IsoBoxMap`. This type represents the structural\n * shape needed to work with UUID boxes at runtime.\n *\n * @internal\n */\nexport type UuidParsedBox = {\n\ttype: string\n\tusertype?: number[]\n\tview: IsoBoxReadView\n\tsize: number\n}\n\n/**\n * Finds the C2PA UUID box in a list of parsed ISO BMFF boxes.\n *\n * Matches against both the C2PA manifest store UUID and the JUMBF UUID\n * (ISO 19566-5), as different tools use different UUIDs.\n *\n * @internal\n */\nexport function findC2paUuidBox(boxes: ParsedIsoBox[]): UuidParsedBox | undefined {\n\treturn (boxes as UuidParsedBox[]).find(\n\t\tbox => box.type === 'uuid' && isC2paUuid(box.usertype ?? []),\n\t)\n}\n\nconst FULLBOX_HEADER_SIZE = 4\nconst AUX_UUID_OFFSET_SIZE = 8\nconst TEXT_DECODER = new TextDecoder()\n\n// Reads a version/flags + null-terminated purpose prefix, or null if malformed.\n/** @internal */\nexport function readUuidBoxPurpose(payload: Uint8Array): { purpose: string; rest: Uint8Array } | null {\n\tif (payload.length < FULLBOX_HEADER_SIZE) return null\n\n\tlet offset = FULLBOX_HEADER_SIZE\n\twhile (offset < payload.length && payload[offset] !== 0) offset++\n\tif (offset >= payload.length) return null\n\n\treturn {\n\t\tpurpose: TEXT_DECODER.decode(payload.subarray(FULLBOX_HEADER_SIZE, offset)),\n\t\trest: payload.subarray(offset + 1),\n\t}\n}\n\n/**\n * Strips the JUMBF UUID box prefix (fullbox header, purpose string, aux offset)\n * to return only the JUMBF manifest data.\n *\n * Structure per ISO 19566-5 / C2PA BMFF storage:\n * version(1) + flags(3) + purpose(null-terminated) + aux_offset(8) + JUMBF data\n *\n * Returns `null` if the payload does not contain a valid JUMBF UUID prefix.\n *\n * @internal\n */\nexport function stripJumbfUuidPrefix(payload: Uint8Array): Uint8Array | null {\n\tconst prefix = readUuidBoxPurpose(payload)\n\tif (!prefix || prefix.rest.length < AUX_UUID_OFFSET_SIZE) return null\n\treturn prefix.rest.subarray(AUX_UUID_OFFSET_SIZE)\n}\n","/**\n * Minimal ASN.1 DER parsing helpers for X.509 certificate navigation.\n *\n * @internal\n */\n\nexport const ASN1_TAG_INTEGER = 0x02\nexport const ASN1_TAG_OBJECT_IDENTIFIER = 0x06\nexport const ASN1_TAG_SEQUENCE = 0x30\nexport const ASN1_TAG_SET = 0x31\nexport const ASN1_TAG_UTC_TIME = 0x17\nexport const ASN1_TAG_GENERALIZED_TIME = 0x18\nexport const ASN1_TAG_CONTEXT_0 = 0xa0\nconst ASN1_LONG_FORM_FLAG = 0x80\nconst ASN1_LONG_FORM_MASK = 0x7f\n\nexport type Asn1Element = {\n\treadonly tag: number\n\treadonly value: Uint8Array\n\treadonly totalSize: number\n}\n\nexport function readLength(bytes: Uint8Array, offset: number): { length: number; bytesRead: number } {\n\tif (offset >= bytes.length) return { length: 0, bytesRead: 0 }\n\tconst first = bytes[offset] ?? 0\n\tif (first < ASN1_LONG_FORM_FLAG) return { length: first, bytesRead: 1 }\n\tconst count = first & ASN1_LONG_FORM_MASK\n\tlet length = 0\n\tfor (let i = 0; i < count; i++) {\n\t\tlength = (length << 8) | (bytes[offset + 1 + i] ?? 0)\n\t}\n\treturn { length, bytesRead: 1 + count }\n}\n\nexport function readElement(bytes: Uint8Array, offset: number): Asn1Element | null {\n\tif (offset + 2 > bytes.length) return null\n\tconst tag = bytes[offset] ?? 0\n\tconst { length, bytesRead } = readLength(bytes, offset + 1)\n\tconst headerSize = 1 + bytesRead\n\tconst valueEnd = offset + headerSize + length\n\tif (valueEnd > bytes.length) return null\n\treturn {\n\t\ttag,\n\t\tvalue: bytes.subarray(offset + headerSize, valueEnd),\n\t\ttotalSize: headerSize + length,\n\t}\n}\n\n/**\n * Reads an ASN.1 element and returns its full DER encoding (tag + length + value).\n *\n * @internal\n */\nexport function readElementRaw(bytes: Uint8Array, offset: number): Uint8Array | null {\n\tconst el = readElement(bytes, offset)\n\tif (!el) return null\n\treturn bytes.subarray(offset, offset + el.totalSize)\n}\n","const TEXT_DECODER = /* @__PURE__ */ new TextDecoder()\n\nimport type { CertificateInfo } from './CertificateInfo.ts'\nimport {\n\tASN1_TAG_CONTEXT_0,\n\tASN1_TAG_GENERALIZED_TIME,\n\tASN1_TAG_INTEGER,\n\tASN1_TAG_OBJECT_IDENTIFIER,\n\tASN1_TAG_SEQUENCE,\n\tASN1_TAG_SET,\n\tASN1_TAG_UTC_TIME,\n\treadElement,\n\ttype Asn1Element,\n} from './asn1.ts'\n\nconst OID_COMMON_NAME = new Uint8Array([0x55, 0x04, 0x03])\nconst OID_ORG_NAME = new Uint8Array([0x55, 0x04, 0x0a])\n\nfunction matchesOID(value: Uint8Array, oid: Uint8Array): boolean {\n\tif (value.length < oid.length) return false\n\tfor (let i = 0; i < oid.length; i++) {\n\t\tif (value[i] !== oid[i]) return false\n\t}\n\treturn true\n}\n\nfunction parseTime(element: Asn1Element): string | null {\n\tconst text = TEXT_DECODER.decode(element.value)\n\tif (element.tag === ASN1_TAG_UTC_TIME) {\n\t\tconst yy = parseInt(text.substring(0, 2), 10)\n\t\tconst year = yy >= 50 ? 1900 + yy : 2000 + yy\n\t\treturn `${year}-${text.substring(2, 4)}-${text.substring(4, 6)}T${text.substring(6, 8)}:${text.substring(8, 10)}:${text.substring(10, 12)}Z`\n\t}\n\tif (element.tag === ASN1_TAG_GENERALIZED_TIME) {\n\t\treturn `${text.substring(0, 4)}-${text.substring(4, 6)}-${text.substring(6, 8)}T${text.substring(8, 10)}:${text.substring(10, 12)}:${text.substring(12, 14)}Z`\n\t}\n\treturn null\n}\n\nfunction findOidValueInSequence(seqValue: Uint8Array, targetOID: Uint8Array): string | null {\n\tconst oidEl = readElement(seqValue, 0)\n\tif (!oidEl || oidEl.tag !== ASN1_TAG_OBJECT_IDENTIFIER) return null\n\tif (!matchesOID(oidEl.value, targetOID)) return null\n\n\tconst valEl = readElement(seqValue, oidEl.totalSize)\n\treturn valEl ? TEXT_DECODER.decode(valEl.value) : null\n}\n\nfunction findRDNValue(issuerValue: Uint8Array, targetOID: Uint8Array): string | null {\n\tlet offset = 0\n\twhile (offset < issuerValue.length) {\n\t\tconst setEl = readElement(issuerValue, offset)\n\t\tif (!setEl || setEl.tag !== ASN1_TAG_SET) break\n\n\t\tlet setOffset = 0\n\t\twhile (setOffset < setEl.value.length) {\n\t\t\tconst seqEl = readElement(setEl.value, setOffset)\n\t\t\tif (!seqEl || seqEl.tag !== ASN1_TAG_SEQUENCE) break\n\n\t\t\tconst found = findOidValueInSequence(seqEl.value, targetOID)\n\t\t\tif (found) return found\n\n\t\t\tsetOffset += seqEl.totalSize\n\t\t}\n\t\toffset += setEl.totalSize\n\t}\n\treturn null\n}\n\n/**\n * Extracts the issuer name and `notBefore` date from a DER-encoded X.509 certificate.\n *\n * Uses a minimal ASN.1 parser that handles the subset of DER structures found in\n * typical C2PA signing certificates. Extracts the issuer Common Name (OID 2.5.4.3)\n * or Organization Name (OID 2.5.4.10) as a fallback, and the `notBefore` validity date.\n *\n * @param certDER - DER-encoded X.509 certificate bytes\n * @returns Certificate information, or `null` if parsing fails\n *\n * @example\n * {@includeCode ../../test/x509/extractCertificateInfo.test.ts#example}\n *\n * @internal\n */\nexport function extractCertificateInfo(certDER: Uint8Array): CertificateInfo | null {\n\ttry {\n\t\tconst cert = readElement(certDER, 0)\n\t\tif (!cert || cert.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tconst tbs = readElement(cert.value, 0)\n\t\tif (!tbs || tbs.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tlet offset = 0\n\t\tlet el = readElement(tbs.value, offset)\n\t\tif (!el) return null\n\n\t\t// Optional version field (context tag [0])\n\t\tif (el.tag === ASN1_TAG_CONTEXT_0) {\n\t\t\toffset += el.totalSize\n\t\t\tel = readElement(tbs.value, offset)\n\t\t\tif (!el) return null\n\t\t}\n\n\t\t// Serial number\n\t\tif (el.tag !== ASN1_TAG_INTEGER) return null\n\t\toffset += el.totalSize\n\n\t\t// Signature algorithm\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// Issuer\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\tconst issuer =\n\t\t\tfindRDNValue(el.value, OID_COMMON_NAME) ??\n\t\t\tfindRDNValue(el.value, OID_ORG_NAME) ??\n\t\t\t'Unknown Issuer'\n\t\toffset += el.totalSize\n\n\t\t// Validity\n\t\tel = readElement(tbs.value, offset)\n\t\tlet notBefore: string | null = null\n\t\tif (el && el.tag === ASN1_TAG_SEQUENCE) {\n\t\t\tconst timeEl = readElement(el.value, 0)\n\t\t\tif (timeEl) notBefore = parseTime(timeEl)\n\t\t}\n\n\t\treturn { issuer, notBefore }\n\t}\n\tcatch {\n\t\treturn null\n\t}\n}\n","const TEXT_DECODER = /* @__PURE__ */ new TextDecoder()\n\nimport { readIsoBoxes, type ParsedIsoBox } from '@svta/cml-iso-bmff'\nimport { decode } from 'cbor-x/decode'\nimport type { C2paAssertion } from './C2paAssertion.ts'\nimport type { C2paManifest } from './C2paManifest.ts'\nimport type { ClaimAssertionRef } from './claim/ClaimAssertionRef.ts'\nimport type { InternalAssertionData, InternalManifestData } from './claim/InternalManifestData.ts'\nimport { decodeCoseSign1 } from './cose/decodeCoseSign1.ts'\nimport type { JumbfBox } from './jumbf/JumbfBox.ts'\nimport { parseJumbfBoxes } from './jumbf/parseJumbfBoxes.ts'\nimport { parseJumbfLabel } from './jumbf/parseJumbfLabel.ts'\nimport { findC2paUuidBox, stripJumbfUuidPrefix } from './utils.ts'\nimport { extractCertificateInfo } from './x509/extractCertificateInfo.ts'\n\n\nconst MAX_JUMBF_NESTING_DEPTH = 20\nconst X5CHAIN_HEADER_LABEL = 33\n\nfunction resolveManifestBoxes(jumbfBoxes: JumbfBox[], depth = 0): JumbfBox[] {\n\tif (depth >= MAX_JUMBF_NESTING_DEPTH) return jumbfBoxes\n\n\t// Skip jumd description boxes — they contain labels, not manifest content\n\tconst contentBoxes = jumbfBoxes.filter(b => b.type !== 'jumd')\n\n\t// Single jumb wrapping — unwrap one level and recurse\n\t// This handles: store jumb → manifest jumb → claim/assertions/signature\n\tconst firstBox = contentBoxes[0]\n\tif (contentBoxes.length === 1 && firstBox?.type === 'jumb') {\n\t\treturn resolveManifestBoxes(parseJumbfBoxes(firstBox.data), depth + 1)\n\t}\n\n\treturn jumbfBoxes\n}\n\nfunction extractManifestLabel(jumbfBoxes: JumbfBox[]): string | null {\n\t// Navigate: store jumb → manifest jumb → jumd label\n\tfor (const box of jumbfBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tfor (const child of inner) {\n\t\t\tif (child.type !== 'jumb') continue\n\t\t\tconst childInner = parseJumbfBoxes(child.data)\n\t\t\tconst jumd = childInner.find(b => b.type === 'jumd')\n\t\t\tif (jumd) {\n\t\t\t\tconst label = parseJumbfLabel(jumd.data)\n\t\t\t\tif (label) return label\n\t\t\t}\n\t\t}\n\t}\n\treturn null\n}\n\nfunction parseAssertionsInternal(assertionStoreBoxes: JumbfBox[]): InternalAssertionData[] {\n\tconst assertions: InternalAssertionData[] = []\n\n\tfor (const box of assertionStoreBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\t\tif (!jumd) continue\n\n\t\tconst label = parseJumbfLabel(jumd.data)\n\t\tif (!label) continue\n\n\t\tconst contentBox = inner.find(\n\t\t\tb => b.type === 'cbor' || b.type === 'json' || b.type === 'jumc' || b.type === 'jp2c' || b.type === 'bidb',\n\t\t)\n\n\t\tlet data: unknown = null\n\t\tif (contentBox) {\n\t\t\tif (contentBox.type === 'cbor') {\n\t\t\t\ttry { data = decode(contentBox.data) as unknown } catch { data = contentBox.data }\n\t\t\t}\n\t\t\telse if (contentBox.type === 'json') {\n\t\t\t\ttry { data = JSON.parse(TEXT_DECODER.decode(contentBox.data)) as unknown } catch { data = contentBox.data }\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdata = contentBox.data\n\t\t\t}\n\t\t}\n\n\t\tassertions.push({ label, data, rawBoxPayload: box.data })\n\t}\n\n\treturn assertions\n}\n\nfunction parseSignatureInfo(signatureBytes: Uint8Array | null): { issuer: string | null; certNotBefore: string | null } {\n\tif (!signatureBytes) return { issuer: null, certNotBefore: null }\n\ttry {\n\t\tconst cose = decodeCoseSign1(signatureBytes)\n\t\tconst x5chain = (cose.protectedHeader[X5CHAIN_HEADER_LABEL] ?? cose.unprotectedHeader[X5CHAIN_HEADER_LABEL]) as Uint8Array | Uint8Array[] | null | undefined\n\t\tif (!x5chain) return { issuer: null, certNotBefore: null }\n\n\t\tconst certDER = Array.isArray(x5chain) ? x5chain[0] : x5chain\n\t\tif (!(certDER instanceof Uint8Array)) return { issuer: null, certNotBefore: null }\n\n\t\tconst certInfo = extractCertificateInfo(certDER)\n\t\treturn { issuer: certInfo?.issuer ?? null, certNotBefore: certInfo?.notBefore ?? null }\n\t} catch {\n\t\t// signature parsing failed — continue without signature info\n\t\treturn { issuer: null, certNotBefore: null }\n\t}\n}\n\nfunction extractClaimAssertionRefs(claimData: Record<string, unknown>): ClaimAssertionRef[] {\n\tconst created = claimData['created_assertions'] as unknown[] | undefined\n\tconst gathered = claimData['gathered_assertions'] as unknown[] | undefined\n\tconst v1 = claimData['assertions'] as unknown[] | undefined\n\n\tconst sources = [...(created ?? []), ...(gathered ?? []), ...(v1 ?? [])]\n\tconst refs: ClaimAssertionRef[] = []\n\n\tfor (const entry of sources) {\n\t\tif (!entry || typeof entry !== 'object') continue\n\t\tconst e = entry as Record<string, unknown>\n\t\tconst url = e['url'] as string | undefined\n\t\tconst hash = e['hash']\n\t\tif (!url || !hash) continue\n\n\t\trefs.push({\n\t\t\turl,\n\t\t\thash: hash instanceof Uint8Array ? hash : new Uint8Array(hash as number[]),\n\t\t\talg: (e['alg'] as string | undefined) ?? null,\n\t\t})\n\t}\n\n\treturn refs\n}\n\n/**\n * Reads a C2PA manifest from raw BMFF bytes.\n *\n * Locates the C2PA UUID box (`d8fec3d6-1a96-4f32-a0f6-f3ecf96c10ea`), navigates\n * the JUMBF manifest store structure (ISO 19566-5), and returns the parsed active\n * manifest with its claims, assertions, and signature information.\n *\n * This function performs structural parsing only. It does not verify the\n * cryptographic signature of the claim.\n *\n * @param bytes - Raw BMFF bytes (e.g. an MP4 init segment or media segment)\n * @param preParsedBoxes - Optional pre-parsed ISO boxes to avoid redundant parsing\n * @returns The parsed manifest data including claim, assertions, and signature bytes\n * @throws If no C2PA UUID box is found, or the JUMBF structure is invalid\n *\n * @example\n * {@includeCode ../test/readC2paManifest.test.ts#example}\n *\n * @internal\n */\nexport function readC2paManifest(bytes: Uint8Array, preParsedBoxes?: ParsedIsoBox[]): InternalManifestData {\n\tconst boxes = preParsedBoxes ?? readIsoBoxes(bytes)\n\tconst uuidBox = findC2paUuidBox(boxes)\n\n\tif (!uuidBox) {\n\t\tthrow new Error('No C2PA UUID box found in the provided bytes')\n\t}\n\n\tconst rawPayload = uuidBox.view.readData(uuidBox.view.bytesRemaining) as Uint8Array\n\tconst jumbfPayload = stripJumbfUuidPrefix(rawPayload)\n\tif (!jumbfPayload) {\n\t\tthrow new Error('Invalid JUMBF UUID prefix in C2PA box')\n\t}\n\tconst jumbfBoxes = parseJumbfBoxes(jumbfPayload)\n\n\tif (jumbfBoxes.length === 0) {\n\t\tthrow new Error('No JUMBF boxes found in C2PA UUID box')\n\t}\n\n\tconst manifestLabel = extractManifestLabel(jumbfBoxes)\n\tconst manifestBoxes = resolveManifestBoxes(jumbfBoxes)\n\n\tlet claimData: Record<string, unknown> | null = null\n\tlet claimCborBytes: Uint8Array | null = null\n\tlet internalAssertions: InternalAssertionData[] = []\n\tlet signatureBytes: Uint8Array | null = null\n\n\tfor (const box of manifestBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\t\tif (!jumd) continue\n\n\t\tconst label = parseJumbfLabel(jumd.data)\n\t\tif (!label) continue\n\n\t\tif (label === 'c2pa.claim' || label === 'c2pa.claim.v2') {\n\t\t\tconst contentBox = inner.find(b => b.type === 'cbor')\n\t\t\tif (contentBox) {\n\t\t\t\tclaimCborBytes = contentBox.data\n\t\t\t\ttry { claimData = decode(contentBox.data) as Record<string, unknown> } catch { /* malformed claim — continue */ }\n\t\t\t}\n\t\t}\n\t\telse if (label === 'c2pa.assertions') {\n\t\t\tinternalAssertions = parseAssertionsInternal(inner)\n\t\t}\n\t\telse if (label === 'c2pa.signature') {\n\t\t\tconst contentBox = inner.find(b => b.type === 'cbor' || b.type === 'jumc')\n\t\t\tif (contentBox) signatureBytes = contentBox.data\n\t\t}\n\t}\n\n\tconst { issuer, certNotBefore } = parseSignatureInfo(signatureBytes)\n\n\tconst instanceId = (claimData?.['instanceID'] ?? claimData?.['instance_id'] ?? null) as string | null\n\tconst claimGenerator = (claimData?.['claim_generator'] ?? claimData?.['claimGenerator'] ?? null) as string | null\n\tconst resolvedLabel =\n\t\tmanifestLabel ??\n\t\t(claimData?.['dc:title'] as string | undefined) ??\n\t\t(claimData?.['title'] as string | undefined) ??\n\t\tinstanceId ??\n\t\t'unknown'\n\n\tconst claimAssertionRefs = claimData ? extractClaimAssertionRefs(claimData) : []\n\n\tconst assertions: C2paAssertion[] = internalAssertions.map(a => ({ label: a.label, data: a.data }))\n\n\tconst manifest: C2paManifest = {\n\t\tlabel: resolvedLabel,\n\t\tinstanceId,\n\t\tclaimGenerator,\n\t\tsignatureInfo: { issuer, certNotBefore },\n\t\tassertions,\n\t}\n\n\treturn {\n\t\tmanifest,\n\t\tclaimAssertionRefs,\n\t\tclaimCborBytes,\n\t\tsignatureBytes,\n\t\tassertions: internalAssertions,\n\t}\n}\n\n","import type { BmffHashConstraint, BmffHashExclusion } from './BmffHashExclusion.ts'\n\nfunction bytesMatchAt(boxData: Uint8Array, offset: number, expected: Uint8Array | readonly number[]): boolean {\n\tconst bytes = expected instanceof Uint8Array ? expected : new Uint8Array(expected as number[])\n\tif (offset + bytes.length > boxData.length) return false\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tif (boxData[offset + i] !== bytes[i]) return false\n\t}\n\treturn true\n}\n\nfunction constraintMatches(boxData: Uint8Array, constraint: BmffHashConstraint): boolean {\n\treturn bytesMatchAt(boxData, constraint.offset, constraint.value)\n}\n\n/**\n * Returns `true` if the given BMFF box should be excluded from the\n * C2PA content hash, based on the provided exclusion list.\n *\n * Exclusions use C2PA xpath notation (e.g. `/emsg`, `/moof/traf`).\n * Optional `data` constraints narrow the match to specific box content by byte offset.\n *\n * @param boxType - Four-character box type code (e.g. `'emsg'`, `'moof'`)\n * @param boxData - Full box bytes including the 8-byte size+type header\n * @param exclusions - Exclusion list from the C2PA `c2pa.hash.bmff.v3` assertion\n * @returns `true` if the box should be excluded from the hash input\n *\n * @example\n * {@includeCode ../../test/bmff/shouldExcludeBox.test.ts#example}\n *\n * @public\n */\nexport function shouldExcludeBox(\n\tboxType: string,\n\tboxData: Uint8Array,\n\texclusions: readonly BmffHashExclusion[],\n): boolean {\n\tfor (const exclusion of exclusions) {\n\t\tif (!exclusion.xpath) continue\n\t\tconst xpathMatchesType = exclusion.xpath === `/${boxType}` || exclusion.xpath.startsWith(`/${boxType}/`)\n\t\tif (!xpathMatchesType) continue\n\t\tconst { data } = exclusion\n\t\tif (!data || data.length === 0) return true\n\t\tif (data.every(constraint => constraintMatches(boxData, constraint))) return true\n\t}\n\treturn false\n}\n","import type { BmffHashExclusion } from './BmffHashExclusion.ts'\nimport { shouldExcludeBox } from './shouldExcludeBox.ts'\n\nconst MINIMUM_BOX_SIZE = 8 // size(4) + type(4)\nconst BOX_TYPE_OFFSET = 4\nconst DEFAULT_HASH_ALG = 'SHA-256'\n\n/**\n * Options for BMFF content hash computation.\n *\n * @internal\n */\nexport type BmffHashOptions = {\n\treadonly exclusions?: readonly BmffHashExclusion[]\n\treadonly alg?: string\n\t/** `8` for offset-prefix mode, `0` (default) for no prefix. */\n\treadonly offsetPrefixSize?: number\n}\n\nfunction readBoxType(bytes: Uint8Array, offset: number): string {\n\treturn String.fromCharCode(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3])\n}\n\nfunction writeUint64BigEndian(bytes: Uint8Array, value: number): void {\n\tnew DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).setBigUint64(0, BigInt(value), false)\n}\n\nfunction buildHashInput(\n\tbytes: Uint8Array,\n\texclusions: readonly BmffHashExclusion[],\n\toffsetPrefixSize: number,\n): Uint8Array {\n\tif (offsetPrefixSize !== 0 && offsetPrefixSize !== 8) {\n\t\tthrow new Error(`offsetPrefixSize must be 0 or 8, got ${offsetPrefixSize}`)\n\t}\n\n\tconst view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t// First pass: calculate total size\n\tlet totalLength = 0\n\tlet offset = 0\n\twhile (offset + MINIMUM_BOX_SIZE <= bytes.length) {\n\t\tconst boxSize = view.getUint32(offset, false)\n\t\tif (boxSize < MINIMUM_BOX_SIZE || offset + boxSize > bytes.length) break\n\t\tconst boxType = readBoxType(bytes, offset + BOX_TYPE_OFFSET)\n\t\tconst boxData = bytes.subarray(offset, offset + boxSize)\n\t\tif (!shouldExcludeBox(boxType, boxData, exclusions)) {\n\t\t\ttotalLength += offsetPrefixSize + boxSize\n\t\t}\n\t\toffset += boxSize\n\t}\n\n\t// Second pass: write directly into pre-sized buffer\n\tconst hashInput = new Uint8Array(totalLength)\n\tlet writeOffset = 0\n\toffset = 0\n\twhile (offset + MINIMUM_BOX_SIZE <= bytes.length) {\n\t\tconst boxSize = view.getUint32(offset, false)\n\t\tif (boxSize < MINIMUM_BOX_SIZE || offset + boxSize > bytes.length) break\n\t\tconst boxType = readBoxType(bytes, offset + BOX_TYPE_OFFSET)\n\t\tconst boxData = bytes.subarray(offset, offset + boxSize)\n\t\tif (!shouldExcludeBox(boxType, boxData, exclusions)) {\n\t\t\tif (offsetPrefixSize > 0) {\n\t\t\t\twriteUint64BigEndian(hashInput.subarray(writeOffset, writeOffset + offsetPrefixSize), offset)\n\t\t\t\twriteOffset += offsetPrefixSize\n\t\t\t}\n\t\t\thashInput.set(boxData, writeOffset)\n\t\t\twriteOffset += boxSize\n\t\t}\n\t\toffset += boxSize\n\t}\n\n\treturn hashInput\n}\n\n/**\n * Computes the C2PA BMFF content hash (`c2pa.hash.bmff.v3`) for a DASH segment.\n *\n * Iterates through top-level BMFF boxes, excludes those matching the exclusion list,\n * concatenates the remaining box bytes (optionally prefixed with each box's file offset),\n * and returns the WebCrypto digest.\n *\n * @param segmentBytes - Raw segment bytes to hash\n * @param options - Hash options (exclusions, algorithm, offset prefix size)\n * @returns The computed hash bytes\n *\n * @example\n * {@includeCode ../../test/bmff/computeBmffHash.test.ts#example}\n *\n * @internal\n */\nexport async function computeBmffHash(segmentBytes: Uint8Array, options?: BmffHashOptions): Promise<Uint8Array> {\n\tconst exclusions = options?.exclusions ?? []\n\tconst alg = options?.alg ?? DEFAULT_HASH_ALG\n\tconst offsetPrefixSize = options?.offsetPrefixSize ?? 0\n\n\tconst hashInput = buildHashInput(segmentBytes, exclusions, offsetPrefixSize)\n\tconst hashBuffer = await crypto.subtle.digest(alg, hashInput)\n\treturn new Uint8Array(hashBuffer)\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Standard C2PA validation status codes for manifest integrity checks,\n * as defined in the C2PA specification chapters 15 and 18.\n *\n * @see {@link https://c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_claim_validation | C2PA Spec §15.10.3}\n *\n * @enum\n *\n * @public\n */\nexport const C2paStatusCode = {\n\t/** Assertion hash does not match the hashed URI in the claim (§15.10.3.1) */\n\tASSERTION_HASHEDURI_MISMATCH: 'assertion.hashedURI.mismatch',\n\t/** An assertion referenced in the claim is missing from the assertion store (§15.10.3.1) */\n\tASSERTION_MISSING: 'assertion.missing',\n\t/** An action requiring an ingredient reference does not have one (§18.15.4.7) */\n\tASSERTION_ACTION_INGREDIENT_MISMATCH: 'assertion.action.ingredientMismatch',\n\t/** Claim signature verification failed, or the signature carries no certificate (§15.7) */\n\tCLAIM_SIGNATURE_MISMATCH: 'claim.signature.mismatch',\n\t/** The manifest has no `c2pa.signature` box, so the claim signature cannot be found (§15.7) */\n\tCLAIM_SIGNATURE_MISSING: 'claimSignature.missing',\n\t/** The manifest has no claim box (§15.6.1) */\n\tCLAIM_MISSING: 'claim.missing',\n\t/** BMFF hash assertion or Merkle structure is malformed (§15.2.2.3) */\n\tASSERTION_BMFFHASH_MALFORMED: 'assertion.bmffHash.malformed',\n\t/** BMFF content hash does not match the committed value (§15.2.2.3) */\n\tASSERTION_BMFFHASH_MISMATCH: 'assertion.bmffHash.mismatch',\n} as const\n\n/**\n * Union type of all {@link (C2paStatusCode:variable)} values.\n *\n * @public\n */\nexport type C2paStatusCode = ValueOf<typeof C2paStatusCode>\n","import { readIsoBoxes } from '@svta/cml-iso-bmff'\nimport { decodeCoseSign1 } from './cose/decodeCoseSign1.ts'\nimport { findC2paUuidBox, stripJumbfUuidPrefix } from './utils.ts'\nimport type { JumbfBox } from './jumbf/JumbfBox.ts'\nimport { parseJumbfBoxes } from './jumbf/parseJumbfBoxes.ts'\nimport { parseJumbfLabel } from './jumbf/parseJumbfLabel.ts'\n\nconst C2PA_SIGNATURE_LABEL = 'c2pa.signature'\nconst X5CHAIN_COSE_HEADER = 33\n\n/**\n * Extracts the end-entity certificate from raw COSE_Sign1 signature bytes.\n *\n * @internal\n */\nexport function extractCertificateFromSignatureBytes(signatureBytes: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst cose = decodeCoseSign1(signatureBytes)\n\t\tconst x5chain = (cose.protectedHeader[X5CHAIN_COSE_HEADER] ??\n\t\t\tcose.unprotectedHeader[X5CHAIN_COSE_HEADER]) as Uint8Array | Uint8Array[] | null | undefined\n\t\tif (!x5chain) return null\n\n\t\tconst certDER = Array.isArray(x5chain) ? x5chain[0] : x5chain\n\t\treturn certDER instanceof Uint8Array ? certDER : null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction findSignatureContentBytes(boxes: JumbfBox[]): Uint8Array | null {\n\tfor (const box of boxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\n\t\tif (jumd && parseJumbfLabel(jumd.data) === C2PA_SIGNATURE_LABEL) {\n\t\t\tconst content = inner.find(b => b.type === 'cbor' || b.type === 'jumc')\n\t\t\treturn content?.data ?? null\n\t\t}\n\n\t\tconst nested = findSignatureContentBytes(inner)\n\t\tif (nested) return nested\n\t}\n\treturn null\n}\n\n/**\n * Extracts the end-entity certificate (DER-encoded) from the C2PA claim signature\n * embedded in a BMFF file.\n *\n * Navigates the JUMBF structure inside the C2PA UUID box to locate the\n * `c2pa.signature` entry, decodes the `COSE_Sign1`, and returns the first\n * certificate from the `x5chain` (COSE protected header label 33).\n *\n * @param mp4Bytes - Raw BMFF bytes (e.g. an MP4 init segment)\n * @returns DER-encoded certificate bytes, or `null` if not found or on any error\n *\n * @example\n * {@includeCode ../test/c2pa/extractManifestCertificate.test.ts#example}\n *\n * @internal\n */\nexport function extractManifestCertificate(mp4Bytes: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst boxes = readIsoBoxes(mp4Bytes)\n\t\tconst uuidBox = findC2paUuidBox(boxes)\n\t\tif (!uuidBox) return null\n\n\t\tconst rawPayload = uuidBox.view.readData(uuidBox.view.bytesRemaining) as Uint8Array\n\t\tconst jumbfPayload = stripJumbfUuidPrefix(rawPayload)\n\t\tif (!jumbfPayload) return null\n\t\tconst signatureBytes = findSignatureContentBytes(parseJumbfBoxes(jumbfPayload))\n\t\tif (!signatureBytes) return null\n\n\t\treturn extractCertificateFromSignatureBytes(signatureBytes)\n\t} catch {\n\t\treturn null\n\t}\n}\n","import { C2paStatusCode } from '../C2paStatusCode.ts'\n\nconst ACTIONS_LABELS = new Set(['c2pa.actions', 'c2pa.actions.v2'])\nconst ACTIONS_REQUIRING_INGREDIENTS = new Set(['c2pa.opened', 'c2pa.placed', 'c2pa.removed'])\n\n/**\n * Validates action ingredient references per C2PA §18.15.4.7.\n *\n * For any `c2pa.actions` or `c2pa.actions.v2` assertion, actions with type\n * `c2pa.opened`, `c2pa.placed`, or `c2pa.removed` must include a\n * `parameters.ingredients` field. Reports `assertion.action.ingredientMismatch`\n * if any such action is missing the required field.\n *\n * @param assertions - Parsed assertions (label + decoded data)\n * @returns Array of C2PA status codes for any failures found\n *\n * @internal\n */\nexport function validateActionIngredients(\n\tassertions: readonly { readonly label: string; readonly data: unknown }[],\n): readonly C2paStatusCode[] {\n\tconst codes: C2paStatusCode[] = []\n\n\tfor (const assertion of assertions) {\n\t\tif (!ACTIONS_LABELS.has(assertion.label)) continue\n\n\t\tconst data = assertion.data as Record<string, unknown> | null\n\t\tif (!data) continue\n\n\t\tconst actions = data['actions'] as unknown[] | undefined\n\t\tif (!Array.isArray(actions)) continue\n\n\t\tfor (const action of actions) {\n\t\t\tif (!action || typeof action !== 'object') continue\n\t\t\tconst record = action as Record<string, unknown>\n\t\t\tconst actionType = record['action'] as string | undefined\n\t\t\tif (!actionType || !ACTIONS_REQUIRING_INGREDIENTS.has(actionType)) continue\n\n\t\t\tconst parameters = record['parameters'] as Record<string, unknown> | undefined\n\t\t\tconst ingredients = parameters?.['ingredients']\n\n\t\t\tif (!Array.isArray(ingredients) || ingredients.length === 0) {\n\t\t\t\tcodes.push(C2paStatusCode.ASSERTION_ACTION_INGREDIENT_MISMATCH)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn codes\n}\n","import { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { hashesEqual, normalizeAlgorithmName } from '../utils.ts'\nimport type { ClaimAssertionRef } from './ClaimAssertionRef.ts'\nimport type { InternalAssertionData } from './InternalManifestData.ts'\n\n/**\n * Extracts the assertion label from a JUMBF URI.\n *\n * Handles both absolute (`self#jumbf=/c2pa/<manifest>/c2pa.assertions/<label>`)\n * and relative URI forms by returning the last path segment.\n */\nfunction extractLabelFromUrl(url: string): string {\n\tconst fragmentIndex = url.indexOf('#jumbf=')\n\tconst path = fragmentIndex >= 0 ? url.substring(fragmentIndex + 7) : url\n\tconst lastSlash = path.lastIndexOf('/')\n\treturn lastSlash >= 0 ? path.substring(lastSlash + 1) : path\n}\n\n/**\n * Validates assertion hashes and presence per C2PA §15.10.3.1.\n *\n * For each assertion referenced in the claim's hashed URI list:\n * - Checks that the assertion exists in the assertion store (`assertion.missing`)\n * - Recomputes the hash of the raw JUMBF box payload and compares it to the\n * expected hash from the claim (`assertion.hashedURI.mismatch`)\n *\n * @param claimRefs - Hashed URI references from the claim\n * @param assertions - Parsed assertions with preserved raw box payloads\n * @returns Array of C2PA status codes for any failures found\n *\n * @internal\n */\nexport async function validateAssertionHashes(\n\tclaimRefs: readonly ClaimAssertionRef[],\n\tassertions: readonly InternalAssertionData[],\n): Promise<readonly C2paStatusCode[]> {\n\tif (claimRefs.length === 0) return []\n\n\tconst assertionsByLabel = new Map<string, InternalAssertionData>()\n\tfor (const assertion of assertions) {\n\t\tassertionsByLabel.set(assertion.label, assertion)\n\t}\n\n\tconst codes: C2paStatusCode[] = []\n\n\tconst hashChecks = claimRefs.map(async (ref) => {\n\t\tconst label = extractLabelFromUrl(ref.url)\n\t\tconst assertion = assertionsByLabel.get(label)\n\n\t\tif (!assertion) {\n\t\t\treturn C2paStatusCode.ASSERTION_MISSING\n\t\t}\n\n\t\tconst alg = ref.alg ? normalizeAlgorithmName(ref.alg) : 'SHA-256'\n\t\tconst computedHash = new Uint8Array(\n\t\t\tawait crypto.subtle.digest(alg, assertion.rawBoxPayload),\n\t\t)\n\n\t\tif (!hashesEqual(computedHash, ref.hash)) {\n\t\t\treturn C2paStatusCode.ASSERTION_HASHEDURI_MISMATCH\n\t\t}\n\n\t\treturn null\n\t})\n\n\tconst results = await Promise.all(hashChecks)\n\tfor (const result of results) {\n\t\tif (result) codes.push(result)\n\t}\n\n\treturn codes\n}\n","// WebCrypto algorithm names\nexport const ECDSA_ALGORITHM = 'ECDSA'\nexport const ED25519_ALGORITHM = 'Ed25519'\nexport const RSA_PSS_ALGORITHM = 'RSA-PSS'\n\n// Named curves\nexport const CURVE_P256 = 'P-256'\nexport const CURVE_P384 = 'P-384'\nexport const CURVE_P521 = 'P-521'\n\n// Hash algorithms\nexport const HASH_SHA256 = 'SHA-256'\nexport const HASH_SHA384 = 'SHA-384'\nexport const HASH_SHA512 = 'SHA-512'\n","import {\n\tCURVE_P256, \n\tCURVE_P384, \n\tCURVE_P521,\n\tECDSA_ALGORITHM, \n\tED25519_ALGORITHM, \n\tRSA_PSS_ALGORITHM,\n\tHASH_SHA256, \n\tHASH_SHA384, \n\tHASH_SHA512,\n} from './constants.ts'\n\nconst COSE_ALG_ES256 = -7\nconst COSE_ALG_ES384 = -35\nconst COSE_ALG_ES512 = -36\nconst COSE_ALG_EDDSA = -8\nconst COSE_ALG_PS256 = -37\nconst COSE_ALG_PS384 = -38\nconst COSE_ALG_PS512 = -39\n\ntype CoseAlgorithm = AlgorithmIdentifier | EcKeyImportParams | RsaHashedImportParams\n\nconst COSE_ALGORITHM_MAP = new Map<number, CoseAlgorithm>([\n\t[COSE_ALG_ES256, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P256 }],\n\t[COSE_ALG_ES384, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P384 }],\n\t[COSE_ALG_ES512, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P521 }],\n\t[COSE_ALG_EDDSA, { name: ED25519_ALGORITHM }],\n\t[COSE_ALG_PS256, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA256 } }],\n\t[COSE_ALG_PS384, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA384 } }],\n\t[COSE_ALG_PS512, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA512 } }],\n])\n\n/**\n * Maps a COSE algorithm number (from a COSE_Sign1 protected header) to the\n * WebCrypto algorithm identifier needed for `crypto.subtle.importKey('spki', ...)`.\n *\n * @param coseAlg - COSE algorithm identifier (e.g. -7 for ES256)\n * @returns WebCrypto algorithm identifier\n * @throws If the COSE algorithm is not supported\n *\n * @internal\n */\nexport function resolveAlgorithmFromCoseAlg(coseAlg: number): CoseAlgorithm {\n\tconst algorithm = COSE_ALGORITHM_MAP.get(coseAlg)\n\tif (!algorithm) {\n\t\tthrow new Error(`Unsupported COSE algorithm: ${coseAlg}`)\n\t}\n\treturn algorithm\n}\n","const CBOR_ARRAY_FOUR_ITEMS = 0x84\nconst CBOR_TEXT_MAJOR_TYPE_BASE = 0x60\nconst CBOR_BYTES_MAJOR_TYPE_BASE = 0x40\nconst CBOR_UINT8_LENGTH_INDICATOR = 0x58\nconst CBOR_UINT16_LENGTH_INDICATOR = 0x59\nconst CBOR_UINT32_LENGTH_INDICATOR = 0x5a\nconst CBOR_INLINE_MAX = 23\nconst CBOR_UINT8_MAX = 255\nconst CBOR_UINT16_MAX = 65535\nconst COSE_SIG1_CONTEXT_BYTES = /* @__PURE__ */ new TextEncoder().encode('Signature1')\n\nfunction byteStringHeaderSize(length: number): number {\n\tif (length <= CBOR_INLINE_MAX) return 1\n\tif (length <= CBOR_UINT8_MAX) return 2\n\tif (length <= CBOR_UINT16_MAX) return 3\n\treturn 5\n}\n\nfunction writeByteStringHeader(output: Uint8Array, offset: number, length: number): number {\n\tif (length <= CBOR_INLINE_MAX) {\n\t\toutput[offset++] = CBOR_BYTES_MAJOR_TYPE_BASE + length\n\t} else if (length <= CBOR_UINT8_MAX) {\n\t\toutput[offset++] = CBOR_UINT8_LENGTH_INDICATOR\n\t\toutput[offset++] = length\n\t} else if (length <= CBOR_UINT16_MAX) {\n\t\toutput[offset++] = CBOR_UINT16_LENGTH_INDICATOR\n\t\toutput[offset++] = (length >> 8) & 0xff\n\t\toutput[offset++] = length & 0xff\n\t} else {\n\t\toutput[offset++] = CBOR_UINT32_LENGTH_INDICATOR\n\t\toutput[offset++] = (length >>> 24) & 0xff\n\t\toutput[offset++] = (length >>> 16) & 0xff\n\t\toutput[offset++] = (length >>> 8) & 0xff\n\t\toutput[offset++] = length & 0xff\n\t}\n\treturn offset\n}\n\n/**\n * Builds the COSE `Sig_Structure` (ToBeSigned) bytes for a `COSE_Sign1` structure (RFC 9052 §4.4).\n *\n * The resulting bytes are the direct input to signature creation or verification via WebCrypto.\n *\n * @param protectedBytes - Serialized protected header (CBOR-encoded byte string)\n * @param payload - Payload bytes\n * @param externalAad - External additional authenticated data (default: empty)\n * @returns CBOR-encoded `Sig_Structure` array ready for signing or verification\n *\n * @example\n * {@includeCode ../../test/cose/buildSigStructure.test.ts#example}\n *\n * @public\n */\nexport function buildSigStructure(\n\tprotectedBytes: Uint8Array,\n\tpayload: Uint8Array,\n\texternalAad: Uint8Array = new Uint8Array(0),\n): Uint8Array {\n\tconst totalLength =\n\t\t1 // array header\n\t\t+ 1 + COSE_SIG1_CONTEXT_BYTES.length // context string (length < 24, fits inline)\n\t\t+ byteStringHeaderSize(protectedBytes.length) + protectedBytes.length\n\t\t+ byteStringHeaderSize(externalAad.length) + externalAad.length\n\t\t+ byteStringHeaderSize(payload.length) + payload.length\n\n\tconst result = new Uint8Array(totalLength)\n\tlet offset = 0\n\n\tresult[offset++] = CBOR_ARRAY_FOUR_ITEMS\n\tresult[offset++] = CBOR_TEXT_MAJOR_TYPE_BASE + COSE_SIG1_CONTEXT_BYTES.length\n\tresult.set(COSE_SIG1_CONTEXT_BYTES, offset)\n\toffset += COSE_SIG1_CONTEXT_BYTES.length\n\n\toffset = writeByteStringHeader(result, offset, protectedBytes.length)\n\tresult.set(protectedBytes, offset)\n\toffset += protectedBytes.length\n\n\toffset = writeByteStringHeader(result, offset, externalAad.length)\n\tresult.set(externalAad, offset)\n\toffset += externalAad.length\n\n\toffset = writeByteStringHeader(result, offset, payload.length)\n\tresult.set(payload, offset)\n\n\treturn result\n}\n","import type { CoseSign1 } from './CoseSign1.ts'\nimport { buildSigStructure } from './buildSigStructure.ts'\nimport {\n\tCURVE_P256, \n\tCURVE_P384, \n\tCURVE_P521,\n\tECDSA_ALGORITHM, \n\tED25519_ALGORITHM, \n\tRSA_PSS_ALGORITHM,\n\tHASH_SHA256, \n\tHASH_SHA384, \n\tHASH_SHA512,\n} from './constants.ts'\n\nconst DER_SEQUENCE_TAG = 0x30\nconst DER_INTEGER_TAG = 0x02\n\nconst CURVE_COMPONENT_BYTES: Record<string, number> = { [CURVE_P256]: 32, [CURVE_P384]: 48, [CURVE_P521]: 66 }\n\ntype EcKeyAlgorithm = KeyAlgorithm & { readonly namedCurve: string }\ntype RsaHashedKeyAlgorithm = KeyAlgorithm & { readonly hash: { readonly name: string } }\n\nconst RSA_PSS_SALT_LENGTH: Record<string, number> = {\n\t[HASH_SHA256]: 32,\n\t[HASH_SHA384]: 48,\n\t[HASH_SHA512]: 64,\n}\n\nfunction getComponentSize(publicKey: CryptoKey): number {\n\tconst curve = (publicKey.algorithm as EcKeyAlgorithm).namedCurve\n\tconst size = CURVE_COMPONENT_BYTES[curve]\n\tif (!size) throw new Error(`Unsupported EC curve: ${curve}`)\n\treturn size\n}\n\nfunction isDerEncoded(signature: Uint8Array, expectedRawLength: number): boolean {\n\treturn signature.length !== expectedRawLength && signature.length > 2 && signature[0] === DER_SEQUENCE_TAG\n}\n\nfunction parseDerLength(der: Uint8Array, offset: number): { length: number; nextOffset: number } {\n\tif (offset >= der.length) throw new Error('DER signature: truncated length')\n\tconst firstByte = der[offset]\n\tif ((firstByte & 0x80) === 0) {\n\t\treturn { length: firstByte, nextOffset: offset + 1 }\n\t}\n\tconst numBytes = firstByte & 0x7f\n\tif (numBytes === 0 || offset + numBytes >= der.length) throw new Error('DER signature: invalid long-form length')\n\tlet length = 0\n\tfor (let i = 1; i <= numBytes; i++) {\n\t\tlength = (length << 8) | der[offset + i]\n\t}\n\treturn { length, nextOffset: offset + 1 + numBytes }\n}\n\nfunction extractDerInteger(\n\tder: Uint8Array,\n\toffset: number,\n): { value: Uint8Array; nextOffset: number } {\n\tif (der[offset] !== DER_INTEGER_TAG) throw new Error('DER signature: expected INTEGER tag')\n\tconst { length, nextOffset: valueStart } = parseDerLength(der, offset + 1)\n\tlet start = valueStart\n\tlet remaining = length\n\tif (remaining > 0 && der[start] === 0x00) {\n\t\tstart++\n\t\tremaining--\n\t}\n\treturn { value: der.slice(start, start + remaining), nextOffset: valueStart + length }\n}\n\nfunction derToRawEcdsaSignature(der: Uint8Array, componentSize: number): Uint8Array {\n\tif (der[0] !== DER_SEQUENCE_TAG) throw new Error('DER signature: expected SEQUENCE tag')\n\tconst { nextOffset: contentStart } = parseDerLength(der, 1)\n\tconst rResult = extractDerInteger(der, contentStart)\n\tconst sResult = extractDerInteger(der, rResult.nextOffset)\n\n\tconst rawLength = componentSize * 2\n\tconst raw = new Uint8Array(rawLength)\n\traw.set(rResult.value, componentSize - rResult.value.length)\n\traw.set(sResult.value, rawLength - sResult.value.length)\n\treturn raw\n}\n\nfunction resolveVerifyAlgorithm(publicKey: CryptoKey) {\n\tconst { name } = publicKey.algorithm\n\tif (name === ED25519_ALGORITHM) return { name: ED25519_ALGORITHM }\n\tif (name === ECDSA_ALGORITHM) {\n\t\tconst curve = (publicKey.algorithm as EcKeyAlgorithm).namedCurve\n\t\tconst hash = curve === CURVE_P384 ? HASH_SHA384 : curve === CURVE_P521 ? HASH_SHA512 : HASH_SHA256\n\t\treturn { name: ECDSA_ALGORITHM, hash: { name: hash } }\n\t}\n\tif (name === RSA_PSS_ALGORITHM) {\n\t\tconst hashName = (publicKey.algorithm as RsaHashedKeyAlgorithm).hash.name\n\t\treturn { name: RSA_PSS_ALGORITHM, saltLength: RSA_PSS_SALT_LENGTH[hashName] ?? 32 }\n\t}\n\tthrow new Error(`Unsupported public key algorithm: ${name}`)\n}\n\nfunction normalizeSignature(signature: Uint8Array, publicKey: CryptoKey): Uint8Array {\n\tif (publicKey.algorithm.name !== ECDSA_ALGORITHM) return signature\n\tconst componentSize = getComponentSize(publicKey)\n\tif (isDerEncoded(signature, componentSize * 2)) {\n\t\treturn derToRawEcdsaSignature(signature, componentSize)\n\t}\n\treturn signature\n}\n\n/**\n * Verifies a `COSE_Sign1` signature using a provided `CryptoKey` (RFC 9052 §4.4).\n *\n * Builds the `Sig_Structure` from the protected header and payload, normalizes\n * DER-encoded ECDSA signatures to raw format if needed, and delegates\n * verification to the WebCrypto API.\n *\n * Supports `ECDSA` (P-256, P-384, P-521), `Ed25519`, and `RSA-PSS` (PS256, PS384, PS512) keys.\n *\n * @param coseSign1 - Decoded COSE_Sign1 structure (from {@link decodeCoseSign1})\n * @param payload - Payload bytes to verify. May differ from `coseSign1.payload` for detached payloads.\n * @param publicKey - Imported public key for verification\n * @returns `true` if the signature is valid\n * @throws If the key algorithm is not supported\n *\n * @example\n * {@includeCode ../../test/cose/verifyCoseSign1.test.ts#example}\n *\n * @public\n */\nexport async function verifyCoseSign1(\n\tcoseSign1: CoseSign1,\n\tpayload: Uint8Array,\n\tpublicKey: CryptoKey,\n): Promise<boolean> {\n\tconst sigStructure = buildSigStructure(coseSign1.protectedBytes, payload)\n\tconst algorithm = resolveVerifyAlgorithm(publicKey)\n\tconst signature = normalizeSignature(coseSign1.signature, publicKey)\n\treturn crypto.subtle.verify(algorithm, publicKey, signature, sigStructure)\n}\n","import {\n\tASN1_TAG_CONTEXT_0,\n\tASN1_TAG_INTEGER,\n\tASN1_TAG_SEQUENCE,\n\treadElement,\n\treadElementRaw,\n} from './asn1.ts'\n\n/**\n * Extracts the SubjectPublicKeyInfo (SPKI) DER bytes from an X.509 DER certificate.\n *\n * Navigates the TBSCertificate structure to reach the 7th field\n * (SubjectPublicKeyInfo), skipping version, serialNumber, signatureAlgorithm,\n * issuer, validity, and subject.\n *\n * The returned bytes can be imported directly via\n * `crypto.subtle.importKey('spki', ...)`.\n *\n * @param certDER - DER-encoded X.509 certificate bytes\n * @returns Full DER encoding of the SubjectPublicKeyInfo, or `null` on parse failure\n *\n * @internal\n */\nexport function extractCertificateSpki(certDER: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst cert = readElement(certDER, 0)\n\t\tif (!cert || cert.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tconst tbs = readElement(cert.value, 0)\n\t\tif (!tbs || tbs.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tlet offset = 0\n\t\tlet el = readElement(tbs.value, offset)\n\t\tif (!el) return null\n\n\t\t// 1. Optional version [0]\n\t\tif (el.tag === ASN1_TAG_CONTEXT_0) {\n\t\t\toffset += el.totalSize\n\t\t\tel = readElement(tbs.value, offset)\n\t\t\tif (!el) return null\n\t\t}\n\n\t\t// 2. Serial number (INTEGER)\n\t\tif (el.tag !== ASN1_TAG_INTEGER) return null\n\t\toffset += el.totalSize\n\n\t\t// 3. Signature algorithm (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 4. Issuer (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 5. Validity (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 6. Subject (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 7. SubjectPublicKeyInfo (SEQUENCE) — return full DER encoding\n\t\treturn readElementRaw(tbs.value, offset)\n\t}\n\tcatch {\n\t\treturn null\n\t}\n}\n","import { readElement, ASN1_TAG_SEQUENCE } from './asn1.ts'\n\n// OID 1.2.840.113549.1.1.10 (rsassaPss)\nconst OID_RSASSA_PSS = new Uint8Array([0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a])\n\n// AlgorithmIdentifier for rsaEncryption (OID 1.2.840.113549.1.1.1) with NULL params\n// SEQUENCE { OID rsaEncryption, NULL }\nconst RSA_ENCRYPTION_ALGORITHM_ID = new Uint8Array([\n\t0x30, 0x0d, // SEQUENCE, 13 bytes\n\t0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, // OID rsaEncryption\n\t0x05, 0x00, // NULL\n])\n\nfunction containsRsaPssOid(bytes: Uint8Array): boolean {\n\tif (bytes.length < OID_RSASSA_PSS.length) return false\n\touter: for (let i = 0; i <= bytes.length - OID_RSASSA_PSS.length; i++) {\n\t\tfor (let j = 0; j < OID_RSASSA_PSS.length; j++) {\n\t\t\tif (bytes[i + j] !== OID_RSASSA_PSS[j]) continue outer\n\t\t}\n\t\treturn true\n\t}\n\treturn false\n}\n\n/**\n * Normalizes an SPKI that uses the `rsassaPss` OID (1.2.840.113549.1.1.10) to\n * use the generic `rsaEncryption` OID (1.2.840.113549.1.1.1) instead.\n *\n * WebCrypto's `importKey('spki', ...)` with `{ name: 'RSA-PSS' }` expects the\n * SPKI to use the generic `rsaEncryption` OID. Certificates signed with\n * RSASSA-PSS often embed the PSS-specific OID and parameters, which causes\n * `DataError` on import.\n *\n * If the SPKI does not use `rsassaPss`, it is returned unchanged.\n *\n * @internal\n */\nexport function normalizeRsaPssSpki(spkiBytes: Uint8Array): Uint8Array {\n\tif (!containsRsaPssOid(spkiBytes)) return spkiBytes\n\n\t// Parse outer SEQUENCE\n\tconst outer = readElement(spkiBytes, 0)\n\tif (!outer || outer.tag !== ASN1_TAG_SEQUENCE) return spkiBytes\n\n\t// First child: AlgorithmIdentifier SEQUENCE\n\tconst algId = readElement(outer.value, 0)\n\tif (!algId || algId.tag !== ASN1_TAG_SEQUENCE) return spkiBytes\n\n\t// Second child: BIT STRING with the public key\n\tconst publicKeyBitString = outer.value.subarray(algId.totalSize)\n\n\t// Build new SPKI: RSA_ENCRYPTION_ALGORITHM_ID + original BIT STRING\n\tconst innerLength = RSA_ENCRYPTION_ALGORITHM_ID.length + publicKeyBitString.length\n\tconst headerBytes = encodeDerLength(innerLength)\n\tconst result = new Uint8Array(1 + headerBytes.length + innerLength)\n\tlet offset = 0\n\tresult[offset++] = ASN1_TAG_SEQUENCE\n\tresult.set(headerBytes, offset)\n\toffset += headerBytes.length\n\tresult.set(RSA_ENCRYPTION_ALGORITHM_ID, offset)\n\toffset += RSA_ENCRYPTION_ALGORITHM_ID.length\n\tresult.set(publicKeyBitString, offset)\n\n\treturn result\n}\n\nfunction encodeDerLength(length: number): Uint8Array {\n\tif (length < 0x80) return new Uint8Array([length])\n\tif (length <= 0xff) return new Uint8Array([0x81, length])\n\tif (length <= 0xffff) return new Uint8Array([0x82, (length >> 8) & 0xff, length & 0xff])\n\treturn new Uint8Array([0x83, (length >> 16) & 0xff, (length >> 8) & 0xff, length & 0xff])\n}\n","import { decodeCoseSign1 } from '../cose/decodeCoseSign1.ts'\nimport { resolveAlgorithmFromCoseAlg } from '../cose/resolveAlgorithmFromCoseAlg.ts'\nimport { verifyCoseSign1 } from '../cose/verifyCoseSign1.ts'\nimport { extractCertificateSpki } from '../x509/extractCertificateSpki.ts'\nimport { normalizeRsaPssSpki } from '../x509/normalizeRsaPssSpki.ts'\n\n/**\n * Verifies the claim signature of a C2PA manifest per §15.7.\n *\n * The `c2pa.signature` JUMBF box contains a `COSE_Sign1` structure whose payload\n * is the claim CBOR bytes. This function verifies the signature against the\n * public key extracted from the end-entity certificate in the `x5chain` header.\n *\n * @param signatureBytes - Raw COSE_Sign1 bytes from the `c2pa.signature` box\n * @param claimCborBytes - Raw CBOR bytes of the claim content box\n * @param certificateDER - DER-encoded end-entity X.509 certificate\n * @returns `true` if the signature is valid\n *\n * @internal\n */\nexport async function verifyClaimSignature(\n\tsignatureBytes: Uint8Array,\n\tclaimCborBytes: Uint8Array,\n\tcertificateDER: Uint8Array,\n): Promise<boolean> {\n\ttry {\n\t\tconst coseSign1 = decodeCoseSign1(signatureBytes)\n\n\t\tconst rawSpki = extractCertificateSpki(certificateDER)\n\t\tif (!rawSpki) return false\n\t\tconst spkiBytes = normalizeRsaPssSpki(rawSpki)\n\n\t\tif (coseSign1.alg == null) return false\n\n\t\tconst importAlgorithm = resolveAlgorithmFromCoseAlg(coseSign1.alg)\n\n\t\tconst publicKey = await crypto.subtle.importKey(\n\t\t\t'spki',\n\t\t\tnew Uint8Array(spkiBytes) as BufferSource,\n\t\t\timportAlgorithm,\n\t\t\ttrue,\n\t\t\t['verify'],\n\t\t)\n\n\t\treturn verifyCoseSign1(coseSign1, claimCborBytes, publicKey)\n\t}\n\tcatch {\n\t\treturn false\n\t}\n}\n","import type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { C2paStatusCode as Code } from '../C2paStatusCode.ts'\nimport { extractCertificateFromSignatureBytes } from '../extractManifestCertificate.ts'\nimport type { InternalManifestData } from './InternalManifestData.ts'\nimport { validateActionIngredients } from './validateActionIngredients.ts'\nimport { validateAssertionHashes } from './validateAssertionHashes.ts'\nimport { verifyClaimSignature } from './verifyClaimSignature.ts'\n\n/**\n * Outcome of the manifest integrity checks.\n *\n * @internal\n */\nexport type ManifestIntegrity = {\n\t/** Status codes for the failures found, empty when every check passes */\n\treadonly codes: readonly C2paStatusCode[]\n\t/** DER-encoded end-entity certificate from the claim signature, or `null` when the signature is absent or carries no certificate */\n\treadonly certificate: Uint8Array | null\n}\n\ntype ClaimSignatureCheck = {\n\treadonly code: C2paStatusCode | null\n\treadonly certificate: Uint8Array | null\n}\n\n/**\n * Checks the claim signature per §15.7 and fails closed: a manifest without a claim box,\n * without a `c2pa.signature` box, or with a signature that carries no certificate or does\n * not verify over the claim bytes, is reported as a failure.\n */\nasync function validateClaimSignature({ claimCborBytes, signatureBytes }: InternalManifestData): Promise<ClaimSignatureCheck> {\n\tconst certificate = signatureBytes ? extractCertificateFromSignatureBytes(signatureBytes) : null\n\n\tif (!claimCborBytes) return { code: Code.CLAIM_MISSING, certificate }\n\tif (!signatureBytes) return { code: Code.CLAIM_SIGNATURE_MISSING, certificate }\n\tif (!certificate) return { code: Code.CLAIM_SIGNATURE_MISMATCH, certificate }\n\n\tconst signatureValid = await verifyClaimSignature(signatureBytes, claimCborBytes, certificate)\n\treturn { code: signatureValid ? null : Code.CLAIM_SIGNATURE_MISMATCH, certificate }\n}\n\n/**\n * Validates the integrity of a C2PA manifest per Chapter 15 and Chapter 18.\n *\n * Runs four validation checks in parallel where possible:\n * 1. Assertion hash verification (§15.10.3.1)\n * 2. Missing assertion detection (§15.10.3.1)\n * 3. Action ingredient validation (§18.15.4.7)\n * 4. Claim signature verification (§15.7)\n *\n * The claim signature is verified with the end-entity certificate from the `x5chain`\n * header of the signature. The certificate is not checked against a trust list.\n *\n * @param internal - Enriched manifest data with raw assertion bytes and claim references\n * @returns The status codes for any failures found, and the certificate of the claim signature\n *\n * @internal\n */\nexport async function validateManifestIntegrity(internal: InternalManifestData): Promise<ManifestIntegrity> {\n\tconst [assertionHashCodes, signature] = await Promise.all([\n\t\tvalidateAssertionHashes(internal.claimAssertionRefs, internal.assertions),\n\t\tvalidateClaimSignature(internal),\n\t])\n\n\tconst codes: C2paStatusCode[] = [...assertionHashCodes, ...validateActionIngredients(internal.assertions)]\n\n\tif (signature.code) {\n\t\tcodes.push(signature.code)\n\t}\n\n\treturn { codes, certificate: signature.certificate }\n}\n","import type { CoseKeyJwk } from './CoseKeyJwk.ts'\n\n// IANA COSE Key Types (RFC 9053)\nconst OKP_KEY_TYPE = 1\nconst EC2_KEY_TYPE = 2\n\n// IANA COSE Elliptic Curves\nconst EC_CURVE_NAMES: Record<number, string> = { 1: 'P-256', 2: 'P-384', 3: 'P-521' }\nconst OKP_CURVE_NAMES: Record<number, string> = { 4: 'X25519', 5: 'X448', 6: 'Ed25519', 7: 'Ed448' }\n\ntype CoseKeyLike = Map<number, unknown> | Record<number | string, unknown>\n\nfunction coseGet(key: CoseKeyLike, intKey: number): unknown {\n\tif (key instanceof Map) return key.get(intKey)\n\treturn (key as Record<number | string, unknown>)[intKey]\n}\n\nfunction toBase64Url(value: unknown): string {\n\tconst bytes = value instanceof Uint8Array ? value : new Uint8Array(value as number[])\n\tlet binary = ''\n\tfor (const byte of bytes) binary += String.fromCharCode(byte)\n\treturn btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\n/**\n * Converts a COSE public key (RFC 9052 / IANA COSE Key registry) to JWK format.\n *\n * Supports EC2 keys (P-256, P-384, P-521) and OKP keys (Ed25519, Ed448, X25519, X448).\n * Input may be a `Map\\<number, unknown\\>` (from CBOR decoders like cbor-x) or a plain\n * object with integer keys.\n *\n * @param coseKey - COSE key structure as decoded from a C2PA `c2pa.session-keys` assertion\n * @returns JWK representation of the public key\n * @throws If the key type or curve is not supported\n *\n * @example\n * {@includeCode ../../test/cose/convertCoseKeyToJwk.test.ts#example}\n *\n * @public\n */\nexport function convertCoseKeyToJwk(coseKey: unknown): CoseKeyJwk {\n\tconst key = coseKey as CoseKeyLike\n\tconst kty = coseGet(key, 1)\n\tconst crv = coseGet(key, -1) as number\n\tconst x = coseGet(key, -2)\n\n\tif (kty === EC2_KEY_TYPE) {\n\t\tconst curveName = EC_CURVE_NAMES[crv]\n\t\tif (!curveName) throw new Error(`Unsupported EC curve: ${crv}`)\n\t\tconst y = coseGet(key, -3)\n\t\tif (!(x instanceof Uint8Array)) throw new Error('EC2 key missing or invalid x coordinate')\n\t\tif (!(y instanceof Uint8Array)) throw new Error('EC2 key missing or invalid y coordinate')\n\t\treturn { kty: 'EC', crv: curveName, x: toBase64Url(x), y: toBase64Url(y) }\n\t}\n\n\tif (kty === OKP_KEY_TYPE) {\n\t\tconst curveName = OKP_CURVE_NAMES[crv]\n\t\tif (!curveName) throw new Error(`Unsupported OKP curve: ${crv}`)\n\t\treturn { kty: 'OKP', crv: curveName, x: toBase64Url(x) }\n\t}\n\n\tthrow new Error(`Unsupported COSE key type: ${kty}`)\n}\n","import { ECDSA_ALGORITHM } from './constants.ts'\n\nconst KEY_TYPE_OKP = 'OKP'\n\nexport function resolveImportAlgorithm(jwk: { kty: string; crv: string }): AlgorithmIdentifier | EcKeyImportParams {\n\treturn jwk.kty === KEY_TYPE_OKP ? { name: jwk.crv } : { name: ECDSA_ALGORITHM, namedCurve: jwk.crv }\n}\n","import { encode } from 'cbor-x/encode'\nimport { convertCoseKeyToJwk } from './convertCoseKeyToJwk.ts'\nimport { decodeCoseSign1 } from './decodeCoseSign1.ts'\nimport { resolveImportAlgorithm } from './resolveImportAlgorithm.ts'\nimport { verifyCoseSign1 } from './verifyCoseSign1.ts'\n\n/**\n * Verifies a C2PA signer binding — a `COSE_Sign1` structure that proves\n * a session key was authorized by the content signer (C2PA spec §18.25.2).\n *\n * The `Sig_Structure` payload is `CBOR(bstr(signerCertBytes))` per the C2PA spec.\n * DER-encoded ECDSA signatures are automatically normalized to raw format.\n *\n * @param signerBindingBytes - Raw `COSE_Sign1` bytes of the signer binding\n * @param sessionCoseKey - COSE public key from the `c2pa.session-keys` assertion\n * @param signerCertBytes - DER-encoded end-entity certificate (from `x5chain`)\n * @returns `true` if the signer binding signature is valid\n * @throws If the COSE key type is not supported or decoding fails\n *\n * @example\n * {@includeCode ../../test/cose/verifySignerBinding.test.ts#example}\n *\n * @public\n */\nexport async function verifySignerBinding(\n\tsignerBindingBytes: Uint8Array,\n\tsessionCoseKey: unknown,\n\tsignerCertBytes: Uint8Array,\n): Promise<boolean> {\n\tconst coseSign1 = decodeCoseSign1(signerBindingBytes)\n\tconst jwk = convertCoseKeyToJwk(sessionCoseKey)\n\tconst publicKey = await crypto.subtle.importKey('jwk', jwk as JsonWebKey, resolveImportAlgorithm(jwk), false, ['verify'])\n\t// Signer binding payload = CBOR(bstr(cert)) per C2PA spec §18.25.2\n\tconst cborCertPayload = encode(signerCertBytes) as Uint8Array\n\treturn verifyCoseSign1(coseSign1, cborCertPayload, publicKey)\n}\n","import type { BmffHashConstraint, BmffHashExclusion } from './BmffHashExclusion.ts'\nimport { toUint8Array } from '../utils.ts'\n\nfunction parseConstraints(rawConstraints: unknown): BmffHashConstraint[] {\n\tif (!Array.isArray(rawConstraints)) return []\n\n\tconst constraints: BmffHashConstraint[] = []\n\tfor (const c of rawConstraints) {\n\t\tif (!c || typeof c !== 'object') continue\n\t\tconst record = c as Record<string, unknown>\n\t\tif (typeof record['offset'] !== 'number') continue\n\t\tconst value = toUint8Array(record['value'])\n\t\tif (value) constraints.push({ offset: record['offset'], value })\n\t}\n\treturn constraints\n}\n\n/**\n * Parses the `exclusions` array of a `c2pa.hash.bmff.v3` assertion.\n *\n * @internal\n */\nexport function parseExclusions(rawExclusions: unknown): BmffHashExclusion[] {\n\tif (!Array.isArray(rawExclusions)) return []\n\n\tconst exclusions: BmffHashExclusion[] = []\n\tfor (const exc of rawExclusions) {\n\t\tif (!exc || typeof exc !== 'object') continue\n\t\tconst record = exc as Record<string, unknown>\n\t\tif (typeof record['xpath'] !== 'string') continue\n\n\t\tconst constraints = parseConstraints(record['data'])\n\t\texclusions.push(constraints.length > 0 ? { xpath: record['xpath'], data: constraints } : { xpath: record['xpath'] })\n\t}\n\treturn exclusions\n}\n","import type { C2paAssertion } from '../C2paAssertion.ts'\nimport { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { computeBmffHash } from '../bmff/computeBmffHash.ts'\nimport { parseExclusions } from '../bmff/parseExclusions.ts'\nimport { asInteger, hashesEqual, normalizeAlgorithmName, toUint8Array } from '../utils.ts'\nimport type { MerkleMap } from './MerkleSegmentValidation.ts'\n\nfunction parseMerkleRow(rawHashes: unknown): Uint8Array[] | null {\n\tif (!Array.isArray(rawHashes) || rawHashes.length === 0) return null\n\tconst row: Uint8Array[] = []\n\tfor (const entry of rawHashes) {\n\t\tconst bytes = toUint8Array(entry)\n\t\tif (!bytes) return null\n\t\trow.push(bytes)\n\t}\n\treturn row\n}\n\nfunction extractMerkleMaps(bmffHashAssertionData: Record<string, unknown>): MerkleMap[] | null {\n\tconst rawMerkle = bmffHashAssertionData['merkle']\n\tif (!Array.isArray(rawMerkle) || rawMerkle.length === 0) return null\n\n\tconst exclusions = parseExclusions(bmffHashAssertionData['exclusions'])\n\tconst assertionAlg = bmffHashAssertionData['alg']\n\tconst offsetPrefixSize = bmffHashAssertionData['hash'] == null ? 8 : 0\n\n\tconst maps: MerkleMap[] = []\n\tfor (const entry of rawMerkle) {\n\t\tif (!entry || typeof entry !== 'object') return null\n\t\tconst record = entry as Record<string, unknown>\n\n\t\tconst uniqueId = asInteger(record['uniqueId'])\n\t\tconst localId = asInteger(record['localId'])\n\t\tconst count = asInteger(record['count'])\n\t\tconst hashes = parseMerkleRow(record['hashes'])\n\t\tif (uniqueId === null || localId === null || count === null || !hashes) return null\n\n\t\t// §A.5.4.2/merkle-map CDDL: initHash is required for fragmented assets, which\n\t\t// is the only case this function handles (it's only called for init segments).\n\t\tconst initHash = toUint8Array(record['initHash'])\n\t\tif (!initHash) return null\n\n\t\t// §A.5.4.2/merkle-map CDDL: falls back from this entry to the enclosing\n\t\t// assertion, then to the Claim's alg (not plumbed through here; c2pa-rs\n\t\t// always writes an assertion-level alg, so this is theoretical), or else\n\t\t// the structure is invalid.\n\t\tconst rawAlg = record['alg'] ?? assertionAlg\n\t\tif (typeof rawAlg !== 'string') return null\n\n\t\tmaps.push({\n\t\t\tuniqueId,\n\t\t\tlocalId,\n\t\t\tcount,\n\t\t\thashes,\n\t\t\tinitHash,\n\t\t\talg: normalizeAlgorithmName(rawAlg),\n\t\t\texclusions,\n\t\t\toffsetPrefixSize,\n\t\t})\n\t}\n\treturn maps\n}\n\nexport async function validateMerkleMaps(\n\tbytes: Uint8Array,\n\tassertion: C2paAssertion | null,\n\tcodes: Set<LiveVideoStatusCode | C2paStatusCode>,\n): Promise<MerkleMap[] | null> {\n\tconst data = assertion?.data\n\tif (data === null || typeof data !== 'object' || Array.isArray(data)) return null\n\tif ((data as Record<string, unknown>)['merkle'] === undefined) return null\n\n\tconst merkleMaps = extractMerkleMaps(data as Record<string, unknown>)\n\tif (!merkleMaps) {\n\t\tcodes.add(C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED)\n\t\treturn []\n\t}\n\n\tconst initHashByAlg = new Map<string | null, Uint8Array>()\n\tfor (const merkleMap of merkleMaps) {\n\t\tif (!merkleMap.initHash) continue\n\t\tlet computed = initHashByAlg.get(merkleMap.alg)\n\t\tif (!computed) {\n\t\t\tcomputed = await computeBmffHash(bytes, {\n\t\t\t\toffsetPrefixSize: merkleMap.offsetPrefixSize,\n\t\t\t\texclusions: merkleMap.exclusions,\n\t\t\t\talg: merkleMap.alg ?? undefined,\n\t\t\t})\n\t\t\tinitHashByAlg.set(merkleMap.alg, computed)\n\t\t}\n\t\tif (!hashesEqual(computed, merkleMap.initHash)) {\n\t\t\tcodes.add(LiveVideoStatusCode.INIT_INVALID)\n\t\t\tcodes.add(C2paStatusCode.ASSERTION_BMFFHASH_MISMATCH)\n\t\t}\n\t}\n\n\treturn merkleMaps\n}\n","import { decode } from 'cbor-x/decode'\nimport { encode } from 'cbor-x/encode'\nimport { findIsoBox, readIsoBoxes } from '@svta/cml-iso-bmff'\nimport type { C2paAssertion } from '../C2paAssertion.ts'\nimport type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { readC2paManifest } from '../readC2paManifest.ts'\nimport { computeBmffHash } from '../bmff/computeBmffHash.ts'\nimport type { BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport { validateManifestIntegrity } from '../claim/validateManifestIntegrity.ts'\nimport { convertCoseKeyToJwk } from '../cose/convertCoseKeyToJwk.ts'\nimport { verifySignerBinding } from '../cose/verifySignerBinding.ts'\nimport type { InitSegmentValidation, ValidatedSessionKey } from './InitSegmentValidation.ts'\nimport { validateMerkleMaps } from '../merkle/validateMerkleMaps.ts'\nimport { bytesToHex, hashesEqual, isKeyExpired, normalizeAlgorithmName } from '../utils.ts'\n\nconst BMFF_HASH_ASSERTION_LABEL = 'c2pa.hash.bmff.v3'\nconst SESSION_KEYS_ASSERTION_LABEL = 'c2pa.session-keys'\nconst COSE_KEY_ID_LABEL = 2\n\n// cbor-x represents CBOR tagged values in multiple ways depending on version/config:\n// - { tag: number, value: unknown } (structured)\n// - Tag class instance with constructor name 'Tag'\n// - { '@@TAGGED@@': [tag, value] } (internal key)\nconst CBOR_TAGGED_KEY = '@@TAGGED@@'\n\nfunction extractCborTaggedValue(value: unknown): unknown | null {\n\tif (typeof value !== 'object' || value === null) return null\n\tconst obj = value as Record<string, unknown>\n\tif (typeof obj['tag'] === 'number' && 'value' in obj) return obj['value']\n\tconst tagged = obj[CBOR_TAGGED_KEY]\n\tif (Array.isArray(tagged) && tagged.length === 2) return tagged[1]\n\treturn null\n}\n\nfunction normalizeToUint8Array(value: unknown): Uint8Array {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\tif (extractCborTaggedValue(value) !== null) return encode(value) as Uint8Array\n\tthrow new Error('Cannot convert value to Uint8Array')\n}\n\nfunction ensureDecodedCbor(value: unknown): unknown {\n\tif (value instanceof Uint8Array) return decode(value)\n\tif (Array.isArray(value) && value.length > 0 && typeof (value as number[])[0] === 'number') {\n\t\treturn decode(new Uint8Array(value as number[]))\n\t}\n\treturn value\n}\n\nfunction parseCreatedAt(value: unknown): string | null {\n\tconst resolved = extractCborTaggedValue(value) ?? value\n\tif (typeof resolved === 'string') return resolved\n\tif (resolved instanceof Date) return resolved.toISOString()\n\treturn null\n}\n\nfunction extractKidHex(keyData: Record<string, unknown>, coseKey: unknown): string | null {\n\tconst kid = keyData['kid']\n\tif (kid instanceof Uint8Array) return bytesToHex(kid)\n\tif (typeof kid === 'string') return kid\n\tif (Array.isArray(kid) && kid.length > 0) return bytesToHex(new Uint8Array(kid as number[]))\n\n\t// Fallback: COSE key field 2 is the key ID per RFC 9052\n\tconst coseKeyLike = coseKey as Map<number, unknown> | Record<number, unknown>\n\tconst coseKid = coseKeyLike instanceof Map ? coseKeyLike.get(COSE_KEY_ID_LABEL) : coseKeyLike[COSE_KEY_ID_LABEL]\n\tif (coseKid instanceof Uint8Array) return bytesToHex(coseKid)\n\tif (Array.isArray(coseKid) && coseKid.length > 0) {\n\t\treturn bytesToHex(new Uint8Array(coseKid as number[]))\n\t}\n\n\treturn null\n}\n\nfunction extractKeyArray(data: unknown): unknown[] {\n\tif (Array.isArray(data)) return data\n\tif (typeof data === 'object' && data !== null) {\n\t\tconst obj = data as Record<string, unknown>\n\t\tconst keys = obj['keys'] ?? obj['sessionKeys']\n\t\tif (Array.isArray(keys)) return keys\n\t\tif (typeof keys === 'object' && keys !== null) {\n\t\t\tconst nested = (keys as Record<string, unknown>)['keys']\n\t\t\tif (Array.isArray(nested)) return nested\n\t\t}\n\t}\n\treturn []\n}\n\nasync function validateBmffHashAssertion(\n\tbytes: Uint8Array,\n\tassertion: C2paAssertion | null,\n): Promise<boolean> {\n\tif (!assertion) return true\n\tconst data = assertion.data as Record<string, unknown>\n\tconst rawHash = data['hash'] ?? data['value']\n\tif (!rawHash) return true\n\tconst expectedHash =\n\t\trawHash instanceof Uint8Array ? rawHash : new Uint8Array(rawHash as number[])\n\tconst alg = normalizeAlgorithmName(data['alg'] as string | undefined)\n\tconst exclusions = (data['exclusions'] as BmffHashExclusion[] | undefined) ?? []\n\t// §18.6.2: the flat v2/v3 hash covers offset || data for every non-excluded root\n\t// box; only Merkle tree hashes may omit the 8-byte offset prefix.\n\tconst computed = await computeBmffHash(bytes, { exclusions, alg, offsetPrefixSize: 8 })\n\treturn hashesEqual(computed, expectedHash)\n}\n\ntype SessionKeyFields = {\n\tminSequenceNumber: number\n\tvalidityPeriod: number\n\tcreatedAt: string\n\tkid: string\n\tcoseKey: unknown\n\tsignerBindingBytes: Uint8Array\n}\n\nfunction extractSessionKeyFields(entry: unknown): SessionKeyFields | null {\n\tconst keyData = entry as Record<string, unknown>\n\n\tconst minSequenceNumber = keyData['minSequenceNumber']\n\tconst validityPeriod = keyData['validityPeriod']\n\tconst createdAt = parseCreatedAt(keyData['createdAt'])\n\n\tif (minSequenceNumber == null || validityPeriod == null || !createdAt) return null\n\n\tconst isNotYetActive = new Date() < new Date(createdAt)\n\tif (isNotYetActive || isKeyExpired(createdAt, Number(validityPeriod))) return null\n\n\tconst coseKey = ensureDecodedCbor(keyData['key'])\n\tconst kid = extractKidHex(keyData, coseKey)\n\tif (!kid) return null\n\n\tconst signerBindingRaw = keyData['signerBinding']\n\tif (!signerBindingRaw) return null\n\n\ttry {\n\t\treturn {\n\t\t\tminSequenceNumber: Number(minSequenceNumber),\n\t\t\tvalidityPeriod: Number(validityPeriod),\n\t\t\tcreatedAt,\n\t\t\tkid,\n\t\t\tcoseKey,\n\t\t\tsignerBindingBytes: normalizeToUint8Array(signerBindingRaw),\n\t\t}\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function verifyAndConvertKey(\n\tfields: SessionKeyFields,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey | null> {\n\tconst isBindingValid = await verifySignerBinding(fields.signerBindingBytes, fields.coseKey, certificate)\n\tif (!isBindingValid) return null\n\n\ttry {\n\t\tconst jwk = convertCoseKeyToJwk(fields.coseKey)\n\t\treturn {\n\t\t\tkid: fields.kid,\n\t\t\tjwk,\n\t\t\tminSequenceNumber: fields.minSequenceNumber,\n\t\t\tvalidityPeriod: fields.validityPeriod,\n\t\t\tcreatedAt: fields.createdAt,\n\t\t}\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function validateSingleSessionKey(\n\tentry: unknown,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey | null> {\n\tconst fields = extractSessionKeyFields(entry)\n\tif (!fields) return null\n\treturn verifyAndConvertKey(fields, certificate)\n}\n\nasync function validateSessionKeys(\n\tassertion: C2paAssertion,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey[]> {\n\tconst keyEntries = extractKeyArray(ensureDecodedCbor(assertion.data))\n\tconst results = await Promise.all(\n\t\tkeyEntries.map(entry => validateSingleSessionKey(entry, certificate)),\n\t)\n\treturn results.filter((key): key is ValidatedSessionKey => key !== null)\n}\n\n/**\n * Validates a C2PA init segment: parses the manifest, extracts and verifies\n * the certificate, validates the BMFF hard binding hash, verifies all\n * session keys from the `c2pa.session-keys` assertion, and performs\n * manifest integrity checks (assertion hashes, missing assertions,\n * action ingredients, and claim signature verification).\n *\n * Only session keys with a valid signer binding and an unexpired validity period\n * are included in the result.\n *\n * @param bytes - Raw init segment bytes\n * @returns Structured validation result (with `INIT_INVALID` error code if `mdat` box is present)\n * @throws If no C2PA UUID box is found\n *\n * @example\n * {@includeCode ../../test/init/validateC2paInitSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paInitSegment(bytes: Uint8Array): Promise<InitSegmentValidation> {\n\tconst boxes = readIsoBoxes(bytes)\n\tif (findIsoBox(boxes, box => box.type === 'mdat')) {\n\t\treturn {\n\t\t\tmanifest: null,\n\t\t\tcertificate: null,\n\t\t\tmanifestId: null,\n\t\t\tsessionKeys: [],\n\t\t\tmerkleMaps: [],\n\t\t\tisValid: false,\n\t\t\terrorCodes: [LiveVideoStatusCode.INIT_INVALID],\n\t\t}\n\t}\n\n\tconst internalData = readC2paManifest(bytes, boxes)\n\tconst { manifest } = internalData\n\tconst { codes: integrityCodes, certificate } = await validateManifestIntegrity(internalData)\n\n\tconst bmffHashAssertion =\n\t\tmanifest.assertions.find(a => a.label === BMFF_HASH_ASSERTION_LABEL) ?? null\n\tconst bmffHashValid = await validateBmffHashAssertion(bytes, bmffHashAssertion)\n\n\tconst sessionKeysAssertion = manifest.assertions.find(\n\t\ta => a.label === SESSION_KEYS_ASSERTION_LABEL,\n\t)\n\tconst sessionKeys =\n\t\tsessionKeysAssertion && certificate\n\t\t\t? await validateSessionKeys(sessionKeysAssertion, certificate)\n\t\t\t: []\n\n\tconst codes = new Set<LiveVideoStatusCode | C2paStatusCode>()\n\tconst merkleMaps = await validateMerkleMaps(bytes, bmffHashAssertion, codes)\n\n\tif (!bmffHashValid) codes.add(LiveVideoStatusCode.INIT_INVALID)\n\t// VOD Merkle streams carry no session keys; only flag their absence in live mode.\n\tif (sessionKeys.length === 0 && merkleMaps === null) {\n\t\tcodes.add(LiveVideoStatusCode.SESSIONKEY_INVALID)\n\t}\n\tfor (const code of integrityCodes) codes.add(code)\n\tconst errorCodes = [...codes]\n\n\treturn {\n\t\tmanifest,\n\t\tcertificate,\n\t\tmanifestId: manifest.instanceId,\n\t\tsessionKeys,\n\t\tmerkleMaps: merkleMaps ?? [],\n\t\tisValid: errorCodes.length === 0,\n\t\terrorCodes,\n\t}\n}\n","import { readEmsg, readIsoBoxes, type EventMessageBox } from '@svta/cml-iso-bmff'\n\nconst EMSG_BOX_TYPE = 'emsg'\nconst VSI_SCHEME_URI = 'urn:c2pa:verifiable-segment-info'\nconst EMSG_READER_CONFIG = { readers: { emsg: readEmsg } }\n\n/**\n * Finds and parses the first C2PA Verifiable Segment Info (VSI) EMSG box\n * in a DASH segment, identified by scheme URI `urn:c2pa:verifiable-segment-info`.\n *\n * @param segmentBytes - Raw DASH segment bytes\n * @returns The parsed VSI EMSG box, or `null` if not found\n *\n * @example\n * {@includeCode ../../test/emsg/extractVsiEmsgBox.test.ts#example}\n *\n * @internal\n */\nexport function extractVsiEmsgBox(segmentBytes: Uint8Array): EventMessageBox | null {\n\tfor (const box of readIsoBoxes(segmentBytes, EMSG_READER_CONFIG)) {\n\t\tif (box.type !== EMSG_BOX_TYPE) continue\n\t\tconst emsg = box as EventMessageBox\n\t\tif (emsg.schemeIdUri === VSI_SCHEME_URI) return emsg\n\t}\n\treturn null\n}\n","import { decode } from 'cbor-x/decode'\nimport type { BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport { normalizeAlgorithmName } from '../utils.ts'\nimport type { VsiMap } from './VsiMap.ts'\n\n\n/**\n * Decodes a C2PA Verifiable Segment Info (VSI) CBOR map from raw bytes.\n *\n * Normalizes hash algorithm names to WebCrypto format (e.g. `sha256` → `SHA-256`).\n *\n * @param vsiCborBytes - Raw CBOR-encoded VSI map bytes from the EMSG `messageData`\n * @returns The decoded VSI map\n * @throws If the bytes are not a valid VSI CBOR map\n *\n * @example\n * {@includeCode ../../test/vsi/decodeVsiMap.test.ts#example}\n *\n * @internal\n */\nexport function decodeVsiMap(vsiCborBytes: Uint8Array): VsiMap {\n\tconst raw = decode(vsiCborBytes) as Record<string, unknown>\n\n\tif (typeof raw !== 'object' || raw === null) {\n\t\tthrow new Error('VSI map must be a CBOR map')\n\t}\n\n\tconst sequenceNumber = raw['sequenceNumber']\n\tif (typeof sequenceNumber !== 'number') throw new Error('VSI map missing or invalid sequenceNumber')\n\n\tconst bmffHashRaw = raw['bmffHash'] as Record<string, unknown> | undefined\n\tif (!bmffHashRaw || typeof bmffHashRaw !== 'object') throw new Error('VSI map missing bmffHash')\n\n\tconst hash = bmffHashRaw['hash']\n\tif (!(hash instanceof Uint8Array)) throw new Error('VSI map bmffHash.hash must be a Uint8Array')\n\n\tconst exclusions = bmffHashRaw['exclusions']\n\tif (exclusions !== undefined && !Array.isArray(exclusions)) throw new Error('VSI map bmffHash.exclusions must be an array')\n\n\tconst manifestId = raw['manifestId']\n\tif (typeof manifestId !== 'string') throw new Error('VSI map missing or invalid manifestId')\n\n\tconst alg = normalizeAlgorithmName(bmffHashRaw['alg'] as string | undefined)\n\n\treturn {\n\t\tsequenceNumber,\n\t\tbmffHash: {\n\t\t\thash,\n\t\t\talg,\n\t\t\texclusions: (exclusions as BmffHashExclusion[] | undefined) ?? [],\n\t\t},\n\t\tmanifestId,\n\t}\n}\n","import type { SequenceState } from './SequenceState.ts'\n\n/**\n * Creates the initial (empty) sequence state for a new stream.\n *\n * @returns A {@link SequenceState} with no history\n *\n * @example\n * {@includeCode ../../test/vsi/validateSequenceNumber.test.ts#example}\n *\n * @internal\n */\nexport function createSequenceState(): SequenceState {\n\treturn { lastSequenceNumber: null, seenSequences: new Set() }\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * State and result types for monotonic sequence number validation\n * per C2PA Live Streaming Specification §18.4.\n *\n * @public\n */\n\n/**\n * Immutable state snapshot for a single stream's sequence number history.\n *\n * Pass to {@link validateC2paSegment} via the `sequenceState` parameter.\n *\n * @public\n */\nexport type SequenceState = {\n\treadonly lastSequenceNumber: number | null\n\treadonly seenSequences: ReadonlySet<number>\n}\n\n/**\n * Reason codes for sequence number validation outcomes.\n *\n * @see {@link SequenceValidationResult}\n *\n * @enum\n *\n * @public\n */\nexport const SequenceValidationReason = {\n\t/** Sequence number is the next expected value */\n\tVALID: 'valid',\n\t/** Sequence number was already seen */\n\tDUPLICATE: 'duplicate',\n\t/** One or more sequence numbers were skipped */\n\tGAP_DETECTED: 'gap_detected',\n\t/** Sequence number is less than the last seen */\n\tOUT_OF_ORDER: 'out_of_order',\n\t/** Below the session key's minSequenceNumber */\n\tSEQUENCE_NUMBER_BELOW_MINIMUM: 'sequence_number_below_minimum',\n} as const\n\n/**\n * Union type of all {@link (SequenceValidationReason:variable)} values.\n *\n * @public\n */\nexport type SequenceValidationReason = ValueOf<typeof SequenceValidationReason>\n\n/**\n * Result of validating a single sequence number against the current stream state.\n *\n * Discriminated on `reason` — narrow to `'gap_detected'` to access\n * `missingFrom` / `missingTo`.\n *\n * @public\n */\nexport type SequenceValidationResult =\n\t| { readonly isValid: true; readonly reason: typeof SequenceValidationReason.VALID }\n\t| {\n\t\t\treadonly isValid: false\n\t\t\treadonly reason:\n\t\t\t\t| typeof SequenceValidationReason.SEQUENCE_NUMBER_BELOW_MINIMUM\n\t\t\t\t| typeof SequenceValidationReason.DUPLICATE\n\t\t\t\t| typeof SequenceValidationReason.OUT_OF_ORDER\n\t\t}\n\t| {\n\t\t\treadonly isValid: false\n\t\t\treadonly reason: typeof SequenceValidationReason.GAP_DETECTED\n\t\t\treadonly missingFrom: number\n\t\t\treadonly missingTo: number\n\t\t}\n","import { SequenceValidationReason } from './SequenceState.ts'\nimport type { SequenceState, SequenceValidationResult } from './SequenceState.ts'\n\nconst SEEN_SEQUENCES_WINDOW_SIZE = 32\n\nfunction pruneSeenSequences(seen: Set<number>, lastSequenceNumber: number): Set<number> {\n\tif (seen.size <= SEEN_SEQUENCES_WINDOW_SIZE) return seen\n\tconst threshold = lastSequenceNumber - SEEN_SEQUENCES_WINDOW_SIZE\n\tconst pruned = new Set<number>()\n\tfor (const seq of seen) {\n\t\tif (seq >= threshold) pruned.add(seq)\n\t}\n\treturn pruned\n}\n\n/**\n * Validates a segment's sequence number against the current stream state\n * per C2PA Live Streaming Specification §18.4.\n *\n * This function is **pure and stateless** — it returns both the validation\n * result and the next state. The caller is responsible for persisting\n * `nextState` between calls.\n *\n * Detects: `duplicate`, `out_of_order`, `gap_detected`, and\n * `sequence_number_below_minimum`.\n *\n * Internally uses a sliding window of the last 32 sequence numbers\n * to bound memory usage during long-running streams.\n *\n * @param state - Current stream state (from {@link createSequenceState} or previous `nextState`)\n * @param sequenceNumber - Sequence number from the segment's VSI map\n * @param minSequenceNumber - Minimum accepted sequence number (from the session key, default 0)\n * @returns Validation result and the updated state to persist\n *\n * @example\n * {@includeCode ../../test/vsi/validateSequenceNumber.test.ts#example}\n *\n * @internal\n */\nexport function validateSequenceNumber(\n\tstate: SequenceState,\n\tsequenceNumber: number,\n\tminSequenceNumber: number,\n): { readonly result: SequenceValidationResult; readonly nextState: SequenceState } {\n\tif (sequenceNumber < minSequenceNumber) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.SEQUENCE_NUMBER_BELOW_MINIMUM },\n\t\t\tnextState: state,\n\t\t}\n\t}\n\n\tif (state.seenSequences.has(sequenceNumber)) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.DUPLICATE },\n\t\t\tnextState: state,\n\t\t}\n\t}\n\n\tconst nextSeenSequences = new Set(state.seenSequences)\n\tnextSeenSequences.add(sequenceNumber)\n\n\tif (state.lastSequenceNumber !== null && sequenceNumber < state.lastSequenceNumber) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.OUT_OF_ORDER },\n\t\t\tnextState: {\n\t\t\t\tlastSequenceNumber: state.lastSequenceNumber,\n\t\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, state.lastSequenceNumber),\n\t\t\t},\n\t\t}\n\t}\n\n\tif (state.lastSequenceNumber !== null && sequenceNumber > state.lastSequenceNumber + 1) {\n\t\tconst missingFrom = state.lastSequenceNumber + 1\n\t\tconst missingTo = sequenceNumber - 1\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.GAP_DETECTED, missingFrom, missingTo },\n\t\t\tnextState: {\n\t\t\t\tlastSequenceNumber: sequenceNumber,\n\t\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, sequenceNumber),\n\t\t\t},\n\t\t}\n\t}\n\n\treturn {\n\t\tresult: { isValid: true, reason: SequenceValidationReason.VALID },\n\t\tnextState: {\n\t\t\tlastSequenceNumber: sequenceNumber,\n\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, sequenceNumber),\n\t\t},\n\t}\n}\n","import type { BmffHashExclusion } from './BmffHashExclusion.ts'\nimport { computeBmffHash } from './computeBmffHash.ts'\nimport { hashesEqual } from '../utils.ts'\n\nconst OFFSET_PREFIX_SIZES_TO_TRY = [8, 0] as const\n\n/**\n * Options for BMFF hash validation.\n *\n * @public\n */\nexport type BmffHashValidationOptions = {\n\treadonly exclusions?: readonly BmffHashExclusion[]\n\treadonly alg?: string\n}\n\n/**\n * Validates the C2PA BMFF content hash (`c2pa.hash.bmff.v3`) for a DASH segment.\n *\n * Tries both offset-prefix modes — 8-byte file offset prefix and no prefix — to handle\n * inter-signer interoperability for hashes carried in the VSI CBOR map (§19.7.3), where\n * the spec does not signal the prefix mode. Flat hashes from a `c2pa.hash.bmff.v3`\n * assertion always use the 8-byte prefix (§18.6.2); verify those with\n * {@link computeBmffHash} and `offsetPrefixSize: 8` instead.\n *\n * @param segmentBytes - Raw segment bytes to validate\n * @param expectedHash - Expected hash bytes from the VSI CBOR map\n * @param options - Validation options (exclusions, algorithm)\n * @returns `true` if the computed hash matches the expected hash in either offset mode\n *\n * @example\n * {@includeCode ../../test/bmff/validateBmffHash.test.ts#example}\n *\n * @public\n */\nexport async function validateBmffHash(\n\tsegmentBytes: Uint8Array,\n\texpectedHash: Uint8Array,\n\toptions?: BmffHashValidationOptions,\n): Promise<boolean> {\n\tfor (const offsetPrefixSize of OFFSET_PREFIX_SIZES_TO_TRY) {\n\t\tconst hash = await computeBmffHash(segmentBytes, { ...options, offsetPrefixSize })\n\t\tif (hashesEqual(hash, expectedHash)) return true\n\t}\n\treturn false\n}\n","import { verifyCoseSign1 } from '../cose/verifyCoseSign1.ts'\nimport { decodeCoseSign1 } from '../cose/decodeCoseSign1.ts'\nimport { extractVsiEmsgBox } from '../emsg/extractVsiEmsgBox.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { decodeVsiMap } from '../vsi/decodeVsiMap.ts'\nimport type { SequenceState } from '../vsi/SequenceState.ts'\nimport { createSequenceState } from '../vsi/createSequenceState.ts'\nimport { validateSequenceNumber } from '../vsi/validateSequenceNumber.ts'\nimport { validateBmffHash } from '../bmff/validateBmffHash.ts'\nimport type { ValidatedSessionKey } from '../init/InitSegmentValidation.ts'\nimport { resolveImportAlgorithm } from '../cose/resolveImportAlgorithm.ts'\nimport { bytesToHex, isKeyExpired } from '../utils.ts'\nimport type { SegmentValidationResult } from './SegmentValidation.ts'\n\nfunction findSessionKey(sessionKeys: readonly ValidatedSessionKey[], kidHex: string | null): ValidatedSessionKey | null {\n\tif (!kidHex || sessionKeys.length === 0) return null\n\treturn sessionKeys.find(k => k.kid === kidHex) ?? null\n}\n\n/**\n * Validates a C2PA live stream segment using the VSI/EMSG method (§19.7.3).\n *\n * Extracts the EMSG box, decodes the COSE_Sign1 and VSI map, matches the\n * session key by kid, then performs all cryptographic checks: signature\n * verification, BMFF content hash, sequence number floor, and key validity.\n *\n * Returns `null` if the segment does not contain a C2PA EMSG box.\n *\n * @param segmentBytes - Raw segment bytes\n * @param sessionKeys - Available session keys from the init segment\n * @param sequenceState - Current sequence state for this stream\n * @returns Validation result and updated sequence state, or `null` if no C2PA EMSG box\n *\n * @example\n * {@includeCode ../../test/segment/validateC2paSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paSegment(\n\tsegmentBytes: Uint8Array,\n\tsessionKeys: readonly ValidatedSessionKey[],\n\tsequenceState: SequenceState = createSequenceState(),\n): Promise<{ readonly result: SegmentValidationResult; readonly nextSequenceState: SequenceState } | null> {\n\tconst emsgBox = extractVsiEmsgBox(segmentBytes)\n\tif (!emsgBox) return null\n\n\tconst coseSign1 = decodeCoseSign1(emsgBox.messageData)\n\tconst { payload } = coseSign1\n\tif (!payload) throw new Error('COSE_Sign1 payload is empty — cannot decode VSI map')\n\tconst vsi = decodeVsiMap(payload)\n\n\tconst kidHex = coseSign1.kid ? bytesToHex(coseSign1.kid) : null\n\tconst sessionKey = findSessionKey(sessionKeys, kidHex)\n\tconst bmffHashHex = bytesToHex(vsi.bmffHash.hash)\n\tconst minSequenceNumber = sessionKey?.minSequenceNumber ?? 0\n\n\tconst { result: sequenceResult, nextState: nextSequenceState } = validateSequenceNumber(\n\t\tsequenceState,\n\t\tvsi.sequenceNumber,\n\t\tminSequenceNumber,\n\t)\n\n\tconst baseFields = {\n\t\tsequenceNumber: vsi.sequenceNumber,\n\t\tmanifestId: vsi.manifestId,\n\t\tbmffHashHex,\n\t\tkidHex,\n\t\tsequenceResult,\n\t}\n\n\tif (!sessionKey) {\n\t\treturn {\n\t\t\tresult: {\n\t\t\t\t...baseFields,\n\t\t\t\tisValid: false,\n\t\t\t\terrorCodes: [LiveVideoStatusCode.SEGMENT_INVALID],\n\t\t\t},\n\t\t\tnextSequenceState,\n\t\t}\n\t}\n\n\tconst algorithm = resolveImportAlgorithm(sessionKey.jwk)\n\tconst publicKey = await crypto.subtle.importKey(\n\t\t'jwk',\n\t\tsessionKey.jwk as JsonWebKey,\n\t\talgorithm,\n\t\tfalse,\n\t\t['verify'],\n\t)\n\n\tconst [signatureValid, hashValid] = await Promise.all([\n\t\tverifyCoseSign1(coseSign1, payload, publicKey),\n\t\tvalidateBmffHash(segmentBytes, vsi.bmffHash.hash, {\n\t\t\texclusions: vsi.bmffHash.exclusions,\n\t\t\talg: vsi.bmffHash.alg,\n\t\t}),\n\t])\n\n\tconst sequenceAboveMin = vsi.sequenceNumber >= sessionKey.minSequenceNumber\n\t// §19.7.3 requires comparing against the segment's presentation time, but the\n\t// VSI map does not carry it. We compare against `now` as an approximation,\n\t// which is accurate for live streams validated in real time.\n\tconst keyExpired = isKeyExpired(sessionKey.createdAt, sessionKey.validityPeriod)\n\n\tconst codes = new Set<LiveVideoStatusCode>()\n\tif (!signatureValid || !hashValid || !sequenceAboveMin) codes.add(LiveVideoStatusCode.SEGMENT_INVALID)\n\tif (!sequenceResult.isValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (keyExpired) codes.add(LiveVideoStatusCode.SESSIONKEY_INVALID)\n\tconst errorCodes = [...codes]\n\n\treturn {\n\t\tresult: { ...baseFields, isValid: errorCodes.length === 0, errorCodes },\n\t\tnextSequenceState,\n\t}\n}\n","import type { C2paAssertion } from '../C2paAssertion.ts'\nimport type { C2paManifest } from '../C2paManifest.ts'\nimport type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { readC2paManifest } from '../readC2paManifest.ts'\nimport { bytesToHex, hashesEqual, normalizeAlgorithmName, toUint8Array } from '../utils.ts'\nimport { computeBmffHash } from '../bmff/computeBmffHash.ts'\nimport { parseExclusions } from '../bmff/parseExclusions.ts'\nimport type { BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport type { InternalManifestData } from '../claim/InternalManifestData.ts'\nimport { validateManifestIntegrity } from '../claim/validateManifestIntegrity.ts'\nimport type {\n\tManifestBoxValidationOptions,\n\tManifestBoxValidationResult,\n\tManifestBoxValidationState,\n} from './ManifestBoxValidation.ts'\n\nconst LIVE_VIDEO_ASSERTION_LABEL = 'c2pa.livevideo.segment'\nconst BMFF_HASH_ASSERTION_LABEL = 'c2pa.hash.bmff.v3'\nconst MANIFEST_ID_PREFIX_PATTERN = /^(xmp:iid:|urn:uuid:)/i\nconst CONTINUITY_METHOD_MANIFEST_ID = 'c2pa.manifestId'\n\nfunction normalizeManifestId(id: string | null): string | null {\n\tif (!id) return null\n\treturn id.replace(MANIFEST_ID_PREFIX_PATTERN, '').toLowerCase()\n}\n\nfunction extractAssertionData(data: unknown): Record<string, unknown> | null {\n\tif (data !== null && typeof data === 'object' && !Array.isArray(data)) {\n\t\treturn data as Record<string, unknown>\n\t}\n\treturn null\n}\n\n// --- Live video assertion parsing ---\n\ntype LiveVideoFields = {\n\tsequenceNumber: number | null\n\tpreviousManifestId: string | null\n\tstreamId: string | null\n\tcontinuityMethod: string | null\n\tdata: Record<string, unknown>\n}\n\nfunction parseLiveVideoAssertion(assertions: readonly C2paAssertion[]): LiveVideoFields | null {\n\tconst assertion = assertions.find(a => a.label === LIVE_VIDEO_ASSERTION_LABEL)\n\tif (!assertion) return null\n\n\tconst data = extractAssertionData(assertion.data)\n\tconst rawSeq = data?.['sequenceNumber']\n\tconst rawPrev = data?.['previousManifestId']\n\tconst rawStreamId = data?.['streamId']\n\tconst rawContinuity = data?.['continuityMethod']\n\n\treturn {\n\t\tsequenceNumber: typeof rawSeq === 'number' ? rawSeq : null,\n\t\tpreviousManifestId: typeof rawPrev === 'string' ? rawPrev : null,\n\t\tstreamId: typeof rawStreamId === 'string' ? rawStreamId : null,\n\t\tcontinuityMethod: typeof rawContinuity === 'string' ? rawContinuity : null,\n\t\tdata: data ?? {},\n\t}\n}\n\n// --- BMFF hash assertion parsing ---\n\ntype BmffHashFields = {\n\thashBytes: Uint8Array | null\n\thashHex: string | null\n\texclusions: readonly BmffHashExclusion[]\n\talg: string | null\n}\n\nconst EMPTY_BMFF_HASH: BmffHashFields = { hashBytes: null, hashHex: null, exclusions: [], alg: null }\n\nfunction parseBmffHashAssertion(assertions: readonly C2paAssertion[]): BmffHashFields {\n\tconst assertion = assertions.find(a => a.label === BMFF_HASH_ASSERTION_LABEL)\n\tif (!assertion) return EMPTY_BMFF_HASH\n\n\tconst data = extractAssertionData(assertion.data)\n\tif (!data) return EMPTY_BMFF_HASH\n\n\tconst hashBytes = toUint8Array(data['hash'] ?? data['value'])\n\tconst hashHex = hashBytes ? bytesToHex(hashBytes) : null\n\tconst exclusions = parseExclusions(data['exclusions'])\n\tconst alg = typeof data['alg'] === 'string' ? normalizeAlgorithmName(data['alg']) : null\n\treturn { hashBytes, hashHex, exclusions, alg }\n}\n\n// --- Manifest parsing ---\n\ntype ParsedManifest = {\n\tmanifest: C2paManifest | null\n\tissuer: string | null\n\tliveVideo: LiveVideoFields | null\n\tbmff: BmffHashFields\n\tinternalData: InternalManifestData | null\n}\n\nfunction parseManifest(bytes: Uint8Array): ParsedManifest {\n\ttry {\n\t\tconst internalData = readC2paManifest(bytes)\n\t\tconst { manifest } = internalData\n\t\tif (!manifest) return { manifest: null, issuer: null, liveVideo: null, bmff: EMPTY_BMFF_HASH, internalData: null }\n\n\t\treturn {\n\t\t\tmanifest,\n\t\t\tissuer: manifest.signatureInfo?.issuer ?? null,\n\t\t\tliveVideo: parseLiveVideoAssertion(manifest.assertions),\n\t\t\tbmff: parseBmffHashAssertion(manifest.assertions),\n\t\t\tinternalData,\n\t\t}\n\t} catch {\n\t\treturn { manifest: null, issuer: null, liveVideo: null, bmff: EMPTY_BMFF_HASH, internalData: null }\n\t}\n}\n\n// --- Validation ---\n\nfunction collectErrorCodes(\n\thasManifest: boolean,\n\thasLiveVideo: boolean,\n\tstreamIdValid: boolean,\n\tsequenceNumberValid: boolean,\n\tbmffHashMatches: boolean,\n): readonly LiveVideoStatusCode[] {\n\tconst codes = new Set<LiveVideoStatusCode>()\n\n\tif (!hasManifest) codes.add(LiveVideoStatusCode.MANIFEST_INVALID)\n\tif (!hasLiveVideo) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!streamIdValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!sequenceNumberValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!bmffHashMatches) codes.add(LiveVideoStatusCode.SEGMENT_INVALID)\n\n\treturn [...codes]\n}\n\nasync function validateContinuity(\n\tparsed: ParsedManifest,\n\tlastManifestId: string | null,\n\toptions?: ManifestBoxValidationOptions,\n): Promise<readonly LiveVideoStatusCode[]> {\n\tconst { manifest, liveVideo } = parsed\n\tconst method = liveVideo?.continuityMethod ?? null\n\n\tif (!method) return [LiveVideoStatusCode.CONTINUITY_METHOD_INVALID]\n\n\tif (method === CONTINUITY_METHOD_MANIFEST_ID) {\n\t\tconst prev = liveVideo?.previousManifestId ?? null\n\t\tif (!prev) return [LiveVideoStatusCode.CONTINUITY_METHOD_INVALID]\n\t\tconst broken = !!lastManifestId && normalizeManifestId(prev) !== normalizeManifestId(lastManifestId)\n\t\treturn broken ? [LiveVideoStatusCode.SEGMENT_INVALID] : []\n\t}\n\n\tconst custom = options?.continuityValidator\n\tif (custom?.method !== method || !manifest || !liveVideo) {\n\t\treturn [LiveVideoStatusCode.CONTINUITY_METHOD_INVALID, LiveVideoStatusCode.CONTINUITY_METHOD_UNSUPPORTED]\n\t}\n\n\tconst ok = await Promise.resolve()\n\t\t.then(() => custom.validate(liveVideo.data, manifest))\n\t\t.catch(() => false)\n\treturn ok ? [] : [LiveVideoStatusCode.SEGMENT_INVALID]\n}\n\n/**\n * Validates a C2PA manifest-box live stream segment.\n *\n * Parses the C2PA manifest embedded in the segment and validates per §19.7.1 and §19.7.2.\n * Recomputes the `c2pa.hash.bmff.v3` content hash from the raw segment bytes and compares\n * it against the expected hash in the manifest assertion. Checks live-video assertions\n * (sequenceNumber, streamId, continuityMethod) and manifest-ID chain continuity.\n * A validator for an implementer-defined continuity method can be registered\n * via {@link ManifestBoxValidationOptions}.\n *\n * This function is **pure** — it does not access any external state. The\n * caller is responsible for persisting `nextManifestId` and `nextState`\n * between calls.\n *\n * @param bytes - Raw segment bytes\n * @param lastManifestId - Manifest ID from the previous segment, or null for the first segment\n * @param state - Optional state from the previous segment for streamId/sequenceNumber checks\n * @param options - Optional custom continuity method validator\n * @returns Validation result, the manifest ID, and state to persist for the next call\n *\n * @example\n * {@includeCode ../../test/manifestbox/validateC2paManifestBoxSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paManifestBoxSegment(\n\tbytes: Uint8Array,\n\tlastManifestId: string | null,\n\tstate?: ManifestBoxValidationState,\n\toptions?: ManifestBoxValidationOptions,\n): Promise<{\n\treadonly result: ManifestBoxValidationResult\n\treadonly nextManifestId: string | null\n\treadonly nextState: ManifestBoxValidationState\n}> {\n\tconst { manifest, issuer, liveVideo, bmff, internalData } = parseManifest(bytes)\n\n\tconst sequenceNumber = liveVideo?.sequenceNumber ?? null\n\tconst previousManifestId = liveVideo?.previousManifestId ?? null\n\tconst streamId = liveVideo?.streamId ?? null\n\tconst continuityMethod = liveVideo?.continuityMethod ?? null\n\n\tconst streamIdValid = state?.lastStreamId == null || streamId === state.lastStreamId\n\tconst sequenceNumberValid =\n\t\tstate?.lastSequenceNumber == null ||\n\t\t(sequenceNumber !== null && sequenceNumber > state.lastSequenceNumber)\n\n\tlet bmffHashMatches = true\n\tif (bmff.hashBytes !== null) {\n\t\t// §18.6.2: the flat v2/v3 hash covers offset || data for every non-excluded root\n\t\t// box; only Merkle tree hashes may omit the 8-byte offset prefix.\n\t\tconst computed = await computeBmffHash(bytes, {\n\t\t\texclusions: bmff.exclusions,\n\t\t\talg: bmff.alg ?? undefined,\n\t\t\toffsetPrefixSize: 8,\n\t\t})\n\t\tbmffHashMatches = hashesEqual(computed, bmff.hashBytes)\n\t}\n\n\tconst continuityCodes = await validateContinuity({ manifest, issuer, liveVideo, bmff, internalData }, lastManifestId, options)\n\n\tconst liveVideoCodes = [...new Set([\n\t\t...collectErrorCodes(\n\t\t\tmanifest !== null, liveVideo !== null,\n\t\t\tstreamIdValid, sequenceNumberValid, bmffHashMatches,\n\t\t),\n\t\t...continuityCodes,\n\t])]\n\n\tconst integrity = internalData ? await validateManifestIntegrity(internalData) : null\n\tconst integrityCodes: readonly C2paStatusCode[] = integrity?.codes ?? []\n\n\tconst errorCodes: (LiveVideoStatusCode | C2paStatusCode)[] = [...liveVideoCodes, ...integrityCodes]\n\n\tconst currentManifestId = manifest?.instanceId ?? null\n\n\treturn {\n\t\tresult: {\n\t\t\tmanifest: manifest ?? null,\n\t\t\tissuer,\n\t\t\tcertificate: integrity?.certificate ?? null,\n\t\t\tsequenceNumber,\n\t\t\tpreviousManifestId,\n\t\t\tstreamId,\n\t\t\tcontinuityMethod,\n\t\t\tbmffHashHex: bmff.hashHex,\n\t\t\tisValid: errorCodes.length === 0,\n\t\t\terrorCodes,\n\t\t},\n\t\tnextManifestId: currentManifestId ?? lastManifestId,\n\t\tnextState: {\n\t\t\tlastStreamId: streamId ?? state?.lastStreamId,\n\t\t\tlastSequenceNumber: sequenceNumber ?? state?.lastSequenceNumber,\n\t\t},\n\t}\n}\n","import { readIsoBoxes } from '@svta/cml-iso-bmff'\nimport { decodeMultiple } from 'cbor-x/decode'\nimport { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { computeBmffHash } from '../bmff/computeBmffHash.ts'\nimport { JUMBF_UUID, asInteger, bytesToHex, hashesEqual, matchesUuid, normalizeAlgorithmName, readUuidBoxPurpose, toUint8Array } from '../utils.ts'\nimport type { UuidParsedBox } from '../utils.ts'\nimport type { MerkleMap, MerkleSegmentState, MerkleSegmentValidation } from './MerkleSegmentValidation.ts'\n\ntype MerkleValidationCode = LiveVideoStatusCode | C2paStatusCode\n\nconst MERKLE_BOX_PURPOSE = 'merkle'\n\n// --- Auxiliary uuid box extraction ---\n\ntype AuxPayload = Uint8Array | 'other'\n\n// §A.5.1.2/A.5.4.1.4: version/flags + null-terminated box_purpose + raw data.\nfunction readAuxPayload(rawPayload: Uint8Array): AuxPayload {\n\tconst prefix = readUuidBoxPurpose(rawPayload)\n\tif (!prefix || prefix.purpose !== MERKLE_BOX_PURPOSE) return 'other'\n\treturn prefix.rest\n}\n\nfunction extractMerkleAuxBoxes(segmentBytes: Uint8Array): Uint8Array[] {\n\tconst payloads: Uint8Array[] = []\n\n\tfor (const box of readIsoBoxes(segmentBytes)) {\n\t\tconst uuidBox = box as unknown as UuidParsedBox\n\t\tif (uuidBox.type !== 'uuid') continue\n\t\tconst usertype = uuidBox.usertype ?? []\n\t\tif (!matchesUuid(usertype, JUMBF_UUID)) continue\n\n\t\tconst rawPayload = uuidBox.view.readData(uuidBox.view.bytesRemaining) as Uint8Array\n\t\tconst payload = readAuxPayload(rawPayload)\n\t\tif (payload !== 'other') payloads.push(payload)\n\t}\n\n\treturn payloads\n}\n\n// --- bmff-merkle-map decoding ---\n\ntype BmffMerkleMapSegment = {\n\treadonly uniqueId: number\n\treadonly localId: number\n\treadonly location: number\n\t/** Sibling proof path; null when the manifest stores the leaf row */\n\treadonly hashes: readonly (Uint8Array | null)[] | null\n}\n\nfunction readMapField(map: unknown, name: string): unknown {\n\tif (map instanceof Map) return map.get(name)\n\treturn (map as Record<string, unknown>)[name]\n}\n\n// §A.5.4.1.4: multiple merkle boxes for one tree are padded to a fixed size,\n// so trailing bytes after the CBOR item are expected and not part of the data.\nfunction decodeFirstCbor(payload: Uint8Array): unknown {\n\tlet first: unknown\n\tlet found = false\n\ttry {\n\t\tdecodeMultiple(payload, value => {\n\t\t\tfirst = value\n\t\t\tfound = true\n\t\t\treturn false\n\t\t})\n\t} catch {\n\t\treturn undefined\n\t}\n\treturn found ? first : undefined\n}\n\nfunction parseBmffMerkleMap(payload: Uint8Array): BmffMerkleMapSegment | null {\n\tconst decoded = decodeFirstCbor(payload)\n\tif (decoded === null || decoded === undefined || typeof decoded !== 'object') return null\n\n\tconst uniqueId = asInteger(readMapField(decoded, 'uniqueId'))\n\tconst localId = asInteger(readMapField(decoded, 'localId'))\n\tconst location = asInteger(readMapField(decoded, 'location'))\n\tif (uniqueId === null || localId === null || location === null) return null\n\n\tconst rawHashes = readMapField(decoded, 'hashes')\n\tif (rawHashes == null) return { uniqueId, localId, location, hashes: null }\n\tif (!Array.isArray(rawHashes)) return null\n\n\tconst hashes: (Uint8Array | null)[] = []\n\tfor (const entry of rawHashes) {\n\t\tif (entry == null) {\n\t\t\thashes.push(null)\n\t\t\tcontinue\n\t\t}\n\t\tconst bytes = toUint8Array(entry)\n\t\tif (!bytes) return null\n\t\thashes.push(bytes)\n\t}\n\treturn { uniqueId, localId, location, hashes }\n}\n\n// --- Merkle proof traversal ---\n\nasync function hashPair(left: Uint8Array, right: Uint8Array, alg: string): Promise<Uint8Array> {\n\tconst input = new Uint8Array(left.length + right.length)\n\tinput.set(left, 0)\n\tinput.set(right, left.length)\n\treturn new Uint8Array(await crypto.subtle.digest(alg, input))\n}\n\n// Layer sizes, leaf level first (61 → [61, 31, 16, 8, 4, 2, 1]).\nfunction treeLayout(leafCount: number): number[] {\n\tconst layers = [leafCount]\n\twhile (layers[layers.length - 1] > 1) {\n\t\tlayers.push(Math.ceil(layers[layers.length - 1] / 2))\n\t}\n\treturn layers\n}\n\n// §15.12.2.2: hash from the leaf up to the layer matching the manifest row length.\nasync function verifyMerkleProof(\n\tleafHash: Uint8Array,\n\tlocation: number,\n\tproofPath: readonly (Uint8Array | null)[] | null,\n\tmerkleMap: MerkleMap,\n): Promise<'ok' | MerkleValidationCode> {\n\tconst { count, hashes: manifestRow } = merkleMap\n\tif (location < 0 || location >= count) {\n\t\treturn C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\t}\n\n\tconst layers = treeLayout(count)\n\tconst committedLevel = layers.indexOf(manifestRow.length)\n\tif (committedLevel === -1) {\n\t\treturn C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\t}\n\n\tconst rawPath = proofPath ?? []\n\tif (rawPath.length > committedLevel) return C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\tconst path = rawPath.filter((node): node is Uint8Array => node !== null)\n\n\tconst alg = normalizeAlgorithmName(merkleMap.alg ?? undefined)\n\n\tlet currentHash = leafHash\n\tlet currentIndex = location\n\tlet proofIndex = 0\n\tfor (const layer of layers) {\n\t\tif (layer === manifestRow.length) {\n\t\t\tbreak\n\t\t}\n\t\tconst siblingIndex = currentIndex % 2 === 0 ? currentIndex + 1 : currentIndex - 1\n\t\tif (siblingIndex >= 0 && siblingIndex < layer) {\n\t\t\tconst sibling = path[proofIndex++]\n\t\t\tif (!sibling) return C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\t\t\tcurrentHash = currentIndex % 2 === 0\n\t\t\t\t? await hashPair(currentHash, sibling, alg)\n\t\t\t\t: await hashPair(sibling, currentHash, alg)\n\t\t}\n\t\tcurrentIndex = Math.floor(currentIndex / 2)\n\t}\n\n\tif (proofIndex !== path.length) return C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\n\tconst expected = manifestRow[currentIndex]\n\tif (!expected) return C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\treturn hashesEqual(currentHash, expected) ? 'ok' : C2paStatusCode.ASSERTION_BMFFHASH_MISMATCH\n}\n\n// --- Public API ---\n\nfunction findMerkleMap(\n\tmerkleMaps: readonly MerkleMap[],\n\tuniqueId: number,\n\tlocalId: number,\n): MerkleMap | null {\n\treturn merkleMaps.find(m => m.uniqueId === uniqueId && m.localId === localId) ?? null\n}\n\ntype LeafHashCache = {\n\talg: string | null\n\toffsetPrefixSize: number\n\texclusions: MerkleMap['exclusions']\n\thash: Uint8Array\n}[]\n\nasync function computeLeafHash(\n\tsegmentBytes: Uint8Array,\n\tmerkleMap: MerkleMap,\n\tcache: LeafHashCache,\n): Promise<Uint8Array> {\n\tconst cached = cache.find(entry =>\n\t\tentry.alg === merkleMap.alg &&\n\t\tentry.offsetPrefixSize === merkleMap.offsetPrefixSize &&\n\t\tentry.exclusions === merkleMap.exclusions,\n\t)\n\tif (cached) return cached.hash\n\n\tconst hash = await computeBmffHash(segmentBytes, {\n\t\toffsetPrefixSize: merkleMap.offsetPrefixSize,\n\t\texclusions: merkleMap.exclusions,\n\t\talg: merkleMap.alg ?? undefined,\n\t})\n\tcache.push({\n\t\talg: merkleMap.alg,\n\t\toffsetPrefixSize: merkleMap.offsetPrefixSize,\n\t\texclusions: merkleMap.exclusions,\n\t\thash,\n\t})\n\treturn hash\n}\n\n/**\n * Validates a fragmented MP4 VOD media segment against the init manifest's\n * merkle maps (§15.12.2.2). Pure: the caller persists `nextState` and resets\n * `state` after a seek.\n *\n * `merkleMaps` must be non-empty; the caller is responsible for only calling\n * this in VOD Merkle mode (i.e. after `InitSegmentValidation.merkleMaps` came\n * back non-empty).\n *\n * @example\n * {@includeCode ../../test/merkle/validateC2paMerkleSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paMerkleSegment(\n\tsegmentBytes: Uint8Array,\n\tmerkleMaps: readonly MerkleMap[],\n\tstate?: MerkleSegmentState,\n): Promise<{\n\treadonly result: MerkleSegmentValidation\n\treadonly nextState: MerkleSegmentState\n}> {\n\tconst previousLocations = state?.lastLocations ?? new Map<string, number>()\n\tconst nextLocations = new Map(previousLocations)\n\tconst codes = new Set<MerkleValidationCode>()\n\tconst leafHashCache: LeafHashCache = []\n\tlet location: number | null = null\n\tlet bmffHashHex: string | null = null\n\n\tconst payloads = extractMerkleAuxBoxes(segmentBytes)\n\tif (payloads.length === 0) {\n\t\tcodes.add(C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED)\n\t}\n\n\tfor (const payload of payloads) {\n\t\tconst segmentMap = parseBmffMerkleMap(payload)\n\t\tif (!segmentMap) {\n\t\t\tcodes.add(C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED)\n\t\t\tcontinue\n\t\t}\n\n\t\tconst merkleMap = findMerkleMap(merkleMaps, segmentMap.uniqueId, segmentMap.localId)\n\t\tif (!merkleMap) {\n\t\t\tcodes.add(C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED)\n\t\t\tcontinue\n\t\t}\n\n\t\tif (location === null) location = segmentMap.location\n\n\t\t// §15.12.2: each track's location must increment by 1 during sequential playback.\n\t\tconst trackKey = `${segmentMap.uniqueId}:${segmentMap.localId}`\n\t\tconst lastLocation = previousLocations.get(trackKey)\n\t\tconst locationValid = lastLocation === undefined || segmentMap.location === lastLocation + 1\n\t\tif (!locationValid) {\n\t\t\tcodes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\t\t}\n\n\t\tconst leafHash = await computeLeafHash(segmentBytes, merkleMap, leafHashCache)\n\t\tif (bmffHashHex === null) bmffHashHex = bytesToHex(leafHash)\n\t\tconst proofResult = await verifyMerkleProof(leafHash, segmentMap.location, segmentMap.hashes, merkleMap)\n\t\tif (proofResult === 'ok') {\n\t\t\t// Advance on any proof-verified location, even a discontinuous one: it's\n\t\t\t// genuinely signed content, so it resyncs continuity checking after a gap\n\t\t\t// instead of leaving every later segment flagged relative to a stale baseline.\n\t\t\tnextLocations.set(trackKey, segmentMap.location)\n\t\t} else {\n\t\t\tcodes.add(proofResult)\n\t\t}\n\t}\n\n\treturn {\n\t\tresult: {\n\t\t\tlocation,\n\t\t\tbmffHashHex,\n\t\t\tisValid: codes.size === 0,\n\t\t\terrorCodes: [...codes],\n\t\t},\n\t\tnextState: { lastLocations: nextLocations },\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["coseGet","toUint8Array","protectedHeader: CoseHeader","TEXT_DECODER","HEX_TABLE: readonly string[]","C2PA_MANIFEST_UUID: readonly number[]","JUMBF_UUID: readonly number[]","TEXT_DECODER","TEXT_DECODER","notBefore: string | null","assertions: InternalAssertionData[]","data: unknown","refs: ClaimAssertionRef[]","claimData: Record<string, unknown> | null","claimCborBytes: Uint8Array | null","internalAssertions: InternalAssertionData[]","signatureBytes: Uint8Array | null","assertions: C2paAssertion[]","codes: C2paStatusCode[]","codes: C2paStatusCode[]","CURVE_COMPONENT_BYTES: Record<string, number>","RSA_PSS_SALT_LENGTH: Record<string, number>","Code","codes: C2paStatusCode[]","EC_CURVE_NAMES: Record<number, string>","OKP_CURVE_NAMES: Record<number, string>","constraints: BmffHashConstraint[]","exclusions: BmffHashExclusion[]","row: Uint8Array[]","maps: MerkleMap[]","BMFF_HASH_ASSERTION_LABEL","EMPTY_BMFF_HASH: BmffHashFields","integrityCodes: readonly C2paStatusCode[]","errorCodes: (LiveVideoStatusCode | C2paStatusCode)[]","payloads: Uint8Array[]","first: unknown","hashes: (Uint8Array | null)[]","leafHashCache: LeafHashCache","location: number | null","bmffHashHex: string | null"],"sources":["../src/LiveVideoStatusCode.ts","../src/cose/decodeCoseSign1.ts","../src/jumbf/parseJumbfBoxes.ts","../src/jumbf/parseJumbfLabel.ts","../src/utils.ts","../src/x509/asn1.ts","../src/x509/extractCertificateInfo.ts","../src/readC2paManifest.ts","../src/bmff/shouldExcludeBox.ts","../src/bmff/computeBmffHash.ts","../src/C2paStatusCode.ts","../src/extractManifestCertificate.ts","../src/claim/validateActionIngredients.ts","../src/claim/validateAssertionHashes.ts","../src/cose/constants.ts","../src/cose/resolveAlgorithmFromCoseAlg.ts","../src/cose/buildSigStructure.ts","../src/cose/verifyCoseSign1.ts","../src/x509/extractCertificateSpki.ts","../src/x509/normalizeRsaPssSpki.ts","../src/claim/verifyClaimSignature.ts","../src/claim/validateManifestIntegrity.ts","../src/cose/convertCoseKeyToJwk.ts","../src/cose/resolveImportAlgorithm.ts","../src/cose/verifySignerBinding.ts","../src/bmff/parseExclusions.ts","../src/merkle/validateMerkleMaps.ts","../src/init/validateC2paInitSegment.ts","../src/emsg/extractVsiEmsgBox.ts","../src/vsi/decodeVsiMap.ts","../src/vsi/createSequenceState.ts","../src/vsi/SequenceState.ts","../src/vsi/validateSequenceNumber.ts","../src/bmff/validateBmffHash.ts","../src/segment/validateC2paSegment.ts","../src/manifestbox/validateC2paManifestBoxSegment.ts","../src/merkle/validateC2paMerkleSegment.ts"],"sourcesContent":["import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Standard C2PA failure status codes for live video validation,\n * as defined in the C2PA specification section 19.7.\n *\n * @see {@link https://c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_live_video_validation_process | C2PA Spec §19.7}\n *\n * @enum\n *\n * @public\n */\nexport const LiveVideoStatusCode = {\n\t/** Init segment contains an `mdat` box (§19.7.1) */\n\tINIT_INVALID: 'livevideo.init.invalid',\n\t/** C2PA Manifest Box failed standard validation (§19.7.1) */\n\tMANIFEST_INVALID: 'livevideo.manifest.invalid',\n\t/** Segment structure invalid: missing Manifest Box/emsg, signature/hash/key failure (§19.7) */\n\tSEGMENT_INVALID: 'livevideo.segment.invalid',\n\t/**\n\t * Live video assertion field invalid: sequenceNumber or streamId mismatch\n\t * (§19.7.2). Also reused for VOD Merkle per-track location discontinuity\n\t * (§15.12.2), which has no dedicated code.\n\t */\n\tASSERTION_INVALID: 'livevideo.assertion.invalid',\n\t/** continuityMethod absent, unsupported, or companion fields incorrect (§19.7.2) */\n\tCONTINUITY_METHOD_INVALID: 'livevideo.continuityMethod.invalid',\n\t/** Custom continuityMethod with no registered validator (§19.7.2) */\n\tCONTINUITY_METHOD_UNSUPPORTED: 'livevideo.continuityMethod.unsupported',\n\t/** Session key invalid: signerBinding failed or required fields absent (§19.7.3) */\n\tSESSIONKEY_INVALID: 'livevideo.sessionkey.invalid',\n} as const\n\n/**\n * Union type of all {@link (LiveVideoStatusCode:variable)} values.\n *\n * @public\n */\nexport type LiveVideoStatusCode = ValueOf<typeof LiveVideoStatusCode>\n","import { decode } from 'cbor-x/decode'\nimport type { CoseSign1 } from './CoseSign1.ts'\n\nconst COSE_SIGN1_TAG_SINGLE_BYTE = 0xd2\nconst COSE_SIGN1_TAG_TWO_BYTE_FIRST = 0xd8\nconst COSE_SIGN1_TAG_TWO_BYTE_SECOND = 0x12\nconst COSE_SIGN1_ARRAY_LENGTH = 4\nconst COSE_KEY_KID = 4\nconst COSE_KEY_ALG = 1\n\ntype CoseHeader = Map<number, unknown> | Record<number | string, unknown>\n\nfunction coseGet(header: CoseHeader, key: number): unknown {\n\tif (header instanceof Map) return header.get(key)\n\treturn (header as Record<number | string, unknown>)[key]\n}\n\nfunction stripCoseTag(bytes: Uint8Array): Uint8Array {\n\tif (bytes[0] === COSE_SIGN1_TAG_SINGLE_BYTE) return bytes.subarray(1)\n\tif (bytes[0] === COSE_SIGN1_TAG_TWO_BYTE_FIRST && bytes[1] === COSE_SIGN1_TAG_TWO_BYTE_SECOND) return bytes.subarray(2)\n\treturn bytes\n}\n\nfunction toUint8Array(value: unknown): Uint8Array {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\tthrow new Error(`Expected Uint8Array or number[], got ${typeof value}`)\n}\n\n/**\n * Decodes a `COSE_Sign1` structure from raw bytes (RFC 9052).\n *\n * Handles CBOR tag 18 in both single-byte (0xD2) and two-byte (0xD8 0x12) form.\n *\n * @param coseBytes - Raw COSE_Sign1 bytes, optionally prefixed with CBOR tag 18\n * @returns The decoded COSE_Sign1 structure\n * @throws If the bytes do not represent a valid COSE_Sign1 structure\n *\n * @example\n * {@includeCode ../../test/cose/decodeCoseSign1.test.ts#example}\n *\n * @internal\n */\nexport function decodeCoseSign1(coseBytes: Uint8Array): CoseSign1 {\n\ttry {\n\t\tconst stripped = stripCoseTag(coseBytes)\n\t\tconst coseArray = decode(stripped) as unknown\n\n\t\tif (!Array.isArray(coseArray) || coseArray.length !== COSE_SIGN1_ARRAY_LENGTH) {\n\t\t\tthrow new Error('Invalid COSE_Sign1 structure: expected array with 4 elements')\n\t\t}\n\n\t\tconst [protectedRaw, unprotectedRaw, payloadRaw, signatureRaw] = coseArray as unknown[]\n\n\t\tconst protectedBytes = toUint8Array(protectedRaw)\n\t\tlet protectedHeader: CoseHeader = {}\n\t\tif (protectedBytes.length > 0) {\n\t\t\tprotectedHeader = decode(protectedBytes) as CoseHeader\n\t\t}\n\n\t\tconst unprotectedHeader = (unprotectedRaw ?? {}) as CoseHeader\n\t\tconst kidRaw = coseGet(protectedHeader, COSE_KEY_KID) ?? coseGet(unprotectedHeader, COSE_KEY_KID) ?? null\n\t\tconst kid = kidRaw != null ? toUint8Array(kidRaw) : null\n\t\tconst alg = (coseGet(protectedHeader, COSE_KEY_ALG) ?? coseGet(unprotectedHeader, COSE_KEY_ALG) ?? null) as number | null\n\n\t\treturn {\n\t\t\tprotectedBytes,\n\t\t\tprotectedHeader: protectedHeader as Readonly<Record<number, unknown>>,\n\t\t\tunprotectedHeader: unprotectedHeader as Readonly<Record<number, unknown>>,\n\t\t\tpayload: payloadRaw == null ? null : toUint8Array(payloadRaw),\n\t\t\tsignature: toUint8Array(signatureRaw),\n\t\t\tkid,\n\t\t\talg,\n\t\t}\n\t}\n\tcatch (error) {\n\t\tthrow new Error(`Failed to decode COSE_Sign1: ${(error as Error).message}`)\n\t}\n}\n","import { readIsoBoxes } from '@svta/cml-iso-bmff'\nimport type { JumbfBox } from './JumbfBox.ts'\n\n/**\n * Parses JUMBF boxes (ISO 19566-5) from raw bytes.\n *\n * JUMBF boxes share the same 4-byte size + 4-byte type structure as ISO BMFF boxes,\n * so they can be parsed with the same reader.\n *\n * @param bytes - Raw bytes containing JUMBF box content\n * @returns Array of parsed JUMBF boxes with their payloads\n *\n * @example\n * {@includeCode ../../test/jumbf/parseJumbfBoxes.test.ts#example}\n *\n * @internal\n */\nexport function parseJumbfBoxes(bytes: Uint8Array): JumbfBox[] {\n\treturn readIsoBoxes(bytes).map(box => ({\n\t\ttype: box.type,\n\t\tdata: box.view.readData(box.view.bytesRemaining),\n\t}))\n}\n","const TEXT_DECODER = /* @__PURE__ */ new TextDecoder()\nconst JUMD_UUID_SIZE = 16\nconst JUMD_TOGGLES_OFFSET = 16\nconst JUMD_LABEL_START = 17\nconst LABEL_FLAG_MASK = 0x03\nconst LABEL_FLAG_EXPECTED = 0x03\n\n/**\n * Extracts the label from a JUMBF Description Box (`jumd`) data payload.\n *\n * The `jumd` format is: 16-byte UUID + 1-byte toggles + null-terminated label string.\n * A label is only present when bits 0 and 1 of the toggles byte are both set.\n *\n * @param jumdData - Raw bytes of the `jumd` box data (payload after the box header)\n * @returns The label string, or `null` if no label is present\n *\n * @example\n * {@includeCode ../../test/jumbf/parseJumbfLabel.test.ts#example}\n *\n * @internal\n */\nexport function parseJumbfLabel(jumdData: Uint8Array): string | null {\n\tif (jumdData.length < JUMD_UUID_SIZE + 1) return null\n\n\tconst toggles = jumdData[JUMD_TOGGLES_OFFSET]\n\tif ((toggles & LABEL_FLAG_MASK) !== LABEL_FLAG_EXPECTED) return null\n\n\tlet end = JUMD_LABEL_START\n\twhile (end < jumdData.length && jumdData[end] !== 0) end++\n\tif (end >= jumdData.length) return null\n\n\treturn TEXT_DECODER.decode(jumdData.subarray(JUMD_LABEL_START, end))\n}\n","import type { IsoBoxReadView, ParsedIsoBox } from '@svta/cml-iso-bmff'\n\nconst MILLISECONDS_PER_SECOND = 1000\nconst SHA_ALGORITHM_PATTERN = /^sha(\\d+)$/i\n\n/**\n * Normalizes hash algorithm names to WebCrypto format (e.g. `sha256` → `SHA-256`).\n *\n * Defaults to `'SHA-256'` when no algorithm is provided.\n *\n * @internal\n */\nexport function normalizeAlgorithmName(rawAlg?: string): string {\n\treturn (rawAlg ?? 'SHA-256').replace(SHA_ALGORITHM_PATTERN, 'SHA-$1')\n}\n\nconst HEX_TABLE: readonly string[] = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'))\n\n/**\n * Converts a Uint8Array to a lowercase hex string.\n *\n * @internal\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n\tlet hex = ''\n\tfor (const byte of bytes) hex += HEX_TABLE[byte]\n\treturn hex\n}\n\n/**\n * Checks whether a session key has expired based on its creation time\n * and validity period.\n *\n * @param createdAt - ISO 8601 date string when the key was created\n * @param validityPeriodSeconds - Validity duration in seconds\n * @param now - Current time (defaults to `new Date()`, injectable for testing)\n * @returns `true` if the key has expired\n *\n * @internal\n */\nexport function isKeyExpired(createdAt: string, validityPeriodSeconds: number, now: Date = new Date()): boolean {\n\tconst createdAtMs = new Date(createdAt).getTime()\n\tif (Number.isNaN(createdAtMs)) return true\n\tconst validityEnd = new Date(createdAtMs + validityPeriodSeconds * MILLISECONDS_PER_SECOND)\n\treturn now > validityEnd\n}\n\n/**\n * Constant-time comparison of two hash byte arrays.\n *\n * @internal\n */\nexport function hashesEqual(a: Uint8Array, b: Uint8Array): boolean {\n\tif (a.length !== b.length) return false\n\tlet diff = 0\n\tfor (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i]\n\treturn diff === 0\n}\n\n// C2PA manifest store UUID per C2PA specification\nconst C2PA_MANIFEST_UUID: readonly number[] = [\n\t0xd8, 0xfe, 0xc3, 0xd6, 0x1a, 0x96, 0x4f, 0x32,\n\t0xa0, 0xf6, 0xf3, 0xec, 0xf9, 0x6c, 0x10, 0xea,\n]\n\n// JUMBF UUID per ISO 19566-5 (used by c2pa-rs and other JUMBF-compliant tools)\n/** @internal */\nexport const JUMBF_UUID: readonly number[] = [\n\t0xd8, 0xfe, 0xc3, 0xd6, 0x1b, 0x0e, 0x48, 0x3c,\n\t0x92, 0x97, 0x58, 0x28, 0x87, 0x7e, 0xc4, 0x81,\n]\n\n// Compares a uuid box usertype against an expected 16-byte extended type.\n/** @internal */\nexport function matchesUuid(usertype: readonly number[], expected: readonly number[]): boolean {\n\treturn usertype.length === expected.length && expected.every((b, i) => b === usertype[i])\n}\n\n// Converts CBOR-decoded bytes (Uint8Array or number[]) to Uint8Array, or null.\n/** @internal */\nexport function toUint8Array(value: unknown): Uint8Array | null {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\treturn null\n}\n\n/** @internal */\nexport function asInteger(value: unknown): number | null {\n\treturn typeof value === 'number' && Number.isInteger(value) ? value : null\n}\n\nfunction isC2paUuid(usertype: readonly number[]): boolean {\n\treturn matchesUuid(usertype, C2PA_MANIFEST_UUID) || matchesUuid(usertype, JUMBF_UUID)\n}\n\n/**\n * A parsed ISO BMFF box with a UUID type.\n *\n * `ParsedIsoBox` does not include 'uuid' in its type union because UUID boxes\n * are not part of the standard `IsoBoxMap`. This type represents the structural\n * shape needed to work with UUID boxes at runtime.\n *\n * @internal\n */\nexport type UuidParsedBox = {\n\ttype: string\n\tusertype?: number[]\n\tview: IsoBoxReadView\n\tsize: number\n}\n\n/**\n * Finds the C2PA UUID box in a list of parsed ISO BMFF boxes.\n *\n * Matches against both the C2PA manifest store UUID and the JUMBF UUID\n * (ISO 19566-5), as different tools use different UUIDs.\n *\n * @internal\n */\nexport function findC2paUuidBox(boxes: ParsedIsoBox[]): UuidParsedBox | undefined {\n\treturn (boxes as UuidParsedBox[]).find(\n\t\tbox => box.type === 'uuid' && isC2paUuid(box.usertype ?? []),\n\t)\n}\n\nconst FULLBOX_HEADER_SIZE = 4\nconst AUX_UUID_OFFSET_SIZE = 8\nconst TEXT_DECODER = new TextDecoder()\n\n// Reads a version/flags + null-terminated purpose prefix, or null if malformed.\n/** @internal */\nexport function readUuidBoxPurpose(payload: Uint8Array): { purpose: string; rest: Uint8Array } | null {\n\tif (payload.length < FULLBOX_HEADER_SIZE) return null\n\n\tlet offset = FULLBOX_HEADER_SIZE\n\twhile (offset < payload.length && payload[offset] !== 0) offset++\n\tif (offset >= payload.length) return null\n\n\treturn {\n\t\tpurpose: TEXT_DECODER.decode(payload.subarray(FULLBOX_HEADER_SIZE, offset)),\n\t\trest: payload.subarray(offset + 1),\n\t}\n}\n\n/**\n * Strips the JUMBF UUID box prefix (fullbox header, purpose string, aux offset)\n * to return only the JUMBF manifest data.\n *\n * Structure per ISO 19566-5 / C2PA BMFF storage:\n * version(1) + flags(3) + purpose(null-terminated) + aux_offset(8) + JUMBF data\n *\n * Returns `null` if the payload does not contain a valid JUMBF UUID prefix.\n *\n * @internal\n */\nexport function stripJumbfUuidPrefix(payload: Uint8Array): Uint8Array | null {\n\tconst prefix = readUuidBoxPurpose(payload)\n\tif (!prefix || prefix.rest.length < AUX_UUID_OFFSET_SIZE) return null\n\treturn prefix.rest.subarray(AUX_UUID_OFFSET_SIZE)\n}\n","/**\n * Minimal ASN.1 DER parsing helpers for X.509 certificate navigation.\n *\n * @internal\n */\n\nexport const ASN1_TAG_INTEGER = 0x02\nexport const ASN1_TAG_OBJECT_IDENTIFIER = 0x06\nexport const ASN1_TAG_SEQUENCE = 0x30\nexport const ASN1_TAG_SET = 0x31\nexport const ASN1_TAG_UTC_TIME = 0x17\nexport const ASN1_TAG_GENERALIZED_TIME = 0x18\nexport const ASN1_TAG_CONTEXT_0 = 0xa0\nconst ASN1_LONG_FORM_FLAG = 0x80\nconst ASN1_LONG_FORM_MASK = 0x7f\n\nexport type Asn1Element = {\n\treadonly tag: number\n\treadonly value: Uint8Array\n\treadonly totalSize: number\n}\n\nexport function readLength(bytes: Uint8Array, offset: number): { length: number; bytesRead: number } {\n\tif (offset >= bytes.length) return { length: 0, bytesRead: 0 }\n\tconst first = bytes[offset] ?? 0\n\tif (first < ASN1_LONG_FORM_FLAG) return { length: first, bytesRead: 1 }\n\tconst count = first & ASN1_LONG_FORM_MASK\n\tlet length = 0\n\tfor (let i = 0; i < count; i++) {\n\t\tlength = (length << 8) | (bytes[offset + 1 + i] ?? 0)\n\t}\n\treturn { length, bytesRead: 1 + count }\n}\n\nexport function readElement(bytes: Uint8Array, offset: number): Asn1Element | null {\n\tif (offset + 2 > bytes.length) return null\n\tconst tag = bytes[offset] ?? 0\n\tconst { length, bytesRead } = readLength(bytes, offset + 1)\n\tconst headerSize = 1 + bytesRead\n\tconst valueEnd = offset + headerSize + length\n\tif (valueEnd > bytes.length) return null\n\treturn {\n\t\ttag,\n\t\tvalue: bytes.subarray(offset + headerSize, valueEnd),\n\t\ttotalSize: headerSize + length,\n\t}\n}\n\n/**\n * Reads an ASN.1 element and returns its full DER encoding (tag + length + value).\n *\n * @internal\n */\nexport function readElementRaw(bytes: Uint8Array, offset: number): Uint8Array | null {\n\tconst el = readElement(bytes, offset)\n\tif (!el) return null\n\treturn bytes.subarray(offset, offset + el.totalSize)\n}\n","const TEXT_DECODER = /* @__PURE__ */ new TextDecoder()\n\nimport type { CertificateInfo } from './CertificateInfo.ts'\nimport {\n\tASN1_TAG_CONTEXT_0,\n\tASN1_TAG_GENERALIZED_TIME,\n\tASN1_TAG_INTEGER,\n\tASN1_TAG_OBJECT_IDENTIFIER,\n\tASN1_TAG_SEQUENCE,\n\tASN1_TAG_SET,\n\tASN1_TAG_UTC_TIME,\n\treadElement,\n\ttype Asn1Element,\n} from './asn1.ts'\n\nconst OID_COMMON_NAME = new Uint8Array([0x55, 0x04, 0x03])\nconst OID_ORG_NAME = new Uint8Array([0x55, 0x04, 0x0a])\n\nfunction matchesOID(value: Uint8Array, oid: Uint8Array): boolean {\n\tif (value.length < oid.length) return false\n\tfor (let i = 0; i < oid.length; i++) {\n\t\tif (value[i] !== oid[i]) return false\n\t}\n\treturn true\n}\n\nfunction parseTime(element: Asn1Element): string | null {\n\tconst text = TEXT_DECODER.decode(element.value)\n\tif (element.tag === ASN1_TAG_UTC_TIME) {\n\t\tconst yy = parseInt(text.substring(0, 2), 10)\n\t\tconst year = yy >= 50 ? 1900 + yy : 2000 + yy\n\t\treturn `${year}-${text.substring(2, 4)}-${text.substring(4, 6)}T${text.substring(6, 8)}:${text.substring(8, 10)}:${text.substring(10, 12)}Z`\n\t}\n\tif (element.tag === ASN1_TAG_GENERALIZED_TIME) {\n\t\treturn `${text.substring(0, 4)}-${text.substring(4, 6)}-${text.substring(6, 8)}T${text.substring(8, 10)}:${text.substring(10, 12)}:${text.substring(12, 14)}Z`\n\t}\n\treturn null\n}\n\nfunction findOidValueInSequence(seqValue: Uint8Array, targetOID: Uint8Array): string | null {\n\tconst oidEl = readElement(seqValue, 0)\n\tif (!oidEl || oidEl.tag !== ASN1_TAG_OBJECT_IDENTIFIER) return null\n\tif (!matchesOID(oidEl.value, targetOID)) return null\n\n\tconst valEl = readElement(seqValue, oidEl.totalSize)\n\treturn valEl ? TEXT_DECODER.decode(valEl.value) : null\n}\n\nfunction findRDNValue(issuerValue: Uint8Array, targetOID: Uint8Array): string | null {\n\tlet offset = 0\n\twhile (offset < issuerValue.length) {\n\t\tconst setEl = readElement(issuerValue, offset)\n\t\tif (!setEl || setEl.tag !== ASN1_TAG_SET) break\n\n\t\tlet setOffset = 0\n\t\twhile (setOffset < setEl.value.length) {\n\t\t\tconst seqEl = readElement(setEl.value, setOffset)\n\t\t\tif (!seqEl || seqEl.tag !== ASN1_TAG_SEQUENCE) break\n\n\t\t\tconst found = findOidValueInSequence(seqEl.value, targetOID)\n\t\t\tif (found) return found\n\n\t\t\tsetOffset += seqEl.totalSize\n\t\t}\n\t\toffset += setEl.totalSize\n\t}\n\treturn null\n}\n\n/**\n * Extracts the issuer name and `notBefore` date from a DER-encoded X.509 certificate.\n *\n * Uses a minimal ASN.1 parser that handles the subset of DER structures found in\n * typical C2PA signing certificates. Extracts the issuer Common Name (OID 2.5.4.3)\n * or Organization Name (OID 2.5.4.10) as a fallback, and the `notBefore` validity date.\n *\n * @param certDER - DER-encoded X.509 certificate bytes\n * @returns Certificate information, or `null` if parsing fails\n *\n * @example\n * {@includeCode ../../test/x509/extractCertificateInfo.test.ts#example}\n *\n * @internal\n */\nexport function extractCertificateInfo(certDER: Uint8Array): CertificateInfo | null {\n\ttry {\n\t\tconst cert = readElement(certDER, 0)\n\t\tif (!cert || cert.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tconst tbs = readElement(cert.value, 0)\n\t\tif (!tbs || tbs.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tlet offset = 0\n\t\tlet el = readElement(tbs.value, offset)\n\t\tif (!el) return null\n\n\t\t// Optional version field (context tag [0])\n\t\tif (el.tag === ASN1_TAG_CONTEXT_0) {\n\t\t\toffset += el.totalSize\n\t\t\tel = readElement(tbs.value, offset)\n\t\t\tif (!el) return null\n\t\t}\n\n\t\t// Serial number\n\t\tif (el.tag !== ASN1_TAG_INTEGER) return null\n\t\toffset += el.totalSize\n\n\t\t// Signature algorithm\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// Issuer\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\tconst issuer =\n\t\t\tfindRDNValue(el.value, OID_COMMON_NAME) ??\n\t\t\tfindRDNValue(el.value, OID_ORG_NAME) ??\n\t\t\t'Unknown Issuer'\n\t\toffset += el.totalSize\n\n\t\t// Validity\n\t\tel = readElement(tbs.value, offset)\n\t\tlet notBefore: string | null = null\n\t\tif (el && el.tag === ASN1_TAG_SEQUENCE) {\n\t\t\tconst timeEl = readElement(el.value, 0)\n\t\t\tif (timeEl) notBefore = parseTime(timeEl)\n\t\t}\n\n\t\treturn { issuer, notBefore }\n\t}\n\tcatch {\n\t\treturn null\n\t}\n}\n","const TEXT_DECODER = /* @__PURE__ */ new TextDecoder()\n\nimport { readIsoBoxes, type ParsedIsoBox } from '@svta/cml-iso-bmff'\nimport { decode } from 'cbor-x/decode'\nimport type { C2paAssertion } from './C2paAssertion.ts'\nimport type { C2paManifest } from './C2paManifest.ts'\nimport type { ClaimAssertionRef } from './claim/ClaimAssertionRef.ts'\nimport type { InternalAssertionData, InternalManifestData } from './claim/InternalManifestData.ts'\nimport { decodeCoseSign1 } from './cose/decodeCoseSign1.ts'\nimport type { JumbfBox } from './jumbf/JumbfBox.ts'\nimport { parseJumbfBoxes } from './jumbf/parseJumbfBoxes.ts'\nimport { parseJumbfLabel } from './jumbf/parseJumbfLabel.ts'\nimport { findC2paUuidBox, stripJumbfUuidPrefix } from './utils.ts'\nimport { extractCertificateInfo } from './x509/extractCertificateInfo.ts'\n\n\nconst MAX_JUMBF_NESTING_DEPTH = 20\nconst X5CHAIN_HEADER_LABEL = 33\n\nfunction resolveManifestBoxes(jumbfBoxes: JumbfBox[], depth = 0): JumbfBox[] {\n\tif (depth >= MAX_JUMBF_NESTING_DEPTH) return jumbfBoxes\n\n\t// Skip jumd description boxes — they contain labels, not manifest content\n\tconst contentBoxes = jumbfBoxes.filter(b => b.type !== 'jumd')\n\n\t// Single jumb wrapping — unwrap one level and recurse\n\t// This handles: store jumb → manifest jumb → claim/assertions/signature\n\tconst firstBox = contentBoxes[0]\n\tif (contentBoxes.length === 1 && firstBox?.type === 'jumb') {\n\t\treturn resolveManifestBoxes(parseJumbfBoxes(firstBox.data), depth + 1)\n\t}\n\n\treturn jumbfBoxes\n}\n\nfunction extractManifestLabel(jumbfBoxes: JumbfBox[]): string | null {\n\t// Navigate: store jumb → manifest jumb → jumd label\n\tfor (const box of jumbfBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tfor (const child of inner) {\n\t\t\tif (child.type !== 'jumb') continue\n\t\t\tconst childInner = parseJumbfBoxes(child.data)\n\t\t\tconst jumd = childInner.find(b => b.type === 'jumd')\n\t\t\tif (jumd) {\n\t\t\t\tconst label = parseJumbfLabel(jumd.data)\n\t\t\t\tif (label) return label\n\t\t\t}\n\t\t}\n\t}\n\treturn null\n}\n\nfunction parseAssertionsInternal(assertionStoreBoxes: JumbfBox[]): InternalAssertionData[] {\n\tconst assertions: InternalAssertionData[] = []\n\n\tfor (const box of assertionStoreBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\t\tif (!jumd) continue\n\n\t\tconst label = parseJumbfLabel(jumd.data)\n\t\tif (!label) continue\n\n\t\tconst contentBox = inner.find(\n\t\t\tb => b.type === 'cbor' || b.type === 'json' || b.type === 'jumc' || b.type === 'jp2c' || b.type === 'bidb',\n\t\t)\n\n\t\tlet data: unknown = null\n\t\tif (contentBox) {\n\t\t\tif (contentBox.type === 'cbor') {\n\t\t\t\ttry { data = decode(contentBox.data) as unknown } catch { data = contentBox.data }\n\t\t\t}\n\t\t\telse if (contentBox.type === 'json') {\n\t\t\t\ttry { data = JSON.parse(TEXT_DECODER.decode(contentBox.data)) as unknown } catch { data = contentBox.data }\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdata = contentBox.data\n\t\t\t}\n\t\t}\n\n\t\tassertions.push({ label, data, rawBoxPayload: box.data })\n\t}\n\n\treturn assertions\n}\n\nfunction parseSignatureInfo(signatureBytes: Uint8Array | null): { issuer: string | null; certNotBefore: string | null } {\n\tif (!signatureBytes) return { issuer: null, certNotBefore: null }\n\ttry {\n\t\tconst cose = decodeCoseSign1(signatureBytes)\n\t\tconst x5chain = (cose.protectedHeader[X5CHAIN_HEADER_LABEL] ?? cose.unprotectedHeader[X5CHAIN_HEADER_LABEL]) as Uint8Array | Uint8Array[] | null | undefined\n\t\tif (!x5chain) return { issuer: null, certNotBefore: null }\n\n\t\tconst certDER = Array.isArray(x5chain) ? x5chain[0] : x5chain\n\t\tif (!(certDER instanceof Uint8Array)) return { issuer: null, certNotBefore: null }\n\n\t\tconst certInfo = extractCertificateInfo(certDER)\n\t\treturn { issuer: certInfo?.issuer ?? null, certNotBefore: certInfo?.notBefore ?? null }\n\t} catch {\n\t\t// signature parsing failed — continue without signature info\n\t\treturn { issuer: null, certNotBefore: null }\n\t}\n}\n\nfunction extractClaimAssertionRefs(claimData: Record<string, unknown>): ClaimAssertionRef[] {\n\tconst created = claimData['created_assertions'] as unknown[] | undefined\n\tconst gathered = claimData['gathered_assertions'] as unknown[] | undefined\n\tconst v1 = claimData['assertions'] as unknown[] | undefined\n\n\tconst sources = [...(created ?? []), ...(gathered ?? []), ...(v1 ?? [])]\n\tconst refs: ClaimAssertionRef[] = []\n\n\tfor (const entry of sources) {\n\t\tif (!entry || typeof entry !== 'object') continue\n\t\tconst e = entry as Record<string, unknown>\n\t\tconst url = e['url'] as string | undefined\n\t\tconst hash = e['hash']\n\t\tif (!url || !hash) continue\n\n\t\trefs.push({\n\t\t\turl,\n\t\t\thash: hash instanceof Uint8Array ? hash : new Uint8Array(hash as number[]),\n\t\t\talg: (e['alg'] as string | undefined) ?? null,\n\t\t})\n\t}\n\n\treturn refs\n}\n\n/**\n * Reads a C2PA manifest from raw BMFF bytes.\n *\n * Locates the C2PA UUID box (`d8fec3d6-1a96-4f32-a0f6-f3ecf96c10ea`), navigates\n * the JUMBF manifest store structure (ISO 19566-5), and returns the parsed active\n * manifest with its claims, assertions, and signature information.\n *\n * This function performs structural parsing only. It does not verify the\n * cryptographic signature of the claim.\n *\n * @param bytes - Raw BMFF bytes (e.g. an MP4 init segment or media segment)\n * @param preParsedBoxes - Optional pre-parsed ISO boxes to avoid redundant parsing\n * @returns The parsed manifest data including claim, assertions, and signature bytes\n * @throws If no C2PA UUID box is found, or the JUMBF structure is invalid\n *\n * @example\n * {@includeCode ../test/readC2paManifest.test.ts#example}\n *\n * @internal\n */\nexport function readC2paManifest(bytes: Uint8Array, preParsedBoxes?: ParsedIsoBox[]): InternalManifestData {\n\tconst boxes = preParsedBoxes ?? readIsoBoxes(bytes)\n\tconst uuidBox = findC2paUuidBox(boxes)\n\n\tif (!uuidBox) {\n\t\tthrow new Error('No C2PA UUID box found in the provided bytes')\n\t}\n\n\tconst rawPayload = uuidBox.view.readData(uuidBox.view.bytesRemaining) as Uint8Array\n\tconst jumbfPayload = stripJumbfUuidPrefix(rawPayload)\n\tif (!jumbfPayload) {\n\t\tthrow new Error('Invalid JUMBF UUID prefix in C2PA box')\n\t}\n\tconst jumbfBoxes = parseJumbfBoxes(jumbfPayload)\n\n\tif (jumbfBoxes.length === 0) {\n\t\tthrow new Error('No JUMBF boxes found in C2PA UUID box')\n\t}\n\n\tconst manifestLabel = extractManifestLabel(jumbfBoxes)\n\tconst manifestBoxes = resolveManifestBoxes(jumbfBoxes)\n\n\tlet claimData: Record<string, unknown> | null = null\n\tlet claimCborBytes: Uint8Array | null = null\n\tlet internalAssertions: InternalAssertionData[] = []\n\tlet signatureBytes: Uint8Array | null = null\n\n\tfor (const box of manifestBoxes) {\n\t\tif (box.type !== 'jumb') continue\n\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\t\tif (!jumd) continue\n\n\t\tconst label = parseJumbfLabel(jumd.data)\n\t\tif (!label) continue\n\n\t\tif (label === 'c2pa.claim' || label === 'c2pa.claim.v2') {\n\t\t\tconst contentBox = inner.find(b => b.type === 'cbor')\n\t\t\tif (contentBox) {\n\t\t\t\tclaimCborBytes = contentBox.data\n\t\t\t\ttry { claimData = decode(contentBox.data) as Record<string, unknown> } catch { /* malformed claim — continue */ }\n\t\t\t}\n\t\t}\n\t\telse if (label === 'c2pa.assertions') {\n\t\t\tinternalAssertions = parseAssertionsInternal(inner)\n\t\t}\n\t\telse if (label === 'c2pa.signature') {\n\t\t\tconst contentBox = inner.find(b => b.type === 'cbor' || b.type === 'jumc')\n\t\t\tif (contentBox) signatureBytes = contentBox.data\n\t\t}\n\t}\n\n\tconst { issuer, certNotBefore } = parseSignatureInfo(signatureBytes)\n\n\tconst instanceId = (claimData?.['instanceID'] ?? claimData?.['instance_id'] ?? null) as string | null\n\tconst claimGenerator = (claimData?.['claim_generator'] ?? claimData?.['claimGenerator'] ?? null) as string | null\n\tconst resolvedLabel =\n\t\tmanifestLabel ??\n\t\t(claimData?.['dc:title'] as string | undefined) ??\n\t\t(claimData?.['title'] as string | undefined) ??\n\t\tinstanceId ??\n\t\t'unknown'\n\n\tconst claimAssertionRefs = claimData ? extractClaimAssertionRefs(claimData) : []\n\n\tconst assertions: C2paAssertion[] = internalAssertions.map(a => ({ label: a.label, data: a.data }))\n\n\tconst manifest: C2paManifest = {\n\t\tlabel: resolvedLabel,\n\t\tinstanceId,\n\t\tclaimGenerator,\n\t\tsignatureInfo: { issuer, certNotBefore },\n\t\tassertions,\n\t}\n\n\treturn {\n\t\tmanifest,\n\t\tclaimAssertionRefs,\n\t\tclaimCborBytes,\n\t\tsignatureBytes,\n\t\tassertions: internalAssertions,\n\t}\n}\n\n","import type { BmffHashConstraint, BmffHashExclusion } from './BmffHashExclusion.ts'\n\nfunction bytesMatchAt(boxData: Uint8Array, offset: number, expected: Uint8Array | readonly number[]): boolean {\n\tconst bytes = expected instanceof Uint8Array ? expected : new Uint8Array(expected as number[])\n\tif (offset + bytes.length > boxData.length) return false\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tif (boxData[offset + i] !== bytes[i]) return false\n\t}\n\treturn true\n}\n\nfunction constraintMatches(boxData: Uint8Array, constraint: BmffHashConstraint): boolean {\n\treturn bytesMatchAt(boxData, constraint.offset, constraint.value)\n}\n\n/**\n * Returns `true` if the given BMFF box should be excluded from the\n * C2PA content hash, based on the provided exclusion list.\n *\n * Exclusions use C2PA xpath notation (e.g. `/emsg`, `/moof/traf`).\n * Optional `data` constraints narrow the match to specific box content by byte offset.\n *\n * @param boxType - Four-character box type code (e.g. `'emsg'`, `'moof'`)\n * @param boxData - Full box bytes including the 8-byte size+type header\n * @param exclusions - Exclusion list from the C2PA `c2pa.hash.bmff.v3` assertion\n * @returns `true` if the box should be excluded from the hash input\n *\n * @example\n * {@includeCode ../../test/bmff/shouldExcludeBox.test.ts#example}\n *\n * @public\n */\nexport function shouldExcludeBox(\n\tboxType: string,\n\tboxData: Uint8Array,\n\texclusions: readonly BmffHashExclusion[],\n): boolean {\n\tfor (const exclusion of exclusions) {\n\t\tif (!exclusion.xpath) continue\n\t\tconst xpathMatchesType = exclusion.xpath === `/${boxType}` || exclusion.xpath.startsWith(`/${boxType}/`)\n\t\tif (!xpathMatchesType) continue\n\t\tconst { data } = exclusion\n\t\tif (!data || data.length === 0) return true\n\t\tif (data.every(constraint => constraintMatches(boxData, constraint))) return true\n\t}\n\treturn false\n}\n","import type { BmffHashExclusion } from './BmffHashExclusion.ts'\nimport { shouldExcludeBox } from './shouldExcludeBox.ts'\n\nconst MINIMUM_BOX_SIZE = 8 // size(4) + type(4)\nconst BOX_TYPE_OFFSET = 4\nconst DEFAULT_HASH_ALG = 'SHA-256'\n\n/**\n * Options for BMFF content hash computation.\n *\n * @internal\n */\nexport type BmffHashOptions = {\n\treadonly exclusions?: readonly BmffHashExclusion[]\n\treadonly alg?: string\n\t/** `8` for offset-prefix mode, `0` (default) for no prefix. */\n\treadonly offsetPrefixSize?: number\n}\n\nfunction readBoxType(bytes: Uint8Array, offset: number): string {\n\treturn String.fromCharCode(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3])\n}\n\nfunction writeUint64BigEndian(bytes: Uint8Array, value: number): void {\n\tnew DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).setBigUint64(0, BigInt(value), false)\n}\n\nfunction buildHashInput(\n\tbytes: Uint8Array,\n\texclusions: readonly BmffHashExclusion[],\n\toffsetPrefixSize: number,\n): Uint8Array {\n\tif (offsetPrefixSize !== 0 && offsetPrefixSize !== 8) {\n\t\tthrow new Error(`offsetPrefixSize must be 0 or 8, got ${offsetPrefixSize}`)\n\t}\n\n\tconst view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n\n\t// First pass: calculate total size\n\tlet totalLength = 0\n\tlet offset = 0\n\twhile (offset + MINIMUM_BOX_SIZE <= bytes.length) {\n\t\tconst boxSize = view.getUint32(offset, false)\n\t\tif (boxSize < MINIMUM_BOX_SIZE || offset + boxSize > bytes.length) break\n\t\tconst boxType = readBoxType(bytes, offset + BOX_TYPE_OFFSET)\n\t\tconst boxData = bytes.subarray(offset, offset + boxSize)\n\t\tif (!shouldExcludeBox(boxType, boxData, exclusions)) {\n\t\t\ttotalLength += offsetPrefixSize + boxSize\n\t\t}\n\t\toffset += boxSize\n\t}\n\n\t// Second pass: write directly into pre-sized buffer\n\tconst hashInput = new Uint8Array(totalLength)\n\tlet writeOffset = 0\n\toffset = 0\n\twhile (offset + MINIMUM_BOX_SIZE <= bytes.length) {\n\t\tconst boxSize = view.getUint32(offset, false)\n\t\tif (boxSize < MINIMUM_BOX_SIZE || offset + boxSize > bytes.length) break\n\t\tconst boxType = readBoxType(bytes, offset + BOX_TYPE_OFFSET)\n\t\tconst boxData = bytes.subarray(offset, offset + boxSize)\n\t\tif (!shouldExcludeBox(boxType, boxData, exclusions)) {\n\t\t\tif (offsetPrefixSize > 0) {\n\t\t\t\twriteUint64BigEndian(hashInput.subarray(writeOffset, writeOffset + offsetPrefixSize), offset)\n\t\t\t\twriteOffset += offsetPrefixSize\n\t\t\t}\n\t\t\thashInput.set(boxData, writeOffset)\n\t\t\twriteOffset += boxSize\n\t\t}\n\t\toffset += boxSize\n\t}\n\n\treturn hashInput\n}\n\n/**\n * Computes the C2PA BMFF content hash (`c2pa.hash.bmff.v3`) for a DASH segment.\n *\n * Iterates through top-level BMFF boxes, excludes those matching the exclusion list,\n * concatenates the remaining box bytes (optionally prefixed with each box's file offset),\n * and returns the WebCrypto digest.\n *\n * @param segmentBytes - Raw segment bytes to hash\n * @param options - Hash options (exclusions, algorithm, offset prefix size)\n * @returns The computed hash bytes\n *\n * @example\n * {@includeCode ../../test/bmff/computeBmffHash.test.ts#example}\n *\n * @internal\n */\nexport async function computeBmffHash(segmentBytes: Uint8Array, options?: BmffHashOptions): Promise<Uint8Array> {\n\tconst exclusions = options?.exclusions ?? []\n\tconst alg = options?.alg ?? DEFAULT_HASH_ALG\n\tconst offsetPrefixSize = options?.offsetPrefixSize ?? 0\n\n\tconst hashInput = buildHashInput(segmentBytes, exclusions, offsetPrefixSize)\n\tconst hashBuffer = await crypto.subtle.digest(alg, hashInput)\n\treturn new Uint8Array(hashBuffer)\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * Standard C2PA validation status codes for manifest integrity checks,\n * as defined in the C2PA specification chapters 15 and 18.\n *\n * @see {@link https://c2pa.org/specifications/specifications/2.3/specs/C2PA_Specification.html#_claim_validation | C2PA Spec §15.10.3}\n *\n * @enum\n *\n * @public\n */\nexport const C2paStatusCode = {\n\t/** Assertion hash does not match the hashed URI in the claim (§15.10.3.1) */\n\tASSERTION_HASHEDURI_MISMATCH: 'assertion.hashedURI.mismatch',\n\t/** An assertion referenced in the claim is missing from the assertion store (§15.10.3.1) */\n\tASSERTION_MISSING: 'assertion.missing',\n\t/** An action requiring an ingredient reference does not have one (§18.15.4.7) */\n\tASSERTION_ACTION_INGREDIENT_MISMATCH: 'assertion.action.ingredientMismatch',\n\t/** Claim signature verification failed, or the signature carries no certificate (§15.7) */\n\tCLAIM_SIGNATURE_MISMATCH: 'claimSignature.mismatch',\n\t/** The manifest has no `c2pa.signature` box, so the claim signature cannot be found (§15.7) */\n\tCLAIM_SIGNATURE_MISSING: 'claimSignature.missing',\n\t/** The manifest has no claim box (§15.6.1) */\n\tCLAIM_MISSING: 'claim.missing',\n\t/** BMFF hash assertion or Merkle structure is malformed (§15.2.2.3) */\n\tASSERTION_BMFFHASH_MALFORMED: 'assertion.bmffHash.malformed',\n\t/** BMFF content hash does not match the committed value (§15.2.2.3) */\n\tASSERTION_BMFFHASH_MISMATCH: 'assertion.bmffHash.mismatch',\n} as const\n\n/**\n * Union type of all {@link (C2paStatusCode:variable)} values.\n *\n * @public\n */\nexport type C2paStatusCode = ValueOf<typeof C2paStatusCode>\n","import { readIsoBoxes } from '@svta/cml-iso-bmff'\nimport { decodeCoseSign1 } from './cose/decodeCoseSign1.ts'\nimport { findC2paUuidBox, stripJumbfUuidPrefix } from './utils.ts'\nimport type { JumbfBox } from './jumbf/JumbfBox.ts'\nimport { parseJumbfBoxes } from './jumbf/parseJumbfBoxes.ts'\nimport { parseJumbfLabel } from './jumbf/parseJumbfLabel.ts'\n\nconst C2PA_SIGNATURE_LABEL = 'c2pa.signature'\nconst X5CHAIN_COSE_HEADER = 33\n\n/**\n * Extracts the end-entity certificate from raw COSE_Sign1 signature bytes.\n *\n * @internal\n */\nexport function extractCertificateFromSignatureBytes(signatureBytes: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst cose = decodeCoseSign1(signatureBytes)\n\t\tconst x5chain = (cose.protectedHeader[X5CHAIN_COSE_HEADER] ??\n\t\t\tcose.unprotectedHeader[X5CHAIN_COSE_HEADER]) as Uint8Array | Uint8Array[] | null | undefined\n\t\tif (!x5chain) return null\n\n\t\tconst certDER = Array.isArray(x5chain) ? x5chain[0] : x5chain\n\t\treturn certDER instanceof Uint8Array ? certDER : null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction findSignatureContentBytes(boxes: JumbfBox[]): Uint8Array | null {\n\tfor (const box of boxes) {\n\t\tif (box.type !== 'jumb') continue\n\t\tconst inner = parseJumbfBoxes(box.data)\n\t\tconst jumd = inner.find(b => b.type === 'jumd')\n\n\t\tif (jumd && parseJumbfLabel(jumd.data) === C2PA_SIGNATURE_LABEL) {\n\t\t\tconst content = inner.find(b => b.type === 'cbor' || b.type === 'jumc')\n\t\t\treturn content?.data ?? null\n\t\t}\n\n\t\tconst nested = findSignatureContentBytes(inner)\n\t\tif (nested) return nested\n\t}\n\treturn null\n}\n\n/**\n * Extracts the end-entity certificate (DER-encoded) from the C2PA claim signature\n * embedded in a BMFF file.\n *\n * Navigates the JUMBF structure inside the C2PA UUID box to locate the\n * `c2pa.signature` entry, decodes the `COSE_Sign1`, and returns the first\n * certificate from the `x5chain` (COSE protected header label 33).\n *\n * @param mp4Bytes - Raw BMFF bytes (e.g. an MP4 init segment)\n * @returns DER-encoded certificate bytes, or `null` if not found or on any error\n *\n * @example\n * {@includeCode ../test/c2pa/extractManifestCertificate.test.ts#example}\n *\n * @internal\n */\nexport function extractManifestCertificate(mp4Bytes: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst boxes = readIsoBoxes(mp4Bytes)\n\t\tconst uuidBox = findC2paUuidBox(boxes)\n\t\tif (!uuidBox) return null\n\n\t\tconst rawPayload = uuidBox.view.readData(uuidBox.view.bytesRemaining) as Uint8Array\n\t\tconst jumbfPayload = stripJumbfUuidPrefix(rawPayload)\n\t\tif (!jumbfPayload) return null\n\t\tconst signatureBytes = findSignatureContentBytes(parseJumbfBoxes(jumbfPayload))\n\t\tif (!signatureBytes) return null\n\n\t\treturn extractCertificateFromSignatureBytes(signatureBytes)\n\t} catch {\n\t\treturn null\n\t}\n}\n","import { C2paStatusCode } from '../C2paStatusCode.ts'\n\nconst ACTIONS_LABELS = new Set(['c2pa.actions', 'c2pa.actions.v2'])\nconst ACTIONS_REQUIRING_INGREDIENTS = new Set(['c2pa.opened', 'c2pa.placed', 'c2pa.removed'])\n\n/**\n * Validates action ingredient references per C2PA §18.15.4.7.\n *\n * For any `c2pa.actions` or `c2pa.actions.v2` assertion, actions with type\n * `c2pa.opened`, `c2pa.placed`, or `c2pa.removed` must include a\n * `parameters.ingredients` field. Reports `assertion.action.ingredientMismatch`\n * if any such action is missing the required field.\n *\n * @param assertions - Parsed assertions (label + decoded data)\n * @returns Array of C2PA status codes for any failures found\n *\n * @internal\n */\nexport function validateActionIngredients(\n\tassertions: readonly { readonly label: string; readonly data: unknown }[],\n): readonly C2paStatusCode[] {\n\tconst codes: C2paStatusCode[] = []\n\n\tfor (const assertion of assertions) {\n\t\tif (!ACTIONS_LABELS.has(assertion.label)) continue\n\n\t\tconst data = assertion.data as Record<string, unknown> | null\n\t\tif (!data) continue\n\n\t\tconst actions = data['actions'] as unknown[] | undefined\n\t\tif (!Array.isArray(actions)) continue\n\n\t\tfor (const action of actions) {\n\t\t\tif (!action || typeof action !== 'object') continue\n\t\t\tconst record = action as Record<string, unknown>\n\t\t\tconst actionType = record['action'] as string | undefined\n\t\t\tif (!actionType || !ACTIONS_REQUIRING_INGREDIENTS.has(actionType)) continue\n\n\t\t\tconst parameters = record['parameters'] as Record<string, unknown> | undefined\n\t\t\tconst ingredients = parameters?.['ingredients']\n\n\t\t\tif (!Array.isArray(ingredients) || ingredients.length === 0) {\n\t\t\t\tcodes.push(C2paStatusCode.ASSERTION_ACTION_INGREDIENT_MISMATCH)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn codes\n}\n","import { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { hashesEqual, normalizeAlgorithmName } from '../utils.ts'\nimport type { ClaimAssertionRef } from './ClaimAssertionRef.ts'\nimport type { InternalAssertionData } from './InternalManifestData.ts'\n\n/**\n * Extracts the assertion label from a JUMBF URI.\n *\n * Handles both absolute (`self#jumbf=/c2pa/<manifest>/c2pa.assertions/<label>`)\n * and relative URI forms by returning the last path segment.\n */\nfunction extractLabelFromUrl(url: string): string {\n\tconst fragmentIndex = url.indexOf('#jumbf=')\n\tconst path = fragmentIndex >= 0 ? url.substring(fragmentIndex + 7) : url\n\tconst lastSlash = path.lastIndexOf('/')\n\treturn lastSlash >= 0 ? path.substring(lastSlash + 1) : path\n}\n\n/**\n * Validates assertion hashes and presence per C2PA §15.10.3.1.\n *\n * For each assertion referenced in the claim's hashed URI list:\n * - Checks that the assertion exists in the assertion store (`assertion.missing`)\n * - Recomputes the hash of the raw JUMBF box payload and compares it to the\n * expected hash from the claim (`assertion.hashedURI.mismatch`)\n *\n * @param claimRefs - Hashed URI references from the claim\n * @param assertions - Parsed assertions with preserved raw box payloads\n * @returns Array of C2PA status codes for any failures found\n *\n * @internal\n */\nexport async function validateAssertionHashes(\n\tclaimRefs: readonly ClaimAssertionRef[],\n\tassertions: readonly InternalAssertionData[],\n): Promise<readonly C2paStatusCode[]> {\n\tif (claimRefs.length === 0) return []\n\n\tconst assertionsByLabel = new Map<string, InternalAssertionData>()\n\tfor (const assertion of assertions) {\n\t\tassertionsByLabel.set(assertion.label, assertion)\n\t}\n\n\tconst codes: C2paStatusCode[] = []\n\n\tconst hashChecks = claimRefs.map(async (ref) => {\n\t\tconst label = extractLabelFromUrl(ref.url)\n\t\tconst assertion = assertionsByLabel.get(label)\n\n\t\tif (!assertion) {\n\t\t\treturn C2paStatusCode.ASSERTION_MISSING\n\t\t}\n\n\t\tconst alg = ref.alg ? normalizeAlgorithmName(ref.alg) : 'SHA-256'\n\t\tconst computedHash = new Uint8Array(\n\t\t\tawait crypto.subtle.digest(alg, assertion.rawBoxPayload),\n\t\t)\n\n\t\tif (!hashesEqual(computedHash, ref.hash)) {\n\t\t\treturn C2paStatusCode.ASSERTION_HASHEDURI_MISMATCH\n\t\t}\n\n\t\treturn null\n\t})\n\n\tconst results = await Promise.all(hashChecks)\n\tfor (const result of results) {\n\t\tif (result) codes.push(result)\n\t}\n\n\treturn codes\n}\n","// WebCrypto algorithm names\nexport const ECDSA_ALGORITHM = 'ECDSA'\nexport const ED25519_ALGORITHM = 'Ed25519'\nexport const RSA_PSS_ALGORITHM = 'RSA-PSS'\n\n// Named curves\nexport const CURVE_P256 = 'P-256'\nexport const CURVE_P384 = 'P-384'\nexport const CURVE_P521 = 'P-521'\n\n// Hash algorithms\nexport const HASH_SHA256 = 'SHA-256'\nexport const HASH_SHA384 = 'SHA-384'\nexport const HASH_SHA512 = 'SHA-512'\n","import {\n\tCURVE_P256, \n\tCURVE_P384, \n\tCURVE_P521,\n\tECDSA_ALGORITHM, \n\tED25519_ALGORITHM, \n\tRSA_PSS_ALGORITHM,\n\tHASH_SHA256, \n\tHASH_SHA384, \n\tHASH_SHA512,\n} from './constants.ts'\n\nconst COSE_ALG_ES256 = -7\nconst COSE_ALG_ES384 = -35\nconst COSE_ALG_ES512 = -36\nconst COSE_ALG_EDDSA = -8\nconst COSE_ALG_PS256 = -37\nconst COSE_ALG_PS384 = -38\nconst COSE_ALG_PS512 = -39\n\ntype CoseAlgorithm = AlgorithmIdentifier | EcKeyImportParams | RsaHashedImportParams\n\nconst COSE_ALGORITHM_MAP = new Map<number, CoseAlgorithm>([\n\t[COSE_ALG_ES256, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P256 }],\n\t[COSE_ALG_ES384, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P384 }],\n\t[COSE_ALG_ES512, { name: ECDSA_ALGORITHM, namedCurve: CURVE_P521 }],\n\t[COSE_ALG_EDDSA, { name: ED25519_ALGORITHM }],\n\t[COSE_ALG_PS256, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA256 } }],\n\t[COSE_ALG_PS384, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA384 } }],\n\t[COSE_ALG_PS512, { name: RSA_PSS_ALGORITHM, hash: { name: HASH_SHA512 } }],\n])\n\n/**\n * Maps a COSE algorithm number (from a COSE_Sign1 protected header) to the\n * WebCrypto algorithm identifier needed for `crypto.subtle.importKey('spki', ...)`.\n *\n * @param coseAlg - COSE algorithm identifier (e.g. -7 for ES256)\n * @returns WebCrypto algorithm identifier\n * @throws If the COSE algorithm is not supported\n *\n * @internal\n */\nexport function resolveAlgorithmFromCoseAlg(coseAlg: number): CoseAlgorithm {\n\tconst algorithm = COSE_ALGORITHM_MAP.get(coseAlg)\n\tif (!algorithm) {\n\t\tthrow new Error(`Unsupported COSE algorithm: ${coseAlg}`)\n\t}\n\treturn algorithm\n}\n","const CBOR_ARRAY_FOUR_ITEMS = 0x84\nconst CBOR_TEXT_MAJOR_TYPE_BASE = 0x60\nconst CBOR_BYTES_MAJOR_TYPE_BASE = 0x40\nconst CBOR_UINT8_LENGTH_INDICATOR = 0x58\nconst CBOR_UINT16_LENGTH_INDICATOR = 0x59\nconst CBOR_UINT32_LENGTH_INDICATOR = 0x5a\nconst CBOR_INLINE_MAX = 23\nconst CBOR_UINT8_MAX = 255\nconst CBOR_UINT16_MAX = 65535\nconst COSE_SIG1_CONTEXT_BYTES = /* @__PURE__ */ new TextEncoder().encode('Signature1')\n\nfunction byteStringHeaderSize(length: number): number {\n\tif (length <= CBOR_INLINE_MAX) return 1\n\tif (length <= CBOR_UINT8_MAX) return 2\n\tif (length <= CBOR_UINT16_MAX) return 3\n\treturn 5\n}\n\nfunction writeByteStringHeader(output: Uint8Array, offset: number, length: number): number {\n\tif (length <= CBOR_INLINE_MAX) {\n\t\toutput[offset++] = CBOR_BYTES_MAJOR_TYPE_BASE + length\n\t} else if (length <= CBOR_UINT8_MAX) {\n\t\toutput[offset++] = CBOR_UINT8_LENGTH_INDICATOR\n\t\toutput[offset++] = length\n\t} else if (length <= CBOR_UINT16_MAX) {\n\t\toutput[offset++] = CBOR_UINT16_LENGTH_INDICATOR\n\t\toutput[offset++] = (length >> 8) & 0xff\n\t\toutput[offset++] = length & 0xff\n\t} else {\n\t\toutput[offset++] = CBOR_UINT32_LENGTH_INDICATOR\n\t\toutput[offset++] = (length >>> 24) & 0xff\n\t\toutput[offset++] = (length >>> 16) & 0xff\n\t\toutput[offset++] = (length >>> 8) & 0xff\n\t\toutput[offset++] = length & 0xff\n\t}\n\treturn offset\n}\n\n/**\n * Builds the COSE `Sig_Structure` (ToBeSigned) bytes for a `COSE_Sign1` structure (RFC 9052 §4.4).\n *\n * The resulting bytes are the direct input to signature creation or verification via WebCrypto.\n *\n * @param protectedBytes - Serialized protected header (CBOR-encoded byte string)\n * @param payload - Payload bytes\n * @param externalAad - External additional authenticated data (default: empty)\n * @returns CBOR-encoded `Sig_Structure` array ready for signing or verification\n *\n * @example\n * {@includeCode ../../test/cose/buildSigStructure.test.ts#example}\n *\n * @public\n */\nexport function buildSigStructure(\n\tprotectedBytes: Uint8Array,\n\tpayload: Uint8Array,\n\texternalAad: Uint8Array = new Uint8Array(0),\n): Uint8Array {\n\tconst totalLength =\n\t\t1 // array header\n\t\t+ 1 + COSE_SIG1_CONTEXT_BYTES.length // context string (length < 24, fits inline)\n\t\t+ byteStringHeaderSize(protectedBytes.length) + protectedBytes.length\n\t\t+ byteStringHeaderSize(externalAad.length) + externalAad.length\n\t\t+ byteStringHeaderSize(payload.length) + payload.length\n\n\tconst result = new Uint8Array(totalLength)\n\tlet offset = 0\n\n\tresult[offset++] = CBOR_ARRAY_FOUR_ITEMS\n\tresult[offset++] = CBOR_TEXT_MAJOR_TYPE_BASE + COSE_SIG1_CONTEXT_BYTES.length\n\tresult.set(COSE_SIG1_CONTEXT_BYTES, offset)\n\toffset += COSE_SIG1_CONTEXT_BYTES.length\n\n\toffset = writeByteStringHeader(result, offset, protectedBytes.length)\n\tresult.set(protectedBytes, offset)\n\toffset += protectedBytes.length\n\n\toffset = writeByteStringHeader(result, offset, externalAad.length)\n\tresult.set(externalAad, offset)\n\toffset += externalAad.length\n\n\toffset = writeByteStringHeader(result, offset, payload.length)\n\tresult.set(payload, offset)\n\n\treturn result\n}\n","import type { CoseSign1 } from './CoseSign1.ts'\nimport { buildSigStructure } from './buildSigStructure.ts'\nimport {\n\tCURVE_P256, \n\tCURVE_P384, \n\tCURVE_P521,\n\tECDSA_ALGORITHM, \n\tED25519_ALGORITHM, \n\tRSA_PSS_ALGORITHM,\n\tHASH_SHA256, \n\tHASH_SHA384, \n\tHASH_SHA512,\n} from './constants.ts'\n\nconst DER_SEQUENCE_TAG = 0x30\nconst DER_INTEGER_TAG = 0x02\n\nconst CURVE_COMPONENT_BYTES: Record<string, number> = { [CURVE_P256]: 32, [CURVE_P384]: 48, [CURVE_P521]: 66 }\n\ntype EcKeyAlgorithm = KeyAlgorithm & { readonly namedCurve: string }\ntype RsaHashedKeyAlgorithm = KeyAlgorithm & { readonly hash: { readonly name: string } }\n\nconst RSA_PSS_SALT_LENGTH: Record<string, number> = {\n\t[HASH_SHA256]: 32,\n\t[HASH_SHA384]: 48,\n\t[HASH_SHA512]: 64,\n}\n\nfunction getComponentSize(publicKey: CryptoKey): number {\n\tconst curve = (publicKey.algorithm as EcKeyAlgorithm).namedCurve\n\tconst size = CURVE_COMPONENT_BYTES[curve]\n\tif (!size) throw new Error(`Unsupported EC curve: ${curve}`)\n\treturn size\n}\n\nfunction isDerEncoded(signature: Uint8Array, expectedRawLength: number): boolean {\n\treturn signature.length !== expectedRawLength && signature.length > 2 && signature[0] === DER_SEQUENCE_TAG\n}\n\nfunction parseDerLength(der: Uint8Array, offset: number): { length: number; nextOffset: number } {\n\tif (offset >= der.length) throw new Error('DER signature: truncated length')\n\tconst firstByte = der[offset]\n\tif ((firstByte & 0x80) === 0) {\n\t\treturn { length: firstByte, nextOffset: offset + 1 }\n\t}\n\tconst numBytes = firstByte & 0x7f\n\tif (numBytes === 0 || offset + numBytes >= der.length) throw new Error('DER signature: invalid long-form length')\n\tlet length = 0\n\tfor (let i = 1; i <= numBytes; i++) {\n\t\tlength = (length << 8) | der[offset + i]\n\t}\n\treturn { length, nextOffset: offset + 1 + numBytes }\n}\n\nfunction extractDerInteger(\n\tder: Uint8Array,\n\toffset: number,\n): { value: Uint8Array; nextOffset: number } {\n\tif (der[offset] !== DER_INTEGER_TAG) throw new Error('DER signature: expected INTEGER tag')\n\tconst { length, nextOffset: valueStart } = parseDerLength(der, offset + 1)\n\tlet start = valueStart\n\tlet remaining = length\n\tif (remaining > 0 && der[start] === 0x00) {\n\t\tstart++\n\t\tremaining--\n\t}\n\treturn { value: der.slice(start, start + remaining), nextOffset: valueStart + length }\n}\n\nfunction derToRawEcdsaSignature(der: Uint8Array, componentSize: number): Uint8Array {\n\tif (der[0] !== DER_SEQUENCE_TAG) throw new Error('DER signature: expected SEQUENCE tag')\n\tconst { nextOffset: contentStart } = parseDerLength(der, 1)\n\tconst rResult = extractDerInteger(der, contentStart)\n\tconst sResult = extractDerInteger(der, rResult.nextOffset)\n\n\tconst rawLength = componentSize * 2\n\tconst raw = new Uint8Array(rawLength)\n\traw.set(rResult.value, componentSize - rResult.value.length)\n\traw.set(sResult.value, rawLength - sResult.value.length)\n\treturn raw\n}\n\nfunction resolveVerifyAlgorithm(publicKey: CryptoKey) {\n\tconst { name } = publicKey.algorithm\n\tif (name === ED25519_ALGORITHM) return { name: ED25519_ALGORITHM }\n\tif (name === ECDSA_ALGORITHM) {\n\t\tconst curve = (publicKey.algorithm as EcKeyAlgorithm).namedCurve\n\t\tconst hash = curve === CURVE_P384 ? HASH_SHA384 : curve === CURVE_P521 ? HASH_SHA512 : HASH_SHA256\n\t\treturn { name: ECDSA_ALGORITHM, hash: { name: hash } }\n\t}\n\tif (name === RSA_PSS_ALGORITHM) {\n\t\tconst hashName = (publicKey.algorithm as RsaHashedKeyAlgorithm).hash.name\n\t\treturn { name: RSA_PSS_ALGORITHM, saltLength: RSA_PSS_SALT_LENGTH[hashName] ?? 32 }\n\t}\n\tthrow new Error(`Unsupported public key algorithm: ${name}`)\n}\n\nfunction normalizeSignature(signature: Uint8Array, publicKey: CryptoKey): Uint8Array {\n\tif (publicKey.algorithm.name !== ECDSA_ALGORITHM) return signature\n\tconst componentSize = getComponentSize(publicKey)\n\tif (isDerEncoded(signature, componentSize * 2)) {\n\t\treturn derToRawEcdsaSignature(signature, componentSize)\n\t}\n\treturn signature\n}\n\n/**\n * Verifies a `COSE_Sign1` signature using a provided `CryptoKey` (RFC 9052 §4.4).\n *\n * Builds the `Sig_Structure` from the protected header and payload, normalizes\n * DER-encoded ECDSA signatures to raw format if needed, and delegates\n * verification to the WebCrypto API.\n *\n * Supports `ECDSA` (P-256, P-384, P-521), `Ed25519`, and `RSA-PSS` (PS256, PS384, PS512) keys.\n *\n * @param coseSign1 - Decoded COSE_Sign1 structure (from {@link decodeCoseSign1})\n * @param payload - Payload bytes to verify. May differ from `coseSign1.payload` for detached payloads.\n * @param publicKey - Imported public key for verification\n * @returns `true` if the signature is valid\n * @throws If the key algorithm is not supported\n *\n * @example\n * {@includeCode ../../test/cose/verifyCoseSign1.test.ts#example}\n *\n * @public\n */\nexport async function verifyCoseSign1(\n\tcoseSign1: CoseSign1,\n\tpayload: Uint8Array,\n\tpublicKey: CryptoKey,\n): Promise<boolean> {\n\tconst sigStructure = buildSigStructure(coseSign1.protectedBytes, payload)\n\tconst algorithm = resolveVerifyAlgorithm(publicKey)\n\tconst signature = normalizeSignature(coseSign1.signature, publicKey)\n\treturn crypto.subtle.verify(algorithm, publicKey, signature, sigStructure)\n}\n","import {\n\tASN1_TAG_CONTEXT_0,\n\tASN1_TAG_INTEGER,\n\tASN1_TAG_SEQUENCE,\n\treadElement,\n\treadElementRaw,\n} from './asn1.ts'\n\n/**\n * Extracts the SubjectPublicKeyInfo (SPKI) DER bytes from an X.509 DER certificate.\n *\n * Navigates the TBSCertificate structure to reach the 7th field\n * (SubjectPublicKeyInfo), skipping version, serialNumber, signatureAlgorithm,\n * issuer, validity, and subject.\n *\n * The returned bytes can be imported directly via\n * `crypto.subtle.importKey('spki', ...)`.\n *\n * @param certDER - DER-encoded X.509 certificate bytes\n * @returns Full DER encoding of the SubjectPublicKeyInfo, or `null` on parse failure\n *\n * @internal\n */\nexport function extractCertificateSpki(certDER: Uint8Array): Uint8Array | null {\n\ttry {\n\t\tconst cert = readElement(certDER, 0)\n\t\tif (!cert || cert.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tconst tbs = readElement(cert.value, 0)\n\t\tif (!tbs || tbs.tag !== ASN1_TAG_SEQUENCE) return null\n\n\t\tlet offset = 0\n\t\tlet el = readElement(tbs.value, offset)\n\t\tif (!el) return null\n\n\t\t// 1. Optional version [0]\n\t\tif (el.tag === ASN1_TAG_CONTEXT_0) {\n\t\t\toffset += el.totalSize\n\t\t\tel = readElement(tbs.value, offset)\n\t\t\tif (!el) return null\n\t\t}\n\n\t\t// 2. Serial number (INTEGER)\n\t\tif (el.tag !== ASN1_TAG_INTEGER) return null\n\t\toffset += el.totalSize\n\n\t\t// 3. Signature algorithm (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 4. Issuer (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 5. Validity (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 6. Subject (SEQUENCE)\n\t\tel = readElement(tbs.value, offset)\n\t\tif (!el || el.tag !== ASN1_TAG_SEQUENCE) return null\n\t\toffset += el.totalSize\n\n\t\t// 7. SubjectPublicKeyInfo (SEQUENCE) — return full DER encoding\n\t\treturn readElementRaw(tbs.value, offset)\n\t}\n\tcatch {\n\t\treturn null\n\t}\n}\n","import { readElement, ASN1_TAG_SEQUENCE } from './asn1.ts'\n\n// OID 1.2.840.113549.1.1.10 (rsassaPss)\nconst OID_RSASSA_PSS = new Uint8Array([0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a])\n\n// AlgorithmIdentifier for rsaEncryption (OID 1.2.840.113549.1.1.1) with NULL params\n// SEQUENCE { OID rsaEncryption, NULL }\nconst RSA_ENCRYPTION_ALGORITHM_ID = new Uint8Array([\n\t0x30, 0x0d, // SEQUENCE, 13 bytes\n\t0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, // OID rsaEncryption\n\t0x05, 0x00, // NULL\n])\n\nfunction containsRsaPssOid(bytes: Uint8Array): boolean {\n\tif (bytes.length < OID_RSASSA_PSS.length) return false\n\touter: for (let i = 0; i <= bytes.length - OID_RSASSA_PSS.length; i++) {\n\t\tfor (let j = 0; j < OID_RSASSA_PSS.length; j++) {\n\t\t\tif (bytes[i + j] !== OID_RSASSA_PSS[j]) continue outer\n\t\t}\n\t\treturn true\n\t}\n\treturn false\n}\n\n/**\n * Normalizes an SPKI that uses the `rsassaPss` OID (1.2.840.113549.1.1.10) to\n * use the generic `rsaEncryption` OID (1.2.840.113549.1.1.1) instead.\n *\n * WebCrypto's `importKey('spki', ...)` with `{ name: 'RSA-PSS' }` expects the\n * SPKI to use the generic `rsaEncryption` OID. Certificates signed with\n * RSASSA-PSS often embed the PSS-specific OID and parameters, which causes\n * `DataError` on import.\n *\n * If the SPKI does not use `rsassaPss`, it is returned unchanged.\n *\n * @internal\n */\nexport function normalizeRsaPssSpki(spkiBytes: Uint8Array): Uint8Array {\n\tif (!containsRsaPssOid(spkiBytes)) return spkiBytes\n\n\t// Parse outer SEQUENCE\n\tconst outer = readElement(spkiBytes, 0)\n\tif (!outer || outer.tag !== ASN1_TAG_SEQUENCE) return spkiBytes\n\n\t// First child: AlgorithmIdentifier SEQUENCE\n\tconst algId = readElement(outer.value, 0)\n\tif (!algId || algId.tag !== ASN1_TAG_SEQUENCE) return spkiBytes\n\n\t// Second child: BIT STRING with the public key\n\tconst publicKeyBitString = outer.value.subarray(algId.totalSize)\n\n\t// Build new SPKI: RSA_ENCRYPTION_ALGORITHM_ID + original BIT STRING\n\tconst innerLength = RSA_ENCRYPTION_ALGORITHM_ID.length + publicKeyBitString.length\n\tconst headerBytes = encodeDerLength(innerLength)\n\tconst result = new Uint8Array(1 + headerBytes.length + innerLength)\n\tlet offset = 0\n\tresult[offset++] = ASN1_TAG_SEQUENCE\n\tresult.set(headerBytes, offset)\n\toffset += headerBytes.length\n\tresult.set(RSA_ENCRYPTION_ALGORITHM_ID, offset)\n\toffset += RSA_ENCRYPTION_ALGORITHM_ID.length\n\tresult.set(publicKeyBitString, offset)\n\n\treturn result\n}\n\nfunction encodeDerLength(length: number): Uint8Array {\n\tif (length < 0x80) return new Uint8Array([length])\n\tif (length <= 0xff) return new Uint8Array([0x81, length])\n\tif (length <= 0xffff) return new Uint8Array([0x82, (length >> 8) & 0xff, length & 0xff])\n\treturn new Uint8Array([0x83, (length >> 16) & 0xff, (length >> 8) & 0xff, length & 0xff])\n}\n","import { decodeCoseSign1 } from '../cose/decodeCoseSign1.ts'\nimport { resolveAlgorithmFromCoseAlg } from '../cose/resolveAlgorithmFromCoseAlg.ts'\nimport { verifyCoseSign1 } from '../cose/verifyCoseSign1.ts'\nimport { extractCertificateSpki } from '../x509/extractCertificateSpki.ts'\nimport { normalizeRsaPssSpki } from '../x509/normalizeRsaPssSpki.ts'\n\n/**\n * Verifies the claim signature of a C2PA manifest per §15.7.\n *\n * The `c2pa.signature` JUMBF box contains a `COSE_Sign1` structure whose payload\n * is the claim CBOR bytes. This function verifies the signature against the\n * public key extracted from the end-entity certificate in the `x5chain` header.\n *\n * @param signatureBytes - Raw COSE_Sign1 bytes from the `c2pa.signature` box\n * @param claimCborBytes - Raw CBOR bytes of the claim content box\n * @param certificateDER - DER-encoded end-entity X.509 certificate\n * @returns `true` if the signature is valid\n *\n * @internal\n */\nexport async function verifyClaimSignature(\n\tsignatureBytes: Uint8Array,\n\tclaimCborBytes: Uint8Array,\n\tcertificateDER: Uint8Array,\n): Promise<boolean> {\n\ttry {\n\t\tconst coseSign1 = decodeCoseSign1(signatureBytes)\n\n\t\tconst rawSpki = extractCertificateSpki(certificateDER)\n\t\tif (!rawSpki) return false\n\t\tconst spkiBytes = normalizeRsaPssSpki(rawSpki)\n\n\t\tif (coseSign1.alg == null) return false\n\n\t\tconst importAlgorithm = resolveAlgorithmFromCoseAlg(coseSign1.alg)\n\n\t\tconst publicKey = await crypto.subtle.importKey(\n\t\t\t'spki',\n\t\t\tnew Uint8Array(spkiBytes) as BufferSource,\n\t\t\timportAlgorithm,\n\t\t\ttrue,\n\t\t\t['verify'],\n\t\t)\n\n\t\treturn verifyCoseSign1(coseSign1, claimCborBytes, publicKey)\n\t}\n\tcatch {\n\t\treturn false\n\t}\n}\n","import type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { C2paStatusCode as Code } from '../C2paStatusCode.ts'\nimport { extractCertificateFromSignatureBytes } from '../extractManifestCertificate.ts'\nimport type { InternalManifestData } from './InternalManifestData.ts'\nimport { validateActionIngredients } from './validateActionIngredients.ts'\nimport { validateAssertionHashes } from './validateAssertionHashes.ts'\nimport { verifyClaimSignature } from './verifyClaimSignature.ts'\n\n/**\n * Outcome of the manifest integrity checks.\n *\n * @internal\n */\nexport type ManifestIntegrity = {\n\t/** Status codes for the failures found, empty when every check passes */\n\treadonly codes: readonly C2paStatusCode[]\n\t/** DER-encoded end-entity certificate from the claim signature, or `null` when the signature is absent or carries no certificate */\n\treadonly certificate: Uint8Array | null\n}\n\ntype ClaimSignatureCheck = {\n\treadonly code: C2paStatusCode | null\n\treadonly certificate: Uint8Array | null\n}\n\n/**\n * Checks the claim signature per §15.7 and fails closed: a manifest without a claim box,\n * without a `c2pa.signature` box, or with a signature that carries no certificate or does\n * not verify over the claim bytes, is reported as a failure.\n */\nasync function validateClaimSignature({ claimCborBytes, signatureBytes }: InternalManifestData): Promise<ClaimSignatureCheck> {\n\tconst certificate = signatureBytes ? extractCertificateFromSignatureBytes(signatureBytes) : null\n\n\tif (!claimCborBytes) return { code: Code.CLAIM_MISSING, certificate }\n\tif (!signatureBytes) return { code: Code.CLAIM_SIGNATURE_MISSING, certificate }\n\tif (!certificate) return { code: Code.CLAIM_SIGNATURE_MISMATCH, certificate }\n\n\tconst signatureValid = await verifyClaimSignature(signatureBytes, claimCborBytes, certificate)\n\treturn { code: signatureValid ? null : Code.CLAIM_SIGNATURE_MISMATCH, certificate }\n}\n\n/**\n * Validates the integrity of a C2PA manifest per Chapter 15 and Chapter 18.\n *\n * Runs four validation checks in parallel where possible:\n * 1. Assertion hash verification (§15.10.3.1)\n * 2. Missing assertion detection (§15.10.3.1)\n * 3. Action ingredient validation (§18.15.4.7)\n * 4. Claim signature verification (§15.7)\n *\n * The claim signature is verified with the end-entity certificate from the `x5chain`\n * header of the signature. The certificate is not checked against a trust list.\n *\n * @param internal - Enriched manifest data with raw assertion bytes and claim references\n * @returns The status codes for any failures found, and the certificate of the claim signature\n *\n * @internal\n */\nexport async function validateManifestIntegrity(internal: InternalManifestData): Promise<ManifestIntegrity> {\n\tconst [assertionHashCodes, signature] = await Promise.all([\n\t\tvalidateAssertionHashes(internal.claimAssertionRefs, internal.assertions),\n\t\tvalidateClaimSignature(internal),\n\t])\n\n\tconst codes: C2paStatusCode[] = [...assertionHashCodes, ...validateActionIngredients(internal.assertions)]\n\n\tif (signature.code) {\n\t\tcodes.push(signature.code)\n\t}\n\n\treturn { codes, certificate: signature.certificate }\n}\n","import type { CoseKeyJwk } from './CoseKeyJwk.ts'\n\n// IANA COSE Key Types (RFC 9053)\nconst OKP_KEY_TYPE = 1\nconst EC2_KEY_TYPE = 2\n\n// IANA COSE Elliptic Curves\nconst EC_CURVE_NAMES: Record<number, string> = { 1: 'P-256', 2: 'P-384', 3: 'P-521' }\nconst OKP_CURVE_NAMES: Record<number, string> = { 4: 'X25519', 5: 'X448', 6: 'Ed25519', 7: 'Ed448' }\n\ntype CoseKeyLike = Map<number, unknown> | Record<number | string, unknown>\n\nfunction coseGet(key: CoseKeyLike, intKey: number): unknown {\n\tif (key instanceof Map) return key.get(intKey)\n\treturn (key as Record<number | string, unknown>)[intKey]\n}\n\nfunction toBase64Url(value: unknown): string {\n\tconst bytes = value instanceof Uint8Array ? value : new Uint8Array(value as number[])\n\tlet binary = ''\n\tfor (const byte of bytes) binary += String.fromCharCode(byte)\n\treturn btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\n/**\n * Converts a COSE public key (RFC 9052 / IANA COSE Key registry) to JWK format.\n *\n * Supports EC2 keys (P-256, P-384, P-521) and OKP keys (Ed25519, Ed448, X25519, X448).\n * Input may be a `Map\\<number, unknown\\>` (from CBOR decoders like cbor-x) or a plain\n * object with integer keys.\n *\n * @param coseKey - COSE key structure as decoded from a C2PA `c2pa.session-keys` assertion\n * @returns JWK representation of the public key\n * @throws If the key type or curve is not supported\n *\n * @example\n * {@includeCode ../../test/cose/convertCoseKeyToJwk.test.ts#example}\n *\n * @public\n */\nexport function convertCoseKeyToJwk(coseKey: unknown): CoseKeyJwk {\n\tconst key = coseKey as CoseKeyLike\n\tconst kty = coseGet(key, 1)\n\tconst crv = coseGet(key, -1) as number\n\tconst x = coseGet(key, -2)\n\n\tif (kty === EC2_KEY_TYPE) {\n\t\tconst curveName = EC_CURVE_NAMES[crv]\n\t\tif (!curveName) throw new Error(`Unsupported EC curve: ${crv}`)\n\t\tconst y = coseGet(key, -3)\n\t\tif (!(x instanceof Uint8Array)) throw new Error('EC2 key missing or invalid x coordinate')\n\t\tif (!(y instanceof Uint8Array)) throw new Error('EC2 key missing or invalid y coordinate')\n\t\treturn { kty: 'EC', crv: curveName, x: toBase64Url(x), y: toBase64Url(y) }\n\t}\n\n\tif (kty === OKP_KEY_TYPE) {\n\t\tconst curveName = OKP_CURVE_NAMES[crv]\n\t\tif (!curveName) throw new Error(`Unsupported OKP curve: ${crv}`)\n\t\treturn { kty: 'OKP', crv: curveName, x: toBase64Url(x) }\n\t}\n\n\tthrow new Error(`Unsupported COSE key type: ${kty}`)\n}\n","import { ECDSA_ALGORITHM } from './constants.ts'\n\nconst KEY_TYPE_OKP = 'OKP'\n\nexport function resolveImportAlgorithm(jwk: { kty: string; crv: string }): AlgorithmIdentifier | EcKeyImportParams {\n\treturn jwk.kty === KEY_TYPE_OKP ? { name: jwk.crv } : { name: ECDSA_ALGORITHM, namedCurve: jwk.crv }\n}\n","import { encode } from 'cbor-x/encode'\nimport { convertCoseKeyToJwk } from './convertCoseKeyToJwk.ts'\nimport { decodeCoseSign1 } from './decodeCoseSign1.ts'\nimport { resolveImportAlgorithm } from './resolveImportAlgorithm.ts'\nimport { verifyCoseSign1 } from './verifyCoseSign1.ts'\n\n/**\n * Verifies a C2PA signer binding — a `COSE_Sign1` structure that proves\n * a session key was authorized by the content signer (C2PA spec §18.25.2).\n *\n * The `Sig_Structure` payload is `CBOR(bstr(signerCertBytes))` per the C2PA spec.\n * DER-encoded ECDSA signatures are automatically normalized to raw format.\n *\n * @param signerBindingBytes - Raw `COSE_Sign1` bytes of the signer binding\n * @param sessionCoseKey - COSE public key from the `c2pa.session-keys` assertion\n * @param signerCertBytes - DER-encoded end-entity certificate (from `x5chain`)\n * @returns `true` if the signer binding signature is valid\n * @throws If the COSE key type is not supported or decoding fails\n *\n * @example\n * {@includeCode ../../test/cose/verifySignerBinding.test.ts#example}\n *\n * @public\n */\nexport async function verifySignerBinding(\n\tsignerBindingBytes: Uint8Array,\n\tsessionCoseKey: unknown,\n\tsignerCertBytes: Uint8Array,\n): Promise<boolean> {\n\tconst coseSign1 = decodeCoseSign1(signerBindingBytes)\n\tconst jwk = convertCoseKeyToJwk(sessionCoseKey)\n\tconst publicKey = await crypto.subtle.importKey('jwk', jwk as JsonWebKey, resolveImportAlgorithm(jwk), false, ['verify'])\n\t// Signer binding payload = CBOR(bstr(cert)) per C2PA spec §18.25.2\n\tconst cborCertPayload = encode(signerCertBytes) as Uint8Array\n\treturn verifyCoseSign1(coseSign1, cborCertPayload, publicKey)\n}\n","import type { BmffHashConstraint, BmffHashExclusion } from './BmffHashExclusion.ts'\nimport { toUint8Array } from '../utils.ts'\n\nfunction parseConstraints(rawConstraints: unknown): BmffHashConstraint[] {\n\tif (!Array.isArray(rawConstraints)) return []\n\n\tconst constraints: BmffHashConstraint[] = []\n\tfor (const c of rawConstraints) {\n\t\tif (!c || typeof c !== 'object') continue\n\t\tconst record = c as Record<string, unknown>\n\t\tif (typeof record['offset'] !== 'number') continue\n\t\tconst value = toUint8Array(record['value'])\n\t\tif (value) constraints.push({ offset: record['offset'], value })\n\t}\n\treturn constraints\n}\n\n/**\n * Parses the `exclusions` array of a `c2pa.hash.bmff.v3` assertion.\n *\n * @internal\n */\nexport function parseExclusions(rawExclusions: unknown): BmffHashExclusion[] {\n\tif (!Array.isArray(rawExclusions)) return []\n\n\tconst exclusions: BmffHashExclusion[] = []\n\tfor (const exc of rawExclusions) {\n\t\tif (!exc || typeof exc !== 'object') continue\n\t\tconst record = exc as Record<string, unknown>\n\t\tif (typeof record['xpath'] !== 'string') continue\n\n\t\tconst constraints = parseConstraints(record['data'])\n\t\texclusions.push(constraints.length > 0 ? { xpath: record['xpath'], data: constraints } : { xpath: record['xpath'] })\n\t}\n\treturn exclusions\n}\n","import type { C2paAssertion } from '../C2paAssertion.ts'\nimport { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { computeBmffHash } from '../bmff/computeBmffHash.ts'\nimport { parseExclusions } from '../bmff/parseExclusions.ts'\nimport { asInteger, hashesEqual, normalizeAlgorithmName, toUint8Array } from '../utils.ts'\nimport type { MerkleMap } from './MerkleSegmentValidation.ts'\n\nfunction parseMerkleRow(rawHashes: unknown): Uint8Array[] | null {\n\tif (!Array.isArray(rawHashes) || rawHashes.length === 0) return null\n\tconst row: Uint8Array[] = []\n\tfor (const entry of rawHashes) {\n\t\tconst bytes = toUint8Array(entry)\n\t\tif (!bytes) return null\n\t\trow.push(bytes)\n\t}\n\treturn row\n}\n\nfunction extractMerkleMaps(bmffHashAssertionData: Record<string, unknown>): MerkleMap[] | null {\n\tconst rawMerkle = bmffHashAssertionData['merkle']\n\tif (!Array.isArray(rawMerkle) || rawMerkle.length === 0) return null\n\n\tconst exclusions = parseExclusions(bmffHashAssertionData['exclusions'])\n\tconst assertionAlg = bmffHashAssertionData['alg']\n\tconst offsetPrefixSize = bmffHashAssertionData['hash'] == null ? 8 : 0\n\n\tconst maps: MerkleMap[] = []\n\tfor (const entry of rawMerkle) {\n\t\tif (!entry || typeof entry !== 'object') return null\n\t\tconst record = entry as Record<string, unknown>\n\n\t\tconst uniqueId = asInteger(record['uniqueId'])\n\t\tconst localId = asInteger(record['localId'])\n\t\tconst count = asInteger(record['count'])\n\t\tconst hashes = parseMerkleRow(record['hashes'])\n\t\tif (uniqueId === null || localId === null || count === null || !hashes) return null\n\n\t\t// §A.5.4.2/merkle-map CDDL: initHash is required for fragmented assets, which\n\t\t// is the only case this function handles (it's only called for init segments).\n\t\tconst initHash = toUint8Array(record['initHash'])\n\t\tif (!initHash) return null\n\n\t\t// §A.5.4.2/merkle-map CDDL: falls back from this entry to the enclosing\n\t\t// assertion, then to the Claim's alg (not plumbed through here; c2pa-rs\n\t\t// always writes an assertion-level alg, so this is theoretical), or else\n\t\t// the structure is invalid.\n\t\tconst rawAlg = record['alg'] ?? assertionAlg\n\t\tif (typeof rawAlg !== 'string') return null\n\n\t\tmaps.push({\n\t\t\tuniqueId,\n\t\t\tlocalId,\n\t\t\tcount,\n\t\t\thashes,\n\t\t\tinitHash,\n\t\t\talg: normalizeAlgorithmName(rawAlg),\n\t\t\texclusions,\n\t\t\toffsetPrefixSize,\n\t\t})\n\t}\n\treturn maps\n}\n\nexport async function validateMerkleMaps(\n\tbytes: Uint8Array,\n\tassertion: C2paAssertion | null,\n\tcodes: Set<LiveVideoStatusCode | C2paStatusCode>,\n): Promise<MerkleMap[] | null> {\n\tconst data = assertion?.data\n\tif (data === null || typeof data !== 'object' || Array.isArray(data)) return null\n\tif ((data as Record<string, unknown>)['merkle'] === undefined) return null\n\n\tconst merkleMaps = extractMerkleMaps(data as Record<string, unknown>)\n\tif (!merkleMaps) {\n\t\tcodes.add(C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED)\n\t\treturn []\n\t}\n\n\tconst initHashByAlg = new Map<string | null, Uint8Array>()\n\tfor (const merkleMap of merkleMaps) {\n\t\tif (!merkleMap.initHash) continue\n\t\tlet computed = initHashByAlg.get(merkleMap.alg)\n\t\tif (!computed) {\n\t\t\tcomputed = await computeBmffHash(bytes, {\n\t\t\t\toffsetPrefixSize: merkleMap.offsetPrefixSize,\n\t\t\t\texclusions: merkleMap.exclusions,\n\t\t\t\talg: merkleMap.alg ?? undefined,\n\t\t\t})\n\t\t\tinitHashByAlg.set(merkleMap.alg, computed)\n\t\t}\n\t\tif (!hashesEqual(computed, merkleMap.initHash)) {\n\t\t\tcodes.add(LiveVideoStatusCode.INIT_INVALID)\n\t\t\tcodes.add(C2paStatusCode.ASSERTION_BMFFHASH_MISMATCH)\n\t\t}\n\t}\n\n\treturn merkleMaps\n}\n","import { decode } from 'cbor-x/decode'\nimport { encode } from 'cbor-x/encode'\nimport { findIsoBox, readIsoBoxes } from '@svta/cml-iso-bmff'\nimport type { C2paAssertion } from '../C2paAssertion.ts'\nimport type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { readC2paManifest } from '../readC2paManifest.ts'\nimport { computeBmffHash } from '../bmff/computeBmffHash.ts'\nimport type { BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport { validateManifestIntegrity } from '../claim/validateManifestIntegrity.ts'\nimport { convertCoseKeyToJwk } from '../cose/convertCoseKeyToJwk.ts'\nimport { verifySignerBinding } from '../cose/verifySignerBinding.ts'\nimport type { InitSegmentValidation, ValidatedSessionKey } from './InitSegmentValidation.ts'\nimport { validateMerkleMaps } from '../merkle/validateMerkleMaps.ts'\nimport { bytesToHex, hashesEqual, isKeyExpired, normalizeAlgorithmName } from '../utils.ts'\n\nconst BMFF_HASH_ASSERTION_LABEL = 'c2pa.hash.bmff.v3'\nconst SESSION_KEYS_ASSERTION_LABEL = 'c2pa.session-keys'\nconst COSE_KEY_ID_LABEL = 2\n\n// cbor-x represents CBOR tagged values in multiple ways depending on version/config:\n// - { tag: number, value: unknown } (structured)\n// - Tag class instance with constructor name 'Tag'\n// - { '@@TAGGED@@': [tag, value] } (internal key)\nconst CBOR_TAGGED_KEY = '@@TAGGED@@'\n\nfunction extractCborTaggedValue(value: unknown): unknown | null {\n\tif (typeof value !== 'object' || value === null) return null\n\tconst obj = value as Record<string, unknown>\n\tif (typeof obj['tag'] === 'number' && 'value' in obj) return obj['value']\n\tconst tagged = obj[CBOR_TAGGED_KEY]\n\tif (Array.isArray(tagged) && tagged.length === 2) return tagged[1]\n\treturn null\n}\n\nfunction normalizeToUint8Array(value: unknown): Uint8Array {\n\tif (value instanceof Uint8Array) return value\n\tif (Array.isArray(value)) return new Uint8Array(value as number[])\n\tif (extractCborTaggedValue(value) !== null) return encode(value) as Uint8Array\n\tthrow new Error('Cannot convert value to Uint8Array')\n}\n\nfunction ensureDecodedCbor(value: unknown): unknown {\n\tif (value instanceof Uint8Array) return decode(value)\n\tif (Array.isArray(value) && value.length > 0 && typeof (value as number[])[0] === 'number') {\n\t\treturn decode(new Uint8Array(value as number[]))\n\t}\n\treturn value\n}\n\nfunction parseCreatedAt(value: unknown): string | null {\n\tconst resolved = extractCborTaggedValue(value) ?? value\n\tif (typeof resolved === 'string') return resolved\n\tif (resolved instanceof Date) return resolved.toISOString()\n\treturn null\n}\n\nfunction extractKidHex(keyData: Record<string, unknown>, coseKey: unknown): string | null {\n\tconst kid = keyData['kid']\n\tif (kid instanceof Uint8Array) return bytesToHex(kid)\n\tif (typeof kid === 'string') return kid\n\tif (Array.isArray(kid) && kid.length > 0) return bytesToHex(new Uint8Array(kid as number[]))\n\n\t// Fallback: COSE key field 2 is the key ID per RFC 9052\n\tconst coseKeyLike = coseKey as Map<number, unknown> | Record<number, unknown>\n\tconst coseKid = coseKeyLike instanceof Map ? coseKeyLike.get(COSE_KEY_ID_LABEL) : coseKeyLike[COSE_KEY_ID_LABEL]\n\tif (coseKid instanceof Uint8Array) return bytesToHex(coseKid)\n\tif (Array.isArray(coseKid) && coseKid.length > 0) {\n\t\treturn bytesToHex(new Uint8Array(coseKid as number[]))\n\t}\n\n\treturn null\n}\n\nfunction extractKeyArray(data: unknown): unknown[] {\n\tif (Array.isArray(data)) return data\n\tif (typeof data === 'object' && data !== null) {\n\t\tconst obj = data as Record<string, unknown>\n\t\tconst keys = obj['keys'] ?? obj['sessionKeys']\n\t\tif (Array.isArray(keys)) return keys\n\t\tif (typeof keys === 'object' && keys !== null) {\n\t\t\tconst nested = (keys as Record<string, unknown>)['keys']\n\t\t\tif (Array.isArray(nested)) return nested\n\t\t}\n\t}\n\treturn []\n}\n\nasync function validateBmffHashAssertion(\n\tbytes: Uint8Array,\n\tassertion: C2paAssertion | null,\n): Promise<boolean> {\n\tif (!assertion) return true\n\tconst data = assertion.data as Record<string, unknown>\n\tconst rawHash = data['hash'] ?? data['value']\n\tif (!rawHash) return true\n\tconst expectedHash =\n\t\trawHash instanceof Uint8Array ? rawHash : new Uint8Array(rawHash as number[])\n\tconst alg = normalizeAlgorithmName(data['alg'] as string | undefined)\n\tconst exclusions = (data['exclusions'] as BmffHashExclusion[] | undefined) ?? []\n\t// §18.6.2: the flat v2/v3 hash covers offset || data for every non-excluded root\n\t// box; only Merkle tree hashes may omit the 8-byte offset prefix.\n\tconst computed = await computeBmffHash(bytes, { exclusions, alg, offsetPrefixSize: 8 })\n\treturn hashesEqual(computed, expectedHash)\n}\n\ntype SessionKeyFields = {\n\tminSequenceNumber: number\n\tvalidityPeriod: number\n\tcreatedAt: string\n\tkid: string\n\tcoseKey: unknown\n\tsignerBindingBytes: Uint8Array\n}\n\nfunction extractSessionKeyFields(entry: unknown): SessionKeyFields | null {\n\tconst keyData = entry as Record<string, unknown>\n\n\tconst minSequenceNumber = keyData['minSequenceNumber']\n\tconst validityPeriod = keyData['validityPeriod']\n\tconst createdAt = parseCreatedAt(keyData['createdAt'])\n\n\tif (minSequenceNumber == null || validityPeriod == null || !createdAt) return null\n\n\tconst isNotYetActive = new Date() < new Date(createdAt)\n\tif (isNotYetActive || isKeyExpired(createdAt, Number(validityPeriod))) return null\n\n\tconst coseKey = ensureDecodedCbor(keyData['key'])\n\tconst kid = extractKidHex(keyData, coseKey)\n\tif (!kid) return null\n\n\tconst signerBindingRaw = keyData['signerBinding']\n\tif (!signerBindingRaw) return null\n\n\ttry {\n\t\treturn {\n\t\t\tminSequenceNumber: Number(minSequenceNumber),\n\t\t\tvalidityPeriod: Number(validityPeriod),\n\t\t\tcreatedAt,\n\t\t\tkid,\n\t\t\tcoseKey,\n\t\t\tsignerBindingBytes: normalizeToUint8Array(signerBindingRaw),\n\t\t}\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function verifyAndConvertKey(\n\tfields: SessionKeyFields,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey | null> {\n\tconst isBindingValid = await verifySignerBinding(fields.signerBindingBytes, fields.coseKey, certificate)\n\tif (!isBindingValid) return null\n\n\ttry {\n\t\tconst jwk = convertCoseKeyToJwk(fields.coseKey)\n\t\treturn {\n\t\t\tkid: fields.kid,\n\t\t\tjwk,\n\t\t\tminSequenceNumber: fields.minSequenceNumber,\n\t\t\tvalidityPeriod: fields.validityPeriod,\n\t\t\tcreatedAt: fields.createdAt,\n\t\t}\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function validateSingleSessionKey(\n\tentry: unknown,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey | null> {\n\tconst fields = extractSessionKeyFields(entry)\n\tif (!fields) return null\n\treturn verifyAndConvertKey(fields, certificate)\n}\n\nasync function validateSessionKeys(\n\tassertion: C2paAssertion,\n\tcertificate: Uint8Array,\n): Promise<ValidatedSessionKey[]> {\n\tconst keyEntries = extractKeyArray(ensureDecodedCbor(assertion.data))\n\tconst results = await Promise.all(\n\t\tkeyEntries.map(entry => validateSingleSessionKey(entry, certificate)),\n\t)\n\treturn results.filter((key): key is ValidatedSessionKey => key !== null)\n}\n\n/**\n * Validates a C2PA init segment: parses the manifest, extracts and verifies\n * the certificate, validates the BMFF hard binding hash, verifies all\n * session keys from the `c2pa.session-keys` assertion, and performs\n * manifest integrity checks (assertion hashes, missing assertions,\n * action ingredients, and claim signature verification).\n *\n * Only session keys with a valid signer binding and an unexpired validity period\n * are included in the result.\n *\n * @param bytes - Raw init segment bytes\n * @returns Structured validation result (with `INIT_INVALID` error code if `mdat` box is present)\n * @throws If no C2PA UUID box is found\n *\n * @example\n * {@includeCode ../../test/init/validateC2paInitSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paInitSegment(bytes: Uint8Array): Promise<InitSegmentValidation> {\n\tconst boxes = readIsoBoxes(bytes)\n\tif (findIsoBox(boxes, box => box.type === 'mdat')) {\n\t\treturn {\n\t\t\tmanifest: null,\n\t\t\tcertificate: null,\n\t\t\tmanifestId: null,\n\t\t\tsessionKeys: [],\n\t\t\tmerkleMaps: [],\n\t\t\tisValid: false,\n\t\t\terrorCodes: [LiveVideoStatusCode.INIT_INVALID],\n\t\t}\n\t}\n\n\tconst internalData = readC2paManifest(bytes, boxes)\n\tconst { manifest } = internalData\n\tconst { codes: integrityCodes, certificate } = await validateManifestIntegrity(internalData)\n\n\tconst bmffHashAssertion =\n\t\tmanifest.assertions.find(a => a.label === BMFF_HASH_ASSERTION_LABEL) ?? null\n\tconst bmffHashValid = await validateBmffHashAssertion(bytes, bmffHashAssertion)\n\n\tconst sessionKeysAssertion = manifest.assertions.find(\n\t\ta => a.label === SESSION_KEYS_ASSERTION_LABEL,\n\t)\n\tconst sessionKeys =\n\t\tsessionKeysAssertion && certificate\n\t\t\t? await validateSessionKeys(sessionKeysAssertion, certificate)\n\t\t\t: []\n\n\tconst codes = new Set<LiveVideoStatusCode | C2paStatusCode>()\n\tconst merkleMaps = await validateMerkleMaps(bytes, bmffHashAssertion, codes)\n\n\tif (!bmffHashValid) codes.add(LiveVideoStatusCode.INIT_INVALID)\n\t// VOD Merkle streams carry no session keys; only flag their absence in live mode.\n\tif (sessionKeys.length === 0 && merkleMaps === null) {\n\t\tcodes.add(LiveVideoStatusCode.SESSIONKEY_INVALID)\n\t}\n\tfor (const code of integrityCodes) codes.add(code)\n\tconst errorCodes = [...codes]\n\n\treturn {\n\t\tmanifest,\n\t\tcertificate,\n\t\tmanifestId: manifest.instanceId,\n\t\tsessionKeys,\n\t\tmerkleMaps: merkleMaps ?? [],\n\t\tisValid: errorCodes.length === 0,\n\t\terrorCodes,\n\t}\n}\n","import { readEmsg, readIsoBoxes, type EventMessageBox } from '@svta/cml-iso-bmff'\n\nconst EMSG_BOX_TYPE = 'emsg'\nconst VSI_SCHEME_URI = 'urn:c2pa:verifiable-segment-info'\nconst EMSG_READER_CONFIG = { readers: { emsg: readEmsg } }\n\n/**\n * Finds and parses the first C2PA Verifiable Segment Info (VSI) EMSG box\n * in a DASH segment, identified by scheme URI `urn:c2pa:verifiable-segment-info`.\n *\n * @param segmentBytes - Raw DASH segment bytes\n * @returns The parsed VSI EMSG box, or `null` if not found\n *\n * @example\n * {@includeCode ../../test/emsg/extractVsiEmsgBox.test.ts#example}\n *\n * @internal\n */\nexport function extractVsiEmsgBox(segmentBytes: Uint8Array): EventMessageBox | null {\n\tfor (const box of readIsoBoxes(segmentBytes, EMSG_READER_CONFIG)) {\n\t\tif (box.type !== EMSG_BOX_TYPE) continue\n\t\tconst emsg = box as EventMessageBox\n\t\tif (emsg.schemeIdUri === VSI_SCHEME_URI) return emsg\n\t}\n\treturn null\n}\n","import { decode } from 'cbor-x/decode'\nimport type { BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport { normalizeAlgorithmName } from '../utils.ts'\nimport type { VsiMap } from './VsiMap.ts'\n\n\n/**\n * Decodes a C2PA Verifiable Segment Info (VSI) CBOR map from raw bytes.\n *\n * Normalizes hash algorithm names to WebCrypto format (e.g. `sha256` → `SHA-256`).\n *\n * @param vsiCborBytes - Raw CBOR-encoded VSI map bytes from the EMSG `messageData`\n * @returns The decoded VSI map\n * @throws If the bytes are not a valid VSI CBOR map\n *\n * @example\n * {@includeCode ../../test/vsi/decodeVsiMap.test.ts#example}\n *\n * @internal\n */\nexport function decodeVsiMap(vsiCborBytes: Uint8Array): VsiMap {\n\tconst raw = decode(vsiCborBytes) as Record<string, unknown>\n\n\tif (typeof raw !== 'object' || raw === null) {\n\t\tthrow new Error('VSI map must be a CBOR map')\n\t}\n\n\tconst sequenceNumber = raw['sequenceNumber']\n\tif (typeof sequenceNumber !== 'number') throw new Error('VSI map missing or invalid sequenceNumber')\n\n\tconst bmffHashRaw = raw['bmffHash'] as Record<string, unknown> | undefined\n\tif (!bmffHashRaw || typeof bmffHashRaw !== 'object') throw new Error('VSI map missing bmffHash')\n\n\tconst hash = bmffHashRaw['hash']\n\tif (!(hash instanceof Uint8Array)) throw new Error('VSI map bmffHash.hash must be a Uint8Array')\n\n\tconst exclusions = bmffHashRaw['exclusions']\n\tif (exclusions !== undefined && !Array.isArray(exclusions)) throw new Error('VSI map bmffHash.exclusions must be an array')\n\n\tconst manifestId = raw['manifestId']\n\tif (typeof manifestId !== 'string') throw new Error('VSI map missing or invalid manifestId')\n\n\tconst alg = normalizeAlgorithmName(bmffHashRaw['alg'] as string | undefined)\n\n\treturn {\n\t\tsequenceNumber,\n\t\tbmffHash: {\n\t\t\thash,\n\t\t\talg,\n\t\t\texclusions: (exclusions as BmffHashExclusion[] | undefined) ?? [],\n\t\t},\n\t\tmanifestId,\n\t}\n}\n","import type { SequenceState } from './SequenceState.ts'\n\n/**\n * Creates the initial (empty) sequence state for a new stream.\n *\n * @returns A {@link SequenceState} with no history\n *\n * @example\n * {@includeCode ../../test/vsi/validateSequenceNumber.test.ts#example}\n *\n * @internal\n */\nexport function createSequenceState(): SequenceState {\n\treturn { lastSequenceNumber: null, seenSequences: new Set() }\n}\n","import type { ValueOf } from '@svta/cml-utils'\n\n/**\n * State and result types for monotonic sequence number validation\n * per C2PA Live Streaming Specification §18.4.\n *\n * @public\n */\n\n/**\n * Immutable state snapshot for a single stream's sequence number history.\n *\n * Pass to {@link validateC2paSegment} via the `sequenceState` parameter.\n *\n * @public\n */\nexport type SequenceState = {\n\treadonly lastSequenceNumber: number | null\n\treadonly seenSequences: ReadonlySet<number>\n}\n\n/**\n * Reason codes for sequence number validation outcomes.\n *\n * @see {@link SequenceValidationResult}\n *\n * @enum\n *\n * @public\n */\nexport const SequenceValidationReason = {\n\t/** Sequence number is the next expected value */\n\tVALID: 'valid',\n\t/** Sequence number was already seen */\n\tDUPLICATE: 'duplicate',\n\t/** One or more sequence numbers were skipped */\n\tGAP_DETECTED: 'gap_detected',\n\t/** Sequence number is less than the last seen */\n\tOUT_OF_ORDER: 'out_of_order',\n\t/** Below the session key's minSequenceNumber */\n\tSEQUENCE_NUMBER_BELOW_MINIMUM: 'sequence_number_below_minimum',\n} as const\n\n/**\n * Union type of all {@link (SequenceValidationReason:variable)} values.\n *\n * @public\n */\nexport type SequenceValidationReason = ValueOf<typeof SequenceValidationReason>\n\n/**\n * Result of validating a single sequence number against the current stream state.\n *\n * Discriminated on `reason` — narrow to `'gap_detected'` to access\n * `missingFrom` / `missingTo`.\n *\n * @public\n */\nexport type SequenceValidationResult =\n\t| { readonly isValid: true; readonly reason: typeof SequenceValidationReason.VALID }\n\t| {\n\t\t\treadonly isValid: false\n\t\t\treadonly reason:\n\t\t\t\t| typeof SequenceValidationReason.SEQUENCE_NUMBER_BELOW_MINIMUM\n\t\t\t\t| typeof SequenceValidationReason.DUPLICATE\n\t\t\t\t| typeof SequenceValidationReason.OUT_OF_ORDER\n\t\t}\n\t| {\n\t\t\treadonly isValid: false\n\t\t\treadonly reason: typeof SequenceValidationReason.GAP_DETECTED\n\t\t\treadonly missingFrom: number\n\t\t\treadonly missingTo: number\n\t\t}\n","import { SequenceValidationReason } from './SequenceState.ts'\nimport type { SequenceState, SequenceValidationResult } from './SequenceState.ts'\n\nconst SEEN_SEQUENCES_WINDOW_SIZE = 32\n\nfunction pruneSeenSequences(seen: Set<number>, lastSequenceNumber: number): Set<number> {\n\tif (seen.size <= SEEN_SEQUENCES_WINDOW_SIZE) return seen\n\tconst threshold = lastSequenceNumber - SEEN_SEQUENCES_WINDOW_SIZE\n\tconst pruned = new Set<number>()\n\tfor (const seq of seen) {\n\t\tif (seq >= threshold) pruned.add(seq)\n\t}\n\treturn pruned\n}\n\n/**\n * Validates a segment's sequence number against the current stream state\n * per C2PA Live Streaming Specification §18.4.\n *\n * This function is **pure and stateless** — it returns both the validation\n * result and the next state. The caller is responsible for persisting\n * `nextState` between calls.\n *\n * Detects: `duplicate`, `out_of_order`, `gap_detected`, and\n * `sequence_number_below_minimum`.\n *\n * Internally uses a sliding window of the last 32 sequence numbers\n * to bound memory usage during long-running streams.\n *\n * @param state - Current stream state (from {@link createSequenceState} or previous `nextState`)\n * @param sequenceNumber - Sequence number from the segment's VSI map\n * @param minSequenceNumber - Minimum accepted sequence number (from the session key, default 0)\n * @returns Validation result and the updated state to persist\n *\n * @example\n * {@includeCode ../../test/vsi/validateSequenceNumber.test.ts#example}\n *\n * @internal\n */\nexport function validateSequenceNumber(\n\tstate: SequenceState,\n\tsequenceNumber: number,\n\tminSequenceNumber: number,\n): { readonly result: SequenceValidationResult; readonly nextState: SequenceState } {\n\tif (sequenceNumber < minSequenceNumber) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.SEQUENCE_NUMBER_BELOW_MINIMUM },\n\t\t\tnextState: state,\n\t\t}\n\t}\n\n\tif (state.seenSequences.has(sequenceNumber)) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.DUPLICATE },\n\t\t\tnextState: state,\n\t\t}\n\t}\n\n\tconst nextSeenSequences = new Set(state.seenSequences)\n\tnextSeenSequences.add(sequenceNumber)\n\n\tif (state.lastSequenceNumber !== null && sequenceNumber < state.lastSequenceNumber) {\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.OUT_OF_ORDER },\n\t\t\tnextState: {\n\t\t\t\tlastSequenceNumber: state.lastSequenceNumber,\n\t\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, state.lastSequenceNumber),\n\t\t\t},\n\t\t}\n\t}\n\n\tif (state.lastSequenceNumber !== null && sequenceNumber > state.lastSequenceNumber + 1) {\n\t\tconst missingFrom = state.lastSequenceNumber + 1\n\t\tconst missingTo = sequenceNumber - 1\n\t\treturn {\n\t\t\tresult: { isValid: false, reason: SequenceValidationReason.GAP_DETECTED, missingFrom, missingTo },\n\t\t\tnextState: {\n\t\t\t\tlastSequenceNumber: sequenceNumber,\n\t\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, sequenceNumber),\n\t\t\t},\n\t\t}\n\t}\n\n\treturn {\n\t\tresult: { isValid: true, reason: SequenceValidationReason.VALID },\n\t\tnextState: {\n\t\t\tlastSequenceNumber: sequenceNumber,\n\t\t\tseenSequences: pruneSeenSequences(nextSeenSequences, sequenceNumber),\n\t\t},\n\t}\n}\n","import type { BmffHashExclusion } from './BmffHashExclusion.ts'\nimport { computeBmffHash } from './computeBmffHash.ts'\nimport { hashesEqual } from '../utils.ts'\n\nconst OFFSET_PREFIX_SIZES_TO_TRY = [8, 0] as const\n\n/**\n * Options for BMFF hash validation.\n *\n * @public\n */\nexport type BmffHashValidationOptions = {\n\treadonly exclusions?: readonly BmffHashExclusion[]\n\treadonly alg?: string\n}\n\n/**\n * Validates the C2PA BMFF content hash (`c2pa.hash.bmff.v3`) for a DASH segment.\n *\n * Tries both offset-prefix modes — 8-byte file offset prefix and no prefix — to handle\n * inter-signer interoperability for hashes carried in the VSI CBOR map (§19.7.3), where\n * the spec does not signal the prefix mode. Flat hashes from a `c2pa.hash.bmff.v3`\n * assertion always use the 8-byte prefix (§18.6.2); verify those with\n * {@link computeBmffHash} and `offsetPrefixSize: 8` instead.\n *\n * @param segmentBytes - Raw segment bytes to validate\n * @param expectedHash - Expected hash bytes from the VSI CBOR map\n * @param options - Validation options (exclusions, algorithm)\n * @returns `true` if the computed hash matches the expected hash in either offset mode\n *\n * @example\n * {@includeCode ../../test/bmff/validateBmffHash.test.ts#example}\n *\n * @public\n */\nexport async function validateBmffHash(\n\tsegmentBytes: Uint8Array,\n\texpectedHash: Uint8Array,\n\toptions?: BmffHashValidationOptions,\n): Promise<boolean> {\n\tfor (const offsetPrefixSize of OFFSET_PREFIX_SIZES_TO_TRY) {\n\t\tconst hash = await computeBmffHash(segmentBytes, { ...options, offsetPrefixSize })\n\t\tif (hashesEqual(hash, expectedHash)) return true\n\t}\n\treturn false\n}\n","import { verifyCoseSign1 } from '../cose/verifyCoseSign1.ts'\nimport { decodeCoseSign1 } from '../cose/decodeCoseSign1.ts'\nimport { extractVsiEmsgBox } from '../emsg/extractVsiEmsgBox.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { decodeVsiMap } from '../vsi/decodeVsiMap.ts'\nimport type { SequenceState } from '../vsi/SequenceState.ts'\nimport { createSequenceState } from '../vsi/createSequenceState.ts'\nimport { validateSequenceNumber } from '../vsi/validateSequenceNumber.ts'\nimport { validateBmffHash } from '../bmff/validateBmffHash.ts'\nimport type { ValidatedSessionKey } from '../init/InitSegmentValidation.ts'\nimport { resolveImportAlgorithm } from '../cose/resolveImportAlgorithm.ts'\nimport { bytesToHex, isKeyExpired } from '../utils.ts'\nimport type { SegmentValidationResult } from './SegmentValidation.ts'\n\nfunction findSessionKey(sessionKeys: readonly ValidatedSessionKey[], kidHex: string | null): ValidatedSessionKey | null {\n\tif (!kidHex || sessionKeys.length === 0) return null\n\treturn sessionKeys.find(k => k.kid === kidHex) ?? null\n}\n\n/**\n * Validates a C2PA live stream segment using the VSI/EMSG method (§19.7.3).\n *\n * Extracts the EMSG box, decodes the COSE_Sign1 and VSI map, matches the\n * session key by kid, then performs all cryptographic checks: signature\n * verification, BMFF content hash, sequence number floor, and key validity.\n *\n * Returns `null` if the segment does not contain a C2PA EMSG box.\n *\n * @param segmentBytes - Raw segment bytes\n * @param sessionKeys - Available session keys from the init segment\n * @param sequenceState - Current sequence state for this stream\n * @returns Validation result and updated sequence state, or `null` if no C2PA EMSG box\n *\n * @example\n * {@includeCode ../../test/segment/validateC2paSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paSegment(\n\tsegmentBytes: Uint8Array,\n\tsessionKeys: readonly ValidatedSessionKey[],\n\tsequenceState: SequenceState = createSequenceState(),\n): Promise<{ readonly result: SegmentValidationResult; readonly nextSequenceState: SequenceState } | null> {\n\tconst emsgBox = extractVsiEmsgBox(segmentBytes)\n\tif (!emsgBox) return null\n\n\tconst coseSign1 = decodeCoseSign1(emsgBox.messageData)\n\tconst { payload } = coseSign1\n\tif (!payload) throw new Error('COSE_Sign1 payload is empty — cannot decode VSI map')\n\tconst vsi = decodeVsiMap(payload)\n\n\tconst kidHex = coseSign1.kid ? bytesToHex(coseSign1.kid) : null\n\tconst sessionKey = findSessionKey(sessionKeys, kidHex)\n\tconst bmffHashHex = bytesToHex(vsi.bmffHash.hash)\n\tconst minSequenceNumber = sessionKey?.minSequenceNumber ?? 0\n\n\tconst { result: sequenceResult, nextState: nextSequenceState } = validateSequenceNumber(\n\t\tsequenceState,\n\t\tvsi.sequenceNumber,\n\t\tminSequenceNumber,\n\t)\n\n\tconst baseFields = {\n\t\tsequenceNumber: vsi.sequenceNumber,\n\t\tmanifestId: vsi.manifestId,\n\t\tbmffHashHex,\n\t\tkidHex,\n\t\tsequenceResult,\n\t}\n\n\tif (!sessionKey) {\n\t\treturn {\n\t\t\tresult: {\n\t\t\t\t...baseFields,\n\t\t\t\tisValid: false,\n\t\t\t\terrorCodes: [LiveVideoStatusCode.SEGMENT_INVALID],\n\t\t\t},\n\t\t\tnextSequenceState,\n\t\t}\n\t}\n\n\tconst algorithm = resolveImportAlgorithm(sessionKey.jwk)\n\tconst publicKey = await crypto.subtle.importKey(\n\t\t'jwk',\n\t\tsessionKey.jwk as JsonWebKey,\n\t\talgorithm,\n\t\tfalse,\n\t\t['verify'],\n\t)\n\n\tconst [signatureValid, hashValid] = await Promise.all([\n\t\tverifyCoseSign1(coseSign1, payload, publicKey),\n\t\tvalidateBmffHash(segmentBytes, vsi.bmffHash.hash, {\n\t\t\texclusions: vsi.bmffHash.exclusions,\n\t\t\talg: vsi.bmffHash.alg,\n\t\t}),\n\t])\n\n\tconst sequenceAboveMin = vsi.sequenceNumber >= sessionKey.minSequenceNumber\n\t// §19.7.3 requires comparing against the segment's presentation time, but the\n\t// VSI map does not carry it. We compare against `now` as an approximation,\n\t// which is accurate for live streams validated in real time.\n\tconst keyExpired = isKeyExpired(sessionKey.createdAt, sessionKey.validityPeriod)\n\n\tconst codes = new Set<LiveVideoStatusCode>()\n\tif (!signatureValid || !hashValid || !sequenceAboveMin) codes.add(LiveVideoStatusCode.SEGMENT_INVALID)\n\tif (!sequenceResult.isValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (keyExpired) codes.add(LiveVideoStatusCode.SESSIONKEY_INVALID)\n\tconst errorCodes = [...codes]\n\n\treturn {\n\t\tresult: { ...baseFields, isValid: errorCodes.length === 0, errorCodes },\n\t\tnextSequenceState,\n\t}\n}\n","import type { C2paAssertion } from '../C2paAssertion.ts'\nimport type { C2paManifest } from '../C2paManifest.ts'\nimport type { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { readC2paManifest } from '../readC2paManifest.ts'\nimport { bytesToHex, hashesEqual, normalizeAlgorithmName, toUint8Array } from '../utils.ts'\nimport { computeBmffHash } from '../bmff/computeBmffHash.ts'\nimport { parseExclusions } from '../bmff/parseExclusions.ts'\nimport type { BmffHashExclusion } from '../bmff/BmffHashExclusion.ts'\nimport type { InternalManifestData } from '../claim/InternalManifestData.ts'\nimport { validateManifestIntegrity } from '../claim/validateManifestIntegrity.ts'\nimport type {\n\tManifestBoxValidationOptions,\n\tManifestBoxValidationResult,\n\tManifestBoxValidationState,\n} from './ManifestBoxValidation.ts'\n\nconst LIVE_VIDEO_ASSERTION_LABEL = 'c2pa.livevideo.segment'\nconst BMFF_HASH_ASSERTION_LABEL = 'c2pa.hash.bmff.v3'\nconst MANIFEST_ID_PREFIX_PATTERN = /^(xmp:iid:|urn:uuid:)/i\nconst CONTINUITY_METHOD_MANIFEST_ID = 'c2pa.manifestId'\n\nfunction normalizeManifestId(id: string | null): string | null {\n\tif (!id) return null\n\treturn id.replace(MANIFEST_ID_PREFIX_PATTERN, '').toLowerCase()\n}\n\nfunction extractAssertionData(data: unknown): Record<string, unknown> | null {\n\tif (data !== null && typeof data === 'object' && !Array.isArray(data)) {\n\t\treturn data as Record<string, unknown>\n\t}\n\treturn null\n}\n\n// --- Live video assertion parsing ---\n\ntype LiveVideoFields = {\n\tsequenceNumber: number | null\n\tpreviousManifestId: string | null\n\tstreamId: string | null\n\tcontinuityMethod: string | null\n\tdata: Record<string, unknown>\n}\n\nfunction parseLiveVideoAssertion(assertions: readonly C2paAssertion[]): LiveVideoFields | null {\n\tconst assertion = assertions.find(a => a.label === LIVE_VIDEO_ASSERTION_LABEL)\n\tif (!assertion) return null\n\n\tconst data = extractAssertionData(assertion.data)\n\tconst rawSeq = data?.['sequenceNumber']\n\tconst rawPrev = data?.['previousManifestId']\n\tconst rawStreamId = data?.['streamId']\n\tconst rawContinuity = data?.['continuityMethod']\n\n\treturn {\n\t\tsequenceNumber: typeof rawSeq === 'number' ? rawSeq : null,\n\t\tpreviousManifestId: typeof rawPrev === 'string' ? rawPrev : null,\n\t\tstreamId: typeof rawStreamId === 'string' ? rawStreamId : null,\n\t\tcontinuityMethod: typeof rawContinuity === 'string' ? rawContinuity : null,\n\t\tdata: data ?? {},\n\t}\n}\n\n// --- BMFF hash assertion parsing ---\n\ntype BmffHashFields = {\n\thashBytes: Uint8Array | null\n\thashHex: string | null\n\texclusions: readonly BmffHashExclusion[]\n\talg: string | null\n}\n\nconst EMPTY_BMFF_HASH: BmffHashFields = { hashBytes: null, hashHex: null, exclusions: [], alg: null }\n\nfunction parseBmffHashAssertion(assertions: readonly C2paAssertion[]): BmffHashFields {\n\tconst assertion = assertions.find(a => a.label === BMFF_HASH_ASSERTION_LABEL)\n\tif (!assertion) return EMPTY_BMFF_HASH\n\n\tconst data = extractAssertionData(assertion.data)\n\tif (!data) return EMPTY_BMFF_HASH\n\n\tconst hashBytes = toUint8Array(data['hash'] ?? data['value'])\n\tconst hashHex = hashBytes ? bytesToHex(hashBytes) : null\n\tconst exclusions = parseExclusions(data['exclusions'])\n\tconst alg = typeof data['alg'] === 'string' ? normalizeAlgorithmName(data['alg']) : null\n\treturn { hashBytes, hashHex, exclusions, alg }\n}\n\n// --- Manifest parsing ---\n\ntype ParsedManifest = {\n\tmanifest: C2paManifest | null\n\tissuer: string | null\n\tliveVideo: LiveVideoFields | null\n\tbmff: BmffHashFields\n\tinternalData: InternalManifestData | null\n}\n\nfunction parseManifest(bytes: Uint8Array): ParsedManifest {\n\ttry {\n\t\tconst internalData = readC2paManifest(bytes)\n\t\tconst { manifest } = internalData\n\t\tif (!manifest) return { manifest: null, issuer: null, liveVideo: null, bmff: EMPTY_BMFF_HASH, internalData: null }\n\n\t\treturn {\n\t\t\tmanifest,\n\t\t\tissuer: manifest.signatureInfo?.issuer ?? null,\n\t\t\tliveVideo: parseLiveVideoAssertion(manifest.assertions),\n\t\t\tbmff: parseBmffHashAssertion(manifest.assertions),\n\t\t\tinternalData,\n\t\t}\n\t} catch {\n\t\treturn { manifest: null, issuer: null, liveVideo: null, bmff: EMPTY_BMFF_HASH, internalData: null }\n\t}\n}\n\n// --- Validation ---\n\nfunction collectErrorCodes(\n\thasManifest: boolean,\n\thasLiveVideo: boolean,\n\tstreamIdValid: boolean,\n\tsequenceNumberValid: boolean,\n\tbmffHashMatches: boolean,\n): readonly LiveVideoStatusCode[] {\n\tconst codes = new Set<LiveVideoStatusCode>()\n\n\tif (!hasManifest) codes.add(LiveVideoStatusCode.MANIFEST_INVALID)\n\tif (!hasLiveVideo) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!streamIdValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!sequenceNumberValid) codes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\tif (!bmffHashMatches) codes.add(LiveVideoStatusCode.SEGMENT_INVALID)\n\n\treturn [...codes]\n}\n\nasync function validateContinuity(\n\tparsed: ParsedManifest,\n\tlastManifestId: string | null,\n\toptions?: ManifestBoxValidationOptions,\n): Promise<readonly LiveVideoStatusCode[]> {\n\tconst { manifest, liveVideo } = parsed\n\tconst method = liveVideo?.continuityMethod ?? null\n\n\tif (!method) return [LiveVideoStatusCode.CONTINUITY_METHOD_INVALID]\n\n\tif (method === CONTINUITY_METHOD_MANIFEST_ID) {\n\t\tconst prev = liveVideo?.previousManifestId ?? null\n\t\tif (!prev) return [LiveVideoStatusCode.CONTINUITY_METHOD_INVALID]\n\t\tconst broken = !!lastManifestId && normalizeManifestId(prev) !== normalizeManifestId(lastManifestId)\n\t\treturn broken ? [LiveVideoStatusCode.SEGMENT_INVALID] : []\n\t}\n\n\tconst custom = options?.continuityValidator\n\tif (custom?.method !== method || !manifest || !liveVideo) {\n\t\treturn [LiveVideoStatusCode.CONTINUITY_METHOD_INVALID, LiveVideoStatusCode.CONTINUITY_METHOD_UNSUPPORTED]\n\t}\n\n\tconst ok = await Promise.resolve()\n\t\t.then(() => custom.validate(liveVideo.data, manifest))\n\t\t.catch(() => false)\n\treturn ok ? [] : [LiveVideoStatusCode.SEGMENT_INVALID]\n}\n\n/**\n * Validates a C2PA manifest-box live stream segment.\n *\n * Parses the C2PA manifest embedded in the segment and validates per §19.7.1 and §19.7.2.\n * Recomputes the `c2pa.hash.bmff.v3` content hash from the raw segment bytes and compares\n * it against the expected hash in the manifest assertion. Checks live-video assertions\n * (sequenceNumber, streamId, continuityMethod) and manifest-ID chain continuity.\n * A validator for an implementer-defined continuity method can be registered\n * via {@link ManifestBoxValidationOptions}.\n *\n * This function is **pure** — it does not access any external state. The\n * caller is responsible for persisting `nextManifestId` and `nextState`\n * between calls.\n *\n * @param bytes - Raw segment bytes\n * @param lastManifestId - Manifest ID from the previous segment, or null for the first segment\n * @param state - Optional state from the previous segment for streamId/sequenceNumber checks\n * @param options - Optional custom continuity method validator\n * @returns Validation result, the manifest ID, and state to persist for the next call\n *\n * @example\n * {@includeCode ../../test/manifestbox/validateC2paManifestBoxSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paManifestBoxSegment(\n\tbytes: Uint8Array,\n\tlastManifestId: string | null,\n\tstate?: ManifestBoxValidationState,\n\toptions?: ManifestBoxValidationOptions,\n): Promise<{\n\treadonly result: ManifestBoxValidationResult\n\treadonly nextManifestId: string | null\n\treadonly nextState: ManifestBoxValidationState\n}> {\n\tconst { manifest, issuer, liveVideo, bmff, internalData } = parseManifest(bytes)\n\n\tconst sequenceNumber = liveVideo?.sequenceNumber ?? null\n\tconst previousManifestId = liveVideo?.previousManifestId ?? null\n\tconst streamId = liveVideo?.streamId ?? null\n\tconst continuityMethod = liveVideo?.continuityMethod ?? null\n\n\tconst streamIdValid = state?.lastStreamId == null || streamId === state.lastStreamId\n\tconst sequenceNumberValid =\n\t\tstate?.lastSequenceNumber == null ||\n\t\t(sequenceNumber !== null && sequenceNumber > state.lastSequenceNumber)\n\n\tlet bmffHashMatches = true\n\tif (bmff.hashBytes !== null) {\n\t\t// §18.6.2: the flat v2/v3 hash covers offset || data for every non-excluded root\n\t\t// box; only Merkle tree hashes may omit the 8-byte offset prefix.\n\t\tconst computed = await computeBmffHash(bytes, {\n\t\t\texclusions: bmff.exclusions,\n\t\t\talg: bmff.alg ?? undefined,\n\t\t\toffsetPrefixSize: 8,\n\t\t})\n\t\tbmffHashMatches = hashesEqual(computed, bmff.hashBytes)\n\t}\n\n\tconst continuityCodes = await validateContinuity({ manifest, issuer, liveVideo, bmff, internalData }, lastManifestId, options)\n\n\tconst liveVideoCodes = [...new Set([\n\t\t...collectErrorCodes(\n\t\t\tmanifest !== null, liveVideo !== null,\n\t\t\tstreamIdValid, sequenceNumberValid, bmffHashMatches,\n\t\t),\n\t\t...continuityCodes,\n\t])]\n\n\tconst integrity = internalData ? await validateManifestIntegrity(internalData) : null\n\tconst integrityCodes: readonly C2paStatusCode[] = integrity?.codes ?? []\n\n\tconst errorCodes: (LiveVideoStatusCode | C2paStatusCode)[] = [...liveVideoCodes, ...integrityCodes]\n\n\tconst currentManifestId = manifest?.instanceId ?? null\n\n\treturn {\n\t\tresult: {\n\t\t\tmanifest: manifest ?? null,\n\t\t\tissuer,\n\t\t\tcertificate: integrity?.certificate ?? null,\n\t\t\tsequenceNumber,\n\t\t\tpreviousManifestId,\n\t\t\tstreamId,\n\t\t\tcontinuityMethod,\n\t\t\tbmffHashHex: bmff.hashHex,\n\t\t\tisValid: errorCodes.length === 0,\n\t\t\terrorCodes,\n\t\t},\n\t\tnextManifestId: currentManifestId ?? lastManifestId,\n\t\tnextState: {\n\t\t\tlastStreamId: streamId ?? state?.lastStreamId,\n\t\t\tlastSequenceNumber: sequenceNumber ?? state?.lastSequenceNumber,\n\t\t},\n\t}\n}\n","import { readIsoBoxes } from '@svta/cml-iso-bmff'\nimport { decodeMultiple } from 'cbor-x/decode'\nimport { C2paStatusCode } from '../C2paStatusCode.ts'\nimport { LiveVideoStatusCode } from '../LiveVideoStatusCode.ts'\nimport { computeBmffHash } from '../bmff/computeBmffHash.ts'\nimport { JUMBF_UUID, asInteger, bytesToHex, hashesEqual, matchesUuid, normalizeAlgorithmName, readUuidBoxPurpose, toUint8Array } from '../utils.ts'\nimport type { UuidParsedBox } from '../utils.ts'\nimport type { MerkleMap, MerkleSegmentState, MerkleSegmentValidation } from './MerkleSegmentValidation.ts'\n\ntype MerkleValidationCode = LiveVideoStatusCode | C2paStatusCode\n\nconst MERKLE_BOX_PURPOSE = 'merkle'\n\n// --- Auxiliary uuid box extraction ---\n\ntype AuxPayload = Uint8Array | 'other'\n\n// §A.5.1.2/A.5.4.1.4: version/flags + null-terminated box_purpose + raw data.\nfunction readAuxPayload(rawPayload: Uint8Array): AuxPayload {\n\tconst prefix = readUuidBoxPurpose(rawPayload)\n\tif (!prefix || prefix.purpose !== MERKLE_BOX_PURPOSE) return 'other'\n\treturn prefix.rest\n}\n\nfunction extractMerkleAuxBoxes(segmentBytes: Uint8Array): Uint8Array[] {\n\tconst payloads: Uint8Array[] = []\n\n\tfor (const box of readIsoBoxes(segmentBytes)) {\n\t\tconst uuidBox = box as unknown as UuidParsedBox\n\t\tif (uuidBox.type !== 'uuid') continue\n\t\tconst usertype = uuidBox.usertype ?? []\n\t\tif (!matchesUuid(usertype, JUMBF_UUID)) continue\n\n\t\tconst rawPayload = uuidBox.view.readData(uuidBox.view.bytesRemaining) as Uint8Array\n\t\tconst payload = readAuxPayload(rawPayload)\n\t\tif (payload !== 'other') payloads.push(payload)\n\t}\n\n\treturn payloads\n}\n\n// --- bmff-merkle-map decoding ---\n\ntype BmffMerkleMapSegment = {\n\treadonly uniqueId: number\n\treadonly localId: number\n\treadonly location: number\n\t/** Sibling proof path; null when the manifest stores the leaf row */\n\treadonly hashes: readonly (Uint8Array | null)[] | null\n}\n\nfunction readMapField(map: unknown, name: string): unknown {\n\tif (map instanceof Map) return map.get(name)\n\treturn (map as Record<string, unknown>)[name]\n}\n\n// §A.5.4.1.4: multiple merkle boxes for one tree are padded to a fixed size,\n// so trailing bytes after the CBOR item are expected and not part of the data.\nfunction decodeFirstCbor(payload: Uint8Array): unknown {\n\tlet first: unknown\n\tlet found = false\n\ttry {\n\t\tdecodeMultiple(payload, value => {\n\t\t\tfirst = value\n\t\t\tfound = true\n\t\t\treturn false\n\t\t})\n\t} catch {\n\t\treturn undefined\n\t}\n\treturn found ? first : undefined\n}\n\nfunction parseBmffMerkleMap(payload: Uint8Array): BmffMerkleMapSegment | null {\n\tconst decoded = decodeFirstCbor(payload)\n\tif (decoded === null || decoded === undefined || typeof decoded !== 'object') return null\n\n\tconst uniqueId = asInteger(readMapField(decoded, 'uniqueId'))\n\tconst localId = asInteger(readMapField(decoded, 'localId'))\n\tconst location = asInteger(readMapField(decoded, 'location'))\n\tif (uniqueId === null || localId === null || location === null) return null\n\n\tconst rawHashes = readMapField(decoded, 'hashes')\n\tif (rawHashes == null) return { uniqueId, localId, location, hashes: null }\n\tif (!Array.isArray(rawHashes)) return null\n\n\tconst hashes: (Uint8Array | null)[] = []\n\tfor (const entry of rawHashes) {\n\t\tif (entry == null) {\n\t\t\thashes.push(null)\n\t\t\tcontinue\n\t\t}\n\t\tconst bytes = toUint8Array(entry)\n\t\tif (!bytes) return null\n\t\thashes.push(bytes)\n\t}\n\treturn { uniqueId, localId, location, hashes }\n}\n\n// --- Merkle proof traversal ---\n\nasync function hashPair(left: Uint8Array, right: Uint8Array, alg: string): Promise<Uint8Array> {\n\tconst input = new Uint8Array(left.length + right.length)\n\tinput.set(left, 0)\n\tinput.set(right, left.length)\n\treturn new Uint8Array(await crypto.subtle.digest(alg, input))\n}\n\n// Layer sizes, leaf level first (61 → [61, 31, 16, 8, 4, 2, 1]).\nfunction treeLayout(leafCount: number): number[] {\n\tconst layers = [leafCount]\n\twhile (layers[layers.length - 1] > 1) {\n\t\tlayers.push(Math.ceil(layers[layers.length - 1] / 2))\n\t}\n\treturn layers\n}\n\n// §15.12.2.2: hash from the leaf up to the layer matching the manifest row length.\nasync function verifyMerkleProof(\n\tleafHash: Uint8Array,\n\tlocation: number,\n\tproofPath: readonly (Uint8Array | null)[] | null,\n\tmerkleMap: MerkleMap,\n): Promise<'ok' | MerkleValidationCode> {\n\tconst { count, hashes: manifestRow } = merkleMap\n\tif (location < 0 || location >= count) {\n\t\treturn C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\t}\n\n\tconst layers = treeLayout(count)\n\tconst committedLevel = layers.indexOf(manifestRow.length)\n\tif (committedLevel === -1) {\n\t\treturn C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\t}\n\n\tconst rawPath = proofPath ?? []\n\tif (rawPath.length > committedLevel) return C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\tconst path = rawPath.filter((node): node is Uint8Array => node !== null)\n\n\tconst alg = normalizeAlgorithmName(merkleMap.alg ?? undefined)\n\n\tlet currentHash = leafHash\n\tlet currentIndex = location\n\tlet proofIndex = 0\n\tfor (const layer of layers) {\n\t\tif (layer === manifestRow.length) {\n\t\t\tbreak\n\t\t}\n\t\tconst siblingIndex = currentIndex % 2 === 0 ? currentIndex + 1 : currentIndex - 1\n\t\tif (siblingIndex >= 0 && siblingIndex < layer) {\n\t\t\tconst sibling = path[proofIndex++]\n\t\t\tif (!sibling) return C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\t\t\tcurrentHash = currentIndex % 2 === 0\n\t\t\t\t? await hashPair(currentHash, sibling, alg)\n\t\t\t\t: await hashPair(sibling, currentHash, alg)\n\t\t}\n\t\tcurrentIndex = Math.floor(currentIndex / 2)\n\t}\n\n\tif (proofIndex !== path.length) return C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\n\tconst expected = manifestRow[currentIndex]\n\tif (!expected) return C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED\n\treturn hashesEqual(currentHash, expected) ? 'ok' : C2paStatusCode.ASSERTION_BMFFHASH_MISMATCH\n}\n\n// --- Public API ---\n\nfunction findMerkleMap(\n\tmerkleMaps: readonly MerkleMap[],\n\tuniqueId: number,\n\tlocalId: number,\n): MerkleMap | null {\n\treturn merkleMaps.find(m => m.uniqueId === uniqueId && m.localId === localId) ?? null\n}\n\ntype LeafHashCache = {\n\talg: string | null\n\toffsetPrefixSize: number\n\texclusions: MerkleMap['exclusions']\n\thash: Uint8Array\n}[]\n\nasync function computeLeafHash(\n\tsegmentBytes: Uint8Array,\n\tmerkleMap: MerkleMap,\n\tcache: LeafHashCache,\n): Promise<Uint8Array> {\n\tconst cached = cache.find(entry =>\n\t\tentry.alg === merkleMap.alg &&\n\t\tentry.offsetPrefixSize === merkleMap.offsetPrefixSize &&\n\t\tentry.exclusions === merkleMap.exclusions,\n\t)\n\tif (cached) return cached.hash\n\n\tconst hash = await computeBmffHash(segmentBytes, {\n\t\toffsetPrefixSize: merkleMap.offsetPrefixSize,\n\t\texclusions: merkleMap.exclusions,\n\t\talg: merkleMap.alg ?? undefined,\n\t})\n\tcache.push({\n\t\talg: merkleMap.alg,\n\t\toffsetPrefixSize: merkleMap.offsetPrefixSize,\n\t\texclusions: merkleMap.exclusions,\n\t\thash,\n\t})\n\treturn hash\n}\n\n/**\n * Validates a fragmented MP4 VOD media segment against the init manifest's\n * merkle maps (§15.12.2.2). Pure: the caller persists `nextState` and resets\n * `state` after a seek.\n *\n * `merkleMaps` must be non-empty; the caller is responsible for only calling\n * this in VOD Merkle mode (i.e. after `InitSegmentValidation.merkleMaps` came\n * back non-empty).\n *\n * @example\n * {@includeCode ../../test/merkle/validateC2paMerkleSegment.test.ts#example}\n *\n * @public\n */\nexport async function validateC2paMerkleSegment(\n\tsegmentBytes: Uint8Array,\n\tmerkleMaps: readonly MerkleMap[],\n\tstate?: MerkleSegmentState,\n): Promise<{\n\treadonly result: MerkleSegmentValidation\n\treadonly nextState: MerkleSegmentState\n}> {\n\tconst previousLocations = state?.lastLocations ?? new Map<string, number>()\n\tconst nextLocations = new Map(previousLocations)\n\tconst codes = new Set<MerkleValidationCode>()\n\tconst leafHashCache: LeafHashCache = []\n\tlet location: number | null = null\n\tlet bmffHashHex: string | null = null\n\n\tconst payloads = extractMerkleAuxBoxes(segmentBytes)\n\tif (payloads.length === 0) {\n\t\tcodes.add(C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED)\n\t}\n\n\tfor (const payload of payloads) {\n\t\tconst segmentMap = parseBmffMerkleMap(payload)\n\t\tif (!segmentMap) {\n\t\t\tcodes.add(C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED)\n\t\t\tcontinue\n\t\t}\n\n\t\tconst merkleMap = findMerkleMap(merkleMaps, segmentMap.uniqueId, segmentMap.localId)\n\t\tif (!merkleMap) {\n\t\t\tcodes.add(C2paStatusCode.ASSERTION_BMFFHASH_MALFORMED)\n\t\t\tcontinue\n\t\t}\n\n\t\tif (location === null) location = segmentMap.location\n\n\t\t// §15.12.2: each track's location must increment by 1 during sequential playback.\n\t\tconst trackKey = `${segmentMap.uniqueId}:${segmentMap.localId}`\n\t\tconst lastLocation = previousLocations.get(trackKey)\n\t\tconst locationValid = lastLocation === undefined || segmentMap.location === lastLocation + 1\n\t\tif (!locationValid) {\n\t\t\tcodes.add(LiveVideoStatusCode.ASSERTION_INVALID)\n\t\t}\n\n\t\tconst leafHash = await computeLeafHash(segmentBytes, merkleMap, leafHashCache)\n\t\tif (bmffHashHex === null) bmffHashHex = bytesToHex(leafHash)\n\t\tconst proofResult = await verifyMerkleProof(leafHash, segmentMap.location, segmentMap.hashes, merkleMap)\n\t\tif (proofResult === 'ok') {\n\t\t\t// Advance on any proof-verified location, even a discontinuous one: it's\n\t\t\t// genuinely signed content, so it resyncs continuity checking after a gap\n\t\t\t// instead of leaving every later segment flagged relative to a stale baseline.\n\t\t\tnextLocations.set(trackKey, segmentMap.location)\n\t\t} else {\n\t\t\tcodes.add(proofResult)\n\t\t}\n\t}\n\n\treturn {\n\t\tresult: {\n\t\t\tlocation,\n\t\t\tbmffHashHex,\n\t\t\tisValid: codes.size === 0,\n\t\t\terrorCodes: [...codes],\n\t\t},\n\t\tnextState: { lastLocations: nextLocations },\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;AAYA,MAAa,sBAAsB;CAElC,cAAc;CAEd,kBAAkB;CAElB,iBAAiB;CAMjB,mBAAmB;CAEnB,2BAA2B;CAE3B,+BAA+B;CAE/B,oBAAoB;CACpB;;;;AC5BD,MAAM,6BAA6B;AACnC,MAAM,gCAAgC;AACtC,MAAM,iCAAiC;AACvC,MAAM,0BAA0B;AAChC,MAAM,eAAe;AACrB,MAAM,eAAe;AAIrB,SAASA,UAAQ,QAAoB,KAAsB;AAC1D,KAAI,kBAAkB,IAAK,QAAO,OAAO,IAAI,IAAI;AACjD,QAAQ,OAA4C;;AAGrD,SAAS,aAAa,OAA+B;AACpD,KAAI,MAAM,OAAO,2BAA4B,QAAO,MAAM,SAAS,EAAE;AACrE,KAAI,MAAM,OAAO,iCAAiC,MAAM,OAAO,+BAAgC,QAAO,MAAM,SAAS,EAAE;AACvH,QAAO;;AAGR,SAASC,eAAa,OAA4B;AACjD,KAAI,iBAAiB,WAAY,QAAO;AACxC,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,IAAI,WAAW,MAAkB;AAClE,OAAM,IAAI,MAAM,wCAAwC,OAAO,QAAQ;;;;;;;;;;;;;;;;AAiBxE,SAAgB,gBAAgB,WAAkC;AACjE,KAAI;EAEH,MAAM,YAAY,OADD,aAAa,UAAU,CACN;AAElC,MAAI,CAAC,MAAM,QAAQ,UAAU,IAAI,UAAU,WAAW,wBACrD,OAAM,IAAI,MAAM,+DAA+D;EAGhF,MAAM,CAAC,cAAc,gBAAgB,YAAY,gBAAgB;EAEjE,MAAM,iBAAiBA,eAAa,aAAa;EACjD,IAAIC,kBAA8B,EAAE;AACpC,MAAI,eAAe,SAAS,EAC3B,mBAAkB,OAAO,eAAe;EAGzC,MAAM,oBAAqB,kBAAkB,EAAE;EAC/C,MAAM,SAASF,UAAQ,iBAAiB,aAAa,IAAIA,UAAQ,mBAAmB,aAAa,IAAI;EACrG,MAAM,MAAM,UAAU,OAAOC,eAAa,OAAO,GAAG;EACpD,MAAM,MAAOD,UAAQ,iBAAiB,aAAa,IAAIA,UAAQ,mBAAmB,aAAa,IAAI;AAEnG,SAAO;GACN;GACiB;GACE;GACnB,SAAS,cAAc,OAAO,OAAOC,eAAa,WAAW;GAC7D,WAAWA,eAAa,aAAa;GACrC;GACA;GACA;UAEK,OAAO;AACb,QAAM,IAAI,MAAM,gCAAiC,MAAgB,UAAU;;;;;;;;;;;;;;;;;;;;AC3D7E,SAAgB,gBAAgB,OAA+B;AAC9D,QAAO,aAAa,MAAM,CAAC,KAAI,SAAQ;EACtC,MAAM,IAAI;EACV,MAAM,IAAI,KAAK,SAAS,IAAI,KAAK,eAAe;EAChD,EAAE;;;;;ACrBJ,MAAME,iCAA+B,IAAI,aAAa;AACtD,MAAM,iBAAiB;AACvB,MAAM,sBAAsB;AAC5B,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;AACxB,MAAM,sBAAsB;;;;;;;;;;;;;;;AAgB5B,SAAgB,gBAAgB,UAAqC;AACpE,KAAI,SAAS,SAAS,iBAAiB,EAAG,QAAO;AAGjD,MADgB,SAAS,uBACV,qBAAqB,oBAAqB,QAAO;CAEhE,IAAI,MAAM;AACV,QAAO,MAAM,SAAS,UAAU,SAAS,SAAS,EAAG;AACrD,KAAI,OAAO,SAAS,OAAQ,QAAO;AAEnC,QAAOA,eAAa,OAAO,SAAS,SAAS,kBAAkB,IAAI,CAAC;;;;;AC7BrE,MAAM,0BAA0B;AAChC,MAAM,wBAAwB;;;;;;;;AAS9B,SAAgB,uBAAuB,QAAyB;AAC/D,SAAQ,UAAU,WAAW,QAAQ,uBAAuB,SAAS;;AAGtE,MAAMC,YAA+C,sBAAM,KAAK,EAAE,QAAQ,KAAK,GAAG,GAAG,MAAM,EAAE,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC;;;;;;AAO3H,SAAgB,WAAW,OAA2B;CACrD,IAAI,MAAM;AACV,MAAK,MAAM,QAAQ,MAAO,QAAO,UAAU;AAC3C,QAAO;;;;;;;;;;;;;AAcR,SAAgB,aAAa,WAAmB,uBAA+B,sBAAY,IAAI,MAAM,EAAW;CAC/G,MAAM,cAAc,IAAI,KAAK,UAAU,CAAC,SAAS;AACjD,KAAI,OAAO,MAAM,YAAY,CAAE,QAAO;AAEtC,QAAO,MADa,IAAI,KAAK,cAAc,wBAAwB,wBAAwB;;;;;;;AAS5F,SAAgB,YAAY,GAAe,GAAwB;AAClE,KAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;CAClC,IAAI,OAAO;AACX,MAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,SAAQ,EAAE,KAAK,EAAE;AACpD,QAAO,SAAS;;AAIjB,MAAMC,qBAAwC;CAC7C;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAC1C;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAC1C;;AAID,MAAaC,aAAgC;CAC5C;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAC1C;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAC1C;;AAID,SAAgB,YAAY,UAA6B,UAAsC;AAC9F,QAAO,SAAS,WAAW,SAAS,UAAU,SAAS,OAAO,GAAG,MAAM,MAAM,SAAS,GAAG;;;AAK1F,SAAgB,aAAa,OAAmC;AAC/D,KAAI,iBAAiB,WAAY,QAAO;AACxC,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,IAAI,WAAW,MAAkB;AAClE,QAAO;;;AAIR,SAAgB,UAAU,OAA+B;AACxD,QAAO,OAAO,UAAU,YAAY,OAAO,UAAU,MAAM,GAAG,QAAQ;;AAGvE,SAAS,WAAW,UAAsC;AACzD,QAAO,YAAY,UAAU,mBAAmB,IAAI,YAAY,UAAU,WAAW;;;;;;;;;;AA2BtF,SAAgB,gBAAgB,OAAkD;AACjF,QAAQ,MAA0B,MACjC,QAAO,IAAI,SAAS,UAAU,WAAW,IAAI,YAAY,EAAE,CAAC,CAC5D;;AAGF,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAMC,iBAAe,IAAI,aAAa;;AAItC,SAAgB,mBAAmB,SAAmE;AACrG,KAAI,QAAQ,SAAS,oBAAqB,QAAO;CAEjD,IAAI,SAAS;AACb,QAAO,SAAS,QAAQ,UAAU,QAAQ,YAAY,EAAG;AACzD,KAAI,UAAU,QAAQ,OAAQ,QAAO;AAErC,QAAO;EACN,SAASA,eAAa,OAAO,QAAQ,SAAS,qBAAqB,OAAO,CAAC;EAC3E,MAAM,QAAQ,SAAS,SAAS,EAAE;EAClC;;;;;;;;;;;;;AAcF,SAAgB,qBAAqB,SAAwC;CAC5E,MAAM,SAAS,mBAAmB,QAAQ;AAC1C,KAAI,CAAC,UAAU,OAAO,KAAK,SAAS,qBAAsB,QAAO;AACjE,QAAO,OAAO,KAAK,SAAS,qBAAqB;;;;;;;;;;ACxJlD,MAAa,mBAAmB;AAChC,MAAa,6BAA6B;AAC1C,MAAa,oBAAoB;AACjC,MAAa,eAAe;AAC5B,MAAa,oBAAoB;AACjC,MAAa,4BAA4B;AACzC,MAAa,qBAAqB;AAClC,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AAQ5B,SAAgB,WAAW,OAAmB,QAAuD;AACpG,KAAI,UAAU,MAAM,OAAQ,QAAO;EAAE,QAAQ;EAAG,WAAW;EAAG;CAC9D,MAAM,QAAQ,MAAM,WAAW;AAC/B,KAAI,QAAQ,oBAAqB,QAAO;EAAE,QAAQ;EAAO,WAAW;EAAG;CACvE,MAAM,QAAQ,QAAQ;CACtB,IAAI,SAAS;AACb,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,IAC1B,UAAU,UAAU,KAAM,MAAM,SAAS,IAAI,MAAM;AAEpD,QAAO;EAAE;EAAQ,WAAW,IAAI;EAAO;;AAGxC,SAAgB,YAAY,OAAmB,QAAoC;AAClF,KAAI,SAAS,IAAI,MAAM,OAAQ,QAAO;CACtC,MAAM,MAAM,MAAM,WAAW;CAC7B,MAAM,EAAE,QAAQ,cAAc,WAAW,OAAO,SAAS,EAAE;CAC3D,MAAM,aAAa,IAAI;CACvB,MAAM,WAAW,SAAS,aAAa;AACvC,KAAI,WAAW,MAAM,OAAQ,QAAO;AACpC,QAAO;EACN;EACA,OAAO,MAAM,SAAS,SAAS,YAAY,SAAS;EACpD,WAAW,aAAa;EACxB;;;;;;;AAQF,SAAgB,eAAe,OAAmB,QAAmC;CACpF,MAAM,KAAK,YAAY,OAAO,OAAO;AACrC,KAAI,CAAC,GAAI,QAAO;AAChB,QAAO,MAAM,SAAS,QAAQ,SAAS,GAAG,UAAU;;;;;ACxDrD,MAAMC,iCAA+B,IAAI,aAAa;AAetD,MAAM,kBAAkB,IAAI,WAAW;CAAC;CAAM;CAAM;CAAK,CAAC;AAC1D,MAAM,eAAe,IAAI,WAAW;CAAC;CAAM;CAAM;CAAK,CAAC;AAEvD,SAAS,WAAW,OAAmB,KAA0B;AAChE,KAAI,MAAM,SAAS,IAAI,OAAQ,QAAO;AACtC,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,IAC/B,KAAI,MAAM,OAAO,IAAI,GAAI,QAAO;AAEjC,QAAO;;AAGR,SAAS,UAAU,SAAqC;CACvD,MAAM,OAAOA,eAAa,OAAO,QAAQ,MAAM;AAC/C,KAAI,QAAQ,QAAQ,mBAAmB;EACtC,MAAM,KAAK,SAAS,KAAK,UAAU,GAAG,EAAE,EAAE,GAAG;AAE7C,SAAO,GADM,MAAM,KAAK,OAAO,KAAK,MAAO,GAC5B,GAAG,KAAK,UAAU,GAAG,EAAE,CAAC,GAAG,KAAK,UAAU,GAAG,EAAE,CAAC,GAAG,KAAK,UAAU,GAAG,EAAE,CAAC,GAAG,KAAK,UAAU,GAAG,GAAG,CAAC,GAAG,KAAK,UAAU,IAAI,GAAG,CAAC;;AAE3I,KAAI,QAAQ,QAAQ,0BACnB,QAAO,GAAG,KAAK,UAAU,GAAG,EAAE,CAAC,GAAG,KAAK,UAAU,GAAG,EAAE,CAAC,GAAG,KAAK,UAAU,GAAG,EAAE,CAAC,GAAG,KAAK,UAAU,GAAG,GAAG,CAAC,GAAG,KAAK,UAAU,IAAI,GAAG,CAAC,GAAG,KAAK,UAAU,IAAI,GAAG,CAAC;AAE7J,QAAO;;AAGR,SAAS,uBAAuB,UAAsB,WAAsC;CAC3F,MAAM,QAAQ,YAAY,UAAU,EAAE;AACtC,KAAI,CAAC,SAAS,MAAM,QAAQ,2BAA4B,QAAO;AAC/D,KAAI,CAAC,WAAW,MAAM,OAAO,UAAU,CAAE,QAAO;CAEhD,MAAM,QAAQ,YAAY,UAAU,MAAM,UAAU;AACpD,QAAO,QAAQA,eAAa,OAAO,MAAM,MAAM,GAAG;;AAGnD,SAAS,aAAa,aAAyB,WAAsC;CACpF,IAAI,SAAS;AACb,QAAO,SAAS,YAAY,QAAQ;EACnC,MAAM,QAAQ,YAAY,aAAa,OAAO;AAC9C,MAAI,CAAC,SAAS,MAAM,QAAQ,aAAc;EAE1C,IAAI,YAAY;AAChB,SAAO,YAAY,MAAM,MAAM,QAAQ;GACtC,MAAM,QAAQ,YAAY,MAAM,OAAO,UAAU;AACjD,OAAI,CAAC,SAAS,MAAM,QAAQ,kBAAmB;GAE/C,MAAM,QAAQ,uBAAuB,MAAM,OAAO,UAAU;AAC5D,OAAI,MAAO,QAAO;AAElB,gBAAa,MAAM;;AAEpB,YAAU,MAAM;;AAEjB,QAAO;;;;;;;;;;;;;;;;;AAkBR,SAAgB,uBAAuB,SAA6C;AACnF,KAAI;EACH,MAAM,OAAO,YAAY,SAAS,EAAE;AACpC,MAAI,CAAC,QAAQ,KAAK,QAAQ,kBAAmB,QAAO;EAEpD,MAAM,MAAM,YAAY,KAAK,OAAO,EAAE;AACtC,MAAI,CAAC,OAAO,IAAI,QAAQ,kBAAmB,QAAO;EAElD,IAAI,SAAS;EACb,IAAI,KAAK,YAAY,IAAI,OAAO,OAAO;AACvC,MAAI,CAAC,GAAI,QAAO;AAGhB,MAAI,GAAG,QAAQ,oBAAoB;AAClC,aAAU,GAAG;AACb,QAAK,YAAY,IAAI,OAAO,OAAO;AACnC,OAAI,CAAC,GAAI,QAAO;;AAIjB,MAAI,GAAG,QAAQ,iBAAkB,QAAO;AACxC,YAAU,GAAG;AAGb,OAAK,YAAY,IAAI,OAAO,OAAO;AACnC,MAAI,CAAC,MAAM,GAAG,QAAQ,kBAAmB,QAAO;AAChD,YAAU,GAAG;AAGb,OAAK,YAAY,IAAI,OAAO,OAAO;AACnC,MAAI,CAAC,MAAM,GAAG,QAAQ,kBAAmB,QAAO;EAChD,MAAM,SACL,aAAa,GAAG,OAAO,gBAAgB,IACvC,aAAa,GAAG,OAAO,aAAa,IACpC;AACD,YAAU,GAAG;AAGb,OAAK,YAAY,IAAI,OAAO,OAAO;EACnC,IAAIC,YAA2B;AAC/B,MAAI,MAAM,GAAG,QAAQ,mBAAmB;GACvC,MAAM,SAAS,YAAY,GAAG,OAAO,EAAE;AACvC,OAAI,OAAQ,aAAY,UAAU,OAAO;;AAG1C,SAAO;GAAE;GAAQ;GAAW;SAEvB;AACL,SAAO;;;;;;ACpIT,MAAM,+BAA+B,IAAI,aAAa;AAgBtD,MAAM,0BAA0B;AAChC,MAAM,uBAAuB;AAE7B,SAAS,qBAAqB,YAAwB,QAAQ,GAAe;AAC5E,KAAI,SAAS,wBAAyB,QAAO;CAG7C,MAAM,eAAe,WAAW,QAAO,MAAK,EAAE,SAAS,OAAO;CAI9D,MAAM,WAAW,aAAa;AAC9B,KAAI,aAAa,WAAW,KAAK,UAAU,SAAS,OACnD,QAAO,qBAAqB,gBAAgB,SAAS,KAAK,EAAE,QAAQ,EAAE;AAGvE,QAAO;;AAGR,SAAS,qBAAqB,YAAuC;AAEpE,MAAK,MAAM,OAAO,YAAY;AAC7B,MAAI,IAAI,SAAS,OAAQ;EACzB,MAAM,QAAQ,gBAAgB,IAAI,KAAK;AACvC,OAAK,MAAM,SAAS,OAAO;AAC1B,OAAI,MAAM,SAAS,OAAQ;GAE3B,MAAM,OADa,gBAAgB,MAAM,KAAK,CACtB,MAAK,MAAK,EAAE,SAAS,OAAO;AACpD,OAAI,MAAM;IACT,MAAM,QAAQ,gBAAgB,KAAK,KAAK;AACxC,QAAI,MAAO,QAAO;;;;AAIrB,QAAO;;AAGR,SAAS,wBAAwB,qBAA0D;CAC1F,MAAMC,aAAsC,EAAE;AAE9C,MAAK,MAAM,OAAO,qBAAqB;AACtC,MAAI,IAAI,SAAS,OAAQ;EACzB,MAAM,QAAQ,gBAAgB,IAAI,KAAK;EAEvC,MAAM,OAAO,MAAM,MAAK,MAAK,EAAE,SAAS,OAAO;AAC/C,MAAI,CAAC,KAAM;EAEX,MAAM,QAAQ,gBAAgB,KAAK,KAAK;AACxC,MAAI,CAAC,MAAO;EAEZ,MAAM,aAAa,MAAM,MACxB,MAAK,EAAE,SAAS,UAAU,EAAE,SAAS,UAAU,EAAE,SAAS,UAAU,EAAE,SAAS,UAAU,EAAE,SAAS,OACpG;EAED,IAAIC,OAAgB;AACpB,MAAI,WACH,KAAI,WAAW,SAAS,OACvB,KAAI;AAAE,UAAO,OAAO,WAAW,KAAK;UAAoB;AAAE,UAAO,WAAW;;WAEpE,WAAW,SAAS,OAC5B,KAAI;AAAE,UAAO,KAAK,MAAM,aAAa,OAAO,WAAW,KAAK,CAAC;UAAoB;AAAE,UAAO,WAAW;;MAGrG,QAAO,WAAW;AAIpB,aAAW,KAAK;GAAE;GAAO;GAAM,eAAe,IAAI;GAAM,CAAC;;AAG1D,QAAO;;AAGR,SAAS,mBAAmB,gBAA4F;AACvH,KAAI,CAAC,eAAgB,QAAO;EAAE,QAAQ;EAAM,eAAe;EAAM;AACjE,KAAI;EACH,MAAM,OAAO,gBAAgB,eAAe;EAC5C,MAAM,UAAW,KAAK,gBAAgB,yBAAyB,KAAK,kBAAkB;AACtF,MAAI,CAAC,QAAS,QAAO;GAAE,QAAQ;GAAM,eAAe;GAAM;EAE1D,MAAM,UAAU,MAAM,QAAQ,QAAQ,GAAG,QAAQ,KAAK;AACtD,MAAI,EAAE,mBAAmB,YAAa,QAAO;GAAE,QAAQ;GAAM,eAAe;GAAM;EAElF,MAAM,WAAW,uBAAuB,QAAQ;AAChD,SAAO;GAAE,QAAQ,UAAU,UAAU;GAAM,eAAe,UAAU,aAAa;GAAM;SAChF;AAEP,SAAO;GAAE,QAAQ;GAAM,eAAe;GAAM;;;AAI9C,SAAS,0BAA0B,WAAyD;CAC3F,MAAM,UAAU,UAAU;CAC1B,MAAM,WAAW,UAAU;CAC3B,MAAM,KAAK,UAAU;CAErB,MAAM,UAAU;EAAC,GAAI,WAAW,EAAE;EAAG,GAAI,YAAY,EAAE;EAAG,GAAI,MAAM,EAAE;EAAE;CACxE,MAAMC,OAA4B,EAAE;AAEpC,MAAK,MAAM,SAAS,SAAS;AAC5B,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU;EACzC,MAAM,IAAI;EACV,MAAM,MAAM,EAAE;EACd,MAAM,OAAO,EAAE;AACf,MAAI,CAAC,OAAO,CAAC,KAAM;AAEnB,OAAK,KAAK;GACT;GACA,MAAM,gBAAgB,aAAa,OAAO,IAAI,WAAW,KAAiB;GAC1E,KAAM,EAAE,UAAiC;GACzC,CAAC;;AAGH,QAAO;;;;;;;;;;;;;;;;;;;;;;AAuBR,SAAgB,iBAAiB,OAAmB,gBAAuD;CAE1G,MAAM,UAAU,gBADF,kBAAkB,aAAa,MAAM,CACb;AAEtC,KAAI,CAAC,QACJ,OAAM,IAAI,MAAM,+CAA+C;CAIhE,MAAM,eAAe,qBADF,QAAQ,KAAK,SAAS,QAAQ,KAAK,eAAe,CAChB;AACrD,KAAI,CAAC,aACJ,OAAM,IAAI,MAAM,wCAAwC;CAEzD,MAAM,aAAa,gBAAgB,aAAa;AAEhD,KAAI,WAAW,WAAW,EACzB,OAAM,IAAI,MAAM,wCAAwC;CAGzD,MAAM,gBAAgB,qBAAqB,WAAW;CACtD,MAAM,gBAAgB,qBAAqB,WAAW;CAEtD,IAAIC,YAA4C;CAChD,IAAIC,iBAAoC;CACxC,IAAIC,qBAA8C,EAAE;CACpD,IAAIC,iBAAoC;AAExC,MAAK,MAAM,OAAO,eAAe;AAChC,MAAI,IAAI,SAAS,OAAQ;EAEzB,MAAM,QAAQ,gBAAgB,IAAI,KAAK;EACvC,MAAM,OAAO,MAAM,MAAK,MAAK,EAAE,SAAS,OAAO;AAC/C,MAAI,CAAC,KAAM;EAEX,MAAM,QAAQ,gBAAgB,KAAK,KAAK;AACxC,MAAI,CAAC,MAAO;AAEZ,MAAI,UAAU,gBAAgB,UAAU,iBAAiB;GACxD,MAAM,aAAa,MAAM,MAAK,MAAK,EAAE,SAAS,OAAO;AACrD,OAAI,YAAY;AACf,qBAAiB,WAAW;AAC5B,QAAI;AAAE,iBAAY,OAAO,WAAW,KAAK;YAAoC;;aAGtE,UAAU,kBAClB,sBAAqB,wBAAwB,MAAM;WAE3C,UAAU,kBAAkB;GACpC,MAAM,aAAa,MAAM,MAAK,MAAK,EAAE,SAAS,UAAU,EAAE,SAAS,OAAO;AAC1E,OAAI,WAAY,kBAAiB,WAAW;;;CAI9C,MAAM,EAAE,QAAQ,kBAAkB,mBAAmB,eAAe;CAEpE,MAAM,aAAc,YAAY,iBAAiB,YAAY,kBAAkB;CAC/E,MAAM,iBAAkB,YAAY,sBAAsB,YAAY,qBAAqB;CAC3F,MAAM,gBACL,iBACC,YAAY,eACZ,YAAY,YACb,cACA;CAED,MAAM,qBAAqB,YAAY,0BAA0B,UAAU,GAAG,EAAE;CAEhF,MAAMC,aAA8B,mBAAmB,KAAI,OAAM;EAAE,OAAO,EAAE;EAAO,MAAM,EAAE;EAAM,EAAE;AAUnG,QAAO;EACN,UAT8B;GAC9B,OAAO;GACP;GACA;GACA,eAAe;IAAE;IAAQ;IAAe;GACxC;GACA;EAIA;EACA;EACA;EACA,YAAY;EACZ;;;;;ACxOF,SAAS,aAAa,SAAqB,QAAgB,UAAmD;CAC7G,MAAM,QAAQ,oBAAoB,aAAa,WAAW,IAAI,WAAW,SAAqB;AAC9F,KAAI,SAAS,MAAM,SAAS,QAAQ,OAAQ,QAAO;AACnD,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IACjC,KAAI,QAAQ,SAAS,OAAO,MAAM,GAAI,QAAO;AAE9C,QAAO;;AAGR,SAAS,kBAAkB,SAAqB,YAAyC;AACxF,QAAO,aAAa,SAAS,WAAW,QAAQ,WAAW,MAAM;;;;;;;;;;;;;;;;;;;AAoBlE,SAAgB,iBACf,SACA,SACA,YACU;AACV,MAAK,MAAM,aAAa,YAAY;AACnC,MAAI,CAAC,UAAU,MAAO;AAEtB,MAAI,EADqB,UAAU,UAAU,IAAI,aAAa,UAAU,MAAM,WAAW,IAAI,QAAQ,GAAG,EACjF;EACvB,MAAM,EAAE,SAAS;AACjB,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AACvC,MAAI,KAAK,OAAM,eAAc,kBAAkB,SAAS,WAAW,CAAC,CAAE,QAAO;;AAE9E,QAAO;;;;;AC1CR,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AAczB,SAAS,YAAY,OAAmB,QAAwB;AAC/D,QAAO,OAAO,aAAa,MAAM,SAAS,MAAM,SAAS,IAAI,MAAM,SAAS,IAAI,MAAM,SAAS,GAAG;;AAGnG,SAAS,qBAAqB,OAAmB,OAAqB;AACrE,KAAI,SAAS,MAAM,QAAQ,MAAM,YAAY,MAAM,WAAW,CAAC,aAAa,GAAG,OAAO,MAAM,EAAE,MAAM;;AAGrG,SAAS,eACR,OACA,YACA,kBACa;AACb,KAAI,qBAAqB,KAAK,qBAAqB,EAClD,OAAM,IAAI,MAAM,wCAAwC,mBAAmB;CAG5E,MAAM,OAAO,IAAI,SAAS,MAAM,QAAQ,MAAM,YAAY,MAAM,WAAW;CAG3E,IAAI,cAAc;CAClB,IAAI,SAAS;AACb,QAAO,SAAS,oBAAoB,MAAM,QAAQ;EACjD,MAAM,UAAU,KAAK,UAAU,QAAQ,MAAM;AAC7C,MAAI,UAAU,oBAAoB,SAAS,UAAU,MAAM,OAAQ;AAGnE,MAAI,CAAC,iBAFW,YAAY,OAAO,SAAS,gBAAgB,EAC5C,MAAM,SAAS,QAAQ,SAAS,QAAQ,EAChB,WAAW,CAClD,gBAAe,mBAAmB;AAEnC,YAAU;;CAIX,MAAM,YAAY,IAAI,WAAW,YAAY;CAC7C,IAAI,cAAc;AAClB,UAAS;AACT,QAAO,SAAS,oBAAoB,MAAM,QAAQ;EACjD,MAAM,UAAU,KAAK,UAAU,QAAQ,MAAM;AAC7C,MAAI,UAAU,oBAAoB,SAAS,UAAU,MAAM,OAAQ;EACnE,MAAM,UAAU,YAAY,OAAO,SAAS,gBAAgB;EAC5D,MAAM,UAAU,MAAM,SAAS,QAAQ,SAAS,QAAQ;AACxD,MAAI,CAAC,iBAAiB,SAAS,SAAS,WAAW,EAAE;AACpD,OAAI,mBAAmB,GAAG;AACzB,yBAAqB,UAAU,SAAS,aAAa,cAAc,iBAAiB,EAAE,OAAO;AAC7F,mBAAe;;AAEhB,aAAU,IAAI,SAAS,YAAY;AACnC,kBAAe;;AAEhB,YAAU;;AAGX,QAAO;;;;;;;;;;;;;;;;;;AAmBR,eAAsB,gBAAgB,cAA0B,SAAgD;CAC/G,MAAM,aAAa,SAAS,cAAc,EAAE;CAC5C,MAAM,MAAM,SAAS,OAAO;CAG5B,MAAM,YAAY,eAAe,cAAc,YAFtB,SAAS,oBAAoB,EAEsB;CAC5E,MAAM,aAAa,MAAM,OAAO,OAAO,OAAO,KAAK,UAAU;AAC7D,QAAO,IAAI,WAAW,WAAW;;;;;;;;;;;;;;;ACtFlC,MAAa,iBAAiB;CAE7B,8BAA8B;CAE9B,mBAAmB;CAEnB,sCAAsC;CAEtC,0BAA0B;CAE1B,yBAAyB;CAEzB,eAAe;CAEf,8BAA8B;CAE9B,6BAA6B;CAC7B;;;;ACrBD,MAAM,sBAAsB;;;;;;AAO5B,SAAgB,qCAAqC,gBAA+C;AACnG,KAAI;EACH,MAAM,OAAO,gBAAgB,eAAe;EAC5C,MAAM,UAAW,KAAK,gBAAgB,wBACrC,KAAK,kBAAkB;AACxB,MAAI,CAAC,QAAS,QAAO;EAErB,MAAM,UAAU,MAAM,QAAQ,QAAQ,GAAG,QAAQ,KAAK;AACtD,SAAO,mBAAmB,aAAa,UAAU;SAC1C;AACP,SAAO;;;;;;ACvBT,MAAM,iBAAiB,IAAI,IAAI,CAAC,gBAAgB,kBAAkB,CAAC;AACnE,MAAM,gCAAgC,IAAI,IAAI;CAAC;CAAe;CAAe;CAAe,CAAC;;;;;;;;;;;;;;AAe7F,SAAgB,0BACf,YAC4B;CAC5B,MAAMC,QAA0B,EAAE;AAElC,MAAK,MAAM,aAAa,YAAY;AACnC,MAAI,CAAC,eAAe,IAAI,UAAU,MAAM,CAAE;EAE1C,MAAM,OAAO,UAAU;AACvB,MAAI,CAAC,KAAM;EAEX,MAAM,UAAU,KAAK;AACrB,MAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE;AAE7B,OAAK,MAAM,UAAU,SAAS;AAC7B,OAAI,CAAC,UAAU,OAAO,WAAW,SAAU;GAC3C,MAAM,SAAS;GACf,MAAM,aAAa,OAAO;AAC1B,OAAI,CAAC,cAAc,CAAC,8BAA8B,IAAI,WAAW,CAAE;GAGnE,MAAM,cADa,OAAO,gBACO;AAEjC,OAAI,CAAC,MAAM,QAAQ,YAAY,IAAI,YAAY,WAAW,EACzD,OAAM,KAAK,eAAe,qCAAqC;;;AAKlE,QAAO;;;;;;;;;;;ACpCR,SAAS,oBAAoB,KAAqB;CACjD,MAAM,gBAAgB,IAAI,QAAQ,UAAU;CAC5C,MAAM,OAAO,iBAAiB,IAAI,IAAI,UAAU,gBAAgB,EAAE,GAAG;CACrE,MAAM,YAAY,KAAK,YAAY,IAAI;AACvC,QAAO,aAAa,IAAI,KAAK,UAAU,YAAY,EAAE,GAAG;;;;;;;;;;;;;;;;AAiBzD,eAAsB,wBACrB,WACA,YACqC;AACrC,KAAI,UAAU,WAAW,EAAG,QAAO,EAAE;CAErC,MAAM,oCAAoB,IAAI,KAAoC;AAClE,MAAK,MAAM,aAAa,WACvB,mBAAkB,IAAI,UAAU,OAAO,UAAU;CAGlD,MAAMC,QAA0B,EAAE;CAElC,MAAM,aAAa,UAAU,IAAI,OAAO,QAAQ;EAC/C,MAAM,QAAQ,oBAAoB,IAAI,IAAI;EAC1C,MAAM,YAAY,kBAAkB,IAAI,MAAM;AAE9C,MAAI,CAAC,UACJ,QAAO,eAAe;EAGvB,MAAM,MAAM,IAAI,MAAM,uBAAuB,IAAI,IAAI,GAAG;AAKxD,MAAI,CAAC,YAJgB,IAAI,WACxB,MAAM,OAAO,OAAO,OAAO,KAAK,UAAU,cAAc,CACxD,EAE8B,IAAI,KAAK,CACvC,QAAO,eAAe;AAGvB,SAAO;GACN;CAEF,MAAM,UAAU,MAAM,QAAQ,IAAI,WAAW;AAC7C,MAAK,MAAM,UAAU,QACpB,KAAI,OAAQ,OAAM,KAAK,OAAO;AAG/B,QAAO;;;;;ACrER,MAAa,kBAAkB;AAC/B,MAAa,oBAAoB;AACjC,MAAa,oBAAoB;AAGjC,MAAa,aAAa;AAC1B,MAAa,aAAa;AAC1B,MAAa,aAAa;AAG1B,MAAa,cAAc;AAC3B,MAAa,cAAc;AAC3B,MAAa,cAAc;;;;ACS3B,MAAM,qBAAqB,IAAI,IAA2B;CACzD,CAXsB,IAWL;EAAE,MAAM;EAAiB,YAAY;EAAY,CAAC;CACnE,CAXsB,KAWL;EAAE,MAAM;EAAiB,YAAY;EAAY,CAAC;CACnE,CAXsB,KAWL;EAAE,MAAM;EAAiB,YAAY;EAAY,CAAC;CACnE,CAXsB,IAWL,EAAE,MAAM,mBAAmB,CAAC;CAC7C,CAXsB,KAWL;EAAE,MAAM;EAAmB,MAAM,EAAE,MAAM,aAAa;EAAE,CAAC;CAC1E,CAXsB,KAWL;EAAE,MAAM;EAAmB,MAAM,EAAE,MAAM,aAAa;EAAE,CAAC;CAC1E,CAXsB,KAWL;EAAE,MAAM;EAAmB,MAAM,EAAE,MAAM,aAAa;EAAE,CAAC;CAC1E,CAAC;;;;;;;;;;;AAYF,SAAgB,4BAA4B,SAAgC;CAC3E,MAAM,YAAY,mBAAmB,IAAI,QAAQ;AACjD,KAAI,CAAC,UACJ,OAAM,IAAI,MAAM,+BAA+B,UAAU;AAE1D,QAAO;;;;;AC/CR,MAAM,wBAAwB;AAC9B,MAAM,4BAA4B;AAClC,MAAM,6BAA6B;AACnC,MAAM,8BAA8B;AACpC,MAAM,+BAA+B;AACrC,MAAM,+BAA+B;AACrC,MAAM,kBAAkB;AACxB,MAAM,iBAAiB;AACvB,MAAM,kBAAkB;AACxB,MAAM,0BAA0C,oBAAI,aAAa,CAAC,OAAO,aAAa;AAEtF,SAAS,qBAAqB,QAAwB;AACrD,KAAI,UAAU,gBAAiB,QAAO;AACtC,KAAI,UAAU,eAAgB,QAAO;AACrC,KAAI,UAAU,gBAAiB,QAAO;AACtC,QAAO;;AAGR,SAAS,sBAAsB,QAAoB,QAAgB,QAAwB;AAC1F,KAAI,UAAU,gBACb,QAAO,YAAY,6BAA6B;UACtC,UAAU,gBAAgB;AACpC,SAAO,YAAY;AACnB,SAAO,YAAY;YACT,UAAU,iBAAiB;AACrC,SAAO,YAAY;AACnB,SAAO,YAAa,UAAU,IAAK;AACnC,SAAO,YAAY,SAAS;QACtB;AACN,SAAO,YAAY;AACnB,SAAO,YAAa,WAAW,KAAM;AACrC,SAAO,YAAa,WAAW,KAAM;AACrC,SAAO,YAAa,WAAW,IAAK;AACpC,SAAO,YAAY,SAAS;;AAE7B,QAAO;;;;;;;;;;;;;;;;;AAkBR,SAAgB,kBACf,gBACA,SACA,cAA0B,IAAI,WAAW,EAAE,EAC9B;CACb,MAAM,cACL,IACM,wBAAwB,SAC5B,qBAAqB,eAAe,OAAO,GAAG,eAAe,SAC7D,qBAAqB,YAAY,OAAO,GAAG,YAAY,SACvD,qBAAqB,QAAQ,OAAO,GAAG,QAAQ;CAElD,MAAM,SAAS,IAAI,WAAW,YAAY;CAC1C,IAAI,SAAS;AAEb,QAAO,YAAY;AACnB,QAAO,YAAY,4BAA4B,wBAAwB;AACvE,QAAO,IAAI,yBAAyB,OAAO;AAC3C,WAAU,wBAAwB;AAElC,UAAS,sBAAsB,QAAQ,QAAQ,eAAe,OAAO;AACrE,QAAO,IAAI,gBAAgB,OAAO;AAClC,WAAU,eAAe;AAEzB,UAAS,sBAAsB,QAAQ,QAAQ,YAAY,OAAO;AAClE,QAAO,IAAI,aAAa,OAAO;AAC/B,WAAU,YAAY;AAEtB,UAAS,sBAAsB,QAAQ,QAAQ,QAAQ,OAAO;AAC9D,QAAO,IAAI,SAAS,OAAO;AAE3B,QAAO;;;;;ACtER,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;AAExB,MAAMC,wBAAgD;EAAG,aAAa;EAAK,aAAa;EAAK,aAAa;CAAI;AAK9G,MAAMC,sBAA8C;EAClD,cAAc;EACd,cAAc;EACd,cAAc;CACf;AAED,SAAS,iBAAiB,WAA8B;CACvD,MAAM,QAAS,UAAU,UAA6B;CACtD,MAAM,OAAO,sBAAsB;AACnC,KAAI,CAAC,KAAM,OAAM,IAAI,MAAM,yBAAyB,QAAQ;AAC5D,QAAO;;AAGR,SAAS,aAAa,WAAuB,mBAAoC;AAChF,QAAO,UAAU,WAAW,qBAAqB,UAAU,SAAS,KAAK,UAAU,OAAO;;AAG3F,SAAS,eAAe,KAAiB,QAAwD;AAChG,KAAI,UAAU,IAAI,OAAQ,OAAM,IAAI,MAAM,kCAAkC;CAC5E,MAAM,YAAY,IAAI;AACtB,MAAK,YAAY,SAAU,EAC1B,QAAO;EAAE,QAAQ;EAAW,YAAY,SAAS;EAAG;CAErD,MAAM,WAAW,YAAY;AAC7B,KAAI,aAAa,KAAK,SAAS,YAAY,IAAI,OAAQ,OAAM,IAAI,MAAM,0CAA0C;CACjH,IAAI,SAAS;AACb,MAAK,IAAI,IAAI,GAAG,KAAK,UAAU,IAC9B,UAAU,UAAU,IAAK,IAAI,SAAS;AAEvC,QAAO;EAAE;EAAQ,YAAY,SAAS,IAAI;EAAU;;AAGrD,SAAS,kBACR,KACA,QAC4C;AAC5C,KAAI,IAAI,YAAY,gBAAiB,OAAM,IAAI,MAAM,sCAAsC;CAC3F,MAAM,EAAE,QAAQ,YAAY,eAAe,eAAe,KAAK,SAAS,EAAE;CAC1E,IAAI,QAAQ;CACZ,IAAI,YAAY;AAChB,KAAI,YAAY,KAAK,IAAI,WAAW,GAAM;AACzC;AACA;;AAED,QAAO;EAAE,OAAO,IAAI,MAAM,OAAO,QAAQ,UAAU;EAAE,YAAY,aAAa;EAAQ;;AAGvF,SAAS,uBAAuB,KAAiB,eAAmC;AACnF,KAAI,IAAI,OAAO,iBAAkB,OAAM,IAAI,MAAM,uCAAuC;CACxF,MAAM,EAAE,YAAY,iBAAiB,eAAe,KAAK,EAAE;CAC3D,MAAM,UAAU,kBAAkB,KAAK,aAAa;CACpD,MAAM,UAAU,kBAAkB,KAAK,QAAQ,WAAW;CAE1D,MAAM,YAAY,gBAAgB;CAClC,MAAM,MAAM,IAAI,WAAW,UAAU;AACrC,KAAI,IAAI,QAAQ,OAAO,gBAAgB,QAAQ,MAAM,OAAO;AAC5D,KAAI,IAAI,QAAQ,OAAO,YAAY,QAAQ,MAAM,OAAO;AACxD,QAAO;;AAGR,SAAS,uBAAuB,WAAsB;CACrD,MAAM,EAAE,SAAS,UAAU;AAC3B,KAAI,SAAS,kBAAmB,QAAO,EAAE,MAAM,mBAAmB;AAClE,KAAI,SAAS,iBAAiB;EAC7B,MAAM,QAAS,UAAU,UAA6B;AAEtD,SAAO;GAAE,MAAM;GAAiB,MAAM,EAAE,MAD3B,UAAU,aAAa,cAAc,UAAU,aAAa,cAAc,aACnC;GAAE;;AAEvD,KAAI,SAAS,kBAEZ,QAAO;EAAE,MAAM;EAAmB,YAAY,oBAD5B,UAAU,UAAoC,KAAK,SACU;EAAI;AAEpF,OAAM,IAAI,MAAM,qCAAqC,OAAO;;AAG7D,SAAS,mBAAmB,WAAuB,WAAkC;AACpF,KAAI,UAAU,UAAU,SAAS,gBAAiB,QAAO;CACzD,MAAM,gBAAgB,iBAAiB,UAAU;AACjD,KAAI,aAAa,WAAW,gBAAgB,EAAE,CAC7C,QAAO,uBAAuB,WAAW,cAAc;AAExD,QAAO;;;;;;;;;;;;;;;;;;;;;;AAuBR,eAAsB,gBACrB,WACA,SACA,WACmB;CACnB,MAAM,eAAe,kBAAkB,UAAU,gBAAgB,QAAQ;CACzE,MAAM,YAAY,uBAAuB,UAAU;CACnD,MAAM,YAAY,mBAAmB,UAAU,WAAW,UAAU;AACpE,QAAO,OAAO,OAAO,OAAO,WAAW,WAAW,WAAW,aAAa;;;;;;;;;;;;;;;;;;;;AC/G3E,SAAgB,uBAAuB,SAAwC;AAC9E,KAAI;EACH,MAAM,OAAO,YAAY,SAAS,EAAE;AACpC,MAAI,CAAC,QAAQ,KAAK,QAAQ,kBAAmB,QAAO;EAEpD,MAAM,MAAM,YAAY,KAAK,OAAO,EAAE;AACtC,MAAI,CAAC,OAAO,IAAI,QAAQ,kBAAmB,QAAO;EAElD,IAAI,SAAS;EACb,IAAI,KAAK,YAAY,IAAI,OAAO,OAAO;AACvC,MAAI,CAAC,GAAI,QAAO;AAGhB,MAAI,GAAG,QAAQ,oBAAoB;AAClC,aAAU,GAAG;AACb,QAAK,YAAY,IAAI,OAAO,OAAO;AACnC,OAAI,CAAC,GAAI,QAAO;;AAIjB,MAAI,GAAG,QAAQ,iBAAkB,QAAO;AACxC,YAAU,GAAG;AAGb,OAAK,YAAY,IAAI,OAAO,OAAO;AACnC,MAAI,CAAC,MAAM,GAAG,QAAQ,kBAAmB,QAAO;AAChD,YAAU,GAAG;AAGb,OAAK,YAAY,IAAI,OAAO,OAAO;AACnC,MAAI,CAAC,MAAM,GAAG,QAAQ,kBAAmB,QAAO;AAChD,YAAU,GAAG;AAGb,OAAK,YAAY,IAAI,OAAO,OAAO;AACnC,MAAI,CAAC,MAAM,GAAG,QAAQ,kBAAmB,QAAO;AAChD,YAAU,GAAG;AAGb,OAAK,YAAY,IAAI,OAAO,OAAO;AACnC,MAAI,CAAC,MAAM,GAAG,QAAQ,kBAAmB,QAAO;AAChD,YAAU,GAAG;AAGb,SAAO,eAAe,IAAI,OAAO,OAAO;SAEnC;AACL,SAAO;;;;;;ACnET,MAAM,iBAAiB,IAAI,WAAW;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAK,CAAC;AAIzG,MAAM,8BAA8B,IAAI,WAAW;CAClD;CAAM;CACN;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAC5D;CAAM;CACN,CAAC;AAEF,SAAS,kBAAkB,OAA4B;AACtD,KAAI,MAAM,SAAS,eAAe,OAAQ,QAAO;AACjD,OAAO,MAAK,IAAI,IAAI,GAAG,KAAK,MAAM,SAAS,eAAe,QAAQ,KAAK;AACtE,OAAK,IAAI,IAAI,GAAG,IAAI,eAAe,QAAQ,IAC1C,KAAI,MAAM,IAAI,OAAO,eAAe,GAAI,UAAS;AAElD,SAAO;;AAER,QAAO;;;;;;;;;;;;;;;AAgBR,SAAgB,oBAAoB,WAAmC;AACtE,KAAI,CAAC,kBAAkB,UAAU,CAAE,QAAO;CAG1C,MAAM,QAAQ,YAAY,WAAW,EAAE;AACvC,KAAI,CAAC,SAAS,MAAM,QAAQ,kBAAmB,QAAO;CAGtD,MAAM,QAAQ,YAAY,MAAM,OAAO,EAAE;AACzC,KAAI,CAAC,SAAS,MAAM,QAAQ,kBAAmB,QAAO;CAGtD,MAAM,qBAAqB,MAAM,MAAM,SAAS,MAAM,UAAU;CAGhE,MAAM,cAAc,4BAA4B,SAAS,mBAAmB;CAC5E,MAAM,cAAc,gBAAgB,YAAY;CAChD,MAAM,SAAS,IAAI,WAAW,IAAI,YAAY,SAAS,YAAY;CACnE,IAAI,SAAS;AACb,QAAO,YAAY;AACnB,QAAO,IAAI,aAAa,OAAO;AAC/B,WAAU,YAAY;AACtB,QAAO,IAAI,6BAA6B,OAAO;AAC/C,WAAU,4BAA4B;AACtC,QAAO,IAAI,oBAAoB,OAAO;AAEtC,QAAO;;AAGR,SAAS,gBAAgB,QAA4B;AACpD,KAAI,SAAS,IAAM,QAAO,IAAI,WAAW,CAAC,OAAO,CAAC;AAClD,KAAI,UAAU,IAAM,QAAO,IAAI,WAAW,CAAC,KAAM,OAAO,CAAC;AACzD,KAAI,UAAU,MAAQ,QAAO,IAAI,WAAW;EAAC;EAAO,UAAU,IAAK;EAAM,SAAS;EAAK,CAAC;AACxF,QAAO,IAAI,WAAW;EAAC;EAAO,UAAU,KAAM;EAAO,UAAU,IAAK;EAAM,SAAS;EAAK,CAAC;;;;;;;;;;;;;;;;;;;AClD1F,eAAsB,qBACrB,gBACA,gBACA,gBACmB;AACnB,KAAI;EACH,MAAM,YAAY,gBAAgB,eAAe;EAEjD,MAAM,UAAU,uBAAuB,eAAe;AACtD,MAAI,CAAC,QAAS,QAAO;EACrB,MAAM,YAAY,oBAAoB,QAAQ;AAE9C,MAAI,UAAU,OAAO,KAAM,QAAO;EAElC,MAAM,kBAAkB,4BAA4B,UAAU,IAAI;AAUlE,SAAO,gBAAgB,WAAW,gBARhB,MAAM,OAAO,OAAO,UACrC,QACA,IAAI,WAAW,UAAU,EACzB,iBACA,MACA,CAAC,SAAS,CACV,CAE2D;SAEvD;AACL,SAAO;;;;;;;;;;;ACjBT,eAAe,uBAAuB,EAAE,gBAAgB,kBAAsE;CAC7H,MAAM,cAAc,iBAAiB,qCAAqC,eAAe,GAAG;AAE5F,KAAI,CAAC,eAAgB,QAAO;EAAE,MAAMC,eAAK;EAAe;EAAa;AACrE,KAAI,CAAC,eAAgB,QAAO;EAAE,MAAMA,eAAK;EAAyB;EAAa;AAC/E,KAAI,CAAC,YAAa,QAAO;EAAE,MAAMA,eAAK;EAA0B;EAAa;AAG7E,QAAO;EAAE,MADc,MAAM,qBAAqB,gBAAgB,gBAAgB,YAAY,GAC9D,OAAOA,eAAK;EAA0B;EAAa;;;;;;;;;;;;;;;;;;;AAoBpF,eAAsB,0BAA0B,UAA4D;CAC3G,MAAM,CAAC,oBAAoB,aAAa,MAAM,QAAQ,IAAI,CACzD,wBAAwB,SAAS,oBAAoB,SAAS,WAAW,EACzE,uBAAuB,SAAS,CAChC,CAAC;CAEF,MAAMC,QAA0B,CAAC,GAAG,oBAAoB,GAAG,0BAA0B,SAAS,WAAW,CAAC;AAE1G,KAAI,UAAU,KACb,OAAM,KAAK,UAAU,KAAK;AAG3B,QAAO;EAAE;EAAO,aAAa,UAAU;EAAa;;;;;ACnErD,MAAM,eAAe;AACrB,MAAM,eAAe;AAGrB,MAAMC,iBAAyC;CAAE,GAAG;CAAS,GAAG;CAAS,GAAG;CAAS;AACrF,MAAMC,kBAA0C;CAAE,GAAG;CAAU,GAAG;CAAQ,GAAG;CAAW,GAAG;CAAS;AAIpG,SAAS,QAAQ,KAAkB,QAAyB;AAC3D,KAAI,eAAe,IAAK,QAAO,IAAI,IAAI,OAAO;AAC9C,QAAQ,IAAyC;;AAGlD,SAAS,YAAY,OAAwB;CAC5C,MAAM,QAAQ,iBAAiB,aAAa,QAAQ,IAAI,WAAW,MAAkB;CACrF,IAAI,SAAS;AACb,MAAK,MAAM,QAAQ,MAAO,WAAU,OAAO,aAAa,KAAK;AAC7D,QAAO,KAAK,OAAO,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,MAAM,GAAG;;;;;;;;;;;;;;;;;;AAmB9E,SAAgB,oBAAoB,SAA8B;CACjE,MAAM,MAAM;CACZ,MAAM,MAAM,QAAQ,KAAK,EAAE;CAC3B,MAAM,MAAM,QAAQ,KAAK,GAAG;CAC5B,MAAM,IAAI,QAAQ,KAAK,GAAG;AAE1B,KAAI,QAAQ,cAAc;EACzB,MAAM,YAAY,eAAe;AACjC,MAAI,CAAC,UAAW,OAAM,IAAI,MAAM,yBAAyB,MAAM;EAC/D,MAAM,IAAI,QAAQ,KAAK,GAAG;AAC1B,MAAI,EAAE,aAAa,YAAa,OAAM,IAAI,MAAM,0CAA0C;AAC1F,MAAI,EAAE,aAAa,YAAa,OAAM,IAAI,MAAM,0CAA0C;AAC1F,SAAO;GAAE,KAAK;GAAM,KAAK;GAAW,GAAG,YAAY,EAAE;GAAE,GAAG,YAAY,EAAE;GAAE;;AAG3E,KAAI,QAAQ,cAAc;EACzB,MAAM,YAAY,gBAAgB;AAClC,MAAI,CAAC,UAAW,OAAM,IAAI,MAAM,0BAA0B,MAAM;AAChE,SAAO;GAAE,KAAK;GAAO,KAAK;GAAW,GAAG,YAAY,EAAE;GAAE;;AAGzD,OAAM,IAAI,MAAM,8BAA8B,MAAM;;;;;AC3DrD,MAAM,eAAe;AAErB,SAAgB,uBAAuB,KAA4E;AAClH,QAAO,IAAI,QAAQ,eAAe,EAAE,MAAM,IAAI,KAAK,GAAG;EAAE,MAAM;EAAiB,YAAY,IAAI;EAAK;;;;;;;;;;;;;;;;;;;;;;;ACmBrG,eAAsB,oBACrB,oBACA,gBACA,iBACmB;CACnB,MAAM,YAAY,gBAAgB,mBAAmB;CACrD,MAAM,MAAM,oBAAoB,eAAe;CAC/C,MAAM,YAAY,MAAM,OAAO,OAAO,UAAU,OAAO,KAAmB,uBAAuB,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC;AAGzH,QAAO,gBAAgB,WADC,OAAO,gBAAgB,EACI,UAAU;;;;;AC/B9D,SAAS,iBAAiB,gBAA+C;AACxE,KAAI,CAAC,MAAM,QAAQ,eAAe,CAAE,QAAO,EAAE;CAE7C,MAAMC,cAAoC,EAAE;AAC5C,MAAK,MAAM,KAAK,gBAAgB;AAC/B,MAAI,CAAC,KAAK,OAAO,MAAM,SAAU;EACjC,MAAM,SAAS;AACf,MAAI,OAAO,OAAO,cAAc,SAAU;EAC1C,MAAM,QAAQ,aAAa,OAAO,SAAS;AAC3C,MAAI,MAAO,aAAY,KAAK;GAAE,QAAQ,OAAO;GAAW;GAAO,CAAC;;AAEjE,QAAO;;;;;;;AAQR,SAAgB,gBAAgB,eAA6C;AAC5E,KAAI,CAAC,MAAM,QAAQ,cAAc,CAAE,QAAO,EAAE;CAE5C,MAAMC,aAAkC,EAAE;AAC1C,MAAK,MAAM,OAAO,eAAe;AAChC,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU;EACrC,MAAM,SAAS;AACf,MAAI,OAAO,OAAO,aAAa,SAAU;EAEzC,MAAM,cAAc,iBAAiB,OAAO,QAAQ;AACpD,aAAW,KAAK,YAAY,SAAS,IAAI;GAAE,OAAO,OAAO;GAAU,MAAM;GAAa,GAAG,EAAE,OAAO,OAAO,UAAU,CAAC;;AAErH,QAAO;;;;;AC1BR,SAAS,eAAe,WAAyC;AAChE,KAAI,CAAC,MAAM,QAAQ,UAAU,IAAI,UAAU,WAAW,EAAG,QAAO;CAChE,MAAMC,MAAoB,EAAE;AAC5B,MAAK,MAAM,SAAS,WAAW;EAC9B,MAAM,QAAQ,aAAa,MAAM;AACjC,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,KAAK,MAAM;;AAEhB,QAAO;;AAGR,SAAS,kBAAkB,uBAAoE;CAC9F,MAAM,YAAY,sBAAsB;AACxC,KAAI,CAAC,MAAM,QAAQ,UAAU,IAAI,UAAU,WAAW,EAAG,QAAO;CAEhE,MAAM,aAAa,gBAAgB,sBAAsB,cAAc;CACvE,MAAM,eAAe,sBAAsB;CAC3C,MAAM,mBAAmB,sBAAsB,WAAW,OAAO,IAAI;CAErE,MAAMC,OAAoB,EAAE;AAC5B,MAAK,MAAM,SAAS,WAAW;AAC9B,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;EAChD,MAAM,SAAS;EAEf,MAAM,WAAW,UAAU,OAAO,YAAY;EAC9C,MAAM,UAAU,UAAU,OAAO,WAAW;EAC5C,MAAM,QAAQ,UAAU,OAAO,SAAS;EACxC,MAAM,SAAS,eAAe,OAAO,UAAU;AAC/C,MAAI,aAAa,QAAQ,YAAY,QAAQ,UAAU,QAAQ,CAAC,OAAQ,QAAO;EAI/E,MAAM,WAAW,aAAa,OAAO,YAAY;AACjD,MAAI,CAAC,SAAU,QAAO;EAMtB,MAAM,SAAS,OAAO,UAAU;AAChC,MAAI,OAAO,WAAW,SAAU,QAAO;AAEvC,OAAK,KAAK;GACT;GACA;GACA;GACA;GACA;GACA,KAAK,uBAAuB,OAAO;GACnC;GACA;GACA,CAAC;;AAEH,QAAO;;AAGR,eAAsB,mBACrB,OACA,WACA,OAC8B;CAC9B,MAAM,OAAO,WAAW;AACxB,KAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,KAAK,CAAE,QAAO;AAC7E,KAAK,KAAiC,cAAc,OAAW,QAAO;CAEtE,MAAM,aAAa,kBAAkB,KAAgC;AACrE,KAAI,CAAC,YAAY;AAChB,QAAM,IAAI,eAAe,6BAA6B;AACtD,SAAO,EAAE;;CAGV,MAAM,gCAAgB,IAAI,KAAgC;AAC1D,MAAK,MAAM,aAAa,YAAY;AACnC,MAAI,CAAC,UAAU,SAAU;EACzB,IAAI,WAAW,cAAc,IAAI,UAAU,IAAI;AAC/C,MAAI,CAAC,UAAU;AACd,cAAW,MAAM,gBAAgB,OAAO;IACvC,kBAAkB,UAAU;IAC5B,YAAY,UAAU;IACtB,KAAK,UAAU,OAAO;IACtB,CAAC;AACF,iBAAc,IAAI,UAAU,KAAK,SAAS;;AAE3C,MAAI,CAAC,YAAY,UAAU,UAAU,SAAS,EAAE;AAC/C,SAAM,IAAI,oBAAoB,aAAa;AAC3C,SAAM,IAAI,eAAe,4BAA4B;;;AAIvD,QAAO;;;;;ACjFR,MAAMC,8BAA4B;AAClC,MAAM,+BAA+B;AACrC,MAAM,oBAAoB;AAM1B,MAAM,kBAAkB;AAExB,SAAS,uBAAuB,OAAgC;AAC/D,KAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;CACxD,MAAM,MAAM;AACZ,KAAI,OAAO,IAAI,WAAW,YAAY,WAAW,IAAK,QAAO,IAAI;CACjE,MAAM,SAAS,IAAI;AACnB,KAAI,MAAM,QAAQ,OAAO,IAAI,OAAO,WAAW,EAAG,QAAO,OAAO;AAChE,QAAO;;AAGR,SAAS,sBAAsB,OAA4B;AAC1D,KAAI,iBAAiB,WAAY,QAAO;AACxC,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,IAAI,WAAW,MAAkB;AAClE,KAAI,uBAAuB,MAAM,KAAK,KAAM,QAAO,OAAO,MAAM;AAChE,OAAM,IAAI,MAAM,qCAAqC;;AAGtD,SAAS,kBAAkB,OAAyB;AACnD,KAAI,iBAAiB,WAAY,QAAO,OAAO,MAAM;AACrD,KAAI,MAAM,QAAQ,MAAM,IAAI,MAAM,SAAS,KAAK,OAAQ,MAAmB,OAAO,SACjF,QAAO,OAAO,IAAI,WAAW,MAAkB,CAAC;AAEjD,QAAO;;AAGR,SAAS,eAAe,OAA+B;CACtD,MAAM,WAAW,uBAAuB,MAAM,IAAI;AAClD,KAAI,OAAO,aAAa,SAAU,QAAO;AACzC,KAAI,oBAAoB,KAAM,QAAO,SAAS,aAAa;AAC3D,QAAO;;AAGR,SAAS,cAAc,SAAkC,SAAiC;CACzF,MAAM,MAAM,QAAQ;AACpB,KAAI,eAAe,WAAY,QAAO,WAAW,IAAI;AACrD,KAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,KAAI,MAAM,QAAQ,IAAI,IAAI,IAAI,SAAS,EAAG,QAAO,WAAW,IAAI,WAAW,IAAgB,CAAC;CAG5F,MAAM,cAAc;CACpB,MAAM,UAAU,uBAAuB,MAAM,YAAY,IAAI,kBAAkB,GAAG,YAAY;AAC9F,KAAI,mBAAmB,WAAY,QAAO,WAAW,QAAQ;AAC7D,KAAI,MAAM,QAAQ,QAAQ,IAAI,QAAQ,SAAS,EAC9C,QAAO,WAAW,IAAI,WAAW,QAAoB,CAAC;AAGvD,QAAO;;AAGR,SAAS,gBAAgB,MAA0B;AAClD,KAAI,MAAM,QAAQ,KAAK,CAAE,QAAO;AAChC,KAAI,OAAO,SAAS,YAAY,SAAS,MAAM;EAC9C,MAAM,MAAM;EACZ,MAAM,OAAO,IAAI,WAAW,IAAI;AAChC,MAAI,MAAM,QAAQ,KAAK,CAAE,QAAO;AAChC,MAAI,OAAO,SAAS,YAAY,SAAS,MAAM;GAC9C,MAAM,SAAU,KAAiC;AACjD,OAAI,MAAM,QAAQ,OAAO,CAAE,QAAO;;;AAGpC,QAAO,EAAE;;AAGV,eAAe,0BACd,OACA,WACmB;AACnB,KAAI,CAAC,UAAW,QAAO;CACvB,MAAM,OAAO,UAAU;CACvB,MAAM,UAAU,KAAK,WAAW,KAAK;AACrC,KAAI,CAAC,QAAS,QAAO;CACrB,MAAM,eACL,mBAAmB,aAAa,UAAU,IAAI,WAAW,QAAoB;CAC9E,MAAM,MAAM,uBAAuB,KAAK,OAA6B;AAKrE,QAAO,YADU,MAAM,gBAAgB,OAAO;EAAE,YAH5B,KAAK,iBAAqD,EAAE;EAGpB;EAAK,kBAAkB;EAAG,CAAC,EAC1D,aAAa;;AAY3C,SAAS,wBAAwB,OAAyC;CACzE,MAAM,UAAU;CAEhB,MAAM,oBAAoB,QAAQ;CAClC,MAAM,iBAAiB,QAAQ;CAC/B,MAAM,YAAY,eAAe,QAAQ,aAAa;AAEtD,KAAI,qBAAqB,QAAQ,kBAAkB,QAAQ,CAAC,UAAW,QAAO;AAG9E,qBADuB,IAAI,MAAM,GAAG,IAAI,KAAK,UAAU,IACjC,aAAa,WAAW,OAAO,eAAe,CAAC,CAAE,QAAO;CAE9E,MAAM,UAAU,kBAAkB,QAAQ,OAAO;CACjD,MAAM,MAAM,cAAc,SAAS,QAAQ;AAC3C,KAAI,CAAC,IAAK,QAAO;CAEjB,MAAM,mBAAmB,QAAQ;AACjC,KAAI,CAAC,iBAAkB,QAAO;AAE9B,KAAI;AACH,SAAO;GACN,mBAAmB,OAAO,kBAAkB;GAC5C,gBAAgB,OAAO,eAAe;GACtC;GACA;GACA;GACA,oBAAoB,sBAAsB,iBAAiB;GAC3D;SACM;AACP,SAAO;;;AAIT,eAAe,oBACd,QACA,aACsC;AAEtC,KAAI,CADmB,MAAM,oBAAoB,OAAO,oBAAoB,OAAO,SAAS,YAAY,CACnF,QAAO;AAE5B,KAAI;EACH,MAAM,MAAM,oBAAoB,OAAO,QAAQ;AAC/C,SAAO;GACN,KAAK,OAAO;GACZ;GACA,mBAAmB,OAAO;GAC1B,gBAAgB,OAAO;GACvB,WAAW,OAAO;GAClB;SACM;AACP,SAAO;;;AAIT,eAAe,yBACd,OACA,aACsC;CACtC,MAAM,SAAS,wBAAwB,MAAM;AAC7C,KAAI,CAAC,OAAQ,QAAO;AACpB,QAAO,oBAAoB,QAAQ,YAAY;;AAGhD,eAAe,oBACd,WACA,aACiC;CACjC,MAAM,aAAa,gBAAgB,kBAAkB,UAAU,KAAK,CAAC;AAIrE,SAHgB,MAAM,QAAQ,IAC7B,WAAW,KAAI,UAAS,yBAAyB,OAAO,YAAY,CAAC,CACrE,EACc,QAAQ,QAAoC,QAAQ,KAAK;;;;;;;;;;;;;;;;;;;;;AAsBzE,eAAsB,wBAAwB,OAAmD;CAChG,MAAM,QAAQ,aAAa,MAAM;AACjC,KAAI,WAAW,QAAO,QAAO,IAAI,SAAS,OAAO,CAChD,QAAO;EACN,UAAU;EACV,aAAa;EACb,YAAY;EACZ,aAAa,EAAE;EACf,YAAY,EAAE;EACd,SAAS;EACT,YAAY,CAAC,oBAAoB,aAAa;EAC9C;CAGF,MAAM,eAAe,iBAAiB,OAAO,MAAM;CACnD,MAAM,EAAE,aAAa;CACrB,MAAM,EAAE,OAAO,gBAAgB,gBAAgB,MAAM,0BAA0B,aAAa;CAE5F,MAAM,oBACL,SAAS,WAAW,MAAK,MAAK,EAAE,UAAUA,4BAA0B,IAAI;CACzE,MAAM,gBAAgB,MAAM,0BAA0B,OAAO,kBAAkB;CAE/E,MAAM,uBAAuB,SAAS,WAAW,MAChD,MAAK,EAAE,UAAU,6BACjB;CACD,MAAM,cACL,wBAAwB,cACrB,MAAM,oBAAoB,sBAAsB,YAAY,GAC5D,EAAE;CAEN,MAAM,wBAAQ,IAAI,KAA2C;CAC7D,MAAM,aAAa,MAAM,mBAAmB,OAAO,mBAAmB,MAAM;AAE5E,KAAI,CAAC,cAAe,OAAM,IAAI,oBAAoB,aAAa;AAE/D,KAAI,YAAY,WAAW,KAAK,eAAe,KAC9C,OAAM,IAAI,oBAAoB,mBAAmB;AAElD,MAAK,MAAM,QAAQ,eAAgB,OAAM,IAAI,KAAK;CAClD,MAAM,aAAa,CAAC,GAAG,MAAM;AAE7B,QAAO;EACN;EACA;EACA,YAAY,SAAS;EACrB;EACA,YAAY,cAAc,EAAE;EAC5B,SAAS,WAAW,WAAW;EAC/B;EACA;;;;;AC/PF,MAAM,gBAAgB;AACtB,MAAM,iBAAiB;AACvB,MAAM,qBAAqB,EAAE,SAAS,EAAE,MAAM,UAAU,EAAE;;;;;;;;;;;;;AAc1D,SAAgB,kBAAkB,cAAkD;AACnF,MAAK,MAAM,OAAO,aAAa,cAAc,mBAAmB,EAAE;AACjE,MAAI,IAAI,SAAS,cAAe;EAChC,MAAM,OAAO;AACb,MAAI,KAAK,gBAAgB,eAAgB,QAAO;;AAEjD,QAAO;;;;;;;;;;;;;;;;;;;ACJR,SAAgB,aAAa,cAAkC;CAC9D,MAAM,MAAM,OAAO,aAAa;AAEhC,KAAI,OAAO,QAAQ,YAAY,QAAQ,KACtC,OAAM,IAAI,MAAM,6BAA6B;CAG9C,MAAM,iBAAiB,IAAI;AAC3B,KAAI,OAAO,mBAAmB,SAAU,OAAM,IAAI,MAAM,4CAA4C;CAEpG,MAAM,cAAc,IAAI;AACxB,KAAI,CAAC,eAAe,OAAO,gBAAgB,SAAU,OAAM,IAAI,MAAM,2BAA2B;CAEhG,MAAM,OAAO,YAAY;AACzB,KAAI,EAAE,gBAAgB,YAAa,OAAM,IAAI,MAAM,6CAA6C;CAEhG,MAAM,aAAa,YAAY;AAC/B,KAAI,eAAe,UAAa,CAAC,MAAM,QAAQ,WAAW,CAAE,OAAM,IAAI,MAAM,+CAA+C;CAE3H,MAAM,aAAa,IAAI;AACvB,KAAI,OAAO,eAAe,SAAU,OAAM,IAAI,MAAM,wCAAwC;AAI5F,QAAO;EACN;EACA,UAAU;GACT;GACA,KANU,uBAAuB,YAAY,OAA6B;GAO1E,YAAa,cAAkD,EAAE;GACjE;EACD;EACA;;;;;;;;;;;;;;;ACxCF,SAAgB,sBAAqC;AACpD,QAAO;EAAE,oBAAoB;EAAM,+BAAe,IAAI,KAAK;EAAE;;;;;;;;;;;;;;ACiB9D,MAAa,2BAA2B;CAEvC,OAAO;CAEP,WAAW;CAEX,cAAc;CAEd,cAAc;CAEd,+BAA+B;CAC/B;;;;ACtCD,MAAM,6BAA6B;AAEnC,SAAS,mBAAmB,MAAmB,oBAAyC;AACvF,KAAI,KAAK,QAAQ,2BAA4B,QAAO;CACpD,MAAM,YAAY,qBAAqB;CACvC,MAAM,yBAAS,IAAI,KAAa;AAChC,MAAK,MAAM,OAAO,KACjB,KAAI,OAAO,UAAW,QAAO,IAAI,IAAI;AAEtC,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BR,SAAgB,uBACf,OACA,gBACA,mBACmF;AACnF,KAAI,iBAAiB,kBACpB,QAAO;EACN,QAAQ;GAAE,SAAS;GAAO,QAAQ,yBAAyB;GAA+B;EAC1F,WAAW;EACX;AAGF,KAAI,MAAM,cAAc,IAAI,eAAe,CAC1C,QAAO;EACN,QAAQ;GAAE,SAAS;GAAO,QAAQ,yBAAyB;GAAW;EACtE,WAAW;EACX;CAGF,MAAM,oBAAoB,IAAI,IAAI,MAAM,cAAc;AACtD,mBAAkB,IAAI,eAAe;AAErC,KAAI,MAAM,uBAAuB,QAAQ,iBAAiB,MAAM,mBAC/D,QAAO;EACN,QAAQ;GAAE,SAAS;GAAO,QAAQ,yBAAyB;GAAc;EACzE,WAAW;GACV,oBAAoB,MAAM;GAC1B,eAAe,mBAAmB,mBAAmB,MAAM,mBAAmB;GAC9E;EACD;AAGF,KAAI,MAAM,uBAAuB,QAAQ,iBAAiB,MAAM,qBAAqB,GAAG;EACvF,MAAM,cAAc,MAAM,qBAAqB;EAC/C,MAAM,YAAY,iBAAiB;AACnC,SAAO;GACN,QAAQ;IAAE,SAAS;IAAO,QAAQ,yBAAyB;IAAc;IAAa;IAAW;GACjG,WAAW;IACV,oBAAoB;IACpB,eAAe,mBAAmB,mBAAmB,eAAe;IACpE;GACD;;AAGF,QAAO;EACN,QAAQ;GAAE,SAAS;GAAM,QAAQ,yBAAyB;GAAO;EACjE,WAAW;GACV,oBAAoB;GACpB,eAAe,mBAAmB,mBAAmB,eAAe;GACpE;EACD;;;;;ACrFF,MAAM,6BAA6B,CAAC,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;AA+BzC,eAAsB,iBACrB,cACA,cACA,SACmB;AACnB,MAAK,MAAM,oBAAoB,2BAE9B,KAAI,YADS,MAAM,gBAAgB,cAAc;EAAE,GAAG;EAAS;EAAkB,CAAC,EAC5D,aAAa,CAAE,QAAO;AAE7C,QAAO;;;;;AC9BR,SAAS,eAAe,aAA6C,QAAmD;AACvH,KAAI,CAAC,UAAU,YAAY,WAAW,EAAG,QAAO;AAChD,QAAO,YAAY,MAAK,MAAK,EAAE,QAAQ,OAAO,IAAI;;;;;;;;;;;;;;;;;;;;;AAsBnD,eAAsB,oBACrB,cACA,aACA,gBAA+B,qBAAqB,EACsD;CAC1G,MAAM,UAAU,kBAAkB,aAAa;AAC/C,KAAI,CAAC,QAAS,QAAO;CAErB,MAAM,YAAY,gBAAgB,QAAQ,YAAY;CACtD,MAAM,EAAE,YAAY;AACpB,KAAI,CAAC,QAAS,OAAM,IAAI,MAAM,sDAAsD;CACpF,MAAM,MAAM,aAAa,QAAQ;CAEjC,MAAM,SAAS,UAAU,MAAM,WAAW,UAAU,IAAI,GAAG;CAC3D,MAAM,aAAa,eAAe,aAAa,OAAO;CACtD,MAAM,cAAc,WAAW,IAAI,SAAS,KAAK;CACjD,MAAM,oBAAoB,YAAY,qBAAqB;CAE3D,MAAM,EAAE,QAAQ,gBAAgB,WAAW,sBAAsB,uBAChE,eACA,IAAI,gBACJ,kBACA;CAED,MAAM,aAAa;EAClB,gBAAgB,IAAI;EACpB,YAAY,IAAI;EAChB;EACA;EACA;EACA;AAED,KAAI,CAAC,WACJ,QAAO;EACN,QAAQ;GACP,GAAG;GACH,SAAS;GACT,YAAY,CAAC,oBAAoB,gBAAgB;GACjD;EACD;EACA;CAGF,MAAM,YAAY,uBAAuB,WAAW,IAAI;CACxD,MAAM,YAAY,MAAM,OAAO,OAAO,UACrC,OACA,WAAW,KACX,WACA,OACA,CAAC,SAAS,CACV;CAED,MAAM,CAAC,gBAAgB,aAAa,MAAM,QAAQ,IAAI,CACrD,gBAAgB,WAAW,SAAS,UAAU,EAC9C,iBAAiB,cAAc,IAAI,SAAS,MAAM;EACjD,YAAY,IAAI,SAAS;EACzB,KAAK,IAAI,SAAS;EAClB,CAAC,CACF,CAAC;CAEF,MAAM,mBAAmB,IAAI,kBAAkB,WAAW;CAI1D,MAAM,aAAa,aAAa,WAAW,WAAW,WAAW,eAAe;CAEhF,MAAM,wBAAQ,IAAI,KAA0B;AAC5C,KAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,iBAAkB,OAAM,IAAI,oBAAoB,gBAAgB;AACtG,KAAI,CAAC,eAAe,QAAS,OAAM,IAAI,oBAAoB,kBAAkB;AAC7E,KAAI,WAAY,OAAM,IAAI,oBAAoB,mBAAmB;CACjE,MAAM,aAAa,CAAC,GAAG,MAAM;AAE7B,QAAO;EACN,QAAQ;GAAE,GAAG;GAAY,SAAS,WAAW,WAAW;GAAG;GAAY;EACvE;EACA;;;;;AChGF,MAAM,6BAA6B;AACnC,MAAM,4BAA4B;AAClC,MAAM,6BAA6B;AACnC,MAAM,gCAAgC;AAEtC,SAAS,oBAAoB,IAAkC;AAC9D,KAAI,CAAC,GAAI,QAAO;AAChB,QAAO,GAAG,QAAQ,4BAA4B,GAAG,CAAC,aAAa;;AAGhE,SAAS,qBAAqB,MAA+C;AAC5E,KAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,KAAK,CACpE,QAAO;AAER,QAAO;;AAaR,SAAS,wBAAwB,YAA8D;CAC9F,MAAM,YAAY,WAAW,MAAK,MAAK,EAAE,UAAU,2BAA2B;AAC9E,KAAI,CAAC,UAAW,QAAO;CAEvB,MAAM,OAAO,qBAAqB,UAAU,KAAK;CACjD,MAAM,SAAS,OAAO;CACtB,MAAM,UAAU,OAAO;CACvB,MAAM,cAAc,OAAO;CAC3B,MAAM,gBAAgB,OAAO;AAE7B,QAAO;EACN,gBAAgB,OAAO,WAAW,WAAW,SAAS;EACtD,oBAAoB,OAAO,YAAY,WAAW,UAAU;EAC5D,UAAU,OAAO,gBAAgB,WAAW,cAAc;EAC1D,kBAAkB,OAAO,kBAAkB,WAAW,gBAAgB;EACtE,MAAM,QAAQ,EAAE;EAChB;;AAYF,MAAMC,kBAAkC;CAAE,WAAW;CAAM,SAAS;CAAM,YAAY,EAAE;CAAE,KAAK;CAAM;AAErG,SAAS,uBAAuB,YAAsD;CACrF,MAAM,YAAY,WAAW,MAAK,MAAK,EAAE,UAAU,0BAA0B;AAC7E,KAAI,CAAC,UAAW,QAAO;CAEvB,MAAM,OAAO,qBAAqB,UAAU,KAAK;AACjD,KAAI,CAAC,KAAM,QAAO;CAElB,MAAM,YAAY,aAAa,KAAK,WAAW,KAAK,SAAS;AAI7D,QAAO;EAAE;EAAW,SAHJ,YAAY,WAAW,UAAU,GAAG;EAGvB,YAFV,gBAAgB,KAAK,cAAc;EAEb,KAD7B,OAAO,KAAK,WAAW,WAAW,uBAAuB,KAAK,OAAO,GAAG;EACtC;;AAa/C,SAAS,cAAc,OAAmC;AACzD,KAAI;EACH,MAAM,eAAe,iBAAiB,MAAM;EAC5C,MAAM,EAAE,aAAa;AACrB,MAAI,CAAC,SAAU,QAAO;GAAE,UAAU;GAAM,QAAQ;GAAM,WAAW;GAAM,MAAM;GAAiB,cAAc;GAAM;AAElH,SAAO;GACN;GACA,QAAQ,SAAS,eAAe,UAAU;GAC1C,WAAW,wBAAwB,SAAS,WAAW;GACvD,MAAM,uBAAuB,SAAS,WAAW;GACjD;GACA;SACM;AACP,SAAO;GAAE,UAAU;GAAM,QAAQ;GAAM,WAAW;GAAM,MAAM;GAAiB,cAAc;GAAM;;;AAMrG,SAAS,kBACR,aACA,cACA,eACA,qBACA,iBACiC;CACjC,MAAM,wBAAQ,IAAI,KAA0B;AAE5C,KAAI,CAAC,YAAa,OAAM,IAAI,oBAAoB,iBAAiB;AACjE,KAAI,CAAC,aAAc,OAAM,IAAI,oBAAoB,kBAAkB;AACnE,KAAI,CAAC,cAAe,OAAM,IAAI,oBAAoB,kBAAkB;AACpE,KAAI,CAAC,oBAAqB,OAAM,IAAI,oBAAoB,kBAAkB;AAC1E,KAAI,CAAC,gBAAiB,OAAM,IAAI,oBAAoB,gBAAgB;AAEpE,QAAO,CAAC,GAAG,MAAM;;AAGlB,eAAe,mBACd,QACA,gBACA,SAC0C;CAC1C,MAAM,EAAE,UAAU,cAAc;CAChC,MAAM,SAAS,WAAW,oBAAoB;AAE9C,KAAI,CAAC,OAAQ,QAAO,CAAC,oBAAoB,0BAA0B;AAEnE,KAAI,WAAW,+BAA+B;EAC7C,MAAM,OAAO,WAAW,sBAAsB;AAC9C,MAAI,CAAC,KAAM,QAAO,CAAC,oBAAoB,0BAA0B;AAEjE,SADe,CAAC,CAAC,kBAAkB,oBAAoB,KAAK,KAAK,oBAAoB,eAAe,GACpF,CAAC,oBAAoB,gBAAgB,GAAG,EAAE;;CAG3D,MAAM,SAAS,SAAS;AACxB,KAAI,QAAQ,WAAW,UAAU,CAAC,YAAY,CAAC,UAC9C,QAAO,CAAC,oBAAoB,2BAA2B,oBAAoB,8BAA8B;AAM1G,QAHW,MAAM,QAAQ,SAAS,CAChC,WAAW,OAAO,SAAS,UAAU,MAAM,SAAS,CAAC,CACrD,YAAY,MAAM,GACR,EAAE,GAAG,CAAC,oBAAoB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BvD,eAAsB,+BACrB,OACA,gBACA,OACA,SAKE;CACF,MAAM,EAAE,UAAU,QAAQ,WAAW,MAAM,iBAAiB,cAAc,MAAM;CAEhF,MAAM,iBAAiB,WAAW,kBAAkB;CACpD,MAAM,qBAAqB,WAAW,sBAAsB;CAC5D,MAAM,WAAW,WAAW,YAAY;CACxC,MAAM,mBAAmB,WAAW,oBAAoB;CAExD,MAAM,gBAAgB,OAAO,gBAAgB,QAAQ,aAAa,MAAM;CACxE,MAAM,sBACL,OAAO,sBAAsB,QAC5B,mBAAmB,QAAQ,iBAAiB,MAAM;CAEpD,IAAI,kBAAkB;AACtB,KAAI,KAAK,cAAc,KAQtB,mBAAkB,YALD,MAAM,gBAAgB,OAAO;EAC7C,YAAY,KAAK;EACjB,KAAK,KAAK,OAAO;EACjB,kBAAkB;EAClB,CAAC,EACsC,KAAK,UAAU;CAGxD,MAAM,kBAAkB,MAAM,mBAAmB;EAAE;EAAU;EAAQ;EAAW;EAAM;EAAc,EAAE,gBAAgB,QAAQ;CAE9H,MAAM,iBAAiB,CAAC,GAAG,IAAI,IAAI,CAClC,GAAG,kBACF,aAAa,MAAM,cAAc,MACjC,eAAe,qBAAqB,gBACpC,EACD,GAAG,gBACH,CAAC,CAAC;CAEH,MAAM,YAAY,eAAe,MAAM,0BAA0B,aAAa,GAAG;CACjF,MAAMC,iBAA4C,WAAW,SAAS,EAAE;CAExE,MAAMC,aAAuD,CAAC,GAAG,gBAAgB,GAAG,eAAe;CAEnG,MAAM,oBAAoB,UAAU,cAAc;AAElD,QAAO;EACN,QAAQ;GACP,UAAU,YAAY;GACtB;GACA,aAAa,WAAW,eAAe;GACvC;GACA;GACA;GACA;GACA,aAAa,KAAK;GAClB,SAAS,WAAW,WAAW;GAC/B;GACA;EACD,gBAAgB,qBAAqB;EACrC,WAAW;GACV,cAAc,YAAY,OAAO;GACjC,oBAAoB,kBAAkB,OAAO;GAC7C;EACD;;;;;ACvPF,MAAM,qBAAqB;AAO3B,SAAS,eAAe,YAAoC;CAC3D,MAAM,SAAS,mBAAmB,WAAW;AAC7C,KAAI,CAAC,UAAU,OAAO,YAAY,mBAAoB,QAAO;AAC7D,QAAO,OAAO;;AAGf,SAAS,sBAAsB,cAAwC;CACtE,MAAMC,WAAyB,EAAE;AAEjC,MAAK,MAAM,OAAO,aAAa,aAAa,EAAE;EAC7C,MAAM,UAAU;AAChB,MAAI,QAAQ,SAAS,OAAQ;AAE7B,MAAI,CAAC,YADY,QAAQ,YAAY,EAAE,EACZ,WAAW,CAAE;EAGxC,MAAM,UAAU,eADG,QAAQ,KAAK,SAAS,QAAQ,KAAK,eAAe,CAC3B;AAC1C,MAAI,YAAY,QAAS,UAAS,KAAK,QAAQ;;AAGhD,QAAO;;AAaR,SAAS,aAAa,KAAc,MAAuB;AAC1D,KAAI,eAAe,IAAK,QAAO,IAAI,IAAI,KAAK;AAC5C,QAAQ,IAAgC;;AAKzC,SAAS,gBAAgB,SAA8B;CACtD,IAAIC;CACJ,IAAI,QAAQ;AACZ,KAAI;AACH,iBAAe,UAAS,UAAS;AAChC,WAAQ;AACR,WAAQ;AACR,UAAO;IACN;SACK;AACP;;AAED,QAAO,QAAQ,QAAQ;;AAGxB,SAAS,mBAAmB,SAAkD;CAC7E,MAAM,UAAU,gBAAgB,QAAQ;AACxC,KAAI,YAAY,QAAQ,YAAY,UAAa,OAAO,YAAY,SAAU,QAAO;CAErF,MAAM,WAAW,UAAU,aAAa,SAAS,WAAW,CAAC;CAC7D,MAAM,UAAU,UAAU,aAAa,SAAS,UAAU,CAAC;CAC3D,MAAM,WAAW,UAAU,aAAa,SAAS,WAAW,CAAC;AAC7D,KAAI,aAAa,QAAQ,YAAY,QAAQ,aAAa,KAAM,QAAO;CAEvE,MAAM,YAAY,aAAa,SAAS,SAAS;AACjD,KAAI,aAAa,KAAM,QAAO;EAAE;EAAU;EAAS;EAAU,QAAQ;EAAM;AAC3E,KAAI,CAAC,MAAM,QAAQ,UAAU,CAAE,QAAO;CAEtC,MAAMC,SAAgC,EAAE;AACxC,MAAK,MAAM,SAAS,WAAW;AAC9B,MAAI,SAAS,MAAM;AAClB,UAAO,KAAK,KAAK;AACjB;;EAED,MAAM,QAAQ,aAAa,MAAM;AACjC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,KAAK,MAAM;;AAEnB,QAAO;EAAE;EAAU;EAAS;EAAU;EAAQ;;AAK/C,eAAe,SAAS,MAAkB,OAAmB,KAAkC;CAC9F,MAAM,QAAQ,IAAI,WAAW,KAAK,SAAS,MAAM,OAAO;AACxD,OAAM,IAAI,MAAM,EAAE;AAClB,OAAM,IAAI,OAAO,KAAK,OAAO;AAC7B,QAAO,IAAI,WAAW,MAAM,OAAO,OAAO,OAAO,KAAK,MAAM,CAAC;;AAI9D,SAAS,WAAW,WAA6B;CAChD,MAAM,SAAS,CAAC,UAAU;AAC1B,QAAO,OAAO,OAAO,SAAS,KAAK,EAClC,QAAO,KAAK,KAAK,KAAK,OAAO,OAAO,SAAS,KAAK,EAAE,CAAC;AAEtD,QAAO;;AAIR,eAAe,kBACd,UACA,UACA,WACA,WACuC;CACvC,MAAM,EAAE,OAAO,QAAQ,gBAAgB;AACvC,KAAI,WAAW,KAAK,YAAY,MAC/B,QAAO,eAAe;CAGvB,MAAM,SAAS,WAAW,MAAM;CAChC,MAAM,iBAAiB,OAAO,QAAQ,YAAY,OAAO;AACzD,KAAI,mBAAmB,GACtB,QAAO,eAAe;CAGvB,MAAM,UAAU,aAAa,EAAE;AAC/B,KAAI,QAAQ,SAAS,eAAgB,QAAO,eAAe;CAC3D,MAAM,OAAO,QAAQ,QAAQ,SAA6B,SAAS,KAAK;CAExE,MAAM,MAAM,uBAAuB,UAAU,OAAO,OAAU;CAE9D,IAAI,cAAc;CAClB,IAAI,eAAe;CACnB,IAAI,aAAa;AACjB,MAAK,MAAM,SAAS,QAAQ;AAC3B,MAAI,UAAU,YAAY,OACzB;EAED,MAAM,eAAe,eAAe,MAAM,IAAI,eAAe,IAAI,eAAe;AAChF,MAAI,gBAAgB,KAAK,eAAe,OAAO;GAC9C,MAAM,UAAU,KAAK;AACrB,OAAI,CAAC,QAAS,QAAO,eAAe;AACpC,iBAAc,eAAe,MAAM,IAChC,MAAM,SAAS,aAAa,SAAS,IAAI,GACzC,MAAM,SAAS,SAAS,aAAa,IAAI;;AAE7C,iBAAe,KAAK,MAAM,eAAe,EAAE;;AAG5C,KAAI,eAAe,KAAK,OAAQ,QAAO,eAAe;CAEtD,MAAM,WAAW,YAAY;AAC7B,KAAI,CAAC,SAAU,QAAO,eAAe;AACrC,QAAO,YAAY,aAAa,SAAS,GAAG,OAAO,eAAe;;AAKnE,SAAS,cACR,YACA,UACA,SACmB;AACnB,QAAO,WAAW,MAAK,MAAK,EAAE,aAAa,YAAY,EAAE,YAAY,QAAQ,IAAI;;AAUlF,eAAe,gBACd,cACA,WACA,OACsB;CACtB,MAAM,SAAS,MAAM,MAAK,UACzB,MAAM,QAAQ,UAAU,OACxB,MAAM,qBAAqB,UAAU,oBACrC,MAAM,eAAe,UAAU,WAC/B;AACD,KAAI,OAAQ,QAAO,OAAO;CAE1B,MAAM,OAAO,MAAM,gBAAgB,cAAc;EAChD,kBAAkB,UAAU;EAC5B,YAAY,UAAU;EACtB,KAAK,UAAU,OAAO;EACtB,CAAC;AACF,OAAM,KAAK;EACV,KAAK,UAAU;EACf,kBAAkB,UAAU;EAC5B,YAAY,UAAU;EACtB;EACA,CAAC;AACF,QAAO;;;;;;;;;;;;;;;;AAiBR,eAAsB,0BACrB,cACA,YACA,OAIE;CACF,MAAM,oBAAoB,OAAO,iCAAiB,IAAI,KAAqB;CAC3E,MAAM,gBAAgB,IAAI,IAAI,kBAAkB;CAChD,MAAM,wBAAQ,IAAI,KAA2B;CAC7C,MAAMC,gBAA+B,EAAE;CACvC,IAAIC,WAA0B;CAC9B,IAAIC,cAA6B;CAEjC,MAAM,WAAW,sBAAsB,aAAa;AACpD,KAAI,SAAS,WAAW,EACvB,OAAM,IAAI,eAAe,6BAA6B;AAGvD,MAAK,MAAM,WAAW,UAAU;EAC/B,MAAM,aAAa,mBAAmB,QAAQ;AAC9C,MAAI,CAAC,YAAY;AAChB,SAAM,IAAI,eAAe,6BAA6B;AACtD;;EAGD,MAAM,YAAY,cAAc,YAAY,WAAW,UAAU,WAAW,QAAQ;AACpF,MAAI,CAAC,WAAW;AACf,SAAM,IAAI,eAAe,6BAA6B;AACtD;;AAGD,MAAI,aAAa,KAAM,YAAW,WAAW;EAG7C,MAAM,WAAW,GAAG,WAAW,SAAS,GAAG,WAAW;EACtD,MAAM,eAAe,kBAAkB,IAAI,SAAS;AAEpD,MAAI,EADkB,iBAAiB,UAAa,WAAW,aAAa,eAAe,GAE1F,OAAM,IAAI,oBAAoB,kBAAkB;EAGjD,MAAM,WAAW,MAAM,gBAAgB,cAAc,WAAW,cAAc;AAC9E,MAAI,gBAAgB,KAAM,eAAc,WAAW,SAAS;EAC5D,MAAM,cAAc,MAAM,kBAAkB,UAAU,WAAW,UAAU,WAAW,QAAQ,UAAU;AACxG,MAAI,gBAAgB,KAInB,eAAc,IAAI,UAAU,WAAW,SAAS;MAEhD,OAAM,IAAI,YAAY;;AAIxB,QAAO;EACN,QAAQ;GACP;GACA;GACA,SAAS,MAAM,SAAS;GACxB,YAAY,CAAC,GAAG,MAAM;GACtB;EACD,WAAW,EAAE,eAAe,eAAe;EAC3C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svta/cml-c2pa",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "C2PA (Coalition for Content Provenance and Authenticity) live video validation for BMFF/MP4 containers",
5
5
  "license": "Apache-2.0",
6
6
  "authors": [