@peac/crypto 0.10.10 → 0.10.12

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.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Internal Ed25519 wrapper -- async-only surface
3
+ *
4
+ * PEAC uses ONLY the async methods from @noble/ed25519.
5
+ * In noble v3, sync methods require explicit hash configuration.
6
+ * Async methods use built-in Web Crypto and need no configuration.
7
+ *
8
+ * This module re-exports only the async surface to prevent accidental
9
+ * sync usage. All other modules in @peac/crypto MUST import from
10
+ * this file, never directly from '@noble/ed25519'.
11
+ *
12
+ * Key material handling:
13
+ * - Private keys are 32-byte Uint8Array (Ed25519 seed)
14
+ * - Public keys are 32-byte Uint8Array (compressed Ed25519 point)
15
+ * - JavaScript cannot guarantee memory zeroization; callers should
16
+ * avoid storing keys longer than necessary and never log key bytes
17
+ * - randomSecretKey() uses crypto.getRandomValues() (CSPRNG)
18
+ * which is available in Node.js >=15 and all modern runtimes
19
+ */
20
+ /** Sign a message with Ed25519 (async, Web Crypto backed) */
21
+ export declare const sign: (message: import("@noble/ed25519").Bytes, secretKey: import("@noble/ed25519").Bytes) => Promise<import("@noble/ed25519").Bytes>;
22
+ /** Verify an Ed25519 signature (async, Web Crypto backed) */
23
+ export declare const verify: (signature: import("@noble/ed25519").Bytes, message: import("@noble/ed25519").Bytes, publicKey: import("@noble/ed25519").Bytes, opts?: import("@noble/ed25519").EdDSAVerifyOpts) => Promise<boolean>;
24
+ /** Derive public key from private key (async, Web Crypto backed) */
25
+ export declare const getPublicKey: (secretKey: import("@noble/ed25519").Bytes) => Promise<import("@noble/ed25519").Bytes>;
26
+ /** Generate a cryptographically random 32-byte secret key (CSPRNG) */
27
+ export declare const randomSecretKey: (seed?: import("@noble/ed25519").Bytes) => import("@noble/ed25519").Bytes;
28
+ //# sourceMappingURL=ed25519.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ed25519.d.ts","sourceRoot":"","sources":["../src/ed25519.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,6DAA6D;AAC7D,eAAO,MAAM,IAAI,iIAAY,CAAC;AAE9B,6DAA6D;AAC7D,eAAO,MAAM,MAAM,sMAAc,CAAC;AAElC,oEAAoE;AACpE,eAAO,MAAM,YAAY,wFAAoB,CAAC;AAE9C,sEAAsE;AACtE,eAAO,MAAM,eAAe,2EAAwB,CAAC"}
package/dist/index.cjs CHANGED
@@ -3,26 +3,6 @@
3
3
  var ed25519 = require('@noble/ed25519');
4
4
  var schema = require('@peac/schema');
5
5
 
6
- function _interopNamespace(e) {
7
- if (e && e.__esModule) return e;
8
- var n = Object.create(null);
9
- if (e) {
10
- Object.keys(e).forEach(function (k) {
11
- if (k !== 'default') {
12
- var d = Object.getOwnPropertyDescriptor(e, k);
13
- Object.defineProperty(n, k, d.get ? d : {
14
- enumerable: true,
15
- get: function () { return e[k]; }
16
- });
17
- }
18
- });
19
- }
20
- n.default = e;
21
- return Object.freeze(n);
22
- }
23
-
24
- var ed25519__namespace = /*#__PURE__*/_interopNamespace(ed25519);
25
-
26
6
  // src/base64url.ts
27
7
  var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
28
8
  var base64Lookup = null;
@@ -229,7 +209,11 @@ async function jcsHash(obj) {
229
209
  const hashArray = new Uint8Array(hashBuffer);
230
210
  return Array.from(hashArray).map((b) => b.toString(16).padStart(2, "0")).join("");
231
211
  }
232
- async function sign(payload, privateKey, kid) {
212
+ var sign = ed25519.signAsync;
213
+ var verify = ed25519.verifyAsync;
214
+ var getPublicKey = ed25519.getPublicKeyAsync;
215
+ var randomSecretKey = ed25519.utils.randomSecretKey;
216
+ async function sign2(payload, privateKey, kid) {
233
217
  if (privateKey.length !== 32) {
234
218
  throw new CryptoError("CRYPTO_INVALID_KEY_LENGTH", "Ed25519 private key must be 32 bytes");
235
219
  }
@@ -242,11 +226,11 @@ async function sign(payload, privateKey, kid) {
242
226
  const payloadB64 = base64urlEncodeString(JSON.stringify(payload));
243
227
  const signingInput = `${headerB64}.${payloadB64}`;
244
228
  const signingInputBytes = new TextEncoder().encode(signingInput);
245
- const signatureBytes = await ed25519__namespace.signAsync(signingInputBytes, privateKey);
229
+ const signatureBytes = await sign(signingInputBytes, privateKey);
246
230
  const signatureB64 = base64urlEncode(signatureBytes);
247
231
  return `${signingInput}.${signatureB64}`;
248
232
  }
249
- async function verify(jws, publicKey) {
233
+ async function verify2(jws, publicKey) {
250
234
  if (publicKey.length !== 32) {
251
235
  throw new CryptoError("CRYPTO_INVALID_KEY_LENGTH", "Ed25519 public key must be 32 bytes");
252
236
  }
@@ -277,7 +261,7 @@ async function verify(jws, publicKey) {
277
261
  const signatureBytes = base64urlDecode(signatureB64);
278
262
  const signingInput = `${headerB64}.${payloadB64}`;
279
263
  const signingInputBytes = new TextEncoder().encode(signingInput);
280
- const valid = await ed25519__namespace.verifyAsync(signatureBytes, signingInputBytes, publicKey);
264
+ const valid = await verify(signatureBytes, signingInputBytes, publicKey);
281
265
  return {
282
266
  header,
283
267
  payload,
@@ -300,15 +284,15 @@ function decode(jws) {
300
284
  return { header, payload };
301
285
  }
302
286
  async function generateKeypair() {
303
- const privateKey = ed25519__namespace.utils.randomPrivateKey();
304
- const publicKey = await ed25519__namespace.getPublicKeyAsync(privateKey);
287
+ const privateKey = randomSecretKey();
288
+ const publicKey = await getPublicKey(privateKey);
305
289
  return { privateKey, publicKey };
306
290
  }
307
291
  async function derivePublicKey(privateKey) {
308
292
  if (privateKey.length !== 32) {
309
293
  throw new CryptoError("CRYPTO_INVALID_KEY_LENGTH", "Ed25519 private key must be 32 bytes");
310
294
  }
311
- return ed25519__namespace.getPublicKeyAsync(privateKey);
295
+ return getPublicKey(privateKey);
312
296
  }
313
297
  async function validateKeypair(jwk) {
314
298
  if (jwk.kty !== "OKP" || jwk.crv !== "Ed25519") {
@@ -325,7 +309,7 @@ async function validateKeypair(jwk) {
325
309
  if (privateKeyBytes.length !== 32 || declaredPublicKeyBytes.length !== 32) {
326
310
  return false;
327
311
  }
328
- const derivedPublicKeyBytes = await ed25519__namespace.getPublicKeyAsync(privateKeyBytes);
312
+ const derivedPublicKeyBytes = await getPublicKey(privateKeyBytes);
329
313
  if (derivedPublicKeyBytes.length !== declaredPublicKeyBytes.length) {
330
314
  return false;
331
315
  }
@@ -358,8 +342,8 @@ exports.jwkToPublicKeyBytes = jwkToPublicKeyBytes;
358
342
  exports.sha256Base64url = sha256Base64url;
359
343
  exports.sha256Bytes = sha256Bytes;
360
344
  exports.sha256Hex = sha256Hex;
361
- exports.sign = sign;
345
+ exports.sign = sign2;
362
346
  exports.validateKeypair = validateKeypair;
363
- exports.verify = verify;
347
+ exports.verify = verify2;
364
348
  //# sourceMappingURL=index.cjs.map
365
349
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/base64url.ts","../src/errors.ts","../src/hash.ts","../src/jcs.ts","../src/jws.ts"],"names":["PEAC_WIRE_TYP","PEAC_ALG","ed25519"],"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\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 * JWS compact serialization with Ed25519 (RFC 8032)\n * Implements peac-receipt/0.1 wire format\n */\n\nimport * as ed25519 from '@noble/ed25519';\nimport { PEAC_WIRE_TYP, PEAC_ALG } from '@peac/schema';\nimport {\n base64urlEncode,\n base64urlDecode,\n base64urlEncodeString,\n base64urlDecodeString,\n} from './base64url';\nimport { CryptoError } from './errors';\n\n/**\n * JWS header for PEAC receipts\n */\nexport interface JWSHeader {\n typ: typeof PEAC_WIRE_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\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 * Sign a payload with Ed25519 and return JWS compact serialization\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 // Create header\n const header: JWSHeader = {\n typ: PEAC_WIRE_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n // Encode header and payload\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n // Create signing input\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n // Sign with Ed25519\n const signatureBytes = await ed25519.signAsync(signingInputBytes, privateKey);\n\n // Encode signature\n const signatureB64 = base64urlEncode(signatureBytes);\n\n // Return JWS compact serialization\n return `${signingInput}.${signatureB64}`;\n}\n\n/**\n * Verify a JWS compact serialization with Ed25519\n *\n * @param jws - JWS compact serialization\n * @param publicKey - Ed25519 public key (32 bytes)\n * @returns Verification result with decoded header and 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 // Split JWS\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 header\n const headerJson = base64urlDecodeString(headerB64);\n const header = JSON.parse(headerJson) as JWSHeader;\n\n // Validate header\n if (header.typ !== PEAC_WIRE_TYP) {\n throw new CryptoError(\n 'CRYPTO_INVALID_TYP',\n `Invalid typ: expected ${PEAC_WIRE_TYP}, got ${header.typ}`\n );\n }\n if (header.alg !== PEAC_ALG) {\n throw new CryptoError(\n 'CRYPTO_INVALID_ALG',\n `Invalid alg: expected ${PEAC_ALG}, got ${header.alg}`\n );\n }\n\n // Decode payload\n const payloadJson = base64urlDecodeString(payloadB64);\n const payload = JSON.parse(payloadJson) as T;\n\n // Decode signature\n const signatureBytes = base64urlDecode(signatureB64);\n\n // Verify signature\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const valid = await ed25519.verifyAsync(signatureBytes, signingInputBytes, publicKey);\n\n return {\n header,\n payload,\n valid,\n };\n}\n\n/**\n * Decode JWS without verifying signature (use with caution!)\n *\n * @param jws - JWS compact serialization\n * @returns Decoded header and payload (unverified)\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 const headerJson = base64urlDecodeString(headerB64);\n const header = JSON.parse(headerJson) as JWSHeader;\n\n const payloadJson = base64urlDecodeString(payloadB64);\n const payload = JSON.parse(payloadJson) as T;\n\n return { header, payload };\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 = ed25519.utils.randomPrivateKey();\n const publicKey = await ed25519.getPublicKeyAsync(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 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 ed25519.getPublicKeyAsync(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 // Validate JWK structure\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n return false;\n }\n\n // Decode the keys\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 // Validate lengths\n if (privateKeyBytes.length !== 32 || declaredPublicKeyBytes.length !== 32) {\n return false;\n }\n\n // Derive the actual public key from the private key\n const derivedPublicKeyBytes = await ed25519.getPublicKeyAsync(privateKeyBytes);\n\n // Compare derived public key with declared public key\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":["signAsync","verifyAsync","getPublicKeyAsync","utils","sign","PEAC_WIRE_TYP","PEAC_ALG","verify"],"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\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\nimport { signAsync, verifyAsync, getPublicKeyAsync, utils } from '@noble/ed25519';\n\n/** Sign a message with Ed25519 (async, Web Crypto backed) */\nexport const sign = signAsync;\n\n/** Verify an Ed25519 signature (async, Web Crypto backed) */\nexport const verify = verifyAsync;\n\n/** Derive public key from private key (async, Web Crypto backed) */\nexport const getPublicKey = getPublicKeyAsync;\n\n/** Generate a cryptographically random 32-byte secret key (CSPRNG) */\nexport const randomSecretKey = utils.randomSecretKey;\n","/**\n * JWS compact serialization with Ed25519 (RFC 8032)\n * Implements peac-receipt/0.1 wire format\n */\n\nimport {\n sign as ed25519Sign,\n verify as ed25519Verify,\n getPublicKey,\n randomSecretKey,\n} from './ed25519.js';\nimport { PEAC_WIRE_TYP, PEAC_ALG } from '@peac/schema';\nimport {\n base64urlEncode,\n base64urlDecode,\n base64urlEncodeString,\n base64urlDecodeString,\n} from './base64url';\nimport { CryptoError } from './errors';\n\n/**\n * JWS header for PEAC receipts\n */\nexport interface JWSHeader {\n typ: typeof PEAC_WIRE_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\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 * Sign a payload with Ed25519 and return JWS compact serialization\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 // Create header\n const header: JWSHeader = {\n typ: PEAC_WIRE_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n // Encode header and payload\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n // Create signing input\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n // Sign with Ed25519\n const signatureBytes = await ed25519Sign(signingInputBytes, privateKey);\n\n // Encode signature\n const signatureB64 = base64urlEncode(signatureBytes);\n\n // Return JWS compact serialization\n return `${signingInput}.${signatureB64}`;\n}\n\n/**\n * Verify a JWS compact serialization with Ed25519\n *\n * @param jws - JWS compact serialization\n * @param publicKey - Ed25519 public key (32 bytes)\n * @returns Verification result with decoded header and 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 // Split JWS\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 header\n const headerJson = base64urlDecodeString(headerB64);\n const header = JSON.parse(headerJson) as JWSHeader;\n\n // Validate header\n if (header.typ !== PEAC_WIRE_TYP) {\n throw new CryptoError(\n 'CRYPTO_INVALID_TYP',\n `Invalid typ: expected ${PEAC_WIRE_TYP}, got ${header.typ}`\n );\n }\n if (header.alg !== PEAC_ALG) {\n throw new CryptoError(\n 'CRYPTO_INVALID_ALG',\n `Invalid alg: expected ${PEAC_ALG}, got ${header.alg}`\n );\n }\n\n // Decode payload\n const payloadJson = base64urlDecodeString(payloadB64);\n const payload = JSON.parse(payloadJson) as T;\n\n // Decode signature\n const signatureBytes = base64urlDecode(signatureB64);\n\n // Verify signature\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const valid = await ed25519Verify(signatureBytes, signingInputBytes, publicKey);\n\n return {\n header,\n payload,\n valid,\n };\n}\n\n/**\n * Decode JWS without verifying signature (use with caution!)\n *\n * @param jws - JWS compact serialization\n * @returns Decoded header and payload (unverified)\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 const headerJson = base64urlDecodeString(headerB64);\n const header = JSON.parse(headerJson) as JWSHeader;\n\n const payloadJson = base64urlDecodeString(payloadB64);\n const payload = JSON.parse(payloadJson) as T;\n\n return { header, payload };\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 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 // Validate JWK structure\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n return false;\n }\n\n // Decode the keys\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 // Validate lengths\n if (privateKeyBytes.length !== 32 || declaredPublicKeyBytes.length !== 32) {\n return false;\n }\n\n // Derive the actual public key from the private key\n const derivedPublicKeyBytes = await getPublicKey(privateKeyBytes);\n\n // Compare derived public key with declared public key\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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import * as ed25519 from '@noble/ed25519';
1
+ import { utils, signAsync, verifyAsync, getPublicKeyAsync } from '@noble/ed25519';
2
2
  import { PEAC_ALG, PEAC_WIRE_TYP } from '@peac/schema';
3
3
 
4
4
  // src/base64url.ts
@@ -207,7 +207,11 @@ async function jcsHash(obj) {
207
207
  const hashArray = new Uint8Array(hashBuffer);
208
208
  return Array.from(hashArray).map((b) => b.toString(16).padStart(2, "0")).join("");
209
209
  }
210
- async function sign(payload, privateKey, kid) {
210
+ var sign = signAsync;
211
+ var verify = verifyAsync;
212
+ var getPublicKey = getPublicKeyAsync;
213
+ var randomSecretKey = utils.randomSecretKey;
214
+ async function sign2(payload, privateKey, kid) {
211
215
  if (privateKey.length !== 32) {
212
216
  throw new CryptoError("CRYPTO_INVALID_KEY_LENGTH", "Ed25519 private key must be 32 bytes");
213
217
  }
@@ -220,11 +224,11 @@ async function sign(payload, privateKey, kid) {
220
224
  const payloadB64 = base64urlEncodeString(JSON.stringify(payload));
221
225
  const signingInput = `${headerB64}.${payloadB64}`;
222
226
  const signingInputBytes = new TextEncoder().encode(signingInput);
223
- const signatureBytes = await ed25519.signAsync(signingInputBytes, privateKey);
227
+ const signatureBytes = await sign(signingInputBytes, privateKey);
224
228
  const signatureB64 = base64urlEncode(signatureBytes);
225
229
  return `${signingInput}.${signatureB64}`;
226
230
  }
227
- async function verify(jws, publicKey) {
231
+ async function verify2(jws, publicKey) {
228
232
  if (publicKey.length !== 32) {
229
233
  throw new CryptoError("CRYPTO_INVALID_KEY_LENGTH", "Ed25519 public key must be 32 bytes");
230
234
  }
@@ -255,7 +259,7 @@ async function verify(jws, publicKey) {
255
259
  const signatureBytes = base64urlDecode(signatureB64);
256
260
  const signingInput = `${headerB64}.${payloadB64}`;
257
261
  const signingInputBytes = new TextEncoder().encode(signingInput);
258
- const valid = await ed25519.verifyAsync(signatureBytes, signingInputBytes, publicKey);
262
+ const valid = await verify(signatureBytes, signingInputBytes, publicKey);
259
263
  return {
260
264
  header,
261
265
  payload,
@@ -278,15 +282,15 @@ function decode(jws) {
278
282
  return { header, payload };
279
283
  }
280
284
  async function generateKeypair() {
281
- const privateKey = ed25519.utils.randomPrivateKey();
282
- const publicKey = await ed25519.getPublicKeyAsync(privateKey);
285
+ const privateKey = randomSecretKey();
286
+ const publicKey = await getPublicKey(privateKey);
283
287
  return { privateKey, publicKey };
284
288
  }
285
289
  async function derivePublicKey(privateKey) {
286
290
  if (privateKey.length !== 32) {
287
291
  throw new CryptoError("CRYPTO_INVALID_KEY_LENGTH", "Ed25519 private key must be 32 bytes");
288
292
  }
289
- return ed25519.getPublicKeyAsync(privateKey);
293
+ return getPublicKey(privateKey);
290
294
  }
291
295
  async function validateKeypair(jwk) {
292
296
  if (jwk.kty !== "OKP" || jwk.crv !== "Ed25519") {
@@ -303,7 +307,7 @@ async function validateKeypair(jwk) {
303
307
  if (privateKeyBytes.length !== 32 || declaredPublicKeyBytes.length !== 32) {
304
308
  return false;
305
309
  }
306
- const derivedPublicKeyBytes = await ed25519.getPublicKeyAsync(privateKeyBytes);
310
+ const derivedPublicKeyBytes = await getPublicKey(privateKeyBytes);
307
311
  if (derivedPublicKeyBytes.length !== declaredPublicKeyBytes.length) {
308
312
  return false;
309
313
  }
@@ -315,6 +319,6 @@ async function validateKeypair(jwk) {
315
319
  return true;
316
320
  }
317
321
 
318
- export { CryptoError, base64urlDecode, base64urlDecodeString, base64urlEncode, base64urlEncodeString, base64urlToHex, bytesToHex, canonicalize, canonicalizeBytes, computeJwkThumbprint, decode, derivePublicKey, generateKeypair, hexToBase64url, hexToBytes, isFormatError, jcsHash, jwkToPublicKeyBytes, sha256Base64url, sha256Bytes, sha256Hex, sign, validateKeypair, verify };
322
+ 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, validateKeypair, verify2 as verify };
319
323
  //# sourceMappingURL=index.mjs.map
320
324
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/base64url.ts","../src/errors.ts","../src/hash.ts","../src/jcs.ts","../src/jws.ts"],"names":[],"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\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 * JWS compact serialization with Ed25519 (RFC 8032)\n * Implements peac-receipt/0.1 wire format\n */\n\nimport * as ed25519 from '@noble/ed25519';\nimport { PEAC_WIRE_TYP, PEAC_ALG } from '@peac/schema';\nimport {\n base64urlEncode,\n base64urlDecode,\n base64urlEncodeString,\n base64urlDecodeString,\n} from './base64url';\nimport { CryptoError } from './errors';\n\n/**\n * JWS header for PEAC receipts\n */\nexport interface JWSHeader {\n typ: typeof PEAC_WIRE_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\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 * Sign a payload with Ed25519 and return JWS compact serialization\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 // Create header\n const header: JWSHeader = {\n typ: PEAC_WIRE_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n // Encode header and payload\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n // Create signing input\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n // Sign with Ed25519\n const signatureBytes = await ed25519.signAsync(signingInputBytes, privateKey);\n\n // Encode signature\n const signatureB64 = base64urlEncode(signatureBytes);\n\n // Return JWS compact serialization\n return `${signingInput}.${signatureB64}`;\n}\n\n/**\n * Verify a JWS compact serialization with Ed25519\n *\n * @param jws - JWS compact serialization\n * @param publicKey - Ed25519 public key (32 bytes)\n * @returns Verification result with decoded header and 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 // Split JWS\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 header\n const headerJson = base64urlDecodeString(headerB64);\n const header = JSON.parse(headerJson) as JWSHeader;\n\n // Validate header\n if (header.typ !== PEAC_WIRE_TYP) {\n throw new CryptoError(\n 'CRYPTO_INVALID_TYP',\n `Invalid typ: expected ${PEAC_WIRE_TYP}, got ${header.typ}`\n );\n }\n if (header.alg !== PEAC_ALG) {\n throw new CryptoError(\n 'CRYPTO_INVALID_ALG',\n `Invalid alg: expected ${PEAC_ALG}, got ${header.alg}`\n );\n }\n\n // Decode payload\n const payloadJson = base64urlDecodeString(payloadB64);\n const payload = JSON.parse(payloadJson) as T;\n\n // Decode signature\n const signatureBytes = base64urlDecode(signatureB64);\n\n // Verify signature\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const valid = await ed25519.verifyAsync(signatureBytes, signingInputBytes, publicKey);\n\n return {\n header,\n payload,\n valid,\n };\n}\n\n/**\n * Decode JWS without verifying signature (use with caution!)\n *\n * @param jws - JWS compact serialization\n * @returns Decoded header and payload (unverified)\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 const headerJson = base64urlDecodeString(headerB64);\n const header = JSON.parse(headerJson) as JWSHeader;\n\n const payloadJson = base64urlDecodeString(payloadB64);\n const payload = JSON.parse(payloadJson) as T;\n\n return { header, payload };\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 = ed25519.utils.randomPrivateKey();\n const publicKey = await ed25519.getPublicKeyAsync(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 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 ed25519.getPublicKeyAsync(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 // Validate JWK structure\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n return false;\n }\n\n // Decode the keys\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 // Validate lengths\n if (privateKeyBytes.length !== 32 || declaredPublicKeyBytes.length !== 32) {\n return false;\n }\n\n // Derive the actual public key from the private key\n const derivedPublicKeyBytes = await ed25519.getPublicKeyAsync(privateKeyBytes);\n\n // Compare derived public key with declared public key\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\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\nimport { signAsync, verifyAsync, getPublicKeyAsync, utils } from '@noble/ed25519';\n\n/** Sign a message with Ed25519 (async, Web Crypto backed) */\nexport const sign = signAsync;\n\n/** Verify an Ed25519 signature (async, Web Crypto backed) */\nexport const verify = verifyAsync;\n\n/** Derive public key from private key (async, Web Crypto backed) */\nexport const getPublicKey = getPublicKeyAsync;\n\n/** Generate a cryptographically random 32-byte secret key (CSPRNG) */\nexport const randomSecretKey = utils.randomSecretKey;\n","/**\n * JWS compact serialization with Ed25519 (RFC 8032)\n * Implements peac-receipt/0.1 wire format\n */\n\nimport {\n sign as ed25519Sign,\n verify as ed25519Verify,\n getPublicKey,\n randomSecretKey,\n} from './ed25519.js';\nimport { PEAC_WIRE_TYP, PEAC_ALG } from '@peac/schema';\nimport {\n base64urlEncode,\n base64urlDecode,\n base64urlEncodeString,\n base64urlDecodeString,\n} from './base64url';\nimport { CryptoError } from './errors';\n\n/**\n * JWS header for PEAC receipts\n */\nexport interface JWSHeader {\n typ: typeof PEAC_WIRE_TYP;\n alg: typeof PEAC_ALG;\n kid: string;\n}\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 * Sign a payload with Ed25519 and return JWS compact serialization\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 // Create header\n const header: JWSHeader = {\n typ: PEAC_WIRE_TYP,\n alg: PEAC_ALG,\n kid,\n };\n\n // Encode header and payload\n const headerB64 = base64urlEncodeString(JSON.stringify(header));\n const payloadB64 = base64urlEncodeString(JSON.stringify(payload));\n\n // Create signing input\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n // Sign with Ed25519\n const signatureBytes = await ed25519Sign(signingInputBytes, privateKey);\n\n // Encode signature\n const signatureB64 = base64urlEncode(signatureBytes);\n\n // Return JWS compact serialization\n return `${signingInput}.${signatureB64}`;\n}\n\n/**\n * Verify a JWS compact serialization with Ed25519\n *\n * @param jws - JWS compact serialization\n * @param publicKey - Ed25519 public key (32 bytes)\n * @returns Verification result with decoded header and 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 // Split JWS\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 header\n const headerJson = base64urlDecodeString(headerB64);\n const header = JSON.parse(headerJson) as JWSHeader;\n\n // Validate header\n if (header.typ !== PEAC_WIRE_TYP) {\n throw new CryptoError(\n 'CRYPTO_INVALID_TYP',\n `Invalid typ: expected ${PEAC_WIRE_TYP}, got ${header.typ}`\n );\n }\n if (header.alg !== PEAC_ALG) {\n throw new CryptoError(\n 'CRYPTO_INVALID_ALG',\n `Invalid alg: expected ${PEAC_ALG}, got ${header.alg}`\n );\n }\n\n // Decode payload\n const payloadJson = base64urlDecodeString(payloadB64);\n const payload = JSON.parse(payloadJson) as T;\n\n // Decode signature\n const signatureBytes = base64urlDecode(signatureB64);\n\n // Verify signature\n const signingInput = `${headerB64}.${payloadB64}`;\n const signingInputBytes = new TextEncoder().encode(signingInput);\n\n const valid = await ed25519Verify(signatureBytes, signingInputBytes, publicKey);\n\n return {\n header,\n payload,\n valid,\n };\n}\n\n/**\n * Decode JWS without verifying signature (use with caution!)\n *\n * @param jws - JWS compact serialization\n * @returns Decoded header and payload (unverified)\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 const headerJson = base64urlDecodeString(headerB64);\n const header = JSON.parse(headerJson) as JWSHeader;\n\n const payloadJson = base64urlDecodeString(payloadB64);\n const payload = JSON.parse(payloadJson) as T;\n\n return { header, payload };\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 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 // Validate JWK structure\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {\n return false;\n }\n\n // Decode the keys\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 // Validate lengths\n if (privateKeyBytes.length !== 32 || declaredPublicKeyBytes.length !== 32) {\n return false;\n }\n\n // Derive the actual public key from the private key\n const derivedPublicKeyBytes = await getPublicKey(privateKeyBytes);\n\n // Compare derived public key with declared public key\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/jws.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"jws.d.ts","sourceRoot":"","sources":["../src/jws.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AASvD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,OAAO,aAAa,CAAC;IAC1B,GAAG,EAAE,OAAO,QAAQ,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BjG;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,CAAC,GAAG,OAAO,EACtC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAoD1B;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,CAAC,CAAA;CAAE,CAkBlF;AAED;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,UAAU,CAAC;CACvB,CAAC,CAKD;AAMD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,KAAK,CAAC;IACX,GAAG,EAAE,SAAS,CAAC;IACf,+CAA+C;IAC/C,CAAC,EAAE,MAAM,CAAC;IACV,gDAAgD;IAChD,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAKjF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAqC9E"}
1
+ {"version":3,"file":"jws.d.ts","sourceRoot":"","sources":["../src/jws.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AASvD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,OAAO,aAAa,CAAC;IAC1B,GAAG,EAAE,OAAO,QAAQ,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BjG;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,CAAC,GAAG,OAAO,EACtC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAoD1B;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,CAAC,CAAA;CAAE,CAkBlF;AAED;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,UAAU,CAAC;CACvB,CAAC,CAKD;AAMD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,KAAK,CAAC;IACX,GAAG,EAAE,SAAS,CAAC;IACf,+CAA+C;IAC/C,CAAC,EAAE,MAAM,CAAC;IACV,gDAAgD;IAChD,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAKjF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAqC9E"}
package/dist/testkit.cjs CHANGED
@@ -2,27 +2,9 @@
2
2
 
3
3
  var ed25519 = require('@noble/ed25519');
4
4
 
5
- function _interopNamespace(e) {
6
- if (e && e.__esModule) return e;
7
- var n = Object.create(null);
8
- if (e) {
9
- Object.keys(e).forEach(function (k) {
10
- if (k !== 'default') {
11
- var d = Object.getOwnPropertyDescriptor(e, k);
12
- Object.defineProperty(n, k, d.get ? d : {
13
- enumerable: true,
14
- get: function () { return e[k]; }
15
- });
16
- }
17
- });
18
- }
19
- n.default = e;
20
- return Object.freeze(n);
21
- }
22
-
23
- var ed25519__namespace = /*#__PURE__*/_interopNamespace(ed25519);
24
-
25
- // src/testkit.ts
5
+ // src/ed25519.ts
6
+ var getPublicKey = ed25519.getPublicKeyAsync;
7
+ ed25519.utils.randomSecretKey;
26
8
 
27
9
  // src/errors.ts
28
10
  var CryptoError = class _CryptoError extends Error {
@@ -41,7 +23,7 @@ async function generateKeypairFromSeed(seed) {
41
23
  throw new CryptoError("CRYPTO_INVALID_SEED_LENGTH", "Ed25519 seed must be 32 bytes");
42
24
  }
43
25
  const privateKey = seed;
44
- const publicKey = await ed25519__namespace.getPublicKeyAsync(privateKey);
26
+ const publicKey = await getPublicKey(privateKey);
45
27
  return { privateKey, publicKey };
46
28
  }
47
29
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/testkit.ts"],"names":["ed25519"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BO,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,CAAA;;;ACHA,eAAsB,wBAAwB,IAAA,EAG3C;AACD,EAAA,IAAI,IAAA,CAAK,WAAW,EAAA,EAAI;AACtB,IAAA,MAAM,IAAI,WAAA,CAAY,4BAAA,EAA8B,+BAA+B,CAAA;AAAA,EACrF;AAIA,EAAA,MAAM,UAAA,GAAa,IAAA;AACnB,EAAA,MAAM,SAAA,GAAY,MAAcA,kBAAA,CAAA,iBAAA,CAAkB,UAAU,CAAA;AAE5D,EAAA,OAAO,EAAE,YAAY,SAAA,EAAU;AACjC","file":"testkit.cjs","sourcesContent":["/**\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\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 * PEAC Crypto Test Kit\n *\n * This module contains utilities for TEST FIXTURES ONLY.\n * These functions are NOT exported from the main entry point.\n *\n * Import path: @peac/crypto/testkit\n *\n * SECURITY: Never use these in production. Production bundlers can\n * tree-shake this module away since it's a separate export path.\n */\n\nimport * as ed25519 from '@noble/ed25519';\nimport { CryptoError } from './errors.js';\n\n/**\n * Generate an Ed25519 keypair from a deterministic seed.\n *\n * WARNING: FOR TEST FIXTURES ONLY. DO NOT USE IN PRODUCTION.\n * Production code should use generateKeypair() which uses cryptographically\n * secure random bytes. Seeded keys are predictable and compromise security.\n *\n * This function is intentionally in a separate module (@peac/crypto/testkit)\n * so that production bundlers can tree-shake it away.\n *\n * @param seed - 32-byte seed (e.g., SHA-256 hash of a known string)\n * @returns Private key (32 bytes) and public key (32 bytes)\n *\n * @example\n * ```ts\n * // Use only in test fixtures for reproducibility\n * import { generateKeypairFromSeed } from '@peac/crypto/testkit';\n *\n * const seed = sha256('peac-test-key-001');\n * const { privateKey, publicKey } = await generateKeypairFromSeed(seed);\n * ```\n */\nexport async function generateKeypairFromSeed(seed: Uint8Array): Promise<{\n privateKey: Uint8Array;\n publicKey: Uint8Array;\n}> {\n if (seed.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_SEED_LENGTH', 'Ed25519 seed must be 32 bytes');\n }\n\n // In Ed25519, the private key IS the seed (32 bytes)\n // The public key is derived from it\n const privateKey = seed;\n const publicKey = await ed25519.getPublicKeyAsync(privateKey);\n\n return { privateKey, publicKey };\n}\n"]}
1
+ {"version":3,"sources":["../src/ed25519.ts","../src/errors.ts","../src/testkit.ts"],"names":["getPublicKeyAsync","utils"],"mappings":";;;;;AA6BO,IAAM,YAAA,GAAeA,yBAAA;AAGGC,aAAA,CAAM;;;ACF9B,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,CAAA;;;ACHA,eAAsB,wBAAwB,IAAA,EAG3C;AACD,EAAA,IAAI,IAAA,CAAK,WAAW,EAAA,EAAI;AACtB,IAAA,MAAM,IAAI,WAAA,CAAY,4BAAA,EAA8B,+BAA+B,CAAA;AAAA,EACrF;AAIA,EAAA,MAAM,UAAA,GAAa,IAAA;AACnB,EAAA,MAAM,SAAA,GAAY,MAAM,YAAA,CAAa,UAAU,CAAA;AAE/C,EAAA,OAAO,EAAE,YAAY,SAAA,EAAU;AACjC","file":"testkit.cjs","sourcesContent":["/**\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\nimport { signAsync, verifyAsync, getPublicKeyAsync, utils } from '@noble/ed25519';\n\n/** Sign a message with Ed25519 (async, Web Crypto backed) */\nexport const sign = signAsync;\n\n/** Verify an Ed25519 signature (async, Web Crypto backed) */\nexport const verify = verifyAsync;\n\n/** Derive public key from private key (async, Web Crypto backed) */\nexport const getPublicKey = getPublicKeyAsync;\n\n/** Generate a cryptographically random 32-byte secret key (CSPRNG) */\nexport const randomSecretKey = utils.randomSecretKey;\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\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 * PEAC Crypto Test Kit\n *\n * This module contains utilities for TEST FIXTURES ONLY.\n * These functions are NOT exported from the main entry point.\n *\n * Import path: @peac/crypto/testkit\n *\n * SECURITY: Never use these in production. Production bundlers can\n * tree-shake this module away since it's a separate export path.\n */\n\nimport { getPublicKey } from './ed25519.js';\nimport { CryptoError } from './errors.js';\n\n/**\n * Generate an Ed25519 keypair from a deterministic seed.\n *\n * WARNING: FOR TEST FIXTURES ONLY. DO NOT USE IN PRODUCTION.\n * Production code should use generateKeypair() which uses cryptographically\n * secure random bytes. Seeded keys are predictable and compromise security.\n *\n * This function is intentionally in a separate module (@peac/crypto/testkit)\n * so that production bundlers can tree-shake it away.\n *\n * @param seed - 32-byte seed (e.g., SHA-256 hash of a known string)\n * @returns Private key (32 bytes) and public key (32 bytes)\n *\n * @example\n * ```ts\n * // Use only in test fixtures for reproducibility\n * import { generateKeypairFromSeed } from '@peac/crypto/testkit';\n *\n * const seed = sha256('peac-test-key-001');\n * const { privateKey, publicKey } = await generateKeypairFromSeed(seed);\n * ```\n */\nexport async function generateKeypairFromSeed(seed: Uint8Array): Promise<{\n privateKey: Uint8Array;\n publicKey: Uint8Array;\n}> {\n if (seed.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_SEED_LENGTH', 'Ed25519 seed must be 32 bytes');\n }\n\n // In Ed25519, the private key IS the seed (32 bytes)\n // The public key is derived from it\n const privateKey = seed;\n const publicKey = await getPublicKey(privateKey);\n\n return { privateKey, publicKey };\n}\n"]}
package/dist/testkit.mjs CHANGED
@@ -1,6 +1,8 @@
1
- import * as ed25519 from '@noble/ed25519';
1
+ import { utils, getPublicKeyAsync } from '@noble/ed25519';
2
2
 
3
- // src/testkit.ts
3
+ // src/ed25519.ts
4
+ var getPublicKey = getPublicKeyAsync;
5
+ utils.randomSecretKey;
4
6
 
5
7
  // src/errors.ts
6
8
  var CryptoError = class _CryptoError extends Error {
@@ -19,7 +21,7 @@ async function generateKeypairFromSeed(seed) {
19
21
  throw new CryptoError("CRYPTO_INVALID_SEED_LENGTH", "Ed25519 seed must be 32 bytes");
20
22
  }
21
23
  const privateKey = seed;
22
- const publicKey = await ed25519.getPublicKeyAsync(privateKey);
24
+ const publicKey = await getPublicKey(privateKey);
23
25
  return { privateKey, publicKey };
24
26
  }
25
27
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/testkit.ts"],"names":[],"mappings":";;;;;AA8BO,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,CAAA;;;ACHA,eAAsB,wBAAwB,IAAA,EAG3C;AACD,EAAA,IAAI,IAAA,CAAK,WAAW,EAAA,EAAI;AACtB,IAAA,MAAM,IAAI,WAAA,CAAY,4BAAA,EAA8B,+BAA+B,CAAA;AAAA,EACrF;AAIA,EAAA,MAAM,UAAA,GAAa,IAAA;AACnB,EAAA,MAAM,SAAA,GAAY,MAAc,OAAA,CAAA,iBAAA,CAAkB,UAAU,CAAA;AAE5D,EAAA,OAAO,EAAE,YAAY,SAAA,EAAU;AACjC","file":"testkit.mjs","sourcesContent":["/**\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\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 * PEAC Crypto Test Kit\n *\n * This module contains utilities for TEST FIXTURES ONLY.\n * These functions are NOT exported from the main entry point.\n *\n * Import path: @peac/crypto/testkit\n *\n * SECURITY: Never use these in production. Production bundlers can\n * tree-shake this module away since it's a separate export path.\n */\n\nimport * as ed25519 from '@noble/ed25519';\nimport { CryptoError } from './errors.js';\n\n/**\n * Generate an Ed25519 keypair from a deterministic seed.\n *\n * WARNING: FOR TEST FIXTURES ONLY. DO NOT USE IN PRODUCTION.\n * Production code should use generateKeypair() which uses cryptographically\n * secure random bytes. Seeded keys are predictable and compromise security.\n *\n * This function is intentionally in a separate module (@peac/crypto/testkit)\n * so that production bundlers can tree-shake it away.\n *\n * @param seed - 32-byte seed (e.g., SHA-256 hash of a known string)\n * @returns Private key (32 bytes) and public key (32 bytes)\n *\n * @example\n * ```ts\n * // Use only in test fixtures for reproducibility\n * import { generateKeypairFromSeed } from '@peac/crypto/testkit';\n *\n * const seed = sha256('peac-test-key-001');\n * const { privateKey, publicKey } = await generateKeypairFromSeed(seed);\n * ```\n */\nexport async function generateKeypairFromSeed(seed: Uint8Array): Promise<{\n privateKey: Uint8Array;\n publicKey: Uint8Array;\n}> {\n if (seed.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_SEED_LENGTH', 'Ed25519 seed must be 32 bytes');\n }\n\n // In Ed25519, the private key IS the seed (32 bytes)\n // The public key is derived from it\n const privateKey = seed;\n const publicKey = await ed25519.getPublicKeyAsync(privateKey);\n\n return { privateKey, publicKey };\n}\n"]}
1
+ {"version":3,"sources":["../src/ed25519.ts","../src/errors.ts","../src/testkit.ts"],"names":[],"mappings":";;;AA6BO,IAAM,YAAA,GAAe,iBAAA;AAGG,KAAA,CAAM;;;ACF9B,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,CAAA;;;ACHA,eAAsB,wBAAwB,IAAA,EAG3C;AACD,EAAA,IAAI,IAAA,CAAK,WAAW,EAAA,EAAI;AACtB,IAAA,MAAM,IAAI,WAAA,CAAY,4BAAA,EAA8B,+BAA+B,CAAA;AAAA,EACrF;AAIA,EAAA,MAAM,UAAA,GAAa,IAAA;AACnB,EAAA,MAAM,SAAA,GAAY,MAAM,YAAA,CAAa,UAAU,CAAA;AAE/C,EAAA,OAAO,EAAE,YAAY,SAAA,EAAU;AACjC","file":"testkit.mjs","sourcesContent":["/**\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\nimport { signAsync, verifyAsync, getPublicKeyAsync, utils } from '@noble/ed25519';\n\n/** Sign a message with Ed25519 (async, Web Crypto backed) */\nexport const sign = signAsync;\n\n/** Verify an Ed25519 signature (async, Web Crypto backed) */\nexport const verify = verifyAsync;\n\n/** Derive public key from private key (async, Web Crypto backed) */\nexport const getPublicKey = getPublicKeyAsync;\n\n/** Generate a cryptographically random 32-byte secret key (CSPRNG) */\nexport const randomSecretKey = utils.randomSecretKey;\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\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 * PEAC Crypto Test Kit\n *\n * This module contains utilities for TEST FIXTURES ONLY.\n * These functions are NOT exported from the main entry point.\n *\n * Import path: @peac/crypto/testkit\n *\n * SECURITY: Never use these in production. Production bundlers can\n * tree-shake this module away since it's a separate export path.\n */\n\nimport { getPublicKey } from './ed25519.js';\nimport { CryptoError } from './errors.js';\n\n/**\n * Generate an Ed25519 keypair from a deterministic seed.\n *\n * WARNING: FOR TEST FIXTURES ONLY. DO NOT USE IN PRODUCTION.\n * Production code should use generateKeypair() which uses cryptographically\n * secure random bytes. Seeded keys are predictable and compromise security.\n *\n * This function is intentionally in a separate module (@peac/crypto/testkit)\n * so that production bundlers can tree-shake it away.\n *\n * @param seed - 32-byte seed (e.g., SHA-256 hash of a known string)\n * @returns Private key (32 bytes) and public key (32 bytes)\n *\n * @example\n * ```ts\n * // Use only in test fixtures for reproducibility\n * import { generateKeypairFromSeed } from '@peac/crypto/testkit';\n *\n * const seed = sha256('peac-test-key-001');\n * const { privateKey, publicKey } = await generateKeypairFromSeed(seed);\n * ```\n */\nexport async function generateKeypairFromSeed(seed: Uint8Array): Promise<{\n privateKey: Uint8Array;\n publicKey: Uint8Array;\n}> {\n if (seed.length !== 32) {\n throw new CryptoError('CRYPTO_INVALID_SEED_LENGTH', 'Ed25519 seed must be 32 bytes');\n }\n\n // In Ed25519, the private key IS the seed (32 bytes)\n // The public key is derived from it\n const privateKey = seed;\n const publicKey = await getPublicKey(privateKey);\n\n return { privateKey, publicKey };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peac/crypto",
3
- "version": "0.10.10",
3
+ "version": "0.10.12",
4
4
  "description": "Ed25519 JWS signing and verification for PEAC protocol",
5
5
  "main": "dist/index.cjs",
6
6
  "types": "dist/index.d.ts",
@@ -37,14 +37,14 @@
37
37
  "access": "public"
38
38
  },
39
39
  "dependencies": {
40
- "@noble/ed25519": "^2.0.0",
41
- "@peac/schema": "0.10.10"
40
+ "@noble/ed25519": "^3.0.0",
41
+ "@peac/schema": "0.10.12"
42
42
  },
43
43
  "devDependencies": {
44
- "@types/node": "^20.10.0",
44
+ "@types/node": "^20.19.33",
45
+ "tsup": "^8.0.0",
45
46
  "typescript": "^5.3.3",
46
- "vitest": "^4.0.0",
47
- "tsup": "^8.0.0"
47
+ "vitest": "^4.0.0"
48
48
  },
49
49
  "scripts": {
50
50
  "prebuild": "rm -rf dist",