{"_id":"@durin/aliro-cose","_rev":"2-2791dad350e2aae8faa522c2a8515e1b","name":"@durin/aliro-cose","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@durin/aliro-cose","version":"0.1.0","_id":"@durin/aliro-cose@0.1.0","maintainers":[{"name":"frederik-delacourt","email":"frederik@durin.ai"}],"dist":{"shasum":"9c8af56327583e143db1d16c3b5e4218ecba81fa","tarball":"https://registry.npmjs.org/@durin/aliro-cose/-/aliro-cose-0.1.0.tgz","fileCount":8,"integrity":"sha512-NWW565A3+vgq4YlVX7grp83YUWeHlveh1rEEBcs1MRzOleMRgxHxqqcDMXrAl6+sHrXhODJCwPG1HisNZbdmqw==","signatures":[{"sig":"MEQCIA/7k90xfcz4dYT0547rAxCWZmvxaGm5HdL/2U3GBON4AiABGuubWw2yCJLufFrKt6Gain+0zscIqcGPqa06zhoX5w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":106750},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"6d528e43530b5f12a2821ac4a2dbb71ff485a3e1","scripts":{"dev":"vitest","lint":"eslint src --ext .ts","test":"vitest run","build":"tsup","prepare":"husky || true","changeset":"changeset","typecheck":"tsc -p tsconfig.test.json","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"frederik-delacourt","email":"frederik@durin.ai"},"_npmVersion":"11.6.2","description":"CBOR encoding, COSE signing, and Aliro-specific data structure assembly for the Aliro access control protocol","directories":{},"lint-staged":{"*.ts":["eslint --fix"],"*.{ts,json,md}":["prettier --write"]},"_nodeVersion":"24.12.0","dependencies":{"cborg":"^4.2.3","@noble/curves":"^1.8.1","@noble/hashes":"^1.7.1"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.15.0","devDependencies":{"tsup":"^8.3.0","husky":"^9.1.0","eslint":"^8.57.0","vitest":"^3.0.0","prettier":"^3.3.0","typescript":"^5.5.0","@types/node":"^25.5.0","lint-staged":"^15.2.0","@changesets/cli":"^2.27.1","@vitest/coverage-v8":"^3.0.0","@typescript-eslint/parser":"^7.18.0","@typescript-eslint/eslint-plugin":"^7.18.0"},"_npmOperationalInternal":{"tmp":"tmp/aliro-cose_0.1.0_1775283415491_0.6163023705021216","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@durin/aliro-cose","version":"0.3.0","type":"module","description":"CBOR encoding, COSE signing, and Aliro-specific data structure assembly for the Aliro access control protocol","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"dependencies":{"@noble/curves":"^1.8.1","@noble/hashes":"^1.7.1","cborg":"^4.2.3"},"devDependencies":{"@changesets/cli":"^2.27.1","@types/node":"^25.5.0","@typescript-eslint/eslint-plugin":"^7.18.0","@typescript-eslint/parser":"^7.18.0","@vitest/coverage-v8":"^3.0.0","eslint":"^8.57.0","husky":"^9.1.0","lint-staged":"^15.2.0","prettier":"^3.3.0","tsup":"^8.3.0","typescript":"^5.5.0","vitest":"^3.0.0"},"lint-staged":{"*.ts":["eslint --fix"],"*.{ts,json,md}":["prettier --write"]},"scripts":{"build":"tsup","dev":"vitest","lint":"eslint src --ext .ts","typecheck":"tsc -p tsconfig.test.json","test":"vitest run","test:coverage":"vitest run --coverage","changeset":"changeset"},"_id":"@durin/aliro-cose@0.3.0","_integrity":"sha512-KVryP6mrefR9Be12+hzEyCLkGiy4Tg0+LJwKYQVL58OpcW4WRKE+Nqc6PErf87kuVPdAfm+LNtN4OLVxiP5b+g==","_resolved":"/tmp/c14e08fc708044f28b3551a40c2fbcb9/durin-aliro-cose-0.3.0.tgz","_from":"file:durin-aliro-cose-0.3.0.tgz","_nodeVersion":"22.22.3","_npmVersion":"10.9.8","dist":{"integrity":"sha512-KVryP6mrefR9Be12+hzEyCLkGiy4Tg0+LJwKYQVL58OpcW4WRKE+Nqc6PErf87kuVPdAfm+LNtN4OLVxiP5b+g==","shasum":"9b3d12abcb7f295e5c6fce5a982503c6f626c9af","tarball":"https://registry.npmjs.org/@durin/aliro-cose/-/aliro-cose-0.3.0.tgz","fileCount":8,"unpackedSize":108540,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHFC3ScT+98RbsYH8CXJ422dkt6yxSTjzy6BdDwIWVsCAiEA1oS/8kFkNQtJ/tnt2D1WkVtSWFOJXH5aDuBRzDU9r6U="}]},"_npmUser":{"name":"frederik-delacourt","email":"frederik@durin.ai"},"directories":{},"maintainers":[{"name":"frederik-delacourt","email":"frederik@durin.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/aliro-cose_0.3.0_1780725311475_0.09434681242359866"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-04T06:16:55.345Z","modified":"2026-06-06T05:55:11.751Z","0.1.0":"2026-04-04T06:16:55.645Z","0.3.0":"2026-06-06T05:55:11.606Z"},"description":"CBOR encoding, COSE signing, and Aliro-specific data structure assembly for the Aliro access control protocol","maintainers":[{"name":"frederik-delacourt","email":"frederik@durin.ai"}],"readme":"# @durin/aliro-cose\n\nCryptographic core of the [Aliro](https://aliro.org) access-control protocol. Encodes, signs, and verifies **Access Documents** and **Revocation Documents** using CBOR (RFC 8949), COSE Sign1 (RFC 9052), and Aliro's ISO 18013-5-based key remapping (Aliro §7).\n\n## Contents\n\n- [Installation](#installation)\n- [Quick start](#quick-start)\n- [Concepts](#concepts)\n- [Issuing an Access Document](#issuing-an-access-document)\n  - [1. Build data elements](#1-build-data-elements)\n  - [2. Assemble and sign](#2-assemble-and-sign)\n  - [3. Build a provisioning payload](#3-build-a-provisioning-payload)\n- [Issuing a Revocation Document](#issuing-a-revocation-document)\n- [Reader-side verification](#reader-side-verification)\n- [HSM / KMS integration](#hsm--kms-integration)\n- [Key utilities](#key-utilities)\n- [Testing utilities](#testing-utilities)\n- [API reference](#api-reference)\n\n---\n\n## Installation\n\n```bash\npnpm add @durin/aliro-cose\n# or\nnpm install @durin/aliro-cose\n```\n\nRequires Node.js 18+.\n\n---\n\n## Quick start\n\n```typescript\nimport {\n  generateCredentialKeyPair,\n  computeKid,\n  buildAccessData,\n  createAccessDocument,\n  signAccessDocument,\n  verifyAccessDocument,\n  ALIRO_DOC_TYPE_ACCESS,\n} from '@durin/aliro-cose';\n\n// 1. Generate a key pair for the issuer (or load from your KMS)\nconst issuerKeys = generateCredentialKeyPair();\n\n// 2. Generate a key pair for the User Device credential\nconst deviceKeys = generateCredentialKeyPair();\n\n// 3. Build a minimal access data element\nconst accessData = buildAccessData({ version: 1 });\n\n// 4. Assemble the unsigned Access Document\nconst now = new Date();\nconst doc = createAccessDocument({\n  elements: [{ identifier: 'primary_access', accessData }],\n  validityInfo: {\n    signed: now,\n    validFrom: now,\n    validUntil: new Date(now.getTime() + 365 * 86_400_000), // 1 year\n  },\n  credentialPublicKey: deviceKeys.publicKey,\n  timeVerificationRequired: false,\n});\n\n// 5. Sign with the issuer's private key\nconst kid = computeKid(issuerKeys.publicKey);\nconst coseSign1Bytes = await signAccessDocument(doc, issuerKeys.privateKey, { kid });\n\n// 6. Verify (Reader side)\nconst result = verifyAccessDocument(coseSign1Bytes, issuerKeys.publicKey, doc.issuerSignedItems);\nconsole.log(result.valid); // true\n```\n\n---\n\n## Concepts\n\n### Document structure\n\nAn Aliro Access Document is a **COSE_Sign1** envelope (RFC 9052 §4.2) containing:\n\n```\nCOSE_Sign1 = [\n  protectedHeader,  // CBOR-encoded map: { alg: ES256, kid/x5chain }\n  {},               // unprotected header (empty in Aliro)\n  payload,          // CBOR-encoded MobileSecurityObject (MSO)\n  signature,        // 64-byte ES256 r‖s compact signature\n]\n```\n\nThe **MSO** payload contains:\n\n- `valueDigests` — SHA-256 of each `IssuerSignedItem` (the integrity binding)\n- `deviceKeyInfo` — the User Device's P-256 public key\n- `validityInfo` — signed/validFrom/validUntil timestamps + optional iteration counter\n- `docType` — `\"aliro-a\"` (Access) or `\"aliro-r\"` (Revocation)\n- `timeVerificationRequired` — whether the Reader must validate timestamps\n\nEach **IssuerSignedItem** wraps a single data element (access rules, schedules, etc.) with a random salt and sequential digest ID. Items can be selectively disclosed to the Reader.\n\n### Key remapping\n\nAliro replaces ISO 18013-5 human-readable map keys with short numeric string keys (`\"1\"`, `\"2\"`, …) encoded as **CBOR text strings** — not integers. This library handles all remapping internally; you work with plain TypeScript objects.\n\n---\n\n## Issuing an Access Document\n\n### 1. Build data elements\n\n#### Minimal element\n\n```typescript\nimport { buildAccessData } from '@durin/aliro-cose';\n\nconst accessData = buildAccessData({ version: 1 });\n```\n\n#### With access rules and schedules\n\n```typescript\nimport {\n  buildAccessData,\n  buildAccessRule,\n  buildSchedule,\n  buildRecurrenceRule,\n} from '@durin/aliro-cose';\n\n// A schedule: weekday business hours, UTC\nconst schedule = buildSchedule({\n  scheduleId: 1,\n  startPeriod: Math.floor(Date.now() / 1000),\n  endPeriod: Math.floor(Date.now() / 1000) + 365 * 86400,\n  flags: { timeInUtc: true },\n  recurrenceRule: buildRecurrenceRule({\n    pattern: 'Weekly',\n    durationSeconds: 9 * 3600, // 9 hours\n    interval: 1,\n    ordinal: 0,\n    mask: { monday: true, tuesday: true, wednesday: true, thursday: true, friday: true },\n  }),\n});\n\n// An access rule: allow secure access during the schedule above\nconst rule = buildAccessRule({\n  capabilities: { secure: true },\n  allowScheduleIds: [1],\n});\n\n// Build the element\nconst accessData = buildAccessData({\n  version: 1,\n  id: new Uint8Array([0x01, 0x02]), // 1–16 bytes, optional\n  accessRules: [rule], // max 8 rules\n  schedules: [schedule], // max 8 schedules\n  readerRuleIds: [100], // max 8, each uint16\n  timeVerificationRequired: false, // set via document opts, not here\n});\n```\n\n**`buildAccessRule` capabilities** (Aliro §7 Table 7-3):\n\n| Field                       | Meaning                     |\n| --------------------------- | --------------------------- |\n| `secure`                    | Lock/unlock when secured    |\n| `unsecured`                 | Lock/unlock when unsecured  |\n| `toggleSecuredOrUnsecured`  | Toggle the secured state    |\n| `momentaryUnsecure`         | Momentary unsecure          |\n| `extendedMomentaryUnsecure` | Extended momentary unsecure |\n\n### 2. Assemble and sign\n\n```typescript\nimport {\n  generateCredentialKeyPair,\n  computeKid,\n  createAccessDocument,\n  signAccessDocument,\n  ALIRO_DOC_TYPE_ACCESS,\n} from '@durin/aliro-cose';\n\nconst issuerKeys = generateCredentialKeyPair();\nconst deviceKeys = generateCredentialKeyPair(); // device generates its own in production\n\nconst now = new Date();\nconst validUntil = new Date(now.getTime() + 30 * 86_400_000); // 30 days\n\n// createAccessDocument returns an unsigned document you can inspect\nconst doc = createAccessDocument({\n  elements: [{ identifier: 'primary_access', accessData }],\n  validityInfo: {\n    signed: now,\n    validFrom: now,\n    validUntil,\n    validityIteration: 0, // optional; increment on each re-issuance\n  },\n  credentialPublicKey: deviceKeys.publicKey, // omit for keyless docs\n  timeVerificationRequired: true,\n});\n\n// Inspect before signing if needed:\nconsole.log(doc.valueDigests.size); // number of IssuerSignedItems\nconsole.log(doc.msoBytes.length); // raw MSO CBOR bytes\n\n// Sign — returns the final COSE_Sign1 bytes\nconst kid = computeKid(issuerKeys.publicKey);\nconst coseSign1Bytes = await signAccessDocument(doc, issuerKeys.privateKey, {\n  kid, // 8-byte key identifier\n  // x5chain: certDerBytes,  // optionally include DER-encoded certificate chain\n});\n```\n\n**Header options** — at least one of `kid` or `x5chain` is required:\n\n| Option    | Type                   | Description                       |\n| --------- | ---------------------- | --------------------------------- |\n| `kid`     | `Uint8Array` (8 bytes) | Key identifier (use `computeKid`) |\n| `x5chain` | `Uint8Array`           | DER-encoded issuer certificate    |\n\n### 3. Build a provisioning payload\n\nTo deliver the credential to the User Device, build a JSON-serializable payload:\n\n```typescript\nimport { buildProvisioningPayload, ALIRO_DOC_TYPE_ACCESS } from '@durin/aliro-cose';\n\nconst payload = buildProvisioningPayload({\n  docType: ALIRO_DOC_TYPE_ACCESS,\n  issuerAuth: coseSign1Bytes, // the signed document\n  issuerSignedItems: doc.issuerSignedItems,\n});\n\n// payload is JSON-serializable — base64 encodes all binary fields\nconst json = JSON.stringify(payload);\n// Send over QR code, BLE OOB, server push, etc.\n\n// payload shape:\n// {\n//   docType: 'aliro-a',\n//   issuerAuthBase64: '<base64>',\n//   items: [\n//     { identifier: 'primary_access', digestId: 0, itemBytesBase64: '<base64>' },\n//   ],\n// }\n```\n\n> **Security note:** The device's private key is generated inside the secure enclave and never leaves it. This library never receives or stores device private keys in production.\n\n---\n\n## Issuing a Revocation Document\n\n```typescript\nimport {\n  buildRevocationData,\n  createRevocationDocument,\n  signRevocationDocument,\n  ALIRO_DOC_TYPE_REVOCATION,\n} from '@durin/aliro-cose';\n\n// Overwrite mode: replace the entire revocation list\nconst revocationData = buildRevocationData({\n  changeMode: 0, // 0 = Overwrite, 1 = Update\n  revocationEntries: [\n    { publicKeyHash: sha256OfRevokedKey }, // SHA-256 of credential public key\n    { keyIdentifier: revokedKid }, // or use the 8-byte KID\n  ],\n});\n\nconst revDoc = createRevocationDocument({\n  elements: [{ identifier: 'revocation_list', accessData: revocationData }],\n  validityInfo: { signed: now, validFrom: now, validUntil },\n  timeVerificationRequired: false,\n  // No credentialPublicKey — Revocation Documents never include deviceKeyInfo\n});\n\nconst revBytes = await signRevocationDocument(revDoc, issuerKeys.privateKey, { kid });\n```\n\n**Update mode** (append/remove from existing list):\n\n```typescript\nconst updateData = buildRevocationData({\n  changeMode: 1, // Update\n  revocationEntries: [\n    { publicKeyHash: newlyRevokedKey }, // entries to add\n  ],\n  entriesToRemove: [\n    { publicKeyHash: restoredKey }, // entries to remove (Update mode only)\n  ],\n});\n```\n\n---\n\n## Reader-side verification\n\n```typescript\nimport { verifyAccessDocument } from '@durin/aliro-cose';\n\nconst result = verifyAccessDocument(\n  coseSign1Bytes, // bytes received from the User Device\n  issuerPublicKey, // 65-byte uncompressed P-256 public key\n  issuerSignedItems, // items presented by the device\n  new Date(), // currentTime (optional, defaults to Date.now())\n  storedIteration, // Reader's stored validityIteration (optional)\n);\n\nif (result.valid) {\n  console.log('Access granted');\n} else {\n  console.log('Access denied:', result.reason);\n}\n\n// Inspect each verification step:\nconst { steps } = result;\nsteps.structureValid; // COSE_Sign1 is well-formed\nsteps.signatureValid; // ES256 signature is valid\nsteps.digestsValid.allValid; // all item digests match the MSO\nsteps.validityInfo.valid; // document is within its validity window\nsteps.validityIteration; // iteration check result (if storedIteration provided)\nsteps.timeVerificationRequired; // value of the flag in the MSO\n```\n\n### Validity iteration rules (Aliro §7.4)\n\n| Condition                   | Result                           |\n| --------------------------- | -------------------------------- |\n| `docIter >= storedIter`     | Valid (current or ahead)         |\n| `storedIter - docIter < 8`  | Valid (within tolerance)         |\n| `storedIter - docIter >= 8` | **Invalid** (document too stale) |\n\n### Lower-level verification helpers\n\n```typescript\nimport {\n  verifySignature,\n  verifyDigests,\n  verifyValidityInfo,\n  verifyValidityIteration,\n} from '@durin/aliro-cose';\n\n// Check only the COSE signature\nconst sigOk = verifySignature(coseSign1Bytes, issuerPublicKey);\n\n// Check only the item digests\nconst digestResult = verifyDigests(issuerSignedItems, valueDigests);\n// { allValid: true, details: [{ digestId: 0, valid: true }, ...] }\n\n// Check only the validity window\nconst validity = verifyValidityInfo(validFrom, validUntil, new Date());\n// { valid: true } or { valid: false, reason: '...' }\n\n// Check only the iteration counter\nconst iterResult = verifyValidityIteration(docIter, storedIter);\n// { valid: true } or { valid: false, reason: '...' }\n```\n\n---\n\n## HSM / KMS integration\n\nThe `signer` parameter in `signAccessDocument` / `signRevocationDocument` accepts either a raw private key (for development) or an async **`SignerFunction`** that delegates signing to an HSM or KMS. The library never sees the private key in the `SignerFunction` path.\n\n```typescript\nimport type { SignerFunction } from '@durin/aliro-cose';\n\n// Production: sign inside your KMS/HSM\nconst signerFn: SignerFunction = async (data: Uint8Array): Promise<Uint8Array> => {\n  // `data` is the RFC 9052 Sig_structure bytes — pass them to your HSM\n  const signature = await myKms.sign({ keyId: 'issuer-key-id', data });\n  // Must return a 64-byte compact r‖s signature (not DER-encoded)\n  return signature;\n};\n\nconst coseSign1Bytes = await signAccessDocument(doc, signerFn, { kid });\n```\n\n> The `data` passed to `SignerFunction` is already the hashed + structured bytes per RFC 9052 §4.4. Most KMS APIs require you to pass the raw `data` to a `sign(data, { alg: 'ES256' })` method — the KMS performs the SHA-256 hash internally.\n\n---\n\n## Key utilities\n\n```typescript\nimport {\n  generateCredentialKeyPair,\n  computeKid,\n  encodePublicKeyAsCoseKey,\n  parseCoseKey,\n} from '@durin/aliro-cose';\n\n// Generate a P-256 key pair\nconst { privateKey, publicKey } = generateCredentialKeyPair();\n// privateKey: Uint8Array (32 bytes) — store in HSM\n// publicKey:  Uint8Array (65 bytes) — 0x04 || x || y\n\n// Compute the 8-byte key identifier\nconst kid = computeKid(publicKey);\n// kid = SHA-256(\"key-identifier\" || publicKey)[0..8]\n\n// Encode a public key as a CBOR COSE_Key (for embedding in external structures)\nconst coseKeyBytes = encodePublicKeyAsCoseKey(publicKey);\n\n// Parse a COSE_Key back to an uncompressed public key\nconst recovered = parseCoseKey(coseKeyBytes);\n```\n\n---\n\n## Testing utilities\n\nImport from the `@durin/aliro-cose/testing` subpath — these are excluded from the production bundle.\n\n```typescript\nimport {\n  createTestKeyPair,\n  createTestVector,\n  makeTestElement,\n  simulateReaderVerification,\n  fuzzAccessData,\n  hexDump,\n  compareCBOR,\n  prettyPrintCBOR,\n} from '@durin/aliro-cose/testing';\n```\n\n### Deterministic test key pairs\n\n```typescript\nconst { privateKey, publicKey } = createTestKeyPair('my-test-seed');\n// Same seed always produces the same key pair — useful for reproducible test vectors\n```\n\n### Test vectors\n\n```typescript\nconst vector = await createTestVector({\n  name: 'access-doc-v1',\n  seed: 'stable-seed',\n  validityInfo: { signed: now, validFrom: now, validUntil: later },\n  elements: [makeTestElement('primary')],\n});\n\n// vector.coseSign1Bytes — the signed document\n// vector.publicKey      — the issuer's public key (derived from seed)\n// vector.msoBytes       — raw MSO for inspection\n```\n\n### Reader simulation\n\n```typescript\nconst result = simulateReaderVerification(\n  coseSign1Bytes,\n  issuerPublicKey,\n  issuerSignedItems,\n  { storedIteration: 3 }, // Reader state\n  new Date(), // fixed time for tests\n);\n// { accessGranted: true, verificationResult: { ... } }\n```\n\n### Fuzzing\n\n```typescript\nconst result = await fuzzAccessData(10_000); // 10k random iterations\nconsole.log(result.passed); // should equal 10000\nconsole.log(result.errors); // should be []\n```\n\n### Diagnostics\n\n```typescript\n// Hex dump\nhexDump(bytes); // 'deadbeef...'\nhexDump(bytes, { groupBy: 4, uppercase: true }); // 'DEADBEEF C0FFEE00...'\n\n// Compare two CBOR byte sequences\nconst diff = compareCBOR(a, b);\n// { equal: false, difference: 'first difference at byte 12: 0x3a vs 0x3b' }\n\n// Pretty-print decoded CBOR structure\nconsole.log(prettyPrintCBOR(msoBytes));\n// {\n//   \"1\": \"1.0\",\n//   \"2\": \"SHA-256\",\n//   \"3\": { ... },\n//   ...\n// }\n```\n\n---\n\n## API reference\n\n### Document builders\n\n| Function                                          | Description                                   |\n| ------------------------------------------------- | --------------------------------------------- |\n| `createAccessDocument(opts)`                      | Assembles unsigned MSO + IssuerSignedItems    |\n| `signAccessDocument(doc, signer, headerOpts)`     | Signs and returns COSE_Sign1 bytes            |\n| `createRevocationDocument(opts)`                  | Assembles unsigned Revocation Document        |\n| `signRevocationDocument(doc, signer, headerOpts)` | Signs and returns COSE_Sign1 bytes            |\n| `buildProvisioningPayload(opts)`                  | JSON-serializable payload for device delivery |\n\n### Data element builders\n\n| Function                    | Description                                        |\n| --------------------------- | -------------------------------------------------- |\n| `buildAccessData(opts)`     | AccessData element (version, id, rules, schedules) |\n| `buildAccessRule(opts)`     | AccessRule with capability bitmask                 |\n| `buildSchedule(opts)`       | Schedule with optional recurrence                  |\n| `buildRecurrenceRule(opts)` | Recurrence rule (Daily/Weekly/Monthly/Yearly)      |\n| `buildRevocationData(opts)` | RevocationData for Overwrite or Update mode        |\n\n### Key utilities\n\n| Function                              | Description                                     |\n| ------------------------------------- | ----------------------------------------------- |\n| `generateCredentialKeyPair()`         | Fresh P-256 key pair                            |\n| `computeKid(publicKey)`               | 8-byte key identifier from public key           |\n| `encodePublicKeyAsCoseKey(publicKey)` | Encode as CBOR COSE_Key                         |\n| `parseCoseKey(bytes)`                 | Decode COSE_Key back to uncompressed public key |\n\n### Verification\n\n| Function                                   | Description                                  |\n| ------------------------------------------ | -------------------------------------------- |\n| `verifyAccessDocument(...)`                | Full §7.4 verification with per-step results |\n| `verifySignature(bytes, publicKey)`        | COSE_Sign1 signature check only              |\n| `verifyDigests(items, valueDigests)`       | Item digest integrity check only             |\n| `verifyValidityInfo(from, until, now?)`    | Timestamp window check                       |\n| `verifyValidityIteration(docIter, stored)` | Iteration counter check                      |\n\n### Constants\n\n| Constant                     | Value       |\n| ---------------------------- | ----------- |\n| `ALIRO_DOC_TYPE_ACCESS`      | `\"aliro-a\"` |\n| `ALIRO_DOC_TYPE_REVOCATION`  | `\"aliro-r\"` |\n| `ALIRO_NAMESPACE_ACCESS`     | `\"aliro-a\"` |\n| `ALIRO_NAMESPACE_REVOCATION` | `\"aliro-r\"` |\n\n### Testing subpath (`@durin/aliro-cose/testing`)\n\n| Export                            | Description                                   |\n| --------------------------------- | --------------------------------------------- |\n| `createTestKeyPair(seed)`         | Deterministic P-256 key pair from string seed |\n| `createTestVector(opts)`          | Signed test document with fixed seed          |\n| `makeTestElement(id)`             | Minimal DataElementInput for test vectors     |\n| `simulateReaderVerification(...)` | End-to-end Reader simulation                  |\n| `fuzzAccessData(iterations?)`     | Random-input round-trip fuzzer                |\n| `hexDump(bytes, opts?)`           | Bytes → hex string with optional grouping     |\n| `compareCBOR(a, b)`               | Byte-level diff of two CBOR sequences         |\n| `prettyPrintCBOR(bytes)`          | Human-readable CBOR decoder                   |\n","readmeFilename":"README.md"}