{"version":3,"file":"proofs.mjs","names":["signature: Uint8Array","out: string[]","out: number[]"],"sources":["../../src/zcap/proofs.ts"],"sourcesContent":["/**\n * JCS (RFC 8785) canonicalization + Ed25519 detached proofs +\n * multibase base58btc.\n */\n\nimport { ed25519 } from '@noble/curves/ed25519'\n\nimport type { CapabilityDict, CapabilityProof } from './model'\n\nexport class JcsCanonError extends Error {\n  public constructor(message: string) {\n    super(message)\n    this.name = 'JcsCanonError'\n  }\n}\n\nexport class ProofVerificationError extends Error {\n  public constructor(message: string) {\n    super(message)\n    this.name = 'ProofVerificationError'\n  }\n}\n\nconst textEncoder = new TextEncoder()\n\n/**\n * RFC 8785 canonical JSON serialization.\n *\n * Rules:\n *   * Keys sorted by UTF-16 code-unit order (which equals Unicode for\n *     BMP characters — what we use).\n *   * No insignificant whitespace.\n *   * Numbers per ECMAScript ToString (integers only — float\n *     canonicalization is intentionally refused).\n *   * Strings: minimal escaping per JSON.\n *   * UTF-8 output.\n */\nexport function canonicalizeJcs(value: unknown): Uint8Array {\n  return textEncoder.encode(serialize(value))\n}\n\nfunction serialize(v: unknown): string {\n  if (v === null || v === undefined) return 'null'\n  if (typeof v === 'boolean') return v ? 'true' : 'false'\n  if (typeof v === 'number') {\n    if (!Number.isFinite(v)) {\n      throw new JcsCanonError('non-finite numbers are not allowed in capability documents')\n    }\n    if (!Number.isInteger(v)) {\n      throw new JcsCanonError(\n        'floats are not allowed in capability documents (ambiguous representation); use ints or string-encoded decimals'\n      )\n    }\n    return String(v)\n  }\n  if (typeof v === 'string') return serializeString(v)\n  if (Array.isArray(v)) return '[' + v.map(serialize).join(',') + ']'\n  if (typeof v === 'object') {\n    const entries = Object.entries(v as Record<string, unknown>).sort(([a], [b]) =>\n      compareUtf16(a, b)\n    )\n    return '{' + entries.map(([k, val]) => serializeString(k) + ':' + serialize(val)).join(',') + '}'\n  }\n  throw new JcsCanonError(`JCS cannot serialize ${typeof v}`)\n}\n\nfunction serializeString(s: string): string {\n  let out = '\"'\n  for (const ch of s) {\n    const cp = ch.codePointAt(0) ?? 0\n    if (cp === 0x22) out += '\\\\\"'\n    else if (cp === 0x5c) out += '\\\\\\\\'\n    else if (cp === 0x08) out += '\\\\b'\n    else if (cp === 0x09) out += '\\\\t'\n    else if (cp === 0x0a) out += '\\\\n'\n    else if (cp === 0x0c) out += '\\\\f'\n    else if (cp === 0x0d) out += '\\\\r'\n    else if (cp < 0x20) out += '\\\\u' + cp.toString(16).padStart(4, '0')\n    else out += ch\n  }\n  return out + '\"'\n}\n\n/** UTF-16 code-unit comparison (RFC 8785 §3.2.3). */\nfunction compareUtf16(a: string, b: string): number {\n  for (let i = 0; i < Math.min(a.length, b.length); i++) {\n    const ca = a.charCodeAt(i)\n    const cb = b.charCodeAt(i)\n    if (ca !== cb) return ca - cb\n  }\n  return a.length - b.length\n}\n\n/**\n * Produce a proof block for a capability. Capability dict MUST NOT\n * already contain a `proof` field (caller strips it).\n *\n * The returned dict is what the caller assigns to `capability.proof`.\n */\nexport function signCapability({\n  capabilityDict,\n  privateKeyBytes,\n  verificationMethod,\n  proofPurpose = 'capabilityDelegation',\n  created,\n}: {\n  capabilityDict: Omit<CapabilityDict, 'proof'> | Record<string, unknown>\n  privateKeyBytes: Uint8Array\n  verificationMethod: string\n  proofPurpose?: string\n  created?: string\n}): CapabilityProof {\n  if ('proof' in capabilityDict) {\n    throw new JcsCanonError(`capabilityDict must not carry 'proof' at signing time`)\n  }\n  if (privateKeyBytes.length !== 32) {\n    throw new ProofVerificationError(\n      `Ed25519 private key must be 32 bytes (got ${privateKeyBytes.length})`\n    )\n  }\n  const canonical = canonicalizeJcs(capabilityDict)\n  const signature = ed25519.sign(canonical, privateKeyBytes)\n  return {\n    type: 'Ed25519Signature2020',\n    created: created ?? new Date().toISOString(),\n    verificationMethod,\n    proofPurpose,\n    proofValue: multibaseBase58btc(signature),\n  }\n}\n\n/**\n * Verify the proof binds the public key to the canonical capability.\n *\n * Throws `ProofVerificationError` on any failure — callers map to\n * `cap-invalid` per spec § grant-access problem reports.\n */\nexport function verifyProof({\n  capabilityDict,\n  proof,\n  publicKeyBytes,\n}: {\n  capabilityDict: CapabilityDict | Record<string, unknown>\n  proof: CapabilityProof\n  publicKeyBytes: Uint8Array\n}): void {\n  if (proof.type !== 'Ed25519Signature2020') {\n    throw new ProofVerificationError(`unsupported proof.type ${JSON.stringify(proof.type)}`)\n  }\n  if (proof.proofPurpose !== 'capabilityDelegation' && proof.proofPurpose !== 'capabilityInvocation') {\n    throw new ProofVerificationError(`unsupported proofPurpose ${JSON.stringify(proof.proofPurpose)}`)\n  }\n  const proofValue = proof.proofValue\n  if (typeof proofValue !== 'string' || !proofValue.startsWith('z')) {\n    throw new ProofVerificationError('proofValue missing or not multibase-z')\n  }\n  let signature: Uint8Array\n  try {\n    signature = multibaseBase58btcDecode(proofValue)\n  } catch (err) {\n    throw new ProofVerificationError(`proofValue decode failed: ${(err as Error).message}`)\n  }\n  if (publicKeyBytes.length !== 32) {\n    throw new ProofVerificationError(\n      `Ed25519 public key must be 32 bytes (got ${publicKeyBytes.length})`\n    )\n  }\n  const payload = { ...(capabilityDict as Record<string, unknown>) }\n  delete (payload as { proof?: unknown }).proof\n  const canonical = canonicalizeJcs(payload)\n  if (!ed25519.verify(signature, canonical, publicKeyBytes)) {\n    throw new ProofVerificationError('Ed25519 signature verify failed')\n  }\n}\n\n// ───────────────────────── multibase base58btc ─────────────────────\n\nconst B58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'\n\nexport function multibaseBase58btc(bytes: Uint8Array): string {\n  return 'z' + base58Encode(bytes)\n}\n\nexport function multibaseBase58btcDecode(s: string): Uint8Array {\n  if (!s.startsWith('z')) {\n    throw new Error(`multibase prefix must be 'z' (base58btc), got ${s[0]}`)\n  }\n  return base58Decode(s.slice(1))\n}\n\nfunction base58Encode(b: Uint8Array): string {\n  let n = 0n\n  for (const x of b) n = n * 256n + BigInt(x)\n  const out: string[] = []\n  while (n > 0n) {\n    const r = Number(n % 58n)\n    n /= 58n\n    out.push(B58_ALPHABET[r])\n  }\n  // Preserve leading zero bytes as leading '1' chars (base58btc convention).\n  for (const byte of b) {\n    if (byte === 0) out.push(B58_ALPHABET[0])\n    else break\n  }\n  return out.reverse().join('')\n}\n\nfunction base58Decode(s: string): Uint8Array {\n  let n = 0n\n  for (const ch of s) {\n    const idx = B58_ALPHABET.indexOf(ch)\n    if (idx < 0) throw new Error(`invalid base58btc char: ${ch}`)\n    n = n * 58n + BigInt(idx)\n  }\n  const out: number[] = []\n  while (n > 0n) {\n    out.push(Number(n & 0xffn))\n    n >>= 8n\n  }\n  out.reverse()\n  // Replay leading '1' → leading zero byte.\n  let zeroPad = 0\n  for (const ch of s) {\n    if (ch === B58_ALPHABET[0]) zeroPad++\n    else break\n  }\n  return new Uint8Array([...Array(zeroPad).fill(0), ...out])\n}\n"],"mappings":"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"}