@peac/crypto 0.12.0-preview.1 → 0.12.0-preview.2
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.cjs +4 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -450,6 +450,10 @@ exports.canonicalizeBytes = canonicalizeBytes;
|
|
|
450
450
|
exports.computeJwkThumbprint = computeJwkThumbprint;
|
|
451
451
|
exports.decode = decode;
|
|
452
452
|
exports.derivePublicKey = derivePublicKey;
|
|
453
|
+
exports.ed25519GetPublicKey = getPublicKey;
|
|
454
|
+
exports.ed25519RandomSecretKey = randomSecretKey;
|
|
455
|
+
exports.ed25519Sign = sign;
|
|
456
|
+
exports.ed25519Verify = verify;
|
|
453
457
|
exports.generateKeypair = generateKeypair;
|
|
454
458
|
exports.hexToBase64url = hexToBase64url;
|
|
455
459
|
exports.hexToBytes = hexToBytes;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/base64url.ts","../src/errors.ts","../src/hash.ts","../src/jcs.ts","../src/ed25519.ts","../src/jws.ts"],"names":["ed","WIRE_01_JWS_TYP","WIRE_02_JWS_TYP_ACCEPT","PEAC_ALG","WIRE_02_JWS_TYP","sign","verify","VERIFIER_LIMITS"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Base64url encoding/decoding (RFC 4648 §5)\n *\n * Platform-agnostic implementation that works in Node.js, browser, and edge runtimes.\n * No Buffer dependency - uses pure JavaScript for maximum portability.\n *\n * @packageDocumentation\n */\n\n// Standard base64 alphabet\nconst BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n// Reverse lookup table (lazily initialized)\nlet base64Lookup: Map<string, number> | null = null;\n\nfunction getBase64Lookup(): Map<string, number> {\n if (!base64Lookup) {\n base64Lookup = new Map();\n for (let i = 0; i < BASE64_ALPHABET.length; i++) {\n base64Lookup.set(BASE64_ALPHABET[i], i);\n }\n }\n return base64Lookup;\n}\n\n/**\n * Encode bytes to base64url string (no padding)\n *\n * @param bytes - Byte array to encode\n * @returns Base64url encoded string (no padding)\n */\nexport function base64urlEncode(bytes: Uint8Array): string {\n let result = '';\n let i = 0;\n\n while (i < bytes.length) {\n const a = bytes[i++];\n const b = bytes[i++] ?? 0;\n const c = bytes[i++] ?? 0;\n\n const triplet = (a << 16) | (b << 8) | c;\n\n result += BASE64_ALPHABET[(triplet >> 18) & 0x3f];\n result += BASE64_ALPHABET[(triplet >> 12) & 0x3f];\n result += i - 2 < bytes.length ? BASE64_ALPHABET[(triplet >> 6) & 0x3f] : '';\n result += i - 1 < bytes.length ? BASE64_ALPHABET[triplet & 0x3f] : '';\n }\n\n // Convert to base64url (no padding)\n return result.replace(/\\+/g, '-').replace(/\\//g, '_');\n}\n\n/**\n * Decode base64url string to bytes\n *\n * @param str - Base64url encoded string\n * @returns Decoded bytes\n */\nexport function base64urlDecode(str: string): Uint8Array {\n // Convert base64url to base64\n let base64 = str.replace(/-/g, '+').replace(/_/g, '/');\n\n // Add padding if needed\n while (base64.length % 4 !== 0) {\n base64 += '=';\n }\n\n const lookup = getBase64Lookup();\n const bytes: number[] = [];\n\n for (let i = 0; i < base64.length; i += 4) {\n const a = lookup.get(base64[i]) ?? 0;\n const b = lookup.get(base64[i + 1]) ?? 0;\n const c = lookup.get(base64[i + 2]) ?? 0;\n const d = lookup.get(base64[i + 3]) ?? 0;\n\n bytes.push((a << 2) | (b >> 4));\n if (base64[i + 2] !== '=') {\n bytes.push(((b & 0x0f) << 4) | (c >> 2));\n }\n if (base64[i + 3] !== '=') {\n bytes.push(((c & 0x03) << 6) | d);\n }\n }\n\n return new Uint8Array(bytes);\n}\n\n/**\n * Encode UTF-8 string to base64url\n *\n * @param str - UTF-8 string to encode\n * @returns Base64url encoded string\n */\nexport function base64urlEncodeString(str: string): string {\n return base64urlEncode(new TextEncoder().encode(str));\n}\n\n/**\n * Decode base64url to UTF-8 string\n *\n * @param str - Base64url encoded string\n * @returns Decoded UTF-8 string\n */\nexport function base64urlDecodeString(str: string): string {\n return new TextDecoder().decode(base64urlDecode(str));\n}\n","/**\n * Typed errors for @peac/crypto\n *\n * These error codes are INTERNAL to @peac/crypto and should NOT be exposed\n * as protocol-stable API. Higher-level packages (like @peac/protocol) should\n * map these to canonical E_* codes from specs/kernel/errors.json.\n *\n * The CRYPTO_ prefix makes it clear these are package-internal codes.\n */\n\n/**\n * Internal error codes for crypto operations\n *\n * These are NOT canonical protocol error codes. They are internal to @peac/crypto.\n * @peac/protocol maps these to canonical E_* codes (E_INVALID_FORMAT, etc).\n */\nexport type CryptoErrorCode =\n | 'CRYPTO_INVALID_KEY_LENGTH'\n | 'CRYPTO_INVALID_SEED_LENGTH'\n | 'CRYPTO_INVALID_JWS_FORMAT'\n | 'CRYPTO_INVALID_TYP'\n | 'CRYPTO_INVALID_ALG'\n | 'CRYPTO_INVALID_SIGNATURE'\n // Wire 0.2 JOSE hardening (v0.12.0-preview.1, DD-156)\n | 'CRYPTO_WIRE_VERSION_MISMATCH'\n | 'CRYPTO_JWS_EMBEDDED_KEY'\n | 'CRYPTO_JWS_CRIT_REJECTED'\n | 'CRYPTO_JWS_MISSING_KID'\n | 'CRYPTO_JWS_B64_REJECTED'\n | 'CRYPTO_JWS_ZIP_REJECTED';\n\n/**\n * Typed error for crypto operations\n *\n * Use `err.code` to handle errors programmatically without message parsing.\n * The code is a CRYPTO_* internal code, not a canonical E_* protocol code.\n */\nexport class CryptoError extends Error {\n readonly code: CryptoErrorCode;\n\n constructor(code: CryptoErrorCode, message: string) {\n super(message);\n this.name = 'CryptoError';\n this.code = code;\n // Maintain proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, CryptoError.prototype);\n }\n}\n\n/**\n * Check if a CryptoError code indicates a format/structure issue\n * (as opposed to a cryptographic verification failure)\n *\n * @internal This is an internal helper, not part of the public API.\n * Use structural checks on CryptoError.code instead of relying on this function.\n */\nexport function isFormatError(code: CryptoErrorCode): boolean {\n return (\n code === 'CRYPTO_INVALID_JWS_FORMAT' ||\n code === 'CRYPTO_INVALID_TYP' ||\n code === 'CRYPTO_INVALID_ALG' ||\n code === 'CRYPTO_INVALID_KEY_LENGTH' ||\n code === 'CRYPTO_INVALID_SEED_LENGTH'\n );\n}\n","/**\n * Cryptographic hash utilities\n *\n * Platform-agnostic SHA-256 implementation that works in Node.js, browser, and edge runtimes.\n * Uses Web Crypto API with Node.js crypto fallback.\n *\n * @packageDocumentation\n */\n\nimport { base64urlDecode, base64urlEncode } from './base64url.js';\n\n/**\n * Compute SHA-256 hash of data and return as lowercase hex string\n *\n * Uses Web Crypto API if available, falls back to Node.js crypto.\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Lowercase hex string (64 characters)\n */\nexport async function sha256Hex(data: Uint8Array | string): Promise<string> {\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;\n\n // Try Web Crypto API first (works in browser, edge, and Node 20+)\n if (typeof globalThis.crypto?.subtle?.digest === 'function') {\n const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', bytes);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');\n }\n\n // Fallback to Node.js crypto\n try {\n const { createHash } = await import('crypto');\n const hash = createHash('sha256');\n hash.update(bytes);\n return hash.digest('hex');\n } catch {\n throw new Error(\n 'No SHA-256 implementation available. Ensure Web Crypto API or Node.js crypto is available.'\n );\n }\n}\n\n/**\n * Compute SHA-256 hash of data and return as Uint8Array (32 bytes)\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Hash as Uint8Array (32 bytes)\n */\nexport async function sha256Bytes(data: Uint8Array | string): Promise<Uint8Array> {\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;\n\n // Try Web Crypto API first\n if (typeof globalThis.crypto?.subtle?.digest === 'function') {\n const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', bytes);\n return new Uint8Array(hashBuffer);\n }\n\n // Fallback to Node.js crypto\n try {\n const { createHash } = await import('crypto');\n const hash = createHash('sha256');\n hash.update(bytes);\n return new Uint8Array(hash.digest());\n } catch {\n throw new Error('No SHA-256 implementation available.');\n }\n}\n\n/**\n * Convert hex string to Uint8Array\n *\n * @param hex - Lowercase hex string\n * @returns Uint8Array\n */\nexport function hexToBytes(hex: string): Uint8Array {\n // Validate: must be even length and contain only hex characters\n if (hex.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex)) {\n throw new Error('Invalid hex string');\n }\n if (hex.length === 0) {\n return new Uint8Array([]);\n }\n const matches = hex.match(/.{2}/g);\n if (!matches) {\n throw new Error('Invalid hex string');\n }\n return new Uint8Array(matches.map((byte) => parseInt(byte, 16)));\n}\n\n/**\n * Convert Uint8Array to lowercase hex string\n *\n * @param bytes - Byte array\n * @returns Lowercase hex string\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Compute SHA-256 hash of data and return as base64url string\n *\n * Used by Wire 0.2 DigestRef format. Evidence bundles use sha256Hex() with\n * \"sha256:<hex>\" prefix instead. A conversion bridge between the two formats\n * (hex <-> base64url) is provided by hexToBase64url() and base64urlToHex().\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Base64url-encoded SHA-256 hash (43 characters)\n */\nexport async function sha256Base64url(data: Uint8Array | string): Promise<string> {\n const hashBytes = await sha256Bytes(data);\n return base64urlEncode(hashBytes);\n}\n\n/**\n * Convert a hex-encoded hash to base64url encoding\n *\n * Bridges evidence bundle format (sha256:<hex>) to Wire 0.2 DigestRef format\n * (base64url value). Strips the \"sha256:\" prefix if present.\n *\n * @param hex - Hex string, optionally prefixed with \"sha256:\"\n * @returns Base64url-encoded bytes (43 characters for SHA-256)\n */\nexport function hexToBase64url(hex: string): string {\n const cleanHex = hex.startsWith('sha256:') ? hex.slice(7) : hex;\n return base64urlEncode(hexToBytes(cleanHex));\n}\n\n/**\n * Convert a base64url-encoded hash to hex encoding\n *\n * Bridges Wire 0.2 DigestRef format (base64url) to evidence bundle format\n * (hex). Does NOT add the \"sha256:\" prefix -- caller adds it if needed.\n *\n * @param b64u - Base64url-encoded hash\n * @returns Lowercase hex string (64 characters for SHA-256)\n */\nexport function base64urlToHex(b64u: string): string {\n return bytesToHex(base64urlDecode(b64u));\n}\n\n/**\n * JWK structure for Ed25519 public keys (minimal required fields for thumbprint)\n */\nexport interface JWKThumbprintInput {\n /** Key type - must be \"OKP\" for Ed25519 */\n kty: string;\n /** Curve - must be \"Ed25519\" */\n crv: string;\n /** Public key (base64url) */\n x: string;\n}\n\n/**\n * Compute RFC 7638 JWK Thumbprint (base64url, SHA-256)\n *\n * For Ed25519 keys, the canonical JSON is: {\"crv\":\"Ed25519\",\"kty\":\"OKP\",\"x\":\"<base64url>\"}\n * Returns base64url-encoded SHA-256 hash (43 characters).\n *\n * @param jwk - JWK with kty, crv, x fields\n * @returns Base64url-encoded SHA-256 thumbprint (43 characters)\n */\nexport async function computeJwkThumbprint(jwk: JWKThumbprintInput): Promise<string> {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n throw new Error('Only Ed25519 keys (OKP/Ed25519) are supported for thumbprint computation');\n }\n\n // Canonical JSON per RFC 7638 (alphabetically sorted members, no whitespace)\n const canonical = JSON.stringify({\n crv: jwk.crv,\n kty: jwk.kty,\n x: jwk.x,\n });\n\n const hashBytes = await sha256Bytes(canonical);\n return base64urlEncode(hashBytes);\n}\n\n/**\n * Convert JWK to Ed25519 public key bytes (32 bytes)\n *\n * @param jwk - JWK with kty, crv, x fields\n * @returns Public key as 32-byte Uint8Array\n */\nexport function jwkToPublicKeyBytes(jwk: JWKThumbprintInput): Uint8Array {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n throw new Error('Only Ed25519 keys (OKP/Ed25519) are supported');\n }\n\n const xBytes = base64urlDecode(jwk.x);\n if (xBytes.length !== 32) {\n throw new Error(`Ed25519 public key must be 32 bytes, got ${xBytes.length}`);\n }\n\n return xBytes;\n}\n","/**\n * JSON Canonicalization Scheme (RFC 8785)\n * Deterministic JSON serialization for cryptographic hashing\n *\n * PROTOCOL DECISION: JavaScript `undefined` Handling\n * ===================================================\n *\n * RFC 8785 canonicalizes JSON values, and `undefined` is NOT a JSON value.\n * This implementation adopts \"JS-ergonomic\" semantics that match JSON.stringify:\n *\n * 1. **Object properties with undefined values are OMITTED**\n * - `canonicalize({a: 1, b: undefined})` -> `{\"a\":1}`\n * - Matches: `JSON.stringify({a: 1, b: undefined})` -> `{\"a\":1}`\n *\n * 2. **Array elements that are undefined become null**\n * - `canonicalize([1, undefined, 3])` -> `[1,null,3]`\n * - Matches: `JSON.stringify([1, undefined, 3])` -> `[1,null,3]`\n *\n * 3. **Top-level undefined THROWS**\n * - `canonicalize(undefined)` -> throws Error\n * - Rationale: No valid JSON representation exists\n *\n * CROSS-LANGUAGE INTEROPERABILITY WARNING:\n * =========================================\n * Cross-language producers MUST NOT rely on \"undefined\" semantics. To achieve\n * identical hashes across implementations, explicitly encode `null` in arrays\n * and omit keys in objects. Other language implementations (Go, Rust, Python)\n * will never produce `undefined` since it's JavaScript-specific.\n *\n * Guidelines:\n * - Producers MUST emit explicit `null` or omit keys; do NOT rely on coercion\n * - Verifiers SHOULD sanitize inputs before hashing (remove undefined properties)\n * - The canonical output is identical whether you pass `{a: undefined}` or `{}`\n *\n * This behavior is NORMATIVE for PEAC hashing and MUST NOT change without\n * a wire format version bump.\n */\n\n/**\n * Canonicalize a JSON value according to RFC 8785.\n *\n * @param obj - The value to canonicalize. Must be a valid JSON type (null, boolean,\n * number, string, array, object). Functions and Symbols throw.\n * @returns Canonical JSON string with sorted keys and no whitespace.\n * @throws Error if the value cannot be canonicalized (undefined at top level,\n * non-finite numbers, functions, symbols).\n *\n * @example\n * ```ts\n * canonicalize({ b: 2, a: 1 }) // '{\"a\":1,\"b\":2}'\n * canonicalize([1, null, \"x\"]) // '[1,null,\"x\"]'\n * ```\n */\nexport function canonicalize(obj: unknown): string {\n if (obj === null) {\n return 'null';\n }\n\n if (typeof obj === 'boolean') {\n return obj ? 'true' : 'false';\n }\n\n if (typeof obj === 'number') {\n // RFC 8785 number serialization (no trailing zeros, no exponential for small numbers)\n if (!Number.isFinite(obj)) {\n throw new Error('Cannot canonicalize non-finite number');\n }\n if (Object.is(obj, -0)) {\n return '0';\n }\n // Use JSON.stringify for proper number formatting per RFC 8785\n const str = JSON.stringify(obj);\n // Ensure no exponential notation for integers\n if (Number.isInteger(obj) && str.includes('e')) {\n return obj.toString();\n }\n return str;\n }\n\n if (typeof obj === 'string') {\n return JSON.stringify(obj);\n }\n\n if (Array.isArray(obj)) {\n // PROTOCOL DECISION: undefined in arrays becomes null (matches JSON.stringify)\n // See module-level documentation for cross-language interoperability notes.\n const elements = obj.map((el) => (el === undefined ? 'null' : canonicalize(el)));\n return `[${elements.join(',')}]`;\n }\n\n if (typeof obj === 'object') {\n // Sort keys lexicographically by UTF-16 code unit (RFC 8785 requirement)\n const keys = Object.keys(obj).sort();\n const pairs: string[] = [];\n for (const key of keys) {\n const value = (obj as Record<string, unknown>)[key];\n // PROTOCOL DECISION: Skip undefined values (matches JSON.stringify)\n // See module-level documentation for cross-language interoperability notes.\n if (value === undefined) {\n continue;\n }\n pairs.push(`${JSON.stringify(key)}:${canonicalize(value)}`);\n }\n return `{${pairs.join(',')}}`;\n }\n\n throw new Error(`Cannot canonicalize type: ${typeof obj}`);\n}\n\n/**\n * Canonicalize and encode as UTF-8 bytes\n */\nexport function canonicalizeBytes(obj: unknown): Uint8Array {\n const canonical = canonicalize(obj);\n return new TextEncoder().encode(canonical);\n}\n\n/**\n * Compute JCS+SHA-256 hash of an object\n */\nexport async function jcsHash(obj: unknown): Promise<string> {\n const bytes = canonicalizeBytes(obj);\n const hashBuffer = await crypto.subtle.digest('SHA-256', bytes);\n const hashArray = new Uint8Array(hashBuffer);\n return Array.from(hashArray)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n","/**\n * Internal Ed25519 wrapper -- async-only surface\n *\n * PEAC uses ONLY the async methods from @noble/ed25519.\n * In noble v3, sync methods require explicit hash configuration.\n * Async methods use built-in Web Crypto and need no configuration.\n *\n * This module re-exports only the async surface to prevent accidental\n * sync usage. All other modules in @peac/crypto MUST import from\n * this file, never directly from '@noble/ed25519'.\n *\n * Key material handling:\n * - Private keys are 32-byte Uint8Array (Ed25519 seed)\n * - Public keys are 32-byte Uint8Array (compressed Ed25519 point)\n * - JavaScript cannot guarantee memory zeroization; callers should\n * avoid storing keys longer than necessary and never log key bytes\n * - randomSecretKey() uses crypto.getRandomValues() (CSPRNG)\n * which is available in Node.js >=15 and all modern runtimes\n */\n\n// Namespace import avoids tsup tree-shaking false positive in multi-entry builds\n// where signAsync/verifyAsync appear unused in the testkit entry point.\nimport * as ed from '@noble/ed25519';\n\n/** Sign a message with Ed25519 (async, Web Crypto backed) */\nexport const sign = ed.signAsync;\n\n/** Verify an Ed25519 signature (async, Web Crypto backed) */\nexport const verify = ed.verifyAsync;\n\n/** Derive public key from private key (async, Web Crypto backed) */\nexport const getPublicKey = ed.getPublicKeyAsync;\n\n/** Generate a cryptographically random 32-byte secret key (CSPRNG) */\nexport const randomSecretKey = ed.utils.randomSecretKey;\n","/**\n * JWS compact serialization with Ed25519 (RFC 8032)\n * Dual-stack: Wire 0.1 (peac-receipt/0.1) and Wire 0.2 (interaction-record+jwt)\n */\n\nimport {\n sign as ed25519Sign,\n verify as ed25519Verify,\n getPublicKey,\n randomSecretKey,\n} from './ed25519.js';\nimport {\n WIRE_01_JWS_TYP,\n WIRE_02_JWS_TYP,\n WIRE_02_JWS_TYP_ACCEPT,\n PEAC_ALG,\n VERIFIER_LIMITS,\n} from '@peac/kernel';\nimport {\n base64urlEncode,\n base64urlDecode,\n base64urlEncodeString,\n base64urlDecodeString,\n} from './base64url';\nimport { CryptoError } from './errors';\n\n// ---------------------------------------------------------------------------\n// JWS header types: 3-variant discriminated union (Correction 1, DD-156)\n// ---------------------------------------------------------------------------\n\n/**\n * JWS header for Wire 0.1 receipts (typ: 'peac-receipt/0.1')\n */\nexport interface Wire01JWSHeader {\n typ: typeof WIRE_01_JWS_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * JWS header for Wire 0.2 receipts (typ: 'interaction-record+jwt', compact canonical form)\n *\n * The full media type 'application/interaction-record+jwt' is accepted by verify()\n * and decode() but normalized to this compact form before returning.\n */\nexport interface Wire02JWSHeader {\n typ: typeof WIRE_02_JWS_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * JWS header for tokens with no typ field\n *\n * Crypto layer passes these through without error.\n * The strictness decision (hard error vs. warning) belongs exclusively\n * in @peac/protocol.verifyLocal() (Correction 1, DD-156).\n */\nexport interface UnTypedJWSHeader {\n typ?: undefined;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * Discriminated union of all recognized JWS header variants.\n *\n * Callers narrow by checking `header.typ`:\n * if (header.typ === WIRE_02_JWS_TYP) { ... Wire 0.2 path ... }\n * if (header.typ === WIRE_01_JWS_TYP) { ... Wire 0.1 path ... }\n * if (header.typ === undefined) { ... UnTyped / interop path ... }\n */\nexport type JWSHeader = Wire01JWSHeader | Wire02JWSHeader | UnTypedJWSHeader;\n\n/**\n * Result of JWS verification\n */\nexport interface VerifyResult<T = unknown> {\n header: JWSHeader;\n payload: T;\n valid: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Internal constants (NOT exported)\n// ---------------------------------------------------------------------------\n\n/** All typ values accepted by verify() / decode(). Includes full media type form. */\nconst ACCEPTED_TYP_VALUES = new Set<string>([WIRE_01_JWS_TYP, ...WIRE_02_JWS_TYP_ACCEPT]);\n\n// ---------------------------------------------------------------------------\n// validateWire02Header (exported, JOSE hardening, Correction 9, DD-156)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate JOSE header fields for Wire 0.2 JOSE hardening requirements.\n *\n * Rejects:\n * - Embedded key material (jwk, x5c, x5u, jku)\n * - crit header (critical extensions)\n * - b64: false (RFC 7797 unencoded payload)\n * - zip header (payload compression)\n * - Missing, empty, or oversized kid (DoS safety: max 256 chars)\n *\n * @param header - Raw parsed JWS header object\n * @throws CryptoError with CRYPTO_JWS_* code on any violation\n */\nexport function validateWire02Header(header: Record<string, unknown>): void {\n // kid: required, non-empty, max 256 chars (Correction 9, DoS safety)\n if (\n !header.kid ||\n typeof header.kid !== 'string' ||\n header.kid.length === 0 ||\n header.kid.length > 256\n ) {\n throw new CryptoError(\n 'CRYPTO_JWS_MISSING_KID',\n 'kid is missing, empty, or exceeds 256 characters'\n );\n }\n\n // Embedded key material: hard reject (prevents key confusion attacks)\n if (\n header.jwk !== undefined ||\n header.x5c !== undefined ||\n header.x5u !== undefined ||\n header.jku !== undefined\n ) {\n throw new CryptoError(\n 'CRYPTO_JWS_EMBEDDED_KEY',\n 'embedded key material (jwk/x5c/x5u/jku) is not permitted'\n );\n }\n\n // crit: hard reject\n if (header.crit !== undefined) {\n throw new CryptoError('CRYPTO_JWS_CRIT_REJECTED', 'crit header is not permitted');\n }\n\n // b64: false: RFC 7797 unencoded payload rejected\n if (header.b64 === false) {\n throw new CryptoError(\n 'CRYPTO_JWS_B64_REJECTED',\n 'b64:false (unencoded payload) is not permitted'\n );\n }\n\n // zip: hard reject\n if (header.zip !== undefined) {\n throw new CryptoError('CRYPTO_JWS_ZIP_REJECTED', 'zip header is not permitted');\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helper: build typed JWSHeader from raw parsed object\n// ---------------------------------------------------------------------------\n\n/**\n * Build a typed JWSHeader from a raw parsed header object, applying typ\n * normalization (Correction 2, DD-156): 'application/interaction-record+jwt'\n * is normalized to 'interaction-record+jwt' before returning.\n *\n * @param raw - Raw header object from JSON.parse\n * @returns Typed JWSHeader\n * @throws CryptoError if alg is not PEAC_ALG, or if typ is present and not in ACCEPTED_TYP_VALUES\n */\nfunction buildHeader(raw: Record<string, unknown>): JWSHeader {\n // Validate alg (required)\n if (raw.alg !== PEAC_ALG) {\n throw new CryptoError(\n 'CRYPTO_INVALID_ALG',\n `Invalid alg: expected ${PEAC_ALG}, got ${String(raw.alg)}`\n );\n }\n\n const rawTyp = raw.typ as string | undefined;\n\n // Normalize full media type to compact form (Correction 2)\n const canonicalTyp = rawTyp === 'application/interaction-record+jwt' ? WIRE_02_JWS_TYP : rawTyp;\n\n if (canonicalTyp !== undefined && !ACCEPTED_TYP_VALUES.has(rawTyp!)) {\n throw new CryptoError('CRYPTO_INVALID_TYP', `Invalid typ: ${String(rawTyp)}`);\n }\n\n const kid = typeof raw.kid === 'string' ? raw.kid : '';\n\n if (canonicalTyp === WIRE_01_JWS_TYP) {\n return { typ: WIRE_01_JWS_TYP, alg: PEAC_ALG, kid } satisfies Wire01JWSHeader;\n }\n if (canonicalTyp === WIRE_02_JWS_TYP) {\n return { typ: WIRE_02_JWS_TYP, alg: PEAC_ALG, kid } satisfies Wire02JWSHeader;\n }\n\n // canonicalTyp is undefined: return UnTypedJWSHeader\n return { typ: undefined, alg: PEAC_ALG, kid } satisfies UnTypedJWSHeader;\n}\n\n// ---------------------------------------------------------------------------\n// sign (Wire 0.1)\n// ---------------------------------------------------------------------------\n\n/**\n * Sign a payload with Ed25519 and return JWS compact serialization (Wire 0.1)\n *\n * Always sets typ to WIRE_01_JWS_TYP ('peac-receipt/0.1').\n * For Wire 0.2, use signWire02() instead.\n *\n * @param payload - JSON-serializable payload\n * @param privateKey - Ed25519 private key (32 bytes)\n * @param kid - Key ID (ISO 8601 timestamp)\n * @returns JWS compact serialization (header.payload.signature)\n */\nexport async function sign(payload: unknown, privateKey: Uint8Array, kid: string): Promise<string> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n\n const header: Wire01JWSHeader = {\n typ: WIRE_01_JWS_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const signatureBytes = await ed25519Sign(signingInputBytes, privateKey);\n const signatureB64 = base64urlEncode(signatureBytes);\n\n return `${signingInput}.${signatureB64}`;\n}\n\n// ---------------------------------------------------------------------------\n// signWire02 (Wire 0.2)\n// ---------------------------------------------------------------------------\n\n/**\n * Sign a Wire 0.2 payload with Ed25519 and return JWS compact serialization\n *\n * Always sets typ to WIRE_02_JWS_TYP ('interaction-record+jwt').\n * The payload MUST include peac_version: '0.2'.\n *\n * @param payload - JSON-serializable Wire 0.2 claims payload\n * @param privateKey - Ed25519 private key (32 bytes)\n * @param kid - Key ID (max 256 chars per JOSE hardening rules)\n * @returns JWS compact serialization (header.payload.signature)\n */\nexport async function signWire02(\n payload: unknown,\n privateKey: Uint8Array,\n kid: string\n): Promise<string> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n\n // Validate kid length (Correction 9, DoS safety)\n if (!kid || kid.length === 0 || kid.length > 256) {\n throw new CryptoError(\n 'CRYPTO_JWS_MISSING_KID',\n 'kid is missing, empty, or exceeds 256 characters'\n );\n }\n\n // Always set typ: WIRE_02_JWS_TYP: no code path may omit it\n const header: Wire02JWSHeader = {\n typ: WIRE_02_JWS_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const signatureBytes = await ed25519Sign(signingInputBytes, privateKey);\n const signatureB64 = base64urlEncode(signatureBytes);\n\n return `${signingInput}.${signatureB64}`;\n}\n\n// ---------------------------------------------------------------------------\n// verify (dual-stack)\n// ---------------------------------------------------------------------------\n\n/**\n * Verify a JWS compact serialization with Ed25519\n *\n * Dual-stack: accepts Wire 0.1 (peac-receipt/0.1) and Wire 0.2\n * (interaction-record+jwt or application/interaction-record+jwt).\n *\n * Typ normalization (Correction 2): 'application/interaction-record+jwt' is\n * normalized to 'interaction-record+jwt' in the returned header.\n *\n * UnTypedJWSHeader (Correction 1): tokens with no typ are returned with\n * typ: undefined without error; @peac/protocol.verifyLocal() applies strictness.\n *\n * Coherence check:\n * - typ === WIRE_02_JWS_TYP but payload.peac_version !== '0.2': CRYPTO_WIRE_VERSION_MISMATCH\n * - typ === WIRE_01_JWS_TYP but payload.peac_version === '0.2': CRYPTO_WIRE_VERSION_MISMATCH\n * - typ absent: no coherence check here; verifyLocal() handles it\n *\n * @param jws - JWS compact serialization\n * @param publicKey - Ed25519 public key (32 bytes)\n * @returns Verification result with typed header and decoded payload\n */\nexport async function verify<T = unknown>(\n jws: string,\n publicKey: Uint8Array\n): Promise<VerifyResult<T>> {\n if (publicKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 public key must be 32 bytes');\n }\n\n // Fast-reject oversized tokens before any parsing (DoS safety).\n // Uses VERIFIER_LIMITS.maxReceiptBytes (256 KB) as the upper bound.\n if (jws.length > VERIFIER_LIMITS.maxReceiptBytes) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n `JWS exceeds maximum size of ${VERIFIER_LIMITS.maxReceiptBytes} bytes`\n );\n }\n\n const parts = jws.split('.');\n if (parts.length !== 3) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n 'Invalid JWS: must have three dot-separated parts'\n );\n }\n\n const [headerB64, payloadB64, signatureB64] = parts;\n\n // Decode and build typed header.\n // Wrap in try/catch to translate SyntaxError / decode failures into stable\n // CryptoError codes; callers depend on CRYPTO_INVALID_JWS_FORMAT for error\n // classification and must never receive a raw SyntaxError at the boundary.\n let rawHeader: Record<string, unknown>;\n try {\n rawHeader = JSON.parse(base64urlDecodeString(headerB64)) as Record<string, unknown>;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS header: invalid base64url or JSON');\n }\n const header = buildHeader(rawHeader);\n\n // Apply JOSE hardening for Wire 0.2 and UnTyped tokens (Correction 1, DD-156).\n // JOSE security invariants (embedded key material, crit, b64:false, zip) MUST be\n // enforced regardless of whether typ is present. Interop mode controls routing only;\n // it does not exempt tokens from key-injection or unencoded-payload attacks.\n // Wire 0.1 tokens are excluded: the legacy format predates these constraints.\n if (header.typ === WIRE_02_JWS_TYP || header.typ === undefined) {\n validateWire02Header(rawHeader);\n }\n\n // Decode payload; same stable-error contract as header decode above.\n let payload: T;\n try {\n payload = JSON.parse(base64urlDecodeString(payloadB64)) as T;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS payload: invalid base64url or JSON');\n }\n\n // Coherence check: wire version consistency (only when typ is present)\n if (header.typ !== undefined) {\n const payloadVersion = (payload as Record<string, unknown>).peac_version;\n if (header.typ === WIRE_02_JWS_TYP && payloadVersion !== '0.2') {\n throw new CryptoError(\n 'CRYPTO_WIRE_VERSION_MISMATCH',\n `typ is ${WIRE_02_JWS_TYP} but peac_version is ${String(payloadVersion)} (expected '0.2')`\n );\n }\n if (header.typ === WIRE_01_JWS_TYP && payloadVersion === '0.2') {\n throw new CryptoError(\n 'CRYPTO_WIRE_VERSION_MISMATCH',\n `typ is ${WIRE_01_JWS_TYP} but peac_version is '0.2' (Wire 0.2 must use ${WIRE_02_JWS_TYP})`\n );\n }\n }\n\n // Verify Ed25519 signature\n const signatureBytes = base64urlDecode(signatureB64);\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n const valid = await ed25519Verify(signatureBytes, signingInputBytes, publicKey);\n\n return { header, payload, valid };\n}\n\n// ---------------------------------------------------------------------------\n// decode (dual-stack, unverified)\n// ---------------------------------------------------------------------------\n\n/**\n * Decode JWS without verifying signature\n *\n * UNSAFE: This function is for debugging and diagnostic inspection only.\n * It does NOT verify the Ed25519 signature and does NOT apply JOSE hardening\n * (embedded-key rejection, b64/zip/crit checks). Tokens returned by decode()\n * must never be trusted for authorization decisions.\n *\n * For secure verification use verify() instead.\n *\n * Applies the same typ normalization and header typing as verify().\n * Unrecognized typ values still throw CryptoError.\n *\n * @param jws - JWS compact serialization\n * @returns Decoded header and payload (unverified, no JOSE hardening applied)\n */\nexport function decode<T = unknown>(jws: string): { header: JWSHeader; payload: T } {\n const parts = jws.split('.');\n if (parts.length !== 3) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n 'Invalid JWS: must have three dot-separated parts'\n );\n }\n\n const [headerB64, payloadB64] = parts;\n\n let rawHeader: Record<string, unknown>;\n try {\n rawHeader = JSON.parse(base64urlDecodeString(headerB64)) as Record<string, unknown>;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS header: invalid base64url or JSON');\n }\n const header = buildHeader(rawHeader);\n\n let payload: T;\n try {\n payload = JSON.parse(base64urlDecodeString(payloadB64)) as T;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS payload: invalid base64url or JSON');\n }\n\n return { header, payload };\n}\n\n// ---------------------------------------------------------------------------\n// generateKeypair\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a random Ed25519 keypair\n *\n * @returns Private key (32 bytes) and public key (32 bytes)\n */\nexport async function generateKeypair(): Promise<{\n privateKey: Uint8Array;\n publicKey: Uint8Array;\n}> {\n const privateKey = randomSecretKey();\n const publicKey = await getPublicKey(privateKey);\n\n return { privateKey, publicKey };\n}\n\n// NOTE: generateKeypairFromSeed has been moved to @peac/crypto/testkit\n// It's intentionally NOT exported from the main module to prevent accidental\n// use in production. Use: import { generateKeypairFromSeed } from '@peac/crypto/testkit'\n\n// ---------------------------------------------------------------------------\n// Ed25519 JWK utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Ed25519 JWK interface for private keys\n */\nexport interface Ed25519PrivateJwk {\n kty: 'OKP';\n crv: 'Ed25519';\n /** Public key (base64url encoded, 32 bytes) */\n x: string;\n /** Private key (base64url encoded, 32 bytes) */\n d: string;\n}\n\n/**\n * Derive the Ed25519 public key from a private key\n *\n * @param privateKey - Ed25519 private key (32 bytes)\n * @returns Public key (32 bytes)\n */\nexport async function derivePublicKey(privateKey: Uint8Array): Promise<Uint8Array> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n return getPublicKey(privateKey);\n}\n\n/**\n * Validate that an Ed25519 JWK has a consistent keypair\n *\n * Derives the public key from the private key (d) and verifies it matches\n * the declared public key (x). This catches configuration errors where\n * the wrong key components are paired.\n *\n * @param jwk - Ed25519 JWK with both public (x) and private (d) components\n * @returns true if the keypair is consistent, false otherwise\n *\n * @example\n * ```typescript\n * const jwk = {\n * kty: 'OKP',\n * crv: 'Ed25519',\n * x: 'base64url-encoded-public-key',\n * d: 'base64url-encoded-private-key',\n * };\n *\n * if (!await validateKeypair(jwk)) {\n * throw new Error('Invalid keypair: d does not derive to x');\n * }\n * ```\n */\nexport async function validateKeypair(jwk: Ed25519PrivateJwk): Promise<boolean> {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n return false;\n }\n\n let privateKeyBytes: Uint8Array;\n let declaredPublicKeyBytes: Uint8Array;\n\n try {\n privateKeyBytes = base64urlDecode(jwk.d);\n declaredPublicKeyBytes = base64urlDecode(jwk.x);\n } catch {\n return false;\n }\n\n if (privateKeyBytes.length !== 32 || declaredPublicKeyBytes.length !== 32) {\n return false;\n }\n\n const derivedPublicKeyBytes = await getPublicKey(privateKeyBytes);\n\n if (derivedPublicKeyBytes.length !== declaredPublicKeyBytes.length) {\n return false;\n }\n\n for (let i = 0; i < derivedPublicKeyBytes.length; i++) {\n if (derivedPublicKeyBytes[i] !== declaredPublicKeyBytes[i]) {\n return false;\n }\n }\n\n return true;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/base64url.ts","../src/errors.ts","../src/hash.ts","../src/jcs.ts","../src/ed25519.ts","../src/jws.ts"],"names":["ed","WIRE_01_JWS_TYP","WIRE_02_JWS_TYP_ACCEPT","PEAC_ALG","WIRE_02_JWS_TYP","sign","verify","VERIFIER_LIMITS"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,IAAM,eAAA,GAAkB,kEAAA;AAGxB,IAAI,YAAA,GAA2C,IAAA;AAE/C,SAAS,eAAA,GAAuC;AAC9C,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,YAAA,uBAAmB,GAAA,EAAI;AACvB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,eAAA,CAAgB,QAAQ,CAAA,EAAA,EAAK;AAC/C,MAAA,YAAA,CAAa,GAAA,CAAI,eAAA,CAAgB,CAAC,CAAA,EAAG,CAAC,CAAA;AAAA,IACxC;AAAA,EACF;AACA,EAAA,OAAO,YAAA;AACT;AAQO,SAAS,gBAAgB,KAAA,EAA2B;AACzD,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,IAAI,CAAA,GAAI,CAAA;AAER,EAAA,OAAO,CAAA,GAAI,MAAM,MAAA,EAAQ;AACvB,IAAA,MAAM,CAAA,GAAI,MAAM,CAAA,EAAG,CAAA;AACnB,IAAA,MAAM,CAAA,GAAI,KAAA,CAAM,CAAA,EAAG,CAAA,IAAK,CAAA;AACxB,IAAA,MAAM,CAAA,GAAI,KAAA,CAAM,CAAA,EAAG,CAAA,IAAK,CAAA;AAExB,IAAA,MAAM,OAAA,GAAW,CAAA,IAAK,EAAA,GAAO,CAAA,IAAK,CAAA,GAAK,CAAA;AAEvC,IAAA,MAAA,IAAU,eAAA,CAAiB,OAAA,IAAW,EAAA,GAAM,EAAI,CAAA;AAChD,IAAA,MAAA,IAAU,eAAA,CAAiB,OAAA,IAAW,EAAA,GAAM,EAAI,CAAA;AAChD,IAAA,MAAA,IAAU,CAAA,GAAI,IAAI,KAAA,CAAM,MAAA,GAAS,gBAAiB,OAAA,IAAW,CAAA,GAAK,EAAI,CAAA,GAAI,EAAA;AAC1E,IAAA,MAAA,IAAU,IAAI,CAAA,GAAI,KAAA,CAAM,SAAS,eAAA,CAAgB,OAAA,GAAU,EAAI,CAAA,GAAI,EAAA;AAAA,EACrE;AAGA,EAAA,OAAO,OAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,OAAO,GAAG,CAAA;AACtD;AAQO,SAAS,gBAAgB,GAAA,EAAyB;AAEvD,EAAA,IAAI,MAAA,GAAS,IAAI,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAM,GAAG,CAAA;AAGrD,EAAA,OAAO,MAAA,CAAO,MAAA,GAAS,CAAA,KAAM,CAAA,EAAG;AAC9B,IAAA,MAAA,IAAU,GAAA;AAAA,EACZ;AAEA,EAAA,MAAM,SAAS,eAAA,EAAgB;AAC/B,EAAA,MAAM,QAAkB,EAAC;AAEzB,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA,EAAG;AACzC,IAAA,MAAM,IAAI,MAAA,CAAO,GAAA,CAAI,MAAA,CAAO,CAAC,CAAC,CAAA,IAAK,CAAA;AACnC,IAAA,MAAM,IAAI,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA,GAAI,CAAC,CAAC,CAAA,IAAK,CAAA;AACvC,IAAA,MAAM,IAAI,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA,GAAI,CAAC,CAAC,CAAA,IAAK,CAAA;AACvC,IAAA,MAAM,IAAI,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA,GAAI,CAAC,CAAC,CAAA,IAAK,CAAA;AAEvC,IAAA,KAAA,CAAM,IAAA,CAAM,CAAA,IAAK,CAAA,GAAM,CAAA,IAAK,CAAE,CAAA;AAC9B,IAAA,IAAI,MAAA,CAAO,CAAA,GAAI,CAAC,CAAA,KAAM,GAAA,EAAK;AACzB,MAAA,KAAA,CAAM,IAAA,CAAA,CAAO,CAAA,GAAI,EAAA,KAAS,CAAA,GAAM,KAAK,CAAE,CAAA;AAAA,IACzC;AACA,IAAA,IAAI,MAAA,CAAO,CAAA,GAAI,CAAC,CAAA,KAAM,GAAA,EAAK;AACzB,MAAA,KAAA,CAAM,IAAA,CAAA,CAAO,CAAA,GAAI,CAAA,KAAS,CAAA,GAAK,CAAC,CAAA;AAAA,IAClC;AAAA,EACF;AAEA,EAAA,OAAO,IAAI,WAAW,KAAK,CAAA;AAC7B;AAQO,SAAS,sBAAsB,GAAA,EAAqB;AACzD,EAAA,OAAO,gBAAgB,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,GAAG,CAAC,CAAA;AACtD;AAQO,SAAS,sBAAsB,GAAA,EAAqB;AACzD,EAAA,OAAO,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,eAAA,CAAgB,GAAG,CAAC,CAAA;AACtD;;;ACrEO,IAAM,WAAA,GAAN,MAAM,YAAA,SAAoB,KAAA,CAAM;AAAA,EAC5B,IAAA;AAAA,EAET,WAAA,CAAY,MAAuB,OAAA,EAAiB;AAClD,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAEZ,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,YAAA,CAAY,SAAS,CAAA;AAAA,EACnD;AACF;AASO,SAAS,cAAc,IAAA,EAAgC;AAC5D,EAAA,OACE,IAAA,KAAS,+BACT,IAAA,KAAS,oBAAA,IACT,SAAS,oBAAA,IACT,IAAA,KAAS,+BACT,IAAA,KAAS,4BAAA;AAEb;;;AC7CA,eAAsB,UAAU,IAAA,EAA4C;AAC1E,EAAA,MAAM,KAAA,GAAQ,OAAO,IAAA,KAAS,QAAA,GAAW,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,IAAI,CAAA,GAAI,IAAA;AAG1E,EAAA,IAAI,OAAO,UAAA,CAAW,MAAA,EAAQ,MAAA,EAAQ,WAAW,UAAA,EAAY;AAC3D,IAAA,MAAM,aAAa,MAAM,UAAA,CAAW,OAAO,MAAA,CAAO,MAAA,CAAO,WAAW,KAAK,CAAA;AACzE,IAAA,MAAM,YAAY,KAAA,CAAM,IAAA,CAAK,IAAI,UAAA,CAAW,UAAU,CAAC,CAAA;AACvD,IAAA,OAAO,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,KAAK,EAAE,CAAA;AAAA,EACtE;AAGA,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,UAAA,EAAW,GAAI,MAAM,OAAO,QAAQ,CAAA;AAC5C,IAAA,MAAM,IAAA,GAAO,WAAW,QAAQ,CAAA;AAChC,IAAA,IAAA,CAAK,OAAO,KAAK,CAAA;AACjB,IAAA,OAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACF;AAQA,eAAsB,YAAY,IAAA,EAAgD;AAChF,EAAA,MAAM,KAAA,GAAQ,OAAO,IAAA,KAAS,QAAA,GAAW,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,IAAI,CAAA,GAAI,IAAA;AAG1E,EAAA,IAAI,OAAO,UAAA,CAAW,MAAA,EAAQ,MAAA,EAAQ,WAAW,UAAA,EAAY;AAC3D,IAAA,MAAM,aAAa,MAAM,UAAA,CAAW,OAAO,MAAA,CAAO,MAAA,CAAO,WAAW,KAAK,CAAA;AACzE,IAAA,OAAO,IAAI,WAAW,UAAU,CAAA;AAAA,EAClC;AAGA,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,UAAA,EAAW,GAAI,MAAM,OAAO,QAAQ,CAAA;AAC5C,IAAA,MAAM,IAAA,GAAO,WAAW,QAAQ,CAAA;AAChC,IAAA,IAAA,CAAK,OAAO,KAAK,CAAA;AACjB,IAAA,OAAO,IAAI,UAAA,CAAW,IAAA,CAAK,MAAA,EAAQ,CAAA;AAAA,EACrC,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,MAAM,sCAAsC,CAAA;AAAA,EACxD;AACF;AAQO,SAAS,WAAW,GAAA,EAAyB;AAElD,EAAA,IAAI,GAAA,CAAI,SAAS,CAAA,KAAM,CAAA,IAAK,CAAC,gBAAA,CAAiB,IAAA,CAAK,GAAG,CAAA,EAAG;AACvD,IAAA,MAAM,IAAI,MAAM,oBAAoB,CAAA;AAAA,EACtC;AACA,EAAA,IAAI,GAAA,CAAI,WAAW,CAAA,EAAG;AACpB,IAAA,OAAO,IAAI,UAAA,CAAW,EAAE,CAAA;AAAA,EAC1B;AACA,EAAA,MAAM,OAAA,GAAU,GAAA,CAAI,KAAA,CAAM,OAAO,CAAA;AACjC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,oBAAoB,CAAA;AAAA,EACtC;AACA,EAAA,OAAO,IAAI,UAAA,CAAW,OAAA,CAAQ,GAAA,CAAI,CAAC,SAAS,QAAA,CAAS,IAAA,EAAM,EAAE,CAAC,CAAC,CAAA;AACjE;AAQO,SAAS,WAAW,KAAA,EAA2B;AACpD,EAAA,OAAO,MAAM,IAAA,CAAK,KAAK,CAAA,CACpB,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAC1C,KAAK,EAAE,CAAA;AACZ;AAYA,eAAsB,gBAAgB,IAAA,EAA4C;AAChF,EAAA,MAAM,SAAA,GAAY,MAAM,WAAA,CAAY,IAAI,CAAA;AACxC,EAAA,OAAO,gBAAgB,SAAS,CAAA;AAClC;AAWO,SAAS,eAAe,GAAA,EAAqB;AAClD,EAAA,MAAM,QAAA,GAAW,IAAI,UAAA,CAAW,SAAS,IAAI,GAAA,CAAI,KAAA,CAAM,CAAC,CAAA,GAAI,GAAA;AAC5D,EAAA,OAAO,eAAA,CAAgB,UAAA,CAAW,QAAQ,CAAC,CAAA;AAC7C;AAWO,SAAS,eAAe,IAAA,EAAsB;AACnD,EAAA,OAAO,UAAA,CAAW,eAAA,CAAgB,IAAI,CAAC,CAAA;AACzC;AAuBA,eAAsB,qBAAqB,GAAA,EAA0C;AACnF,EAAA,IAAI,GAAA,CAAI,GAAA,KAAQ,KAAA,IAAS,GAAA,CAAI,QAAQ,SAAA,EAAW;AAC9C,IAAA,MAAM,IAAI,MAAM,0EAA0E,CAAA;AAAA,EAC5F;AAGA,EAAA,MAAM,SAAA,GAAY,KAAK,SAAA,CAAU;AAAA,IAC/B,KAAK,GAAA,CAAI,GAAA;AAAA,IACT,KAAK,GAAA,CAAI,GAAA;AAAA,IACT,GAAG,GAAA,CAAI;AAAA,GACR,CAAA;AAED,EAAA,MAAM,SAAA,GAAY,MAAM,WAAA,CAAY,SAAS,CAAA;AAC7C,EAAA,OAAO,gBAAgB,SAAS,CAAA;AAClC;AAQO,SAAS,oBAAoB,GAAA,EAAqC;AACvE,EAAA,IAAI,GAAA,CAAI,GAAA,KAAQ,KAAA,IAAS,GAAA,CAAI,QAAQ,SAAA,EAAW;AAC9C,IAAA,MAAM,IAAI,MAAM,+CAA+C,CAAA;AAAA,EACjE;AAEA,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,GAAA,CAAI,CAAC,CAAA;AACpC,EAAA,IAAI,MAAA,CAAO,WAAW,EAAA,EAAI;AACxB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yCAAA,EAA4C,MAAA,CAAO,MAAM,CAAA,CAAE,CAAA;AAAA,EAC7E;AAEA,EAAA,OAAO,MAAA;AACT;;;AChJO,SAAS,aAAa,GAAA,EAAsB;AACjD,EAAA,IAAI,QAAQ,IAAA,EAAM;AAChB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,QAAQ,SAAA,EAAW;AAC5B,IAAA,OAAO,MAAM,MAAA,GAAS,OAAA;AAAA,EACxB;AAEA,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAE3B,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,EAAG;AACzB,MAAA,MAAM,IAAI,MAAM,uCAAuC,CAAA;AAAA,IACzD;AACA,IAAA,IAAI,MAAA,CAAO,EAAA,CAAG,GAAA,EAAK,EAAE,CAAA,EAAG;AACtB,MAAA,OAAO,GAAA;AAAA,IACT;AAEA,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA;AAE9B,IAAA,IAAI,OAAO,SAAA,CAAU,GAAG,KAAK,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,EAAG;AAC9C,MAAA,OAAO,IAAI,QAAA,EAAS;AAAA,IACtB;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,IAAA,OAAO,IAAA,CAAK,UAAU,GAAG,CAAA;AAAA,EAC3B;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AAGtB,IAAA,MAAM,QAAA,GAAW,GAAA,CAAI,GAAA,CAAI,CAAC,EAAA,KAAQ,OAAO,MAAA,GAAY,MAAA,GAAS,YAAA,CAAa,EAAE,CAAE,CAAA;AAC/E,IAAA,OAAO,CAAA,CAAA,EAAI,QAAA,CAAS,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AAAA,EAC/B;AAEA,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAE3B,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,GAAG,EAAE,IAAA,EAAK;AACnC,IAAA,MAAM,QAAkB,EAAC;AACzB,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,MAAM,KAAA,GAAS,IAAgC,GAAG,CAAA;AAGlD,MAAA,IAAI,UAAU,MAAA,EAAW;AACvB,QAAA;AAAA,MACF;AACA,MAAA,KAAA,CAAM,IAAA,CAAK,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,GAAG,CAAC,CAAA,CAAA,EAAI,YAAA,CAAa,KAAK,CAAC,CAAA,CAAE,CAAA;AAAA,IAC5D;AACA,IAAA,OAAO,CAAA,CAAA,EAAI,KAAA,CAAM,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AAAA,EAC5B;AAEA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,OAAO,GAAG,CAAA,CAAE,CAAA;AAC3D;AAKO,SAAS,kBAAkB,GAAA,EAA0B;AAC1D,EAAA,MAAM,SAAA,GAAY,aAAa,GAAG,CAAA;AAClC,EAAA,OAAO,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,SAAS,CAAA;AAC3C;AAKA,eAAsB,QAAQ,GAAA,EAA+B;AAC3D,EAAA,MAAM,KAAA,GAAQ,kBAAkB,GAAG,CAAA;AACnC,EAAA,MAAM,aAAa,MAAM,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,WAAW,KAAK,CAAA;AAC9D,EAAA,MAAM,SAAA,GAAY,IAAI,UAAA,CAAW,UAAU,CAAA;AAC3C,EAAA,OAAO,MAAM,IAAA,CAAK,SAAS,CAAA,CACxB,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAC1C,KAAK,EAAE,CAAA;AACZ;ACtGO,IAAM,IAAA,GAAUA,aAAA,CAAA;AAGhB,IAAM,MAAA,GAAYA,aAAA,CAAA;AAGlB,IAAM,YAAA,GAAkBA,aAAA,CAAA;AAGxB,IAAM,kBAAqBA,aAAA,CAAA,KAAA,CAAM;ACsDxC,IAAM,sCAAsB,IAAI,GAAA,CAAY,CAACC,sBAAA,EAAiB,GAAGC,6BAAsB,CAAC,CAAA;AAmBjF,SAAS,qBAAqB,MAAA,EAAuC;AAE1E,EAAA,IACE,CAAC,MAAA,CAAO,GAAA,IACR,OAAO,OAAO,GAAA,KAAQ,QAAA,IACtB,MAAA,CAAO,GAAA,CAAI,MAAA,KAAW,CAAA,IACtB,MAAA,CAAO,GAAA,CAAI,SAAS,GAAA,EACpB;AACA,IAAA,MAAM,IAAI,WAAA;AAAA,MACR,wBAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAGA,EAAA,IACE,MAAA,CAAO,GAAA,KAAQ,MAAA,IACf,MAAA,CAAO,GAAA,KAAQ,MAAA,IACf,MAAA,CAAO,GAAA,KAAQ,MAAA,IACf,MAAA,CAAO,GAAA,KAAQ,MAAA,EACf;AACA,IAAA,MAAM,IAAI,WAAA;AAAA,MACR,yBAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAGA,EAAA,IAAI,MAAA,CAAO,SAAS,MAAA,EAAW;AAC7B,IAAA,MAAM,IAAI,WAAA,CAAY,0BAAA,EAA4B,8BAA8B,CAAA;AAAA,EAClF;AAGA,EAAA,IAAI,MAAA,CAAO,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,IAAI,WAAA;AAAA,MACR,yBAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAGA,EAAA,IAAI,MAAA,CAAO,QAAQ,MAAA,EAAW;AAC5B,IAAA,MAAM,IAAI,WAAA,CAAY,yBAAA,EAA2B,6BAA6B,CAAA;AAAA,EAChF;AACF;AAeA,SAAS,YAAY,GAAA,EAAyC;AAE5D,EAAA,IAAI,GAAA,CAAI,QAAQC,eAAA,EAAU;AACxB,IAAA,MAAM,IAAI,WAAA;AAAA,MACR,oBAAA;AAAA,MACA,yBAAyBA,eAAQ,CAAA,MAAA,EAAS,MAAA,CAAO,GAAA,CAAI,GAAG,CAAC,CAAA;AAAA,KAC3D;AAAA,EACF;AAEA,EAAA,MAAM,SAAS,GAAA,CAAI,GAAA;AAGnB,EAAA,MAAM,YAAA,GAAe,MAAA,KAAW,oCAAA,GAAuCC,sBAAA,GAAkB,MAAA;AAEzF,EAAA,IAAI,iBAAiB,MAAA,IAAa,CAAC,mBAAA,CAAoB,GAAA,CAAI,MAAO,CAAA,EAAG;AACnE,IAAA,MAAM,IAAI,WAAA,CAAY,oBAAA,EAAsB,gBAAgB,MAAA,CAAO,MAAM,CAAC,CAAA,CAAE,CAAA;AAAA,EAC9E;AAEA,EAAA,MAAM,MAAM,OAAO,GAAA,CAAI,GAAA,KAAQ,QAAA,GAAW,IAAI,GAAA,GAAM,EAAA;AAEpD,EAAA,IAAI,iBAAiBH,sBAAA,EAAiB;AACpC,IAAA,OAAO,EAAE,GAAA,EAAKA,sBAAA,EAAiB,GAAA,EAAKE,iBAAU,GAAA,EAAI;AAAA,EACpD;AACA,EAAA,IAAI,iBAAiBC,sBAAA,EAAiB;AACpC,IAAA,OAAO,EAAE,GAAA,EAAKA,sBAAA,EAAiB,GAAA,EAAKD,iBAAU,GAAA,EAAI;AAAA,EACpD;AAGA,EAAA,OAAO,EAAE,GAAA,EAAK,MAAA,EAAW,GAAA,EAAKA,iBAAU,GAAA,EAAI;AAC9C;AAiBA,eAAsBE,KAAAA,CAAK,OAAA,EAAkB,UAAA,EAAwB,GAAA,EAA8B;AACjG,EAAA,IAAI,UAAA,CAAW,WAAW,EAAA,EAAI;AAC5B,IAAA,MAAM,IAAI,WAAA,CAAY,2BAAA,EAA6B,sCAAsC,CAAA;AAAA,EAC3F;AAEA,EAAA,MAAM,MAAA,GAA0B;AAAA,IAC9B,GAAA,EAAKJ,sBAAA;AAAA,IACL,GAAA,EAAKE,eAAA;AAAA,IACL;AAAA,GACF;AAEA,EAAA,MAAM,SAAA,GAAY,qBAAA,CAAsB,IAAA,CAAK,SAAA,CAAU,MAAM,CAAC,CAAA;AAC9D,EAAA,MAAM,UAAA,GAAa,qBAAA,CAAsB,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAEhE,EAAA,MAAM,YAAA,GAAe,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AAC/C,EAAA,MAAM,iBAAA,GAAoB,IAAI,WAAA,EAAY,CAAE,OAAO,YAAY,CAAA;AAE/D,EAAA,MAAM,cAAA,GAAiB,MAAM,IAAA,CAAY,iBAAA,EAAmB,UAAU,CAAA;AACtE,EAAA,MAAM,YAAA,GAAe,gBAAgB,cAAc,CAAA;AAEnD,EAAA,OAAO,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AACxC;AAiBA,eAAsB,UAAA,CACpB,OAAA,EACA,UAAA,EACA,GAAA,EACiB;AACjB,EAAA,IAAI,UAAA,CAAW,WAAW,EAAA,EAAI;AAC5B,IAAA,MAAM,IAAI,WAAA,CAAY,2BAAA,EAA6B,sCAAsC,CAAA;AAAA,EAC3F;AAGA,EAAA,IAAI,CAAC,GAAA,IAAO,GAAA,CAAI,WAAW,CAAA,IAAK,GAAA,CAAI,SAAS,GAAA,EAAK;AAChD,IAAA,MAAM,IAAI,WAAA;AAAA,MACR,wBAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAGA,EAAA,MAAM,MAAA,GAA0B;AAAA,IAC9B,GAAA,EAAKC,sBAAA;AAAA,IACL,GAAA,EAAKD,eAAA;AAAA,IACL;AAAA,GACF;AAEA,EAAA,MAAM,SAAA,GAAY,qBAAA,CAAsB,IAAA,CAAK,SAAA,CAAU,MAAM,CAAC,CAAA;AAC9D,EAAA,MAAM,UAAA,GAAa,qBAAA,CAAsB,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAEhE,EAAA,MAAM,YAAA,GAAe,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AAC/C,EAAA,MAAM,iBAAA,GAAoB,IAAI,WAAA,EAAY,CAAE,OAAO,YAAY,CAAA;AAE/D,EAAA,MAAM,cAAA,GAAiB,MAAM,IAAA,CAAY,iBAAA,EAAmB,UAAU,CAAA;AACtE,EAAA,MAAM,YAAA,GAAe,gBAAgB,cAAc,CAAA;AAEnD,EAAA,OAAO,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AACxC;AA2BA,eAAsBG,OAAAA,CACpB,KACA,SAAA,EAC0B;AAC1B,EAAA,IAAI,SAAA,CAAU,WAAW,EAAA,EAAI;AAC3B,IAAA,MAAM,IAAI,WAAA,CAAY,2BAAA,EAA6B,qCAAqC,CAAA;AAAA,EAC1F;AAIA,EAAA,IAAI,GAAA,CAAI,MAAA,GAASC,sBAAA,CAAgB,eAAA,EAAiB;AAChD,IAAA,MAAM,IAAI,WAAA;AAAA,MACR,2BAAA;AAAA,MACA,CAAA,4BAAA,EAA+BA,uBAAgB,eAAe,CAAA,MAAA;AAAA,KAChE;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAC3B,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,MAAM,IAAI,WAAA;AAAA,MACR,2BAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,CAAC,SAAA,EAAW,UAAA,EAAY,YAAY,CAAA,GAAI,KAAA;AAM9C,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI;AACF,IAAA,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,qBAAA,CAAsB,SAAS,CAAC,CAAA;AAAA,EACzD,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,WAAA,CAAY,2BAAA,EAA6B,uCAAuC,CAAA;AAAA,EAC5F;AACA,EAAA,MAAM,MAAA,GAAS,YAAY,SAAS,CAAA;AAOpC,EAAA,IAAI,MAAA,CAAO,GAAA,KAAQH,sBAAA,IAAmB,MAAA,CAAO,QAAQ,MAAA,EAAW;AAC9D,IAAA,oBAAA,CAAqB,SAAS,CAAA;AAAA,EAChC;AAGA,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,qBAAA,CAAsB,UAAU,CAAC,CAAA;AAAA,EACxD,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,WAAA,CAAY,2BAAA,EAA6B,wCAAwC,CAAA;AAAA,EAC7F;AAGA,EAAA,IAAI,MAAA,CAAO,QAAQ,MAAA,EAAW;AAC5B,IAAA,MAAM,iBAAkB,OAAA,CAAoC,YAAA;AAC5D,IAAA,IAAI,MAAA,CAAO,GAAA,KAAQA,sBAAA,IAAmB,cAAA,KAAmB,KAAA,EAAO;AAC9D,MAAA,MAAM,IAAI,WAAA;AAAA,QACR,8BAAA;AAAA,QACA,CAAA,OAAA,EAAUA,sBAAe,CAAA,qBAAA,EAAwB,MAAA,CAAO,cAAc,CAAC,CAAA,iBAAA;AAAA,OACzE;AAAA,IACF;AACA,IAAA,IAAI,MAAA,CAAO,GAAA,KAAQH,sBAAA,IAAmB,cAAA,KAAmB,KAAA,EAAO;AAC9D,MAAA,MAAM,IAAI,WAAA;AAAA,QACR,8BAAA;AAAA,QACA,CAAA,OAAA,EAAUA,sBAAe,CAAA,8CAAA,EAAiDG,sBAAe,CAAA,CAAA;AAAA,OAC3F;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,cAAA,GAAiB,gBAAgB,YAAY,CAAA;AACnD,EAAA,MAAM,YAAA,GAAe,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AAC/C,EAAA,MAAM,iBAAA,GAAoB,IAAI,WAAA,EAAY,CAAE,OAAO,YAAY,CAAA;AAC/D,EAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAc,cAAA,EAAgB,mBAAmB,SAAS,CAAA;AAE9E,EAAA,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,KAAA,EAAM;AAClC;AAsBO,SAAS,OAAoB,GAAA,EAAgD;AAClF,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAC3B,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,MAAM,IAAI,WAAA;AAAA,MACR,2BAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,CAAC,SAAA,EAAW,UAAU,CAAA,GAAI,KAAA;AAEhC,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI;AACF,IAAA,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,qBAAA,CAAsB,SAAS,CAAC,CAAA;AAAA,EACzD,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,WAAA,CAAY,2BAAA,EAA6B,uCAAuC,CAAA;AAAA,EAC5F;AACA,EAAA,MAAM,MAAA,GAAS,YAAY,SAAS,CAAA;AAEpC,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,qBAAA,CAAsB,UAAU,CAAC,CAAA;AAAA,EACxD,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,WAAA,CAAY,2BAAA,EAA6B,wCAAwC,CAAA;AAAA,EAC7F;AAEA,EAAA,OAAO,EAAE,QAAQ,OAAA,EAAQ;AAC3B;AAWA,eAAsB,eAAA,GAGnB;AACD,EAAA,MAAM,aAAa,eAAA,EAAgB;AACnC,EAAA,MAAM,SAAA,GAAY,MAAM,YAAA,CAAa,UAAU,CAAA;AAE/C,EAAA,OAAO,EAAE,YAAY,SAAA,EAAU;AACjC;AA4BA,eAAsB,gBAAgB,UAAA,EAA6C;AACjF,EAAA,IAAI,UAAA,CAAW,WAAW,EAAA,EAAI;AAC5B,IAAA,MAAM,IAAI,WAAA,CAAY,2BAAA,EAA6B,sCAAsC,CAAA;AAAA,EAC3F;AACA,EAAA,OAAO,aAAa,UAAU,CAAA;AAChC;AA0BA,eAAsB,gBAAgB,GAAA,EAA0C;AAC9E,EAAA,IAAI,GAAA,CAAI,GAAA,KAAQ,KAAA,IAAS,GAAA,CAAI,QAAQ,SAAA,EAAW;AAC9C,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,eAAA;AACJ,EAAA,IAAI,sBAAA;AAEJ,EAAA,IAAI;AACF,IAAA,eAAA,GAAkB,eAAA,CAAgB,IAAI,CAAC,CAAA;AACvC,IAAA,sBAAA,GAAyB,eAAA,CAAgB,IAAI,CAAC,CAAA;AAAA,EAChD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,eAAA,CAAgB,MAAA,KAAW,EAAA,IAAM,sBAAA,CAAuB,WAAW,EAAA,EAAI;AACzE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,qBAAA,GAAwB,MAAM,YAAA,CAAa,eAAe,CAAA;AAEhE,EAAA,IAAI,qBAAA,CAAsB,MAAA,KAAW,sBAAA,CAAuB,MAAA,EAAQ;AAClE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,qBAAA,CAAsB,QAAQ,CAAA,EAAA,EAAK;AACrD,IAAA,IAAI,qBAAA,CAAsB,CAAC,CAAA,KAAM,sBAAA,CAAuB,CAAC,CAAA,EAAG;AAC1D,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT","file":"index.cjs","sourcesContent":["/**\n * Base64url encoding/decoding (RFC 4648 §5)\n *\n * Platform-agnostic implementation that works in Node.js, browser, and edge runtimes.\n * No Buffer dependency - uses pure JavaScript for maximum portability.\n *\n * @packageDocumentation\n */\n\n// Standard base64 alphabet\nconst BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n// Reverse lookup table (lazily initialized)\nlet base64Lookup: Map<string, number> | null = null;\n\nfunction getBase64Lookup(): Map<string, number> {\n if (!base64Lookup) {\n base64Lookup = new Map();\n for (let i = 0; i < BASE64_ALPHABET.length; i++) {\n base64Lookup.set(BASE64_ALPHABET[i], i);\n }\n }\n return base64Lookup;\n}\n\n/**\n * Encode bytes to base64url string (no padding)\n *\n * @param bytes - Byte array to encode\n * @returns Base64url encoded string (no padding)\n */\nexport function base64urlEncode(bytes: Uint8Array): string {\n let result = '';\n let i = 0;\n\n while (i < bytes.length) {\n const a = bytes[i++];\n const b = bytes[i++] ?? 0;\n const c = bytes[i++] ?? 0;\n\n const triplet = (a << 16) | (b << 8) | c;\n\n result += BASE64_ALPHABET[(triplet >> 18) & 0x3f];\n result += BASE64_ALPHABET[(triplet >> 12) & 0x3f];\n result += i - 2 < bytes.length ? BASE64_ALPHABET[(triplet >> 6) & 0x3f] : '';\n result += i - 1 < bytes.length ? BASE64_ALPHABET[triplet & 0x3f] : '';\n }\n\n // Convert to base64url (no padding)\n return result.replace(/\\+/g, '-').replace(/\\//g, '_');\n}\n\n/**\n * Decode base64url string to bytes\n *\n * @param str - Base64url encoded string\n * @returns Decoded bytes\n */\nexport function base64urlDecode(str: string): Uint8Array {\n // Convert base64url to base64\n let base64 = str.replace(/-/g, '+').replace(/_/g, '/');\n\n // Add padding if needed\n while (base64.length % 4 !== 0) {\n base64 += '=';\n }\n\n const lookup = getBase64Lookup();\n const bytes: number[] = [];\n\n for (let i = 0; i < base64.length; i += 4) {\n const a = lookup.get(base64[i]) ?? 0;\n const b = lookup.get(base64[i + 1]) ?? 0;\n const c = lookup.get(base64[i + 2]) ?? 0;\n const d = lookup.get(base64[i + 3]) ?? 0;\n\n bytes.push((a << 2) | (b >> 4));\n if (base64[i + 2] !== '=') {\n bytes.push(((b & 0x0f) << 4) | (c >> 2));\n }\n if (base64[i + 3] !== '=') {\n bytes.push(((c & 0x03) << 6) | d);\n }\n }\n\n return new Uint8Array(bytes);\n}\n\n/**\n * Encode UTF-8 string to base64url\n *\n * @param str - UTF-8 string to encode\n * @returns Base64url encoded string\n */\nexport function base64urlEncodeString(str: string): string {\n return base64urlEncode(new TextEncoder().encode(str));\n}\n\n/**\n * Decode base64url to UTF-8 string\n *\n * @param str - Base64url encoded string\n * @returns Decoded UTF-8 string\n */\nexport function base64urlDecodeString(str: string): string {\n return new TextDecoder().decode(base64urlDecode(str));\n}\n","/**\n * Typed errors for @peac/crypto\n *\n * These error codes are INTERNAL to @peac/crypto and should NOT be exposed\n * as protocol-stable API. Higher-level packages (like @peac/protocol) should\n * map these to canonical E_* codes from specs/kernel/errors.json.\n *\n * The CRYPTO_ prefix makes it clear these are package-internal codes.\n */\n\n/**\n * Internal error codes for crypto operations\n *\n * These are NOT canonical protocol error codes. They are internal to @peac/crypto.\n * @peac/protocol maps these to canonical E_* codes (E_INVALID_FORMAT, etc).\n */\nexport type CryptoErrorCode =\n | 'CRYPTO_INVALID_KEY_LENGTH'\n | 'CRYPTO_INVALID_SEED_LENGTH'\n | 'CRYPTO_INVALID_JWS_FORMAT'\n | 'CRYPTO_INVALID_TYP'\n | 'CRYPTO_INVALID_ALG'\n | 'CRYPTO_INVALID_SIGNATURE'\n // Wire 0.2 JOSE hardening (v0.12.0-preview.1, DD-156)\n | 'CRYPTO_WIRE_VERSION_MISMATCH'\n | 'CRYPTO_JWS_EMBEDDED_KEY'\n | 'CRYPTO_JWS_CRIT_REJECTED'\n | 'CRYPTO_JWS_MISSING_KID'\n | 'CRYPTO_JWS_B64_REJECTED'\n | 'CRYPTO_JWS_ZIP_REJECTED';\n\n/**\n * Typed error for crypto operations\n *\n * Use `err.code` to handle errors programmatically without message parsing.\n * The code is a CRYPTO_* internal code, not a canonical E_* protocol code.\n */\nexport class CryptoError extends Error {\n readonly code: CryptoErrorCode;\n\n constructor(code: CryptoErrorCode, message: string) {\n super(message);\n this.name = 'CryptoError';\n this.code = code;\n // Maintain proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, CryptoError.prototype);\n }\n}\n\n/**\n * Check if a CryptoError code indicates a format/structure issue\n * (as opposed to a cryptographic verification failure)\n *\n * @internal This is an internal helper, not part of the public API.\n * Use structural checks on CryptoError.code instead of relying on this function.\n */\nexport function isFormatError(code: CryptoErrorCode): boolean {\n return (\n code === 'CRYPTO_INVALID_JWS_FORMAT' ||\n code === 'CRYPTO_INVALID_TYP' ||\n code === 'CRYPTO_INVALID_ALG' ||\n code === 'CRYPTO_INVALID_KEY_LENGTH' ||\n code === 'CRYPTO_INVALID_SEED_LENGTH'\n );\n}\n","/**\n * Cryptographic hash utilities\n *\n * Platform-agnostic SHA-256 implementation that works in Node.js, browser, and edge runtimes.\n * Uses Web Crypto API with Node.js crypto fallback.\n *\n * @packageDocumentation\n */\n\nimport { base64urlDecode, base64urlEncode } from './base64url.js';\n\n/**\n * Compute SHA-256 hash of data and return as lowercase hex string\n *\n * Uses Web Crypto API if available, falls back to Node.js crypto.\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Lowercase hex string (64 characters)\n */\nexport async function sha256Hex(data: Uint8Array | string): Promise<string> {\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;\n\n // Try Web Crypto API first (works in browser, edge, and Node 22+)\n if (typeof globalThis.crypto?.subtle?.digest === 'function') {\n const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', bytes);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');\n }\n\n // Fallback to Node.js crypto\n try {\n const { createHash } = await import('crypto');\n const hash = createHash('sha256');\n hash.update(bytes);\n return hash.digest('hex');\n } catch {\n throw new Error(\n 'No SHA-256 implementation available. Ensure Web Crypto API or Node.js crypto is available.'\n );\n }\n}\n\n/**\n * Compute SHA-256 hash of data and return as Uint8Array (32 bytes)\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Hash as Uint8Array (32 bytes)\n */\nexport async function sha256Bytes(data: Uint8Array | string): Promise<Uint8Array> {\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;\n\n // Try Web Crypto API first\n if (typeof globalThis.crypto?.subtle?.digest === 'function') {\n const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', bytes);\n return new Uint8Array(hashBuffer);\n }\n\n // Fallback to Node.js crypto\n try {\n const { createHash } = await import('crypto');\n const hash = createHash('sha256');\n hash.update(bytes);\n return new Uint8Array(hash.digest());\n } catch {\n throw new Error('No SHA-256 implementation available.');\n }\n}\n\n/**\n * Convert hex string to Uint8Array\n *\n * @param hex - Lowercase hex string\n * @returns Uint8Array\n */\nexport function hexToBytes(hex: string): Uint8Array {\n // Validate: must be even length and contain only hex characters\n if (hex.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex)) {\n throw new Error('Invalid hex string');\n }\n if (hex.length === 0) {\n return new Uint8Array([]);\n }\n const matches = hex.match(/.{2}/g);\n if (!matches) {\n throw new Error('Invalid hex string');\n }\n return new Uint8Array(matches.map((byte) => parseInt(byte, 16)));\n}\n\n/**\n * Convert Uint8Array to lowercase hex string\n *\n * @param bytes - Byte array\n * @returns Lowercase hex string\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Compute SHA-256 hash of data and return as base64url string\n *\n * Used by Wire 0.2 DigestRef format. Evidence bundles use sha256Hex() with\n * \"sha256:<hex>\" prefix instead. A conversion bridge between the two formats\n * (hex <-> base64url) is provided by hexToBase64url() and base64urlToHex().\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Base64url-encoded SHA-256 hash (43 characters)\n */\nexport async function sha256Base64url(data: Uint8Array | string): Promise<string> {\n const hashBytes = await sha256Bytes(data);\n return base64urlEncode(hashBytes);\n}\n\n/**\n * Convert a hex-encoded hash to base64url encoding\n *\n * Bridges evidence bundle format (sha256:<hex>) to Wire 0.2 DigestRef format\n * (base64url value). Strips the \"sha256:\" prefix if present.\n *\n * @param hex - Hex string, optionally prefixed with \"sha256:\"\n * @returns Base64url-encoded bytes (43 characters for SHA-256)\n */\nexport function hexToBase64url(hex: string): string {\n const cleanHex = hex.startsWith('sha256:') ? hex.slice(7) : hex;\n return base64urlEncode(hexToBytes(cleanHex));\n}\n\n/**\n * Convert a base64url-encoded hash to hex encoding\n *\n * Bridges Wire 0.2 DigestRef format (base64url) to evidence bundle format\n * (hex). Does NOT add the \"sha256:\" prefix -- caller adds it if needed.\n *\n * @param b64u - Base64url-encoded hash\n * @returns Lowercase hex string (64 characters for SHA-256)\n */\nexport function base64urlToHex(b64u: string): string {\n return bytesToHex(base64urlDecode(b64u));\n}\n\n/**\n * JWK structure for Ed25519 public keys (minimal required fields for thumbprint)\n */\nexport interface JWKThumbprintInput {\n /** Key type - must be \"OKP\" for Ed25519 */\n kty: string;\n /** Curve - must be \"Ed25519\" */\n crv: string;\n /** Public key (base64url) */\n x: string;\n}\n\n/**\n * Compute RFC 7638 JWK Thumbprint (base64url, SHA-256)\n *\n * For Ed25519 keys, the canonical JSON is: {\"crv\":\"Ed25519\",\"kty\":\"OKP\",\"x\":\"<base64url>\"}\n * Returns base64url-encoded SHA-256 hash (43 characters).\n *\n * @param jwk - JWK with kty, crv, x fields\n * @returns Base64url-encoded SHA-256 thumbprint (43 characters)\n */\nexport async function computeJwkThumbprint(jwk: JWKThumbprintInput): Promise<string> {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n throw new Error('Only Ed25519 keys (OKP/Ed25519) are supported for thumbprint computation');\n }\n\n // Canonical JSON per RFC 7638 (alphabetically sorted members, no whitespace)\n const canonical = JSON.stringify({\n crv: jwk.crv,\n kty: jwk.kty,\n x: jwk.x,\n });\n\n const hashBytes = await sha256Bytes(canonical);\n return base64urlEncode(hashBytes);\n}\n\n/**\n * Convert JWK to Ed25519 public key bytes (32 bytes)\n *\n * @param jwk - JWK with kty, crv, x fields\n * @returns Public key as 32-byte Uint8Array\n */\nexport function jwkToPublicKeyBytes(jwk: JWKThumbprintInput): Uint8Array {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n throw new Error('Only Ed25519 keys (OKP/Ed25519) are supported');\n }\n\n const xBytes = base64urlDecode(jwk.x);\n if (xBytes.length !== 32) {\n throw new Error(`Ed25519 public key must be 32 bytes, got ${xBytes.length}`);\n }\n\n return xBytes;\n}\n","/**\n * JSON Canonicalization Scheme (RFC 8785)\n * Deterministic JSON serialization for cryptographic hashing\n *\n * PROTOCOL DECISION: JavaScript `undefined` Handling\n * ===================================================\n *\n * RFC 8785 canonicalizes JSON values, and `undefined` is NOT a JSON value.\n * This implementation adopts \"JS-ergonomic\" semantics that match JSON.stringify:\n *\n * 1. **Object properties with undefined values are OMITTED**\n * - `canonicalize({a: 1, b: undefined})` -> `{\"a\":1}`\n * - Matches: `JSON.stringify({a: 1, b: undefined})` -> `{\"a\":1}`\n *\n * 2. **Array elements that are undefined become null**\n * - `canonicalize([1, undefined, 3])` -> `[1,null,3]`\n * - Matches: `JSON.stringify([1, undefined, 3])` -> `[1,null,3]`\n *\n * 3. **Top-level undefined THROWS**\n * - `canonicalize(undefined)` -> throws Error\n * - Rationale: No valid JSON representation exists\n *\n * CROSS-LANGUAGE INTEROPERABILITY WARNING:\n * =========================================\n * Cross-language producers MUST NOT rely on \"undefined\" semantics. To achieve\n * identical hashes across implementations, explicitly encode `null` in arrays\n * and omit keys in objects. Other language implementations (Go, Rust, Python)\n * will never produce `undefined` since it's JavaScript-specific.\n *\n * Guidelines:\n * - Producers MUST emit explicit `null` or omit keys; do NOT rely on coercion\n * - Verifiers SHOULD sanitize inputs before hashing (remove undefined properties)\n * - The canonical output is identical whether you pass `{a: undefined}` or `{}`\n *\n * This behavior is NORMATIVE for PEAC hashing and MUST NOT change without\n * a wire format version bump.\n */\n\n/**\n * Canonicalize a JSON value according to RFC 8785.\n *\n * @param obj - The value to canonicalize. Must be a valid JSON type (null, boolean,\n * number, string, array, object). Functions and Symbols throw.\n * @returns Canonical JSON string with sorted keys and no whitespace.\n * @throws Error if the value cannot be canonicalized (undefined at top level,\n * non-finite numbers, functions, symbols).\n *\n * @example\n * ```ts\n * canonicalize({ b: 2, a: 1 }) // '{\"a\":1,\"b\":2}'\n * canonicalize([1, null, \"x\"]) // '[1,null,\"x\"]'\n * ```\n */\nexport function canonicalize(obj: unknown): string {\n if (obj === null) {\n return 'null';\n }\n\n if (typeof obj === 'boolean') {\n return obj ? 'true' : 'false';\n }\n\n if (typeof obj === 'number') {\n // RFC 8785 number serialization (no trailing zeros, no exponential for small numbers)\n if (!Number.isFinite(obj)) {\n throw new Error('Cannot canonicalize non-finite number');\n }\n if (Object.is(obj, -0)) {\n return '0';\n }\n // Use JSON.stringify for proper number formatting per RFC 8785\n const str = JSON.stringify(obj);\n // Ensure no exponential notation for integers\n if (Number.isInteger(obj) && str.includes('e')) {\n return obj.toString();\n }\n return str;\n }\n\n if (typeof obj === 'string') {\n return JSON.stringify(obj);\n }\n\n if (Array.isArray(obj)) {\n // PROTOCOL DECISION: undefined in arrays becomes null (matches JSON.stringify)\n // See module-level documentation for cross-language interoperability notes.\n const elements = obj.map((el) => (el === undefined ? 'null' : canonicalize(el)));\n return `[${elements.join(',')}]`;\n }\n\n if (typeof obj === 'object') {\n // Sort keys lexicographically by UTF-16 code unit (RFC 8785 requirement)\n const keys = Object.keys(obj).sort();\n const pairs: string[] = [];\n for (const key of keys) {\n const value = (obj as Record<string, unknown>)[key];\n // PROTOCOL DECISION: Skip undefined values (matches JSON.stringify)\n // See module-level documentation for cross-language interoperability notes.\n if (value === undefined) {\n continue;\n }\n pairs.push(`${JSON.stringify(key)}:${canonicalize(value)}`);\n }\n return `{${pairs.join(',')}}`;\n }\n\n throw new Error(`Cannot canonicalize type: ${typeof obj}`);\n}\n\n/**\n * Canonicalize and encode as UTF-8 bytes\n */\nexport function canonicalizeBytes(obj: unknown): Uint8Array {\n const canonical = canonicalize(obj);\n return new TextEncoder().encode(canonical);\n}\n\n/**\n * Compute JCS+SHA-256 hash of an object\n */\nexport async function jcsHash(obj: unknown): Promise<string> {\n const bytes = canonicalizeBytes(obj);\n const hashBuffer = await crypto.subtle.digest('SHA-256', bytes);\n const hashArray = new Uint8Array(hashBuffer);\n return Array.from(hashArray)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n","/**\n * Internal Ed25519 wrapper -- async-only surface\n *\n * PEAC uses ONLY the async methods from @noble/ed25519.\n * In noble v3, sync methods require explicit hash configuration.\n * Async methods use built-in Web Crypto and need no configuration.\n *\n * This module re-exports only the async surface to prevent accidental\n * sync usage. All other modules in @peac/crypto MUST import from\n * this file, never directly from '@noble/ed25519'.\n *\n * Key material handling:\n * - Private keys are 32-byte Uint8Array (Ed25519 seed)\n * - Public keys are 32-byte Uint8Array (compressed Ed25519 point)\n * - JavaScript cannot guarantee memory zeroization; callers should\n * avoid storing keys longer than necessary and never log key bytes\n * - randomSecretKey() uses crypto.getRandomValues() (CSPRNG)\n * which is available in Node.js >=15 and all modern runtimes\n */\n\n// Namespace import avoids tsup tree-shaking false positive in multi-entry builds\n// where signAsync/verifyAsync appear unused in the testkit entry point.\nimport * as ed from '@noble/ed25519';\n\n/** Sign a message with Ed25519 (async, Web Crypto backed) */\nexport const sign = ed.signAsync;\n\n/** Verify an Ed25519 signature (async, Web Crypto backed) */\nexport const verify = ed.verifyAsync;\n\n/** Derive public key from private key (async, Web Crypto backed) */\nexport const getPublicKey = ed.getPublicKeyAsync;\n\n/** Generate a cryptographically random 32-byte secret key (CSPRNG) */\nexport const randomSecretKey = ed.utils.randomSecretKey;\n","/**\n * JWS compact serialization with Ed25519 (RFC 8032)\n * Dual-stack: Wire 0.1 (peac-receipt/0.1) and Wire 0.2 (interaction-record+jwt)\n */\n\nimport {\n sign as ed25519Sign,\n verify as ed25519Verify,\n getPublicKey,\n randomSecretKey,\n} from './ed25519.js';\nimport {\n WIRE_01_JWS_TYP,\n WIRE_02_JWS_TYP,\n WIRE_02_JWS_TYP_ACCEPT,\n PEAC_ALG,\n VERIFIER_LIMITS,\n} from '@peac/kernel';\nimport {\n base64urlEncode,\n base64urlDecode,\n base64urlEncodeString,\n base64urlDecodeString,\n} from './base64url';\nimport { CryptoError } from './errors';\n\n// ---------------------------------------------------------------------------\n// JWS header types: 3-variant discriminated union (Correction 1, DD-156)\n// ---------------------------------------------------------------------------\n\n/**\n * JWS header for Wire 0.1 receipts (typ: 'peac-receipt/0.1')\n */\nexport interface Wire01JWSHeader {\n typ: typeof WIRE_01_JWS_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * JWS header for Wire 0.2 receipts (typ: 'interaction-record+jwt', compact canonical form)\n *\n * The full media type 'application/interaction-record+jwt' is accepted by verify()\n * and decode() but normalized to this compact form before returning.\n */\nexport interface Wire02JWSHeader {\n typ: typeof WIRE_02_JWS_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * JWS header for tokens with no typ field\n *\n * Crypto layer passes these through without error.\n * The strictness decision (hard error vs. warning) belongs exclusively\n * in @peac/protocol.verifyLocal() (Correction 1, DD-156).\n */\nexport interface UnTypedJWSHeader {\n typ?: undefined;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * Discriminated union of all recognized JWS header variants.\n *\n * Callers narrow by checking `header.typ`:\n * if (header.typ === WIRE_02_JWS_TYP) { ... Wire 0.2 path ... }\n * if (header.typ === WIRE_01_JWS_TYP) { ... Wire 0.1 path ... }\n * if (header.typ === undefined) { ... UnTyped / interop path ... }\n */\nexport type JWSHeader = Wire01JWSHeader | Wire02JWSHeader | UnTypedJWSHeader;\n\n/**\n * Result of JWS verification\n */\nexport interface VerifyResult<T = unknown> {\n header: JWSHeader;\n payload: T;\n valid: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Internal constants (NOT exported)\n// ---------------------------------------------------------------------------\n\n/** All typ values accepted by verify() / decode(). Includes full media type form. */\nconst ACCEPTED_TYP_VALUES = new Set<string>([WIRE_01_JWS_TYP, ...WIRE_02_JWS_TYP_ACCEPT]);\n\n// ---------------------------------------------------------------------------\n// validateWire02Header (exported, JOSE hardening, Correction 9, DD-156)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate JOSE header fields for Wire 0.2 JOSE hardening requirements.\n *\n * Rejects:\n * - Embedded key material (jwk, x5c, x5u, jku)\n * - crit header (critical extensions)\n * - b64: false (RFC 7797 unencoded payload)\n * - zip header (payload compression)\n * - Missing, empty, or oversized kid (DoS safety: max 256 chars)\n *\n * @param header - Raw parsed JWS header object\n * @throws CryptoError with CRYPTO_JWS_* code on any violation\n */\nexport function validateWire02Header(header: Record<string, unknown>): void {\n // kid: required, non-empty, max 256 chars (Correction 9, DoS safety)\n if (\n !header.kid ||\n typeof header.kid !== 'string' ||\n header.kid.length === 0 ||\n header.kid.length > 256\n ) {\n throw new CryptoError(\n 'CRYPTO_JWS_MISSING_KID',\n 'kid is missing, empty, or exceeds 256 characters'\n );\n }\n\n // Embedded key material: hard reject (prevents key confusion attacks)\n if (\n header.jwk !== undefined ||\n header.x5c !== undefined ||\n header.x5u !== undefined ||\n header.jku !== undefined\n ) {\n throw new CryptoError(\n 'CRYPTO_JWS_EMBEDDED_KEY',\n 'embedded key material (jwk/x5c/x5u/jku) is not permitted'\n );\n }\n\n // crit: hard reject\n if (header.crit !== undefined) {\n throw new CryptoError('CRYPTO_JWS_CRIT_REJECTED', 'crit header is not permitted');\n }\n\n // b64: false: RFC 7797 unencoded payload rejected\n if (header.b64 === false) {\n throw new CryptoError(\n 'CRYPTO_JWS_B64_REJECTED',\n 'b64:false (unencoded payload) is not permitted'\n );\n }\n\n // zip: hard reject\n if (header.zip !== undefined) {\n throw new CryptoError('CRYPTO_JWS_ZIP_REJECTED', 'zip header is not permitted');\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helper: build typed JWSHeader from raw parsed object\n// ---------------------------------------------------------------------------\n\n/**\n * Build a typed JWSHeader from a raw parsed header object, applying typ\n * normalization (Correction 2, DD-156): 'application/interaction-record+jwt'\n * is normalized to 'interaction-record+jwt' before returning.\n *\n * @param raw - Raw header object from JSON.parse\n * @returns Typed JWSHeader\n * @throws CryptoError if alg is not PEAC_ALG, or if typ is present and not in ACCEPTED_TYP_VALUES\n */\nfunction buildHeader(raw: Record<string, unknown>): JWSHeader {\n // Validate alg (required)\n if (raw.alg !== PEAC_ALG) {\n throw new CryptoError(\n 'CRYPTO_INVALID_ALG',\n `Invalid alg: expected ${PEAC_ALG}, got ${String(raw.alg)}`\n );\n }\n\n const rawTyp = raw.typ as string | undefined;\n\n // Normalize full media type to compact form (Correction 2)\n const canonicalTyp = rawTyp === 'application/interaction-record+jwt' ? WIRE_02_JWS_TYP : rawTyp;\n\n if (canonicalTyp !== undefined && !ACCEPTED_TYP_VALUES.has(rawTyp!)) {\n throw new CryptoError('CRYPTO_INVALID_TYP', `Invalid typ: ${String(rawTyp)}`);\n }\n\n const kid = typeof raw.kid === 'string' ? raw.kid : '';\n\n if (canonicalTyp === WIRE_01_JWS_TYP) {\n return { typ: WIRE_01_JWS_TYP, alg: PEAC_ALG, kid } satisfies Wire01JWSHeader;\n }\n if (canonicalTyp === WIRE_02_JWS_TYP) {\n return { typ: WIRE_02_JWS_TYP, alg: PEAC_ALG, kid } satisfies Wire02JWSHeader;\n }\n\n // canonicalTyp is undefined: return UnTypedJWSHeader\n return { typ: undefined, alg: PEAC_ALG, kid } satisfies UnTypedJWSHeader;\n}\n\n// ---------------------------------------------------------------------------\n// sign (Wire 0.1)\n// ---------------------------------------------------------------------------\n\n/**\n * Sign a payload with Ed25519 and return JWS compact serialization (Wire 0.1)\n *\n * Always sets typ to WIRE_01_JWS_TYP ('peac-receipt/0.1').\n * For Wire 0.2, use signWire02() instead.\n *\n * @param payload - JSON-serializable payload\n * @param privateKey - Ed25519 private key (32 bytes)\n * @param kid - Key ID (ISO 8601 timestamp)\n * @returns JWS compact serialization (header.payload.signature)\n */\nexport async function sign(payload: unknown, privateKey: Uint8Array, kid: string): Promise<string> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n\n const header: Wire01JWSHeader = {\n typ: WIRE_01_JWS_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const signatureBytes = await ed25519Sign(signingInputBytes, privateKey);\n const signatureB64 = base64urlEncode(signatureBytes);\n\n return `${signingInput}.${signatureB64}`;\n}\n\n// ---------------------------------------------------------------------------\n// signWire02 (Wire 0.2)\n// ---------------------------------------------------------------------------\n\n/**\n * Sign a Wire 0.2 payload with Ed25519 and return JWS compact serialization\n *\n * Always sets typ to WIRE_02_JWS_TYP ('interaction-record+jwt').\n * The payload MUST include peac_version: '0.2'.\n *\n * @param payload - JSON-serializable Wire 0.2 claims payload\n * @param privateKey - Ed25519 private key (32 bytes)\n * @param kid - Key ID (max 256 chars per JOSE hardening rules)\n * @returns JWS compact serialization (header.payload.signature)\n */\nexport async function signWire02(\n payload: unknown,\n privateKey: Uint8Array,\n kid: string\n): Promise<string> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n\n // Validate kid length (Correction 9, DoS safety)\n if (!kid || kid.length === 0 || kid.length > 256) {\n throw new CryptoError(\n 'CRYPTO_JWS_MISSING_KID',\n 'kid is missing, empty, or exceeds 256 characters'\n );\n }\n\n // Always set typ: WIRE_02_JWS_TYP: no code path may omit it\n const header: Wire02JWSHeader = {\n typ: WIRE_02_JWS_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const signatureBytes = await ed25519Sign(signingInputBytes, privateKey);\n const signatureB64 = base64urlEncode(signatureBytes);\n\n return `${signingInput}.${signatureB64}`;\n}\n\n// ---------------------------------------------------------------------------\n// verify (dual-stack)\n// ---------------------------------------------------------------------------\n\n/**\n * Verify a JWS compact serialization with Ed25519\n *\n * Dual-stack: accepts Wire 0.1 (peac-receipt/0.1) and Wire 0.2\n * (interaction-record+jwt or application/interaction-record+jwt).\n *\n * Typ normalization (Correction 2): 'application/interaction-record+jwt' is\n * normalized to 'interaction-record+jwt' in the returned header.\n *\n * UnTypedJWSHeader (Correction 1): tokens with no typ are returned with\n * typ: undefined without error; @peac/protocol.verifyLocal() applies strictness.\n *\n * Coherence check:\n * - typ === WIRE_02_JWS_TYP but payload.peac_version !== '0.2': CRYPTO_WIRE_VERSION_MISMATCH\n * - typ === WIRE_01_JWS_TYP but payload.peac_version === '0.2': CRYPTO_WIRE_VERSION_MISMATCH\n * - typ absent: no coherence check here; verifyLocal() handles it\n *\n * @param jws - JWS compact serialization\n * @param publicKey - Ed25519 public key (32 bytes)\n * @returns Verification result with typed header and decoded payload\n */\nexport async function verify<T = unknown>(\n jws: string,\n publicKey: Uint8Array\n): Promise<VerifyResult<T>> {\n if (publicKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 public key must be 32 bytes');\n }\n\n // Fast-reject oversized tokens before any parsing (DoS safety).\n // Uses VERIFIER_LIMITS.maxReceiptBytes (256 KB) as the upper bound.\n if (jws.length > VERIFIER_LIMITS.maxReceiptBytes) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n `JWS exceeds maximum size of ${VERIFIER_LIMITS.maxReceiptBytes} bytes`\n );\n }\n\n const parts = jws.split('.');\n if (parts.length !== 3) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n 'Invalid JWS: must have three dot-separated parts'\n );\n }\n\n const [headerB64, payloadB64, signatureB64] = parts;\n\n // Decode and build typed header.\n // Wrap in try/catch to translate SyntaxError / decode failures into stable\n // CryptoError codes; callers depend on CRYPTO_INVALID_JWS_FORMAT for error\n // classification and must never receive a raw SyntaxError at the boundary.\n let rawHeader: Record<string, unknown>;\n try {\n rawHeader = JSON.parse(base64urlDecodeString(headerB64)) as Record<string, unknown>;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS header: invalid base64url or JSON');\n }\n const header = buildHeader(rawHeader);\n\n // Apply JOSE hardening for Wire 0.2 and UnTyped tokens (Correction 1, DD-156).\n // JOSE security invariants (embedded key material, crit, b64:false, zip) MUST be\n // enforced regardless of whether typ is present. Interop mode controls routing only;\n // it does not exempt tokens from key-injection or unencoded-payload attacks.\n // Wire 0.1 tokens are excluded: the legacy format predates these constraints.\n if (header.typ === WIRE_02_JWS_TYP || header.typ === undefined) {\n validateWire02Header(rawHeader);\n }\n\n // Decode payload; same stable-error contract as header decode above.\n let payload: T;\n try {\n payload = JSON.parse(base64urlDecodeString(payloadB64)) as T;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS payload: invalid base64url or JSON');\n }\n\n // Coherence check: wire version consistency (only when typ is present)\n if (header.typ !== undefined) {\n const payloadVersion = (payload as Record<string, unknown>).peac_version;\n if (header.typ === WIRE_02_JWS_TYP && payloadVersion !== '0.2') {\n throw new CryptoError(\n 'CRYPTO_WIRE_VERSION_MISMATCH',\n `typ is ${WIRE_02_JWS_TYP} but peac_version is ${String(payloadVersion)} (expected '0.2')`\n );\n }\n if (header.typ === WIRE_01_JWS_TYP && payloadVersion === '0.2') {\n throw new CryptoError(\n 'CRYPTO_WIRE_VERSION_MISMATCH',\n `typ is ${WIRE_01_JWS_TYP} but peac_version is '0.2' (Wire 0.2 must use ${WIRE_02_JWS_TYP})`\n );\n }\n }\n\n // Verify Ed25519 signature\n const signatureBytes = base64urlDecode(signatureB64);\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n const valid = await ed25519Verify(signatureBytes, signingInputBytes, publicKey);\n\n return { header, payload, valid };\n}\n\n// ---------------------------------------------------------------------------\n// decode (dual-stack, unverified)\n// ---------------------------------------------------------------------------\n\n/**\n * Decode JWS without verifying signature\n *\n * UNSAFE: This function is for debugging and diagnostic inspection only.\n * It does NOT verify the Ed25519 signature and does NOT apply JOSE hardening\n * (embedded-key rejection, b64/zip/crit checks). Tokens returned by decode()\n * must never be trusted for authorization decisions.\n *\n * For secure verification use verify() instead.\n *\n * Applies the same typ normalization and header typing as verify().\n * Unrecognized typ values still throw CryptoError.\n *\n * @param jws - JWS compact serialization\n * @returns Decoded header and payload (unverified, no JOSE hardening applied)\n */\nexport function decode<T = unknown>(jws: string): { header: JWSHeader; payload: T } {\n const parts = jws.split('.');\n if (parts.length !== 3) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n 'Invalid JWS: must have three dot-separated parts'\n );\n }\n\n const [headerB64, payloadB64] = parts;\n\n let rawHeader: Record<string, unknown>;\n try {\n rawHeader = JSON.parse(base64urlDecodeString(headerB64)) as Record<string, unknown>;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS header: invalid base64url or JSON');\n }\n const header = buildHeader(rawHeader);\n\n let payload: T;\n try {\n payload = JSON.parse(base64urlDecodeString(payloadB64)) as T;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS payload: invalid base64url or JSON');\n }\n\n return { header, payload };\n}\n\n// ---------------------------------------------------------------------------\n// generateKeypair\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a random Ed25519 keypair\n *\n * @returns Private key (32 bytes) and public key (32 bytes)\n */\nexport async function generateKeypair(): Promise<{\n privateKey: Uint8Array;\n publicKey: Uint8Array;\n}> {\n const privateKey = randomSecretKey();\n const publicKey = await getPublicKey(privateKey);\n\n return { privateKey, publicKey };\n}\n\n// NOTE: generateKeypairFromSeed has been moved to @peac/crypto/testkit\n// It's intentionally NOT exported from the main module to prevent accidental\n// use in production. Use: import { generateKeypairFromSeed } from '@peac/crypto/testkit'\n\n// ---------------------------------------------------------------------------\n// Ed25519 JWK utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Ed25519 JWK interface for private keys\n */\nexport interface Ed25519PrivateJwk {\n kty: 'OKP';\n crv: 'Ed25519';\n /** Public key (base64url encoded, 32 bytes) */\n x: string;\n /** Private key (base64url encoded, 32 bytes) */\n d: string;\n}\n\n/**\n * Derive the Ed25519 public key from a private key\n *\n * @param privateKey - Ed25519 private key (32 bytes)\n * @returns Public key (32 bytes)\n */\nexport async function derivePublicKey(privateKey: Uint8Array): Promise<Uint8Array> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n return getPublicKey(privateKey);\n}\n\n/**\n * Validate that an Ed25519 JWK has a consistent keypair\n *\n * Derives the public key from the private key (d) and verifies it matches\n * the declared public key (x). This catches configuration errors where\n * the wrong key components are paired.\n *\n * @param jwk - Ed25519 JWK with both public (x) and private (d) components\n * @returns true if the keypair is consistent, false otherwise\n *\n * @example\n * ```typescript\n * const jwk = {\n * kty: 'OKP',\n * crv: 'Ed25519',\n * x: 'base64url-encoded-public-key',\n * d: 'base64url-encoded-private-key',\n * };\n *\n * if (!await validateKeypair(jwk)) {\n * throw new Error('Invalid keypair: d does not derive to x');\n * }\n * ```\n */\nexport async function validateKeypair(jwk: Ed25519PrivateJwk): Promise<boolean> {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n return false;\n }\n\n let privateKeyBytes: Uint8Array;\n let declaredPublicKeyBytes: Uint8Array;\n\n try {\n privateKeyBytes = base64urlDecode(jwk.d);\n declaredPublicKeyBytes = base64urlDecode(jwk.x);\n } catch {\n return false;\n }\n\n if (privateKeyBytes.length !== 32 || declaredPublicKeyBytes.length !== 32) {\n return false;\n }\n\n const derivedPublicKeyBytes = await getPublicKey(privateKeyBytes);\n\n if (derivedPublicKeyBytes.length !== declaredPublicKeyBytes.length) {\n return false;\n }\n\n for (let i = 0; i < derivedPublicKeyBytes.length; i++) {\n if (derivedPublicKeyBytes[i] !== declaredPublicKeyBytes[i]) {\n return false;\n }\n }\n\n return true;\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,4 +13,5 @@ export * from './errors';
|
|
|
13
13
|
export * from './hash';
|
|
14
14
|
export * from './jcs';
|
|
15
15
|
export * from './jws';
|
|
16
|
+
export { sign as ed25519Sign, verify as ed25519Verify, getPublicKey as ed25519GetPublicKey, randomSecretKey as ed25519RandomSecretKey, } from './ed25519';
|
|
16
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC;AAGtB,OAAO,EACL,IAAI,IAAI,WAAW,EACnB,MAAM,IAAI,aAAa,EACvB,YAAY,IAAI,mBAAmB,EACnC,eAAe,IAAI,sBAAsB,GAC1C,MAAM,WAAW,CAAC"}
|
package/dist/index.mjs
CHANGED
|
@@ -416,6 +416,6 @@ async function validateKeypair(jwk) {
|
|
|
416
416
|
return true;
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
-
export { CryptoError, base64urlDecode, base64urlDecodeString, base64urlEncode, base64urlEncodeString, base64urlToHex, bytesToHex, canonicalize, canonicalizeBytes, computeJwkThumbprint, decode, derivePublicKey, generateKeypair, hexToBase64url, hexToBytes, isFormatError, jcsHash, jwkToPublicKeyBytes, sha256Base64url, sha256Bytes, sha256Hex, sign2 as sign, signWire02, validateKeypair, validateWire02Header, verify2 as verify };
|
|
419
|
+
export { CryptoError, base64urlDecode, base64urlDecodeString, base64urlEncode, base64urlEncodeString, base64urlToHex, bytesToHex, canonicalize, canonicalizeBytes, computeJwkThumbprint, decode, derivePublicKey, getPublicKey as ed25519GetPublicKey, randomSecretKey as ed25519RandomSecretKey, sign as ed25519Sign, verify as ed25519Verify, generateKeypair, hexToBase64url, hexToBytes, isFormatError, jcsHash, jwkToPublicKeyBytes, sha256Base64url, sha256Bytes, sha256Hex, sign2 as sign, signWire02, validateKeypair, validateWire02Header, verify2 as verify };
|
|
420
420
|
//# sourceMappingURL=index.mjs.map
|
|
421
421
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/base64url.ts","../src/errors.ts","../src/hash.ts","../src/jcs.ts","../src/ed25519.ts","../src/jws.ts"],"names":["sign","verify"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Base64url encoding/decoding (RFC 4648 §5)\n *\n * Platform-agnostic implementation that works in Node.js, browser, and edge runtimes.\n * No Buffer dependency - uses pure JavaScript for maximum portability.\n *\n * @packageDocumentation\n */\n\n// Standard base64 alphabet\nconst BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n// Reverse lookup table (lazily initialized)\nlet base64Lookup: Map<string, number> | null = null;\n\nfunction getBase64Lookup(): Map<string, number> {\n if (!base64Lookup) {\n base64Lookup = new Map();\n for (let i = 0; i < BASE64_ALPHABET.length; i++) {\n base64Lookup.set(BASE64_ALPHABET[i], i);\n }\n }\n return base64Lookup;\n}\n\n/**\n * Encode bytes to base64url string (no padding)\n *\n * @param bytes - Byte array to encode\n * @returns Base64url encoded string (no padding)\n */\nexport function base64urlEncode(bytes: Uint8Array): string {\n let result = '';\n let i = 0;\n\n while (i < bytes.length) {\n const a = bytes[i++];\n const b = bytes[i++] ?? 0;\n const c = bytes[i++] ?? 0;\n\n const triplet = (a << 16) | (b << 8) | c;\n\n result += BASE64_ALPHABET[(triplet >> 18) & 0x3f];\n result += BASE64_ALPHABET[(triplet >> 12) & 0x3f];\n result += i - 2 < bytes.length ? BASE64_ALPHABET[(triplet >> 6) & 0x3f] : '';\n result += i - 1 < bytes.length ? BASE64_ALPHABET[triplet & 0x3f] : '';\n }\n\n // Convert to base64url (no padding)\n return result.replace(/\\+/g, '-').replace(/\\//g, '_');\n}\n\n/**\n * Decode base64url string to bytes\n *\n * @param str - Base64url encoded string\n * @returns Decoded bytes\n */\nexport function base64urlDecode(str: string): Uint8Array {\n // Convert base64url to base64\n let base64 = str.replace(/-/g, '+').replace(/_/g, '/');\n\n // Add padding if needed\n while (base64.length % 4 !== 0) {\n base64 += '=';\n }\n\n const lookup = getBase64Lookup();\n const bytes: number[] = [];\n\n for (let i = 0; i < base64.length; i += 4) {\n const a = lookup.get(base64[i]) ?? 0;\n const b = lookup.get(base64[i + 1]) ?? 0;\n const c = lookup.get(base64[i + 2]) ?? 0;\n const d = lookup.get(base64[i + 3]) ?? 0;\n\n bytes.push((a << 2) | (b >> 4));\n if (base64[i + 2] !== '=') {\n bytes.push(((b & 0x0f) << 4) | (c >> 2));\n }\n if (base64[i + 3] !== '=') {\n bytes.push(((c & 0x03) << 6) | d);\n }\n }\n\n return new Uint8Array(bytes);\n}\n\n/**\n * Encode UTF-8 string to base64url\n *\n * @param str - UTF-8 string to encode\n * @returns Base64url encoded string\n */\nexport function base64urlEncodeString(str: string): string {\n return base64urlEncode(new TextEncoder().encode(str));\n}\n\n/**\n * Decode base64url to UTF-8 string\n *\n * @param str - Base64url encoded string\n * @returns Decoded UTF-8 string\n */\nexport function base64urlDecodeString(str: string): string {\n return new TextDecoder().decode(base64urlDecode(str));\n}\n","/**\n * Typed errors for @peac/crypto\n *\n * These error codes are INTERNAL to @peac/crypto and should NOT be exposed\n * as protocol-stable API. Higher-level packages (like @peac/protocol) should\n * map these to canonical E_* codes from specs/kernel/errors.json.\n *\n * The CRYPTO_ prefix makes it clear these are package-internal codes.\n */\n\n/**\n * Internal error codes for crypto operations\n *\n * These are NOT canonical protocol error codes. They are internal to @peac/crypto.\n * @peac/protocol maps these to canonical E_* codes (E_INVALID_FORMAT, etc).\n */\nexport type CryptoErrorCode =\n | 'CRYPTO_INVALID_KEY_LENGTH'\n | 'CRYPTO_INVALID_SEED_LENGTH'\n | 'CRYPTO_INVALID_JWS_FORMAT'\n | 'CRYPTO_INVALID_TYP'\n | 'CRYPTO_INVALID_ALG'\n | 'CRYPTO_INVALID_SIGNATURE'\n // Wire 0.2 JOSE hardening (v0.12.0-preview.1, DD-156)\n | 'CRYPTO_WIRE_VERSION_MISMATCH'\n | 'CRYPTO_JWS_EMBEDDED_KEY'\n | 'CRYPTO_JWS_CRIT_REJECTED'\n | 'CRYPTO_JWS_MISSING_KID'\n | 'CRYPTO_JWS_B64_REJECTED'\n | 'CRYPTO_JWS_ZIP_REJECTED';\n\n/**\n * Typed error for crypto operations\n *\n * Use `err.code` to handle errors programmatically without message parsing.\n * The code is a CRYPTO_* internal code, not a canonical E_* protocol code.\n */\nexport class CryptoError extends Error {\n readonly code: CryptoErrorCode;\n\n constructor(code: CryptoErrorCode, message: string) {\n super(message);\n this.name = 'CryptoError';\n this.code = code;\n // Maintain proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, CryptoError.prototype);\n }\n}\n\n/**\n * Check if a CryptoError code indicates a format/structure issue\n * (as opposed to a cryptographic verification failure)\n *\n * @internal This is an internal helper, not part of the public API.\n * Use structural checks on CryptoError.code instead of relying on this function.\n */\nexport function isFormatError(code: CryptoErrorCode): boolean {\n return (\n code === 'CRYPTO_INVALID_JWS_FORMAT' ||\n code === 'CRYPTO_INVALID_TYP' ||\n code === 'CRYPTO_INVALID_ALG' ||\n code === 'CRYPTO_INVALID_KEY_LENGTH' ||\n code === 'CRYPTO_INVALID_SEED_LENGTH'\n );\n}\n","/**\n * Cryptographic hash utilities\n *\n * Platform-agnostic SHA-256 implementation that works in Node.js, browser, and edge runtimes.\n * Uses Web Crypto API with Node.js crypto fallback.\n *\n * @packageDocumentation\n */\n\nimport { base64urlDecode, base64urlEncode } from './base64url.js';\n\n/**\n * Compute SHA-256 hash of data and return as lowercase hex string\n *\n * Uses Web Crypto API if available, falls back to Node.js crypto.\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Lowercase hex string (64 characters)\n */\nexport async function sha256Hex(data: Uint8Array | string): Promise<string> {\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;\n\n // Try Web Crypto API first (works in browser, edge, and Node 20+)\n if (typeof globalThis.crypto?.subtle?.digest === 'function') {\n const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', bytes);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');\n }\n\n // Fallback to Node.js crypto\n try {\n const { createHash } = await import('crypto');\n const hash = createHash('sha256');\n hash.update(bytes);\n return hash.digest('hex');\n } catch {\n throw new Error(\n 'No SHA-256 implementation available. Ensure Web Crypto API or Node.js crypto is available.'\n );\n }\n}\n\n/**\n * Compute SHA-256 hash of data and return as Uint8Array (32 bytes)\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Hash as Uint8Array (32 bytes)\n */\nexport async function sha256Bytes(data: Uint8Array | string): Promise<Uint8Array> {\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;\n\n // Try Web Crypto API first\n if (typeof globalThis.crypto?.subtle?.digest === 'function') {\n const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', bytes);\n return new Uint8Array(hashBuffer);\n }\n\n // Fallback to Node.js crypto\n try {\n const { createHash } = await import('crypto');\n const hash = createHash('sha256');\n hash.update(bytes);\n return new Uint8Array(hash.digest());\n } catch {\n throw new Error('No SHA-256 implementation available.');\n }\n}\n\n/**\n * Convert hex string to Uint8Array\n *\n * @param hex - Lowercase hex string\n * @returns Uint8Array\n */\nexport function hexToBytes(hex: string): Uint8Array {\n // Validate: must be even length and contain only hex characters\n if (hex.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex)) {\n throw new Error('Invalid hex string');\n }\n if (hex.length === 0) {\n return new Uint8Array([]);\n }\n const matches = hex.match(/.{2}/g);\n if (!matches) {\n throw new Error('Invalid hex string');\n }\n return new Uint8Array(matches.map((byte) => parseInt(byte, 16)));\n}\n\n/**\n * Convert Uint8Array to lowercase hex string\n *\n * @param bytes - Byte array\n * @returns Lowercase hex string\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Compute SHA-256 hash of data and return as base64url string\n *\n * Used by Wire 0.2 DigestRef format. Evidence bundles use sha256Hex() with\n * \"sha256:<hex>\" prefix instead. A conversion bridge between the two formats\n * (hex <-> base64url) is provided by hexToBase64url() and base64urlToHex().\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Base64url-encoded SHA-256 hash (43 characters)\n */\nexport async function sha256Base64url(data: Uint8Array | string): Promise<string> {\n const hashBytes = await sha256Bytes(data);\n return base64urlEncode(hashBytes);\n}\n\n/**\n * Convert a hex-encoded hash to base64url encoding\n *\n * Bridges evidence bundle format (sha256:<hex>) to Wire 0.2 DigestRef format\n * (base64url value). Strips the \"sha256:\" prefix if present.\n *\n * @param hex - Hex string, optionally prefixed with \"sha256:\"\n * @returns Base64url-encoded bytes (43 characters for SHA-256)\n */\nexport function hexToBase64url(hex: string): string {\n const cleanHex = hex.startsWith('sha256:') ? hex.slice(7) : hex;\n return base64urlEncode(hexToBytes(cleanHex));\n}\n\n/**\n * Convert a base64url-encoded hash to hex encoding\n *\n * Bridges Wire 0.2 DigestRef format (base64url) to evidence bundle format\n * (hex). Does NOT add the \"sha256:\" prefix -- caller adds it if needed.\n *\n * @param b64u - Base64url-encoded hash\n * @returns Lowercase hex string (64 characters for SHA-256)\n */\nexport function base64urlToHex(b64u: string): string {\n return bytesToHex(base64urlDecode(b64u));\n}\n\n/**\n * JWK structure for Ed25519 public keys (minimal required fields for thumbprint)\n */\nexport interface JWKThumbprintInput {\n /** Key type - must be \"OKP\" for Ed25519 */\n kty: string;\n /** Curve - must be \"Ed25519\" */\n crv: string;\n /** Public key (base64url) */\n x: string;\n}\n\n/**\n * Compute RFC 7638 JWK Thumbprint (base64url, SHA-256)\n *\n * For Ed25519 keys, the canonical JSON is: {\"crv\":\"Ed25519\",\"kty\":\"OKP\",\"x\":\"<base64url>\"}\n * Returns base64url-encoded SHA-256 hash (43 characters).\n *\n * @param jwk - JWK with kty, crv, x fields\n * @returns Base64url-encoded SHA-256 thumbprint (43 characters)\n */\nexport async function computeJwkThumbprint(jwk: JWKThumbprintInput): Promise<string> {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n throw new Error('Only Ed25519 keys (OKP/Ed25519) are supported for thumbprint computation');\n }\n\n // Canonical JSON per RFC 7638 (alphabetically sorted members, no whitespace)\n const canonical = JSON.stringify({\n crv: jwk.crv,\n kty: jwk.kty,\n x: jwk.x,\n });\n\n const hashBytes = await sha256Bytes(canonical);\n return base64urlEncode(hashBytes);\n}\n\n/**\n * Convert JWK to Ed25519 public key bytes (32 bytes)\n *\n * @param jwk - JWK with kty, crv, x fields\n * @returns Public key as 32-byte Uint8Array\n */\nexport function jwkToPublicKeyBytes(jwk: JWKThumbprintInput): Uint8Array {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n throw new Error('Only Ed25519 keys (OKP/Ed25519) are supported');\n }\n\n const xBytes = base64urlDecode(jwk.x);\n if (xBytes.length !== 32) {\n throw new Error(`Ed25519 public key must be 32 bytes, got ${xBytes.length}`);\n }\n\n return xBytes;\n}\n","/**\n * JSON Canonicalization Scheme (RFC 8785)\n * Deterministic JSON serialization for cryptographic hashing\n *\n * PROTOCOL DECISION: JavaScript `undefined` Handling\n * ===================================================\n *\n * RFC 8785 canonicalizes JSON values, and `undefined` is NOT a JSON value.\n * This implementation adopts \"JS-ergonomic\" semantics that match JSON.stringify:\n *\n * 1. **Object properties with undefined values are OMITTED**\n * - `canonicalize({a: 1, b: undefined})` -> `{\"a\":1}`\n * - Matches: `JSON.stringify({a: 1, b: undefined})` -> `{\"a\":1}`\n *\n * 2. **Array elements that are undefined become null**\n * - `canonicalize([1, undefined, 3])` -> `[1,null,3]`\n * - Matches: `JSON.stringify([1, undefined, 3])` -> `[1,null,3]`\n *\n * 3. **Top-level undefined THROWS**\n * - `canonicalize(undefined)` -> throws Error\n * - Rationale: No valid JSON representation exists\n *\n * CROSS-LANGUAGE INTEROPERABILITY WARNING:\n * =========================================\n * Cross-language producers MUST NOT rely on \"undefined\" semantics. To achieve\n * identical hashes across implementations, explicitly encode `null` in arrays\n * and omit keys in objects. Other language implementations (Go, Rust, Python)\n * will never produce `undefined` since it's JavaScript-specific.\n *\n * Guidelines:\n * - Producers MUST emit explicit `null` or omit keys; do NOT rely on coercion\n * - Verifiers SHOULD sanitize inputs before hashing (remove undefined properties)\n * - The canonical output is identical whether you pass `{a: undefined}` or `{}`\n *\n * This behavior is NORMATIVE for PEAC hashing and MUST NOT change without\n * a wire format version bump.\n */\n\n/**\n * Canonicalize a JSON value according to RFC 8785.\n *\n * @param obj - The value to canonicalize. Must be a valid JSON type (null, boolean,\n * number, string, array, object). Functions and Symbols throw.\n * @returns Canonical JSON string with sorted keys and no whitespace.\n * @throws Error if the value cannot be canonicalized (undefined at top level,\n * non-finite numbers, functions, symbols).\n *\n * @example\n * ```ts\n * canonicalize({ b: 2, a: 1 }) // '{\"a\":1,\"b\":2}'\n * canonicalize([1, null, \"x\"]) // '[1,null,\"x\"]'\n * ```\n */\nexport function canonicalize(obj: unknown): string {\n if (obj === null) {\n return 'null';\n }\n\n if (typeof obj === 'boolean') {\n return obj ? 'true' : 'false';\n }\n\n if (typeof obj === 'number') {\n // RFC 8785 number serialization (no trailing zeros, no exponential for small numbers)\n if (!Number.isFinite(obj)) {\n throw new Error('Cannot canonicalize non-finite number');\n }\n if (Object.is(obj, -0)) {\n return '0';\n }\n // Use JSON.stringify for proper number formatting per RFC 8785\n const str = JSON.stringify(obj);\n // Ensure no exponential notation for integers\n if (Number.isInteger(obj) && str.includes('e')) {\n return obj.toString();\n }\n return str;\n }\n\n if (typeof obj === 'string') {\n return JSON.stringify(obj);\n }\n\n if (Array.isArray(obj)) {\n // PROTOCOL DECISION: undefined in arrays becomes null (matches JSON.stringify)\n // See module-level documentation for cross-language interoperability notes.\n const elements = obj.map((el) => (el === undefined ? 'null' : canonicalize(el)));\n return `[${elements.join(',')}]`;\n }\n\n if (typeof obj === 'object') {\n // Sort keys lexicographically by UTF-16 code unit (RFC 8785 requirement)\n const keys = Object.keys(obj).sort();\n const pairs: string[] = [];\n for (const key of keys) {\n const value = (obj as Record<string, unknown>)[key];\n // PROTOCOL DECISION: Skip undefined values (matches JSON.stringify)\n // See module-level documentation for cross-language interoperability notes.\n if (value === undefined) {\n continue;\n }\n pairs.push(`${JSON.stringify(key)}:${canonicalize(value)}`);\n }\n return `{${pairs.join(',')}}`;\n }\n\n throw new Error(`Cannot canonicalize type: ${typeof obj}`);\n}\n\n/**\n * Canonicalize and encode as UTF-8 bytes\n */\nexport function canonicalizeBytes(obj: unknown): Uint8Array {\n const canonical = canonicalize(obj);\n return new TextEncoder().encode(canonical);\n}\n\n/**\n * Compute JCS+SHA-256 hash of an object\n */\nexport async function jcsHash(obj: unknown): Promise<string> {\n const bytes = canonicalizeBytes(obj);\n const hashBuffer = await crypto.subtle.digest('SHA-256', bytes);\n const hashArray = new Uint8Array(hashBuffer);\n return Array.from(hashArray)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n","/**\n * Internal Ed25519 wrapper -- async-only surface\n *\n * PEAC uses ONLY the async methods from @noble/ed25519.\n * In noble v3, sync methods require explicit hash configuration.\n * Async methods use built-in Web Crypto and need no configuration.\n *\n * This module re-exports only the async surface to prevent accidental\n * sync usage. All other modules in @peac/crypto MUST import from\n * this file, never directly from '@noble/ed25519'.\n *\n * Key material handling:\n * - Private keys are 32-byte Uint8Array (Ed25519 seed)\n * - Public keys are 32-byte Uint8Array (compressed Ed25519 point)\n * - JavaScript cannot guarantee memory zeroization; callers should\n * avoid storing keys longer than necessary and never log key bytes\n * - randomSecretKey() uses crypto.getRandomValues() (CSPRNG)\n * which is available in Node.js >=15 and all modern runtimes\n */\n\n// Namespace import avoids tsup tree-shaking false positive in multi-entry builds\n// where signAsync/verifyAsync appear unused in the testkit entry point.\nimport * as ed from '@noble/ed25519';\n\n/** Sign a message with Ed25519 (async, Web Crypto backed) */\nexport const sign = ed.signAsync;\n\n/** Verify an Ed25519 signature (async, Web Crypto backed) */\nexport const verify = ed.verifyAsync;\n\n/** Derive public key from private key (async, Web Crypto backed) */\nexport const getPublicKey = ed.getPublicKeyAsync;\n\n/** Generate a cryptographically random 32-byte secret key (CSPRNG) */\nexport const randomSecretKey = ed.utils.randomSecretKey;\n","/**\n * JWS compact serialization with Ed25519 (RFC 8032)\n * Dual-stack: Wire 0.1 (peac-receipt/0.1) and Wire 0.2 (interaction-record+jwt)\n */\n\nimport {\n sign as ed25519Sign,\n verify as ed25519Verify,\n getPublicKey,\n randomSecretKey,\n} from './ed25519.js';\nimport {\n WIRE_01_JWS_TYP,\n WIRE_02_JWS_TYP,\n WIRE_02_JWS_TYP_ACCEPT,\n PEAC_ALG,\n VERIFIER_LIMITS,\n} from '@peac/kernel';\nimport {\n base64urlEncode,\n base64urlDecode,\n base64urlEncodeString,\n base64urlDecodeString,\n} from './base64url';\nimport { CryptoError } from './errors';\n\n// ---------------------------------------------------------------------------\n// JWS header types: 3-variant discriminated union (Correction 1, DD-156)\n// ---------------------------------------------------------------------------\n\n/**\n * JWS header for Wire 0.1 receipts (typ: 'peac-receipt/0.1')\n */\nexport interface Wire01JWSHeader {\n typ: typeof WIRE_01_JWS_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * JWS header for Wire 0.2 receipts (typ: 'interaction-record+jwt', compact canonical form)\n *\n * The full media type 'application/interaction-record+jwt' is accepted by verify()\n * and decode() but normalized to this compact form before returning.\n */\nexport interface Wire02JWSHeader {\n typ: typeof WIRE_02_JWS_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * JWS header for tokens with no typ field\n *\n * Crypto layer passes these through without error.\n * The strictness decision (hard error vs. warning) belongs exclusively\n * in @peac/protocol.verifyLocal() (Correction 1, DD-156).\n */\nexport interface UnTypedJWSHeader {\n typ?: undefined;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * Discriminated union of all recognized JWS header variants.\n *\n * Callers narrow by checking `header.typ`:\n * if (header.typ === WIRE_02_JWS_TYP) { ... Wire 0.2 path ... }\n * if (header.typ === WIRE_01_JWS_TYP) { ... Wire 0.1 path ... }\n * if (header.typ === undefined) { ... UnTyped / interop path ... }\n */\nexport type JWSHeader = Wire01JWSHeader | Wire02JWSHeader | UnTypedJWSHeader;\n\n/**\n * Result of JWS verification\n */\nexport interface VerifyResult<T = unknown> {\n header: JWSHeader;\n payload: T;\n valid: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Internal constants (NOT exported)\n// ---------------------------------------------------------------------------\n\n/** All typ values accepted by verify() / decode(). Includes full media type form. */\nconst ACCEPTED_TYP_VALUES = new Set<string>([WIRE_01_JWS_TYP, ...WIRE_02_JWS_TYP_ACCEPT]);\n\n// ---------------------------------------------------------------------------\n// validateWire02Header (exported, JOSE hardening, Correction 9, DD-156)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate JOSE header fields for Wire 0.2 JOSE hardening requirements.\n *\n * Rejects:\n * - Embedded key material (jwk, x5c, x5u, jku)\n * - crit header (critical extensions)\n * - b64: false (RFC 7797 unencoded payload)\n * - zip header (payload compression)\n * - Missing, empty, or oversized kid (DoS safety: max 256 chars)\n *\n * @param header - Raw parsed JWS header object\n * @throws CryptoError with CRYPTO_JWS_* code on any violation\n */\nexport function validateWire02Header(header: Record<string, unknown>): void {\n // kid: required, non-empty, max 256 chars (Correction 9, DoS safety)\n if (\n !header.kid ||\n typeof header.kid !== 'string' ||\n header.kid.length === 0 ||\n header.kid.length > 256\n ) {\n throw new CryptoError(\n 'CRYPTO_JWS_MISSING_KID',\n 'kid is missing, empty, or exceeds 256 characters'\n );\n }\n\n // Embedded key material: hard reject (prevents key confusion attacks)\n if (\n header.jwk !== undefined ||\n header.x5c !== undefined ||\n header.x5u !== undefined ||\n header.jku !== undefined\n ) {\n throw new CryptoError(\n 'CRYPTO_JWS_EMBEDDED_KEY',\n 'embedded key material (jwk/x5c/x5u/jku) is not permitted'\n );\n }\n\n // crit: hard reject\n if (header.crit !== undefined) {\n throw new CryptoError('CRYPTO_JWS_CRIT_REJECTED', 'crit header is not permitted');\n }\n\n // b64: false: RFC 7797 unencoded payload rejected\n if (header.b64 === false) {\n throw new CryptoError(\n 'CRYPTO_JWS_B64_REJECTED',\n 'b64:false (unencoded payload) is not permitted'\n );\n }\n\n // zip: hard reject\n if (header.zip !== undefined) {\n throw new CryptoError('CRYPTO_JWS_ZIP_REJECTED', 'zip header is not permitted');\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helper: build typed JWSHeader from raw parsed object\n// ---------------------------------------------------------------------------\n\n/**\n * Build a typed JWSHeader from a raw parsed header object, applying typ\n * normalization (Correction 2, DD-156): 'application/interaction-record+jwt'\n * is normalized to 'interaction-record+jwt' before returning.\n *\n * @param raw - Raw header object from JSON.parse\n * @returns Typed JWSHeader\n * @throws CryptoError if alg is not PEAC_ALG, or if typ is present and not in ACCEPTED_TYP_VALUES\n */\nfunction buildHeader(raw: Record<string, unknown>): JWSHeader {\n // Validate alg (required)\n if (raw.alg !== PEAC_ALG) {\n throw new CryptoError(\n 'CRYPTO_INVALID_ALG',\n `Invalid alg: expected ${PEAC_ALG}, got ${String(raw.alg)}`\n );\n }\n\n const rawTyp = raw.typ as string | undefined;\n\n // Normalize full media type to compact form (Correction 2)\n const canonicalTyp = rawTyp === 'application/interaction-record+jwt' ? WIRE_02_JWS_TYP : rawTyp;\n\n if (canonicalTyp !== undefined && !ACCEPTED_TYP_VALUES.has(rawTyp!)) {\n throw new CryptoError('CRYPTO_INVALID_TYP', `Invalid typ: ${String(rawTyp)}`);\n }\n\n const kid = typeof raw.kid === 'string' ? raw.kid : '';\n\n if (canonicalTyp === WIRE_01_JWS_TYP) {\n return { typ: WIRE_01_JWS_TYP, alg: PEAC_ALG, kid } satisfies Wire01JWSHeader;\n }\n if (canonicalTyp === WIRE_02_JWS_TYP) {\n return { typ: WIRE_02_JWS_TYP, alg: PEAC_ALG, kid } satisfies Wire02JWSHeader;\n }\n\n // canonicalTyp is undefined: return UnTypedJWSHeader\n return { typ: undefined, alg: PEAC_ALG, kid } satisfies UnTypedJWSHeader;\n}\n\n// ---------------------------------------------------------------------------\n// sign (Wire 0.1)\n// ---------------------------------------------------------------------------\n\n/**\n * Sign a payload with Ed25519 and return JWS compact serialization (Wire 0.1)\n *\n * Always sets typ to WIRE_01_JWS_TYP ('peac-receipt/0.1').\n * For Wire 0.2, use signWire02() instead.\n *\n * @param payload - JSON-serializable payload\n * @param privateKey - Ed25519 private key (32 bytes)\n * @param kid - Key ID (ISO 8601 timestamp)\n * @returns JWS compact serialization (header.payload.signature)\n */\nexport async function sign(payload: unknown, privateKey: Uint8Array, kid: string): Promise<string> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n\n const header: Wire01JWSHeader = {\n typ: WIRE_01_JWS_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const signatureBytes = await ed25519Sign(signingInputBytes, privateKey);\n const signatureB64 = base64urlEncode(signatureBytes);\n\n return `${signingInput}.${signatureB64}`;\n}\n\n// ---------------------------------------------------------------------------\n// signWire02 (Wire 0.2)\n// ---------------------------------------------------------------------------\n\n/**\n * Sign a Wire 0.2 payload with Ed25519 and return JWS compact serialization\n *\n * Always sets typ to WIRE_02_JWS_TYP ('interaction-record+jwt').\n * The payload MUST include peac_version: '0.2'.\n *\n * @param payload - JSON-serializable Wire 0.2 claims payload\n * @param privateKey - Ed25519 private key (32 bytes)\n * @param kid - Key ID (max 256 chars per JOSE hardening rules)\n * @returns JWS compact serialization (header.payload.signature)\n */\nexport async function signWire02(\n payload: unknown,\n privateKey: Uint8Array,\n kid: string\n): Promise<string> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n\n // Validate kid length (Correction 9, DoS safety)\n if (!kid || kid.length === 0 || kid.length > 256) {\n throw new CryptoError(\n 'CRYPTO_JWS_MISSING_KID',\n 'kid is missing, empty, or exceeds 256 characters'\n );\n }\n\n // Always set typ: WIRE_02_JWS_TYP: no code path may omit it\n const header: Wire02JWSHeader = {\n typ: WIRE_02_JWS_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const signatureBytes = await ed25519Sign(signingInputBytes, privateKey);\n const signatureB64 = base64urlEncode(signatureBytes);\n\n return `${signingInput}.${signatureB64}`;\n}\n\n// ---------------------------------------------------------------------------\n// verify (dual-stack)\n// ---------------------------------------------------------------------------\n\n/**\n * Verify a JWS compact serialization with Ed25519\n *\n * Dual-stack: accepts Wire 0.1 (peac-receipt/0.1) and Wire 0.2\n * (interaction-record+jwt or application/interaction-record+jwt).\n *\n * Typ normalization (Correction 2): 'application/interaction-record+jwt' is\n * normalized to 'interaction-record+jwt' in the returned header.\n *\n * UnTypedJWSHeader (Correction 1): tokens with no typ are returned with\n * typ: undefined without error; @peac/protocol.verifyLocal() applies strictness.\n *\n * Coherence check:\n * - typ === WIRE_02_JWS_TYP but payload.peac_version !== '0.2': CRYPTO_WIRE_VERSION_MISMATCH\n * - typ === WIRE_01_JWS_TYP but payload.peac_version === '0.2': CRYPTO_WIRE_VERSION_MISMATCH\n * - typ absent: no coherence check here; verifyLocal() handles it\n *\n * @param jws - JWS compact serialization\n * @param publicKey - Ed25519 public key (32 bytes)\n * @returns Verification result with typed header and decoded payload\n */\nexport async function verify<T = unknown>(\n jws: string,\n publicKey: Uint8Array\n): Promise<VerifyResult<T>> {\n if (publicKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 public key must be 32 bytes');\n }\n\n // Fast-reject oversized tokens before any parsing (DoS safety).\n // Uses VERIFIER_LIMITS.maxReceiptBytes (256 KB) as the upper bound.\n if (jws.length > VERIFIER_LIMITS.maxReceiptBytes) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n `JWS exceeds maximum size of ${VERIFIER_LIMITS.maxReceiptBytes} bytes`\n );\n }\n\n const parts = jws.split('.');\n if (parts.length !== 3) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n 'Invalid JWS: must have three dot-separated parts'\n );\n }\n\n const [headerB64, payloadB64, signatureB64] = parts;\n\n // Decode and build typed header.\n // Wrap in try/catch to translate SyntaxError / decode failures into stable\n // CryptoError codes; callers depend on CRYPTO_INVALID_JWS_FORMAT for error\n // classification and must never receive a raw SyntaxError at the boundary.\n let rawHeader: Record<string, unknown>;\n try {\n rawHeader = JSON.parse(base64urlDecodeString(headerB64)) as Record<string, unknown>;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS header: invalid base64url or JSON');\n }\n const header = buildHeader(rawHeader);\n\n // Apply JOSE hardening for Wire 0.2 and UnTyped tokens (Correction 1, DD-156).\n // JOSE security invariants (embedded key material, crit, b64:false, zip) MUST be\n // enforced regardless of whether typ is present. Interop mode controls routing only;\n // it does not exempt tokens from key-injection or unencoded-payload attacks.\n // Wire 0.1 tokens are excluded: the legacy format predates these constraints.\n if (header.typ === WIRE_02_JWS_TYP || header.typ === undefined) {\n validateWire02Header(rawHeader);\n }\n\n // Decode payload; same stable-error contract as header decode above.\n let payload: T;\n try {\n payload = JSON.parse(base64urlDecodeString(payloadB64)) as T;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS payload: invalid base64url or JSON');\n }\n\n // Coherence check: wire version consistency (only when typ is present)\n if (header.typ !== undefined) {\n const payloadVersion = (payload as Record<string, unknown>).peac_version;\n if (header.typ === WIRE_02_JWS_TYP && payloadVersion !== '0.2') {\n throw new CryptoError(\n 'CRYPTO_WIRE_VERSION_MISMATCH',\n `typ is ${WIRE_02_JWS_TYP} but peac_version is ${String(payloadVersion)} (expected '0.2')`\n );\n }\n if (header.typ === WIRE_01_JWS_TYP && payloadVersion === '0.2') {\n throw new CryptoError(\n 'CRYPTO_WIRE_VERSION_MISMATCH',\n `typ is ${WIRE_01_JWS_TYP} but peac_version is '0.2' (Wire 0.2 must use ${WIRE_02_JWS_TYP})`\n );\n }\n }\n\n // Verify Ed25519 signature\n const signatureBytes = base64urlDecode(signatureB64);\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n const valid = await ed25519Verify(signatureBytes, signingInputBytes, publicKey);\n\n return { header, payload, valid };\n}\n\n// ---------------------------------------------------------------------------\n// decode (dual-stack, unverified)\n// ---------------------------------------------------------------------------\n\n/**\n * Decode JWS without verifying signature\n *\n * UNSAFE: This function is for debugging and diagnostic inspection only.\n * It does NOT verify the Ed25519 signature and does NOT apply JOSE hardening\n * (embedded-key rejection, b64/zip/crit checks). Tokens returned by decode()\n * must never be trusted for authorization decisions.\n *\n * For secure verification use verify() instead.\n *\n * Applies the same typ normalization and header typing as verify().\n * Unrecognized typ values still throw CryptoError.\n *\n * @param jws - JWS compact serialization\n * @returns Decoded header and payload (unverified, no JOSE hardening applied)\n */\nexport function decode<T = unknown>(jws: string): { header: JWSHeader; payload: T } {\n const parts = jws.split('.');\n if (parts.length !== 3) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n 'Invalid JWS: must have three dot-separated parts'\n );\n }\n\n const [headerB64, payloadB64] = parts;\n\n let rawHeader: Record<string, unknown>;\n try {\n rawHeader = JSON.parse(base64urlDecodeString(headerB64)) as Record<string, unknown>;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS header: invalid base64url or JSON');\n }\n const header = buildHeader(rawHeader);\n\n let payload: T;\n try {\n payload = JSON.parse(base64urlDecodeString(payloadB64)) as T;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS payload: invalid base64url or JSON');\n }\n\n return { header, payload };\n}\n\n// ---------------------------------------------------------------------------\n// generateKeypair\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a random Ed25519 keypair\n *\n * @returns Private key (32 bytes) and public key (32 bytes)\n */\nexport async function generateKeypair(): Promise<{\n privateKey: Uint8Array;\n publicKey: Uint8Array;\n}> {\n const privateKey = randomSecretKey();\n const publicKey = await getPublicKey(privateKey);\n\n return { privateKey, publicKey };\n}\n\n// NOTE: generateKeypairFromSeed has been moved to @peac/crypto/testkit\n// It's intentionally NOT exported from the main module to prevent accidental\n// use in production. Use: import { generateKeypairFromSeed } from '@peac/crypto/testkit'\n\n// ---------------------------------------------------------------------------\n// Ed25519 JWK utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Ed25519 JWK interface for private keys\n */\nexport interface Ed25519PrivateJwk {\n kty: 'OKP';\n crv: 'Ed25519';\n /** Public key (base64url encoded, 32 bytes) */\n x: string;\n /** Private key (base64url encoded, 32 bytes) */\n d: string;\n}\n\n/**\n * Derive the Ed25519 public key from a private key\n *\n * @param privateKey - Ed25519 private key (32 bytes)\n * @returns Public key (32 bytes)\n */\nexport async function derivePublicKey(privateKey: Uint8Array): Promise<Uint8Array> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n return getPublicKey(privateKey);\n}\n\n/**\n * Validate that an Ed25519 JWK has a consistent keypair\n *\n * Derives the public key from the private key (d) and verifies it matches\n * the declared public key (x). This catches configuration errors where\n * the wrong key components are paired.\n *\n * @param jwk - Ed25519 JWK with both public (x) and private (d) components\n * @returns true if the keypair is consistent, false otherwise\n *\n * @example\n * ```typescript\n * const jwk = {\n * kty: 'OKP',\n * crv: 'Ed25519',\n * x: 'base64url-encoded-public-key',\n * d: 'base64url-encoded-private-key',\n * };\n *\n * if (!await validateKeypair(jwk)) {\n * throw new Error('Invalid keypair: d does not derive to x');\n * }\n * ```\n */\nexport async function validateKeypair(jwk: Ed25519PrivateJwk): Promise<boolean> {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n return false;\n }\n\n let privateKeyBytes: Uint8Array;\n let declaredPublicKeyBytes: Uint8Array;\n\n try {\n privateKeyBytes = base64urlDecode(jwk.d);\n declaredPublicKeyBytes = base64urlDecode(jwk.x);\n } catch {\n return false;\n }\n\n if (privateKeyBytes.length !== 32 || declaredPublicKeyBytes.length !== 32) {\n return false;\n }\n\n const derivedPublicKeyBytes = await getPublicKey(privateKeyBytes);\n\n if (derivedPublicKeyBytes.length !== declaredPublicKeyBytes.length) {\n return false;\n }\n\n for (let i = 0; i < derivedPublicKeyBytes.length; i++) {\n if (derivedPublicKeyBytes[i] !== declaredPublicKeyBytes[i]) {\n return false;\n }\n }\n\n return true;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/base64url.ts","../src/errors.ts","../src/hash.ts","../src/jcs.ts","../src/ed25519.ts","../src/jws.ts"],"names":["sign","verify"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Base64url encoding/decoding (RFC 4648 §5)\n *\n * Platform-agnostic implementation that works in Node.js, browser, and edge runtimes.\n * No Buffer dependency - uses pure JavaScript for maximum portability.\n *\n * @packageDocumentation\n */\n\n// Standard base64 alphabet\nconst BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n// Reverse lookup table (lazily initialized)\nlet base64Lookup: Map<string, number> | null = null;\n\nfunction getBase64Lookup(): Map<string, number> {\n if (!base64Lookup) {\n base64Lookup = new Map();\n for (let i = 0; i < BASE64_ALPHABET.length; i++) {\n base64Lookup.set(BASE64_ALPHABET[i], i);\n }\n }\n return base64Lookup;\n}\n\n/**\n * Encode bytes to base64url string (no padding)\n *\n * @param bytes - Byte array to encode\n * @returns Base64url encoded string (no padding)\n */\nexport function base64urlEncode(bytes: Uint8Array): string {\n let result = '';\n let i = 0;\n\n while (i < bytes.length) {\n const a = bytes[i++];\n const b = bytes[i++] ?? 0;\n const c = bytes[i++] ?? 0;\n\n const triplet = (a << 16) | (b << 8) | c;\n\n result += BASE64_ALPHABET[(triplet >> 18) & 0x3f];\n result += BASE64_ALPHABET[(triplet >> 12) & 0x3f];\n result += i - 2 < bytes.length ? BASE64_ALPHABET[(triplet >> 6) & 0x3f] : '';\n result += i - 1 < bytes.length ? BASE64_ALPHABET[triplet & 0x3f] : '';\n }\n\n // Convert to base64url (no padding)\n return result.replace(/\\+/g, '-').replace(/\\//g, '_');\n}\n\n/**\n * Decode base64url string to bytes\n *\n * @param str - Base64url encoded string\n * @returns Decoded bytes\n */\nexport function base64urlDecode(str: string): Uint8Array {\n // Convert base64url to base64\n let base64 = str.replace(/-/g, '+').replace(/_/g, '/');\n\n // Add padding if needed\n while (base64.length % 4 !== 0) {\n base64 += '=';\n }\n\n const lookup = getBase64Lookup();\n const bytes: number[] = [];\n\n for (let i = 0; i < base64.length; i += 4) {\n const a = lookup.get(base64[i]) ?? 0;\n const b = lookup.get(base64[i + 1]) ?? 0;\n const c = lookup.get(base64[i + 2]) ?? 0;\n const d = lookup.get(base64[i + 3]) ?? 0;\n\n bytes.push((a << 2) | (b >> 4));\n if (base64[i + 2] !== '=') {\n bytes.push(((b & 0x0f) << 4) | (c >> 2));\n }\n if (base64[i + 3] !== '=') {\n bytes.push(((c & 0x03) << 6) | d);\n }\n }\n\n return new Uint8Array(bytes);\n}\n\n/**\n * Encode UTF-8 string to base64url\n *\n * @param str - UTF-8 string to encode\n * @returns Base64url encoded string\n */\nexport function base64urlEncodeString(str: string): string {\n return base64urlEncode(new TextEncoder().encode(str));\n}\n\n/**\n * Decode base64url to UTF-8 string\n *\n * @param str - Base64url encoded string\n * @returns Decoded UTF-8 string\n */\nexport function base64urlDecodeString(str: string): string {\n return new TextDecoder().decode(base64urlDecode(str));\n}\n","/**\n * Typed errors for @peac/crypto\n *\n * These error codes are INTERNAL to @peac/crypto and should NOT be exposed\n * as protocol-stable API. Higher-level packages (like @peac/protocol) should\n * map these to canonical E_* codes from specs/kernel/errors.json.\n *\n * The CRYPTO_ prefix makes it clear these are package-internal codes.\n */\n\n/**\n * Internal error codes for crypto operations\n *\n * These are NOT canonical protocol error codes. They are internal to @peac/crypto.\n * @peac/protocol maps these to canonical E_* codes (E_INVALID_FORMAT, etc).\n */\nexport type CryptoErrorCode =\n | 'CRYPTO_INVALID_KEY_LENGTH'\n | 'CRYPTO_INVALID_SEED_LENGTH'\n | 'CRYPTO_INVALID_JWS_FORMAT'\n | 'CRYPTO_INVALID_TYP'\n | 'CRYPTO_INVALID_ALG'\n | 'CRYPTO_INVALID_SIGNATURE'\n // Wire 0.2 JOSE hardening (v0.12.0-preview.1, DD-156)\n | 'CRYPTO_WIRE_VERSION_MISMATCH'\n | 'CRYPTO_JWS_EMBEDDED_KEY'\n | 'CRYPTO_JWS_CRIT_REJECTED'\n | 'CRYPTO_JWS_MISSING_KID'\n | 'CRYPTO_JWS_B64_REJECTED'\n | 'CRYPTO_JWS_ZIP_REJECTED';\n\n/**\n * Typed error for crypto operations\n *\n * Use `err.code` to handle errors programmatically without message parsing.\n * The code is a CRYPTO_* internal code, not a canonical E_* protocol code.\n */\nexport class CryptoError extends Error {\n readonly code: CryptoErrorCode;\n\n constructor(code: CryptoErrorCode, message: string) {\n super(message);\n this.name = 'CryptoError';\n this.code = code;\n // Maintain proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, CryptoError.prototype);\n }\n}\n\n/**\n * Check if a CryptoError code indicates a format/structure issue\n * (as opposed to a cryptographic verification failure)\n *\n * @internal This is an internal helper, not part of the public API.\n * Use structural checks on CryptoError.code instead of relying on this function.\n */\nexport function isFormatError(code: CryptoErrorCode): boolean {\n return (\n code === 'CRYPTO_INVALID_JWS_FORMAT' ||\n code === 'CRYPTO_INVALID_TYP' ||\n code === 'CRYPTO_INVALID_ALG' ||\n code === 'CRYPTO_INVALID_KEY_LENGTH' ||\n code === 'CRYPTO_INVALID_SEED_LENGTH'\n );\n}\n","/**\n * Cryptographic hash utilities\n *\n * Platform-agnostic SHA-256 implementation that works in Node.js, browser, and edge runtimes.\n * Uses Web Crypto API with Node.js crypto fallback.\n *\n * @packageDocumentation\n */\n\nimport { base64urlDecode, base64urlEncode } from './base64url.js';\n\n/**\n * Compute SHA-256 hash of data and return as lowercase hex string\n *\n * Uses Web Crypto API if available, falls back to Node.js crypto.\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Lowercase hex string (64 characters)\n */\nexport async function sha256Hex(data: Uint8Array | string): Promise<string> {\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;\n\n // Try Web Crypto API first (works in browser, edge, and Node 22+)\n if (typeof globalThis.crypto?.subtle?.digest === 'function') {\n const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', bytes);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');\n }\n\n // Fallback to Node.js crypto\n try {\n const { createHash } = await import('crypto');\n const hash = createHash('sha256');\n hash.update(bytes);\n return hash.digest('hex');\n } catch {\n throw new Error(\n 'No SHA-256 implementation available. Ensure Web Crypto API or Node.js crypto is available.'\n );\n }\n}\n\n/**\n * Compute SHA-256 hash of data and return as Uint8Array (32 bytes)\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Hash as Uint8Array (32 bytes)\n */\nexport async function sha256Bytes(data: Uint8Array | string): Promise<Uint8Array> {\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;\n\n // Try Web Crypto API first\n if (typeof globalThis.crypto?.subtle?.digest === 'function') {\n const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', bytes);\n return new Uint8Array(hashBuffer);\n }\n\n // Fallback to Node.js crypto\n try {\n const { createHash } = await import('crypto');\n const hash = createHash('sha256');\n hash.update(bytes);\n return new Uint8Array(hash.digest());\n } catch {\n throw new Error('No SHA-256 implementation available.');\n }\n}\n\n/**\n * Convert hex string to Uint8Array\n *\n * @param hex - Lowercase hex string\n * @returns Uint8Array\n */\nexport function hexToBytes(hex: string): Uint8Array {\n // Validate: must be even length and contain only hex characters\n if (hex.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex)) {\n throw new Error('Invalid hex string');\n }\n if (hex.length === 0) {\n return new Uint8Array([]);\n }\n const matches = hex.match(/.{2}/g);\n if (!matches) {\n throw new Error('Invalid hex string');\n }\n return new Uint8Array(matches.map((byte) => parseInt(byte, 16)));\n}\n\n/**\n * Convert Uint8Array to lowercase hex string\n *\n * @param bytes - Byte array\n * @returns Lowercase hex string\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Compute SHA-256 hash of data and return as base64url string\n *\n * Used by Wire 0.2 DigestRef format. Evidence bundles use sha256Hex() with\n * \"sha256:<hex>\" prefix instead. A conversion bridge between the two formats\n * (hex <-> base64url) is provided by hexToBase64url() and base64urlToHex().\n *\n * @param data - Data to hash (Uint8Array or string)\n * @returns Base64url-encoded SHA-256 hash (43 characters)\n */\nexport async function sha256Base64url(data: Uint8Array | string): Promise<string> {\n const hashBytes = await sha256Bytes(data);\n return base64urlEncode(hashBytes);\n}\n\n/**\n * Convert a hex-encoded hash to base64url encoding\n *\n * Bridges evidence bundle format (sha256:<hex>) to Wire 0.2 DigestRef format\n * (base64url value). Strips the \"sha256:\" prefix if present.\n *\n * @param hex - Hex string, optionally prefixed with \"sha256:\"\n * @returns Base64url-encoded bytes (43 characters for SHA-256)\n */\nexport function hexToBase64url(hex: string): string {\n const cleanHex = hex.startsWith('sha256:') ? hex.slice(7) : hex;\n return base64urlEncode(hexToBytes(cleanHex));\n}\n\n/**\n * Convert a base64url-encoded hash to hex encoding\n *\n * Bridges Wire 0.2 DigestRef format (base64url) to evidence bundle format\n * (hex). Does NOT add the \"sha256:\" prefix -- caller adds it if needed.\n *\n * @param b64u - Base64url-encoded hash\n * @returns Lowercase hex string (64 characters for SHA-256)\n */\nexport function base64urlToHex(b64u: string): string {\n return bytesToHex(base64urlDecode(b64u));\n}\n\n/**\n * JWK structure for Ed25519 public keys (minimal required fields for thumbprint)\n */\nexport interface JWKThumbprintInput {\n /** Key type - must be \"OKP\" for Ed25519 */\n kty: string;\n /** Curve - must be \"Ed25519\" */\n crv: string;\n /** Public key (base64url) */\n x: string;\n}\n\n/**\n * Compute RFC 7638 JWK Thumbprint (base64url, SHA-256)\n *\n * For Ed25519 keys, the canonical JSON is: {\"crv\":\"Ed25519\",\"kty\":\"OKP\",\"x\":\"<base64url>\"}\n * Returns base64url-encoded SHA-256 hash (43 characters).\n *\n * @param jwk - JWK with kty, crv, x fields\n * @returns Base64url-encoded SHA-256 thumbprint (43 characters)\n */\nexport async function computeJwkThumbprint(jwk: JWKThumbprintInput): Promise<string> {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n throw new Error('Only Ed25519 keys (OKP/Ed25519) are supported for thumbprint computation');\n }\n\n // Canonical JSON per RFC 7638 (alphabetically sorted members, no whitespace)\n const canonical = JSON.stringify({\n crv: jwk.crv,\n kty: jwk.kty,\n x: jwk.x,\n });\n\n const hashBytes = await sha256Bytes(canonical);\n return base64urlEncode(hashBytes);\n}\n\n/**\n * Convert JWK to Ed25519 public key bytes (32 bytes)\n *\n * @param jwk - JWK with kty, crv, x fields\n * @returns Public key as 32-byte Uint8Array\n */\nexport function jwkToPublicKeyBytes(jwk: JWKThumbprintInput): Uint8Array {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n throw new Error('Only Ed25519 keys (OKP/Ed25519) are supported');\n }\n\n const xBytes = base64urlDecode(jwk.x);\n if (xBytes.length !== 32) {\n throw new Error(`Ed25519 public key must be 32 bytes, got ${xBytes.length}`);\n }\n\n return xBytes;\n}\n","/**\n * JSON Canonicalization Scheme (RFC 8785)\n * Deterministic JSON serialization for cryptographic hashing\n *\n * PROTOCOL DECISION: JavaScript `undefined` Handling\n * ===================================================\n *\n * RFC 8785 canonicalizes JSON values, and `undefined` is NOT a JSON value.\n * This implementation adopts \"JS-ergonomic\" semantics that match JSON.stringify:\n *\n * 1. **Object properties with undefined values are OMITTED**\n * - `canonicalize({a: 1, b: undefined})` -> `{\"a\":1}`\n * - Matches: `JSON.stringify({a: 1, b: undefined})` -> `{\"a\":1}`\n *\n * 2. **Array elements that are undefined become null**\n * - `canonicalize([1, undefined, 3])` -> `[1,null,3]`\n * - Matches: `JSON.stringify([1, undefined, 3])` -> `[1,null,3]`\n *\n * 3. **Top-level undefined THROWS**\n * - `canonicalize(undefined)` -> throws Error\n * - Rationale: No valid JSON representation exists\n *\n * CROSS-LANGUAGE INTEROPERABILITY WARNING:\n * =========================================\n * Cross-language producers MUST NOT rely on \"undefined\" semantics. To achieve\n * identical hashes across implementations, explicitly encode `null` in arrays\n * and omit keys in objects. Other language implementations (Go, Rust, Python)\n * will never produce `undefined` since it's JavaScript-specific.\n *\n * Guidelines:\n * - Producers MUST emit explicit `null` or omit keys; do NOT rely on coercion\n * - Verifiers SHOULD sanitize inputs before hashing (remove undefined properties)\n * - The canonical output is identical whether you pass `{a: undefined}` or `{}`\n *\n * This behavior is NORMATIVE for PEAC hashing and MUST NOT change without\n * a wire format version bump.\n */\n\n/**\n * Canonicalize a JSON value according to RFC 8785.\n *\n * @param obj - The value to canonicalize. Must be a valid JSON type (null, boolean,\n * number, string, array, object). Functions and Symbols throw.\n * @returns Canonical JSON string with sorted keys and no whitespace.\n * @throws Error if the value cannot be canonicalized (undefined at top level,\n * non-finite numbers, functions, symbols).\n *\n * @example\n * ```ts\n * canonicalize({ b: 2, a: 1 }) // '{\"a\":1,\"b\":2}'\n * canonicalize([1, null, \"x\"]) // '[1,null,\"x\"]'\n * ```\n */\nexport function canonicalize(obj: unknown): string {\n if (obj === null) {\n return 'null';\n }\n\n if (typeof obj === 'boolean') {\n return obj ? 'true' : 'false';\n }\n\n if (typeof obj === 'number') {\n // RFC 8785 number serialization (no trailing zeros, no exponential for small numbers)\n if (!Number.isFinite(obj)) {\n throw new Error('Cannot canonicalize non-finite number');\n }\n if (Object.is(obj, -0)) {\n return '0';\n }\n // Use JSON.stringify for proper number formatting per RFC 8785\n const str = JSON.stringify(obj);\n // Ensure no exponential notation for integers\n if (Number.isInteger(obj) && str.includes('e')) {\n return obj.toString();\n }\n return str;\n }\n\n if (typeof obj === 'string') {\n return JSON.stringify(obj);\n }\n\n if (Array.isArray(obj)) {\n // PROTOCOL DECISION: undefined in arrays becomes null (matches JSON.stringify)\n // See module-level documentation for cross-language interoperability notes.\n const elements = obj.map((el) => (el === undefined ? 'null' : canonicalize(el)));\n return `[${elements.join(',')}]`;\n }\n\n if (typeof obj === 'object') {\n // Sort keys lexicographically by UTF-16 code unit (RFC 8785 requirement)\n const keys = Object.keys(obj).sort();\n const pairs: string[] = [];\n for (const key of keys) {\n const value = (obj as Record<string, unknown>)[key];\n // PROTOCOL DECISION: Skip undefined values (matches JSON.stringify)\n // See module-level documentation for cross-language interoperability notes.\n if (value === undefined) {\n continue;\n }\n pairs.push(`${JSON.stringify(key)}:${canonicalize(value)}`);\n }\n return `{${pairs.join(',')}}`;\n }\n\n throw new Error(`Cannot canonicalize type: ${typeof obj}`);\n}\n\n/**\n * Canonicalize and encode as UTF-8 bytes\n */\nexport function canonicalizeBytes(obj: unknown): Uint8Array {\n const canonical = canonicalize(obj);\n return new TextEncoder().encode(canonical);\n}\n\n/**\n * Compute JCS+SHA-256 hash of an object\n */\nexport async function jcsHash(obj: unknown): Promise<string> {\n const bytes = canonicalizeBytes(obj);\n const hashBuffer = await crypto.subtle.digest('SHA-256', bytes);\n const hashArray = new Uint8Array(hashBuffer);\n return Array.from(hashArray)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n","/**\n * Internal Ed25519 wrapper -- async-only surface\n *\n * PEAC uses ONLY the async methods from @noble/ed25519.\n * In noble v3, sync methods require explicit hash configuration.\n * Async methods use built-in Web Crypto and need no configuration.\n *\n * This module re-exports only the async surface to prevent accidental\n * sync usage. All other modules in @peac/crypto MUST import from\n * this file, never directly from '@noble/ed25519'.\n *\n * Key material handling:\n * - Private keys are 32-byte Uint8Array (Ed25519 seed)\n * - Public keys are 32-byte Uint8Array (compressed Ed25519 point)\n * - JavaScript cannot guarantee memory zeroization; callers should\n * avoid storing keys longer than necessary and never log key bytes\n * - randomSecretKey() uses crypto.getRandomValues() (CSPRNG)\n * which is available in Node.js >=15 and all modern runtimes\n */\n\n// Namespace import avoids tsup tree-shaking false positive in multi-entry builds\n// where signAsync/verifyAsync appear unused in the testkit entry point.\nimport * as ed from '@noble/ed25519';\n\n/** Sign a message with Ed25519 (async, Web Crypto backed) */\nexport const sign = ed.signAsync;\n\n/** Verify an Ed25519 signature (async, Web Crypto backed) */\nexport const verify = ed.verifyAsync;\n\n/** Derive public key from private key (async, Web Crypto backed) */\nexport const getPublicKey = ed.getPublicKeyAsync;\n\n/** Generate a cryptographically random 32-byte secret key (CSPRNG) */\nexport const randomSecretKey = ed.utils.randomSecretKey;\n","/**\n * JWS compact serialization with Ed25519 (RFC 8032)\n * Dual-stack: Wire 0.1 (peac-receipt/0.1) and Wire 0.2 (interaction-record+jwt)\n */\n\nimport {\n sign as ed25519Sign,\n verify as ed25519Verify,\n getPublicKey,\n randomSecretKey,\n} from './ed25519.js';\nimport {\n WIRE_01_JWS_TYP,\n WIRE_02_JWS_TYP,\n WIRE_02_JWS_TYP_ACCEPT,\n PEAC_ALG,\n VERIFIER_LIMITS,\n} from '@peac/kernel';\nimport {\n base64urlEncode,\n base64urlDecode,\n base64urlEncodeString,\n base64urlDecodeString,\n} from './base64url';\nimport { CryptoError } from './errors';\n\n// ---------------------------------------------------------------------------\n// JWS header types: 3-variant discriminated union (Correction 1, DD-156)\n// ---------------------------------------------------------------------------\n\n/**\n * JWS header for Wire 0.1 receipts (typ: 'peac-receipt/0.1')\n */\nexport interface Wire01JWSHeader {\n typ: typeof WIRE_01_JWS_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * JWS header for Wire 0.2 receipts (typ: 'interaction-record+jwt', compact canonical form)\n *\n * The full media type 'application/interaction-record+jwt' is accepted by verify()\n * and decode() but normalized to this compact form before returning.\n */\nexport interface Wire02JWSHeader {\n typ: typeof WIRE_02_JWS_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * JWS header for tokens with no typ field\n *\n * Crypto layer passes these through without error.\n * The strictness decision (hard error vs. warning) belongs exclusively\n * in @peac/protocol.verifyLocal() (Correction 1, DD-156).\n */\nexport interface UnTypedJWSHeader {\n typ?: undefined;\n alg: typeof PEAC_ALG;\n kid: string;\n}\n\n/**\n * Discriminated union of all recognized JWS header variants.\n *\n * Callers narrow by checking `header.typ`:\n * if (header.typ === WIRE_02_JWS_TYP) { ... Wire 0.2 path ... }\n * if (header.typ === WIRE_01_JWS_TYP) { ... Wire 0.1 path ... }\n * if (header.typ === undefined) { ... UnTyped / interop path ... }\n */\nexport type JWSHeader = Wire01JWSHeader | Wire02JWSHeader | UnTypedJWSHeader;\n\n/**\n * Result of JWS verification\n */\nexport interface VerifyResult<T = unknown> {\n header: JWSHeader;\n payload: T;\n valid: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Internal constants (NOT exported)\n// ---------------------------------------------------------------------------\n\n/** All typ values accepted by verify() / decode(). Includes full media type form. */\nconst ACCEPTED_TYP_VALUES = new Set<string>([WIRE_01_JWS_TYP, ...WIRE_02_JWS_TYP_ACCEPT]);\n\n// ---------------------------------------------------------------------------\n// validateWire02Header (exported, JOSE hardening, Correction 9, DD-156)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate JOSE header fields for Wire 0.2 JOSE hardening requirements.\n *\n * Rejects:\n * - Embedded key material (jwk, x5c, x5u, jku)\n * - crit header (critical extensions)\n * - b64: false (RFC 7797 unencoded payload)\n * - zip header (payload compression)\n * - Missing, empty, or oversized kid (DoS safety: max 256 chars)\n *\n * @param header - Raw parsed JWS header object\n * @throws CryptoError with CRYPTO_JWS_* code on any violation\n */\nexport function validateWire02Header(header: Record<string, unknown>): void {\n // kid: required, non-empty, max 256 chars (Correction 9, DoS safety)\n if (\n !header.kid ||\n typeof header.kid !== 'string' ||\n header.kid.length === 0 ||\n header.kid.length > 256\n ) {\n throw new CryptoError(\n 'CRYPTO_JWS_MISSING_KID',\n 'kid is missing, empty, or exceeds 256 characters'\n );\n }\n\n // Embedded key material: hard reject (prevents key confusion attacks)\n if (\n header.jwk !== undefined ||\n header.x5c !== undefined ||\n header.x5u !== undefined ||\n header.jku !== undefined\n ) {\n throw new CryptoError(\n 'CRYPTO_JWS_EMBEDDED_KEY',\n 'embedded key material (jwk/x5c/x5u/jku) is not permitted'\n );\n }\n\n // crit: hard reject\n if (header.crit !== undefined) {\n throw new CryptoError('CRYPTO_JWS_CRIT_REJECTED', 'crit header is not permitted');\n }\n\n // b64: false: RFC 7797 unencoded payload rejected\n if (header.b64 === false) {\n throw new CryptoError(\n 'CRYPTO_JWS_B64_REJECTED',\n 'b64:false (unencoded payload) is not permitted'\n );\n }\n\n // zip: hard reject\n if (header.zip !== undefined) {\n throw new CryptoError('CRYPTO_JWS_ZIP_REJECTED', 'zip header is not permitted');\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helper: build typed JWSHeader from raw parsed object\n// ---------------------------------------------------------------------------\n\n/**\n * Build a typed JWSHeader from a raw parsed header object, applying typ\n * normalization (Correction 2, DD-156): 'application/interaction-record+jwt'\n * is normalized to 'interaction-record+jwt' before returning.\n *\n * @param raw - Raw header object from JSON.parse\n * @returns Typed JWSHeader\n * @throws CryptoError if alg is not PEAC_ALG, or if typ is present and not in ACCEPTED_TYP_VALUES\n */\nfunction buildHeader(raw: Record<string, unknown>): JWSHeader {\n // Validate alg (required)\n if (raw.alg !== PEAC_ALG) {\n throw new CryptoError(\n 'CRYPTO_INVALID_ALG',\n `Invalid alg: expected ${PEAC_ALG}, got ${String(raw.alg)}`\n );\n }\n\n const rawTyp = raw.typ as string | undefined;\n\n // Normalize full media type to compact form (Correction 2)\n const canonicalTyp = rawTyp === 'application/interaction-record+jwt' ? WIRE_02_JWS_TYP : rawTyp;\n\n if (canonicalTyp !== undefined && !ACCEPTED_TYP_VALUES.has(rawTyp!)) {\n throw new CryptoError('CRYPTO_INVALID_TYP', `Invalid typ: ${String(rawTyp)}`);\n }\n\n const kid = typeof raw.kid === 'string' ? raw.kid : '';\n\n if (canonicalTyp === WIRE_01_JWS_TYP) {\n return { typ: WIRE_01_JWS_TYP, alg: PEAC_ALG, kid } satisfies Wire01JWSHeader;\n }\n if (canonicalTyp === WIRE_02_JWS_TYP) {\n return { typ: WIRE_02_JWS_TYP, alg: PEAC_ALG, kid } satisfies Wire02JWSHeader;\n }\n\n // canonicalTyp is undefined: return UnTypedJWSHeader\n return { typ: undefined, alg: PEAC_ALG, kid } satisfies UnTypedJWSHeader;\n}\n\n// ---------------------------------------------------------------------------\n// sign (Wire 0.1)\n// ---------------------------------------------------------------------------\n\n/**\n * Sign a payload with Ed25519 and return JWS compact serialization (Wire 0.1)\n *\n * Always sets typ to WIRE_01_JWS_TYP ('peac-receipt/0.1').\n * For Wire 0.2, use signWire02() instead.\n *\n * @param payload - JSON-serializable payload\n * @param privateKey - Ed25519 private key (32 bytes)\n * @param kid - Key ID (ISO 8601 timestamp)\n * @returns JWS compact serialization (header.payload.signature)\n */\nexport async function sign(payload: unknown, privateKey: Uint8Array, kid: string): Promise<string> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n\n const header: Wire01JWSHeader = {\n typ: WIRE_01_JWS_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const signatureBytes = await ed25519Sign(signingInputBytes, privateKey);\n const signatureB64 = base64urlEncode(signatureBytes);\n\n return `${signingInput}.${signatureB64}`;\n}\n\n// ---------------------------------------------------------------------------\n// signWire02 (Wire 0.2)\n// ---------------------------------------------------------------------------\n\n/**\n * Sign a Wire 0.2 payload with Ed25519 and return JWS compact serialization\n *\n * Always sets typ to WIRE_02_JWS_TYP ('interaction-record+jwt').\n * The payload MUST include peac_version: '0.2'.\n *\n * @param payload - JSON-serializable Wire 0.2 claims payload\n * @param privateKey - Ed25519 private key (32 bytes)\n * @param kid - Key ID (max 256 chars per JOSE hardening rules)\n * @returns JWS compact serialization (header.payload.signature)\n */\nexport async function signWire02(\n payload: unknown,\n privateKey: Uint8Array,\n kid: string\n): Promise<string> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n\n // Validate kid length (Correction 9, DoS safety)\n if (!kid || kid.length === 0 || kid.length > 256) {\n throw new CryptoError(\n 'CRYPTO_JWS_MISSING_KID',\n 'kid is missing, empty, or exceeds 256 characters'\n );\n }\n\n // Always set typ: WIRE_02_JWS_TYP: no code path may omit it\n const header: Wire02JWSHeader = {\n typ: WIRE_02_JWS_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const signatureBytes = await ed25519Sign(signingInputBytes, privateKey);\n const signatureB64 = base64urlEncode(signatureBytes);\n\n return `${signingInput}.${signatureB64}`;\n}\n\n// ---------------------------------------------------------------------------\n// verify (dual-stack)\n// ---------------------------------------------------------------------------\n\n/**\n * Verify a JWS compact serialization with Ed25519\n *\n * Dual-stack: accepts Wire 0.1 (peac-receipt/0.1) and Wire 0.2\n * (interaction-record+jwt or application/interaction-record+jwt).\n *\n * Typ normalization (Correction 2): 'application/interaction-record+jwt' is\n * normalized to 'interaction-record+jwt' in the returned header.\n *\n * UnTypedJWSHeader (Correction 1): tokens with no typ are returned with\n * typ: undefined without error; @peac/protocol.verifyLocal() applies strictness.\n *\n * Coherence check:\n * - typ === WIRE_02_JWS_TYP but payload.peac_version !== '0.2': CRYPTO_WIRE_VERSION_MISMATCH\n * - typ === WIRE_01_JWS_TYP but payload.peac_version === '0.2': CRYPTO_WIRE_VERSION_MISMATCH\n * - typ absent: no coherence check here; verifyLocal() handles it\n *\n * @param jws - JWS compact serialization\n * @param publicKey - Ed25519 public key (32 bytes)\n * @returns Verification result with typed header and decoded payload\n */\nexport async function verify<T = unknown>(\n jws: string,\n publicKey: Uint8Array\n): Promise<VerifyResult<T>> {\n if (publicKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 public key must be 32 bytes');\n }\n\n // Fast-reject oversized tokens before any parsing (DoS safety).\n // Uses VERIFIER_LIMITS.maxReceiptBytes (256 KB) as the upper bound.\n if (jws.length > VERIFIER_LIMITS.maxReceiptBytes) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n `JWS exceeds maximum size of ${VERIFIER_LIMITS.maxReceiptBytes} bytes`\n );\n }\n\n const parts = jws.split('.');\n if (parts.length !== 3) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n 'Invalid JWS: must have three dot-separated parts'\n );\n }\n\n const [headerB64, payloadB64, signatureB64] = parts;\n\n // Decode and build typed header.\n // Wrap in try/catch to translate SyntaxError / decode failures into stable\n // CryptoError codes; callers depend on CRYPTO_INVALID_JWS_FORMAT for error\n // classification and must never receive a raw SyntaxError at the boundary.\n let rawHeader: Record<string, unknown>;\n try {\n rawHeader = JSON.parse(base64urlDecodeString(headerB64)) as Record<string, unknown>;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS header: invalid base64url or JSON');\n }\n const header = buildHeader(rawHeader);\n\n // Apply JOSE hardening for Wire 0.2 and UnTyped tokens (Correction 1, DD-156).\n // JOSE security invariants (embedded key material, crit, b64:false, zip) MUST be\n // enforced regardless of whether typ is present. Interop mode controls routing only;\n // it does not exempt tokens from key-injection or unencoded-payload attacks.\n // Wire 0.1 tokens are excluded: the legacy format predates these constraints.\n if (header.typ === WIRE_02_JWS_TYP || header.typ === undefined) {\n validateWire02Header(rawHeader);\n }\n\n // Decode payload; same stable-error contract as header decode above.\n let payload: T;\n try {\n payload = JSON.parse(base64urlDecodeString(payloadB64)) as T;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS payload: invalid base64url or JSON');\n }\n\n // Coherence check: wire version consistency (only when typ is present)\n if (header.typ !== undefined) {\n const payloadVersion = (payload as Record<string, unknown>).peac_version;\n if (header.typ === WIRE_02_JWS_TYP && payloadVersion !== '0.2') {\n throw new CryptoError(\n 'CRYPTO_WIRE_VERSION_MISMATCH',\n `typ is ${WIRE_02_JWS_TYP} but peac_version is ${String(payloadVersion)} (expected '0.2')`\n );\n }\n if (header.typ === WIRE_01_JWS_TYP && payloadVersion === '0.2') {\n throw new CryptoError(\n 'CRYPTO_WIRE_VERSION_MISMATCH',\n `typ is ${WIRE_01_JWS_TYP} but peac_version is '0.2' (Wire 0.2 must use ${WIRE_02_JWS_TYP})`\n );\n }\n }\n\n // Verify Ed25519 signature\n const signatureBytes = base64urlDecode(signatureB64);\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n const valid = await ed25519Verify(signatureBytes, signingInputBytes, publicKey);\n\n return { header, payload, valid };\n}\n\n// ---------------------------------------------------------------------------\n// decode (dual-stack, unverified)\n// ---------------------------------------------------------------------------\n\n/**\n * Decode JWS without verifying signature\n *\n * UNSAFE: This function is for debugging and diagnostic inspection only.\n * It does NOT verify the Ed25519 signature and does NOT apply JOSE hardening\n * (embedded-key rejection, b64/zip/crit checks). Tokens returned by decode()\n * must never be trusted for authorization decisions.\n *\n * For secure verification use verify() instead.\n *\n * Applies the same typ normalization and header typing as verify().\n * Unrecognized typ values still throw CryptoError.\n *\n * @param jws - JWS compact serialization\n * @returns Decoded header and payload (unverified, no JOSE hardening applied)\n */\nexport function decode<T = unknown>(jws: string): { header: JWSHeader; payload: T } {\n const parts = jws.split('.');\n if (parts.length !== 3) {\n throw new CryptoError(\n 'CRYPTO_INVALID_JWS_FORMAT',\n 'Invalid JWS: must have three dot-separated parts'\n );\n }\n\n const [headerB64, payloadB64] = parts;\n\n let rawHeader: Record<string, unknown>;\n try {\n rawHeader = JSON.parse(base64urlDecodeString(headerB64)) as Record<string, unknown>;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS header: invalid base64url or JSON');\n }\n const header = buildHeader(rawHeader);\n\n let payload: T;\n try {\n payload = JSON.parse(base64urlDecodeString(payloadB64)) as T;\n } catch {\n throw new CryptoError('CRYPTO_INVALID_JWS_FORMAT', 'JWS payload: invalid base64url or JSON');\n }\n\n return { header, payload };\n}\n\n// ---------------------------------------------------------------------------\n// generateKeypair\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a random Ed25519 keypair\n *\n * @returns Private key (32 bytes) and public key (32 bytes)\n */\nexport async function generateKeypair(): Promise<{\n privateKey: Uint8Array;\n publicKey: Uint8Array;\n}> {\n const privateKey = randomSecretKey();\n const publicKey = await getPublicKey(privateKey);\n\n return { privateKey, publicKey };\n}\n\n// NOTE: generateKeypairFromSeed has been moved to @peac/crypto/testkit\n// It's intentionally NOT exported from the main module to prevent accidental\n// use in production. Use: import { generateKeypairFromSeed } from '@peac/crypto/testkit'\n\n// ---------------------------------------------------------------------------\n// Ed25519 JWK utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Ed25519 JWK interface for private keys\n */\nexport interface Ed25519PrivateJwk {\n kty: 'OKP';\n crv: 'Ed25519';\n /** Public key (base64url encoded, 32 bytes) */\n x: string;\n /** Private key (base64url encoded, 32 bytes) */\n d: string;\n}\n\n/**\n * Derive the Ed25519 public key from a private key\n *\n * @param privateKey - Ed25519 private key (32 bytes)\n * @returns Public key (32 bytes)\n */\nexport async function derivePublicKey(privateKey: Uint8Array): Promise<Uint8Array> {\n if (privateKey.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_KEY_LENGTH', 'Ed25519 private key must be 32 bytes');\n }\n return getPublicKey(privateKey);\n}\n\n/**\n * Validate that an Ed25519 JWK has a consistent keypair\n *\n * Derives the public key from the private key (d) and verifies it matches\n * the declared public key (x). This catches configuration errors where\n * the wrong key components are paired.\n *\n * @param jwk - Ed25519 JWK with both public (x) and private (d) components\n * @returns true if the keypair is consistent, false otherwise\n *\n * @example\n * ```typescript\n * const jwk = {\n * kty: 'OKP',\n * crv: 'Ed25519',\n * x: 'base64url-encoded-public-key',\n * d: 'base64url-encoded-private-key',\n * };\n *\n * if (!await validateKeypair(jwk)) {\n * throw new Error('Invalid keypair: d does not derive to x');\n * }\n * ```\n */\nexport async function validateKeypair(jwk: Ed25519PrivateJwk): Promise<boolean> {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n return false;\n }\n\n let privateKeyBytes: Uint8Array;\n let declaredPublicKeyBytes: Uint8Array;\n\n try {\n privateKeyBytes = base64urlDecode(jwk.d);\n declaredPublicKeyBytes = base64urlDecode(jwk.x);\n } catch {\n return false;\n }\n\n if (privateKeyBytes.length !== 32 || declaredPublicKeyBytes.length !== 32) {\n return false;\n }\n\n const derivedPublicKeyBytes = await getPublicKey(privateKeyBytes);\n\n if (derivedPublicKeyBytes.length !== declaredPublicKeyBytes.length) {\n return false;\n }\n\n for (let i = 0; i < derivedPublicKeyBytes.length; i++) {\n if (derivedPublicKeyBytes[i] !== declaredPublicKeyBytes[i]) {\n return false;\n }\n }\n\n return true;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peac/crypto",
|
|
3
|
-
"version": "0.12.0-preview.
|
|
3
|
+
"version": "0.12.0-preview.2",
|
|
4
4
|
"description": "Ed25519 JWS signing and verification for PEAC protocol",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@noble/ed25519": "^3.0.0",
|
|
41
|
-
"@peac/kernel": "0.12.0-preview.
|
|
41
|
+
"@peac/kernel": "0.12.0-preview.2"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^22.19.11",
|