did-jwt
Version:
Library for Signing and Verifying JWTs that use DIDs as issuers and JWEs that use DIDs as recipients
1 lines • 152 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/util.ts","../src/Digest.ts","../src/signers/ES256KSigner.ts","../src/signers/SimpleSigner.ts","../src/signers/EllipticSigner.ts","../src/signers/EdDSASigner.ts","../src/signers/NaclSigner.ts","../src/signers/ES256Signer.ts","../src/SignerAlgorithm.ts","../src/blockchains/bip122.ts","../src/blockchains/cosmos.ts","../src/blockchains/index.ts","../src/VerifierAlgorithm.ts","../src/Errors.ts","../src/ConditionalAlgorithm.ts","../src/JWT.ts","../src/encryption/JWE.ts","../src/encryption/xc20pDir.ts","../src/encryption/X25519-ECDH-ES.ts","../src/encryption/X25519-ECDH-1PU.ts","../src/encryption/ECDH.ts","../src/encryption/createEncrypter.ts","../src/encryption/xc20pEncryption.ts"],"sourcesContent":["import { concat, fromString, toString } from 'uint8arrays'\nimport { x25519 } from '@noble/curves/ed25519'\nimport type { EphemeralKeyPair } from './encryption/types.js'\nimport { varint } from 'multiformats'\nimport { BaseName, decode, encode } from 'multibase'\nimport type { VerificationMethod } from 'did-resolver'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { p256 } from '@noble/curves/p256'\n\nconst u8a = { toString, fromString, concat }\n\n/**\n * @deprecated Signers will be expected to return base64url `string` signatures.\n */\nexport interface EcdsaSignature {\n r: string\n s: string\n recoveryParam?: number\n}\n\n/**\n * @deprecated Signers will be expected to return base64url `string` signatures.\n */\nexport type ECDSASignature = {\n compact: Uint8Array\n recovery?: number\n}\n\nexport type JsonWebKey = {\n crv: string\n kty: string\n x?: string\n y?: string\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any\n}\n\nexport function bytesToBase64url(b: Uint8Array): string {\n return u8a.toString(b, 'base64url')\n}\n\nexport function base64ToBytes(s: string): Uint8Array {\n const inputBase64Url = s.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n return u8a.fromString(inputBase64Url, 'base64url')\n}\n\nexport function bytesToBase64(b: Uint8Array): string {\n return u8a.toString(b, 'base64pad')\n}\n\nexport function base58ToBytes(s: string): Uint8Array {\n return u8a.fromString(s, 'base58btc')\n}\n\nexport function bytesToBase58(b: Uint8Array): string {\n return u8a.toString(b, 'base58btc')\n}\n\nexport type KNOWN_JWA = 'ES256' | 'ES256K' | 'ES256K-R' | 'Ed25519' | 'EdDSA'\n\nexport type KNOWN_VERIFICATION_METHOD =\n | 'JsonWebKey2020'\n | 'Multikey'\n | 'Secp256k1SignatureVerificationKey2018' // deprecated in favor of EcdsaSecp256k1VerificationKey2019\n | 'Secp256k1VerificationKey2018' // deprecated in favor of EcdsaSecp256k1VerificationKey2019\n | 'EcdsaSecp256k1VerificationKey2019' // ES256K / ES256K-R\n | 'EcdsaPublicKeySecp256k1' // deprecated in favor of EcdsaSecp256k1VerificationKey2019\n | 'EcdsaSecp256k1RecoveryMethod2020' // ES256K-R (ES256K also supported with 1 less bit of security)\n | 'EcdsaSecp256r1VerificationKey2019' // ES256 / P-256\n | 'Ed25519VerificationKey2018'\n | 'Ed25519VerificationKey2020'\n | 'ED25519SignatureVerification' // deprecated\n | 'ConditionalProof2022'\n | 'X25519KeyAgreementKey2019' // deprecated\n | 'X25519KeyAgreementKey2020'\n\nexport type KNOWN_KEY_TYPE = 'Secp256k1' | 'Ed25519' | 'X25519' | 'Bls12381G1' | 'Bls12381G2' | 'P-256'\n\nexport type PublicKeyTypes = Record<KNOWN_JWA, KNOWN_VERIFICATION_METHOD[]>\n\nexport const SUPPORTED_PUBLIC_KEY_TYPES: PublicKeyTypes = {\n ES256: ['JsonWebKey2020', 'Multikey', 'EcdsaSecp256r1VerificationKey2019'],\n ES256K: [\n 'EcdsaSecp256k1VerificationKey2019',\n /**\n * Equivalent to EcdsaSecp256k1VerificationKey2019 when key is an ethereumAddress\n */\n 'EcdsaSecp256k1RecoveryMethod2020',\n /**\n * @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is\n * not an ethereumAddress\n */\n 'Secp256k1VerificationKey2018',\n /**\n * @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is\n * not an ethereumAddress\n */\n 'Secp256k1SignatureVerificationKey2018',\n /**\n * @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is\n * not an ethereumAddress\n */\n 'EcdsaPublicKeySecp256k1',\n /**\n * TODO - support R1 key as well\n * 'ConditionalProof2022',\n */\n 'JsonWebKey2020',\n 'Multikey',\n ],\n 'ES256K-R': [\n 'EcdsaSecp256k1VerificationKey2019',\n /**\n * Equivalent to EcdsaSecp256k1VerificationKey2019 when key is an ethereumAddress\n */\n 'EcdsaSecp256k1RecoveryMethod2020',\n /**\n * @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is\n * not an ethereumAddress\n */\n 'Secp256k1VerificationKey2018',\n /**\n * @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is\n * not an ethereumAddress\n */\n 'Secp256k1SignatureVerificationKey2018',\n /**\n * @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is\n * not an ethereumAddress\n */\n 'EcdsaPublicKeySecp256k1',\n 'ConditionalProof2022',\n 'JsonWebKey2020',\n 'Multikey',\n ],\n Ed25519: [\n 'ED25519SignatureVerification',\n 'Ed25519VerificationKey2018',\n 'Ed25519VerificationKey2020',\n 'JsonWebKey2020',\n 'Multikey',\n ],\n EdDSA: [\n 'ED25519SignatureVerification',\n 'Ed25519VerificationKey2018',\n 'Ed25519VerificationKey2020',\n 'JsonWebKey2020',\n 'Multikey',\n ],\n}\n\nexport const VM_TO_KEY_TYPE: Record<KNOWN_VERIFICATION_METHOD, KNOWN_KEY_TYPE | undefined> = {\n Secp256k1SignatureVerificationKey2018: 'Secp256k1',\n Secp256k1VerificationKey2018: 'Secp256k1',\n EcdsaSecp256k1VerificationKey2019: 'Secp256k1',\n EcdsaPublicKeySecp256k1: 'Secp256k1',\n EcdsaSecp256k1RecoveryMethod2020: 'Secp256k1',\n EcdsaSecp256r1VerificationKey2019: 'P-256',\n Ed25519VerificationKey2018: 'Ed25519',\n Ed25519VerificationKey2020: 'Ed25519',\n ED25519SignatureVerification: 'Ed25519',\n X25519KeyAgreementKey2019: 'X25519',\n X25519KeyAgreementKey2020: 'X25519',\n ConditionalProof2022: undefined,\n JsonWebKey2020: undefined, // key type must be specified in the JWK\n Multikey: undefined, // key type must be extracted from the multicodec\n}\n\nexport type KNOWN_CODECS =\n | 'ed25519-pub'\n | 'x25519-pub'\n | 'secp256k1-pub'\n | 'bls12_381-g1-pub'\n | 'bls12_381-g2-pub'\n | 'p256-pub'\n\n// this is from the multicodec table https://github.com/multiformats/multicodec/blob/master/table.csv\nexport const supportedCodecs: Record<KNOWN_CODECS, number> = {\n 'ed25519-pub': 0xed,\n 'x25519-pub': 0xec,\n 'secp256k1-pub': 0xe7,\n 'bls12_381-g1-pub': 0xea,\n 'bls12_381-g2-pub': 0xeb,\n 'p256-pub': 0x1200,\n}\n\nexport const CODEC_TO_KEY_TYPE: Record<KNOWN_CODECS, KNOWN_KEY_TYPE> = {\n 'bls12_381-g1-pub': 'Bls12381G1',\n 'bls12_381-g2-pub': 'Bls12381G2',\n 'ed25519-pub': 'Ed25519',\n 'p256-pub': 'P-256',\n 'secp256k1-pub': 'Secp256k1',\n 'x25519-pub': 'X25519',\n}\n\n/**\n * Extracts the raw byte representation of a public key from a VerificationMethod along with an inferred key type\n * @param pk a VerificationMethod entry from a DIDDocument\n * @return an object containing the `keyBytes` of the public key and an inferred `keyType`\n */\nexport function extractPublicKeyBytes(pk: VerificationMethod): { keyBytes: Uint8Array; keyType?: KNOWN_KEY_TYPE } {\n if (pk.publicKeyBase58) {\n return {\n keyBytes: base58ToBytes(pk.publicKeyBase58),\n keyType: VM_TO_KEY_TYPE[pk.type as KNOWN_VERIFICATION_METHOD],\n }\n } else if (pk.publicKeyBase64) {\n return {\n keyBytes: base64ToBytes(pk.publicKeyBase64),\n keyType: VM_TO_KEY_TYPE[pk.type as KNOWN_VERIFICATION_METHOD],\n }\n } else if (pk.publicKeyHex) {\n return { keyBytes: hexToBytes(pk.publicKeyHex), keyType: VM_TO_KEY_TYPE[pk.type as KNOWN_VERIFICATION_METHOD] }\n } else if (pk.publicKeyJwk && pk.publicKeyJwk.crv === 'secp256k1' && pk.publicKeyJwk.x && pk.publicKeyJwk.y) {\n return {\n keyBytes: secp256k1.ProjectivePoint.fromAffine({\n x: bytesToBigInt(base64ToBytes(pk.publicKeyJwk.x)),\n y: bytesToBigInt(base64ToBytes(pk.publicKeyJwk.y)),\n }).toRawBytes(false),\n keyType: 'Secp256k1',\n }\n } else if (pk.publicKeyJwk && pk.publicKeyJwk.crv === 'P-256' && pk.publicKeyJwk.x && pk.publicKeyJwk.y) {\n return {\n keyBytes: p256.ProjectivePoint.fromAffine({\n x: bytesToBigInt(base64ToBytes(pk.publicKeyJwk.x)),\n y: bytesToBigInt(base64ToBytes(pk.publicKeyJwk.y)),\n }).toRawBytes(false),\n keyType: 'P-256',\n }\n } else if (\n pk.publicKeyJwk &&\n pk.publicKeyJwk.kty === 'OKP' &&\n ['Ed25519', 'X25519'].includes(pk.publicKeyJwk.crv ?? '') &&\n pk.publicKeyJwk.x\n ) {\n return { keyBytes: base64ToBytes(pk.publicKeyJwk.x), keyType: pk.publicKeyJwk.crv as KNOWN_KEY_TYPE }\n } else if (pk.publicKeyMultibase) {\n const { keyBytes, keyType } = multibaseToBytes(pk.publicKeyMultibase)\n return { keyBytes, keyType: keyType ?? VM_TO_KEY_TYPE[pk.type as KNOWN_VERIFICATION_METHOD] }\n }\n return { keyBytes: new Uint8Array() }\n}\n\n/**\n * Encodes the given byte array to a multibase string (defaulting to base58btc).\n * If a codec is provided, the corresponding multicodec prefix will be added.\n *\n * @param b - the Uint8Array to be encoded\n * @param base - the base to use for encoding (defaults to base58btc)\n * @param codec - the codec to use for encoding (defaults to no codec)\n *\n * @returns the multibase encoded string\n *\n * @public\n */\nexport function bytesToMultibase(\n b: Uint8Array,\n base: BaseName = 'base58btc',\n codec?: keyof typeof supportedCodecs | number\n): string {\n if (!codec) {\n return u8a.toString(encode(base, b), 'utf-8')\n } else {\n const codecCode = typeof codec === 'string' ? supportedCodecs[codec] : codec\n const prefixLength = varint.encodingLength(codecCode)\n const multicodecEncoding = new Uint8Array(prefixLength + b.length)\n varint.encodeTo(codecCode, multicodecEncoding) // set prefix\n multicodecEncoding.set(b, prefixLength) // add the original bytes\n return u8a.toString(encode(base, multicodecEncoding), 'utf-8')\n }\n}\n\n/**\n * Converts a multibase string to the Uint8Array it represents.\n * This method will assume the byte array that is multibase encoded is a multicodec and will attempt to decode it.\n *\n * @param s - the string to be converted\n *\n * @throws if the string is not formatted correctly.\n *\n * @public\n */\nexport function multibaseToBytes(s: string): { keyBytes: Uint8Array; keyType?: KNOWN_KEY_TYPE } {\n const bytes = decode(s)\n\n // look for known key lengths first\n // Ed25519/X25519, secp256k1/P256 compressed or not, BLS12-381 G1/G2 compressed\n if ([32, 33, 48, 64, 65, 96].includes(bytes.length)) {\n return { keyBytes: bytes }\n }\n\n // then assume multicodec, otherwise return the bytes\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const [codec, length] = varint.decode(bytes)\n const possibleCodec: string | undefined =\n Object.entries(supportedCodecs).filter(([, code]) => code === codec)?.[0][0] ?? ''\n return { keyBytes: bytes.slice(length), keyType: CODEC_TO_KEY_TYPE[possibleCodec as KNOWN_CODECS] }\n } catch (e) {\n // not a multicodec, return the bytes\n return { keyBytes: bytes }\n }\n}\n\nexport function hexToBytes(s: string, minLength?: number): Uint8Array {\n let input = s.startsWith('0x') ? s.substring(2) : s\n\n if (input.length % 2 !== 0) {\n input = `0${input}`\n }\n\n if (minLength) {\n const paddedLength = Math.max(input.length, minLength * 2)\n input = input.padStart(paddedLength, '00')\n }\n\n return u8a.fromString(input.toLowerCase(), 'base16')\n}\n\nexport function encodeBase64url(s: string): string {\n return bytesToBase64url(u8a.fromString(s))\n}\n\nexport function decodeBase64url(s: string): string {\n return u8a.toString(base64ToBytes(s))\n}\n\nexport function bytesToHex(b: Uint8Array): string {\n return u8a.toString(b, 'base16')\n}\n\nexport function bytesToBigInt(b: Uint8Array): bigint {\n return BigInt(`0x` + u8a.toString(b, 'base16'))\n}\n\nexport function bigintToBytes(n: bigint, minLength?: number): Uint8Array {\n return hexToBytes(n.toString(16), minLength)\n}\n\nexport function stringToBytes(s: string): Uint8Array {\n return u8a.fromString(s, 'utf-8')\n}\n\nexport function toJose({ r, s, recoveryParam }: EcdsaSignature, recoverable?: boolean): string {\n const jose = new Uint8Array(recoverable ? 65 : 64)\n jose.set(u8a.fromString(r, 'base16'), 0)\n jose.set(u8a.fromString(s, 'base16'), 32)\n if (recoverable) {\n if (typeof recoveryParam === 'undefined') {\n throw new Error('Signer did not return a recoveryParam')\n }\n jose[64] = <number>recoveryParam\n }\n return bytesToBase64url(jose)\n}\n\nexport function fromJose(signature: string): { r: string; s: string; recoveryParam?: number } {\n const signatureBytes: Uint8Array = base64ToBytes(signature)\n if (signatureBytes.length < 64 || signatureBytes.length > 65) {\n throw new TypeError(`Wrong size for signature. Expected 64 or 65 bytes, but got ${signatureBytes.length}`)\n }\n const r = bytesToHex(signatureBytes.slice(0, 32))\n const s = bytesToHex(signatureBytes.slice(32, 64))\n const recoveryParam = signatureBytes.length === 65 ? signatureBytes[64] : undefined\n return { r, s, recoveryParam }\n}\n\nexport function toSealed(ciphertext: string, tag?: string): Uint8Array {\n return u8a.concat([base64ToBytes(ciphertext), tag ? base64ToBytes(tag) : new Uint8Array(0)])\n}\n\nexport function leftpad(data: string, size = 64): string {\n if (data.length === size) return data\n return '0'.repeat(size - data.length) + data\n}\n\n/**\n * Generate random x25519 key pair.\n */\nexport function generateKeyPair(): { secretKey: Uint8Array; publicKey: Uint8Array } {\n const secretKey = x25519.utils.randomPrivateKey()\n const publicKey = x25519.getPublicKey(secretKey)\n return {\n secretKey: secretKey,\n publicKey: publicKey,\n }\n}\n\n/**\n * Generate private-public x25519 key pair from `seed`.\n */\nexport function generateKeyPairFromSeed(seed: Uint8Array): { secretKey: Uint8Array; publicKey: Uint8Array } {\n if (seed.length !== 32) {\n throw new Error(`x25519: seed must be ${32} bytes`)\n }\n return {\n publicKey: x25519.getPublicKey(seed),\n secretKey: seed,\n }\n}\n\nexport function genX25519EphemeralKeyPair(): EphemeralKeyPair {\n const epk = generateKeyPair()\n return {\n publicKeyJWK: { kty: 'OKP', crv: 'X25519', x: bytesToBase64url(epk.publicKey) },\n secretKey: epk.secretKey,\n }\n}\n\n/**\n * Checks if a variable is defined and not null.\n * After this check, typescript sees the variable as defined.\n *\n * @param arg - The input to be verified\n *\n * @returns true if the input variable is defined.\n */\nexport function isDefined<T>(arg: T): arg is Exclude<T, null | undefined> {\n return arg !== null && typeof arg !== 'undefined'\n}\n","import { sha256 as sha256Hash } from '@noble/hashes/sha256'\nexport { ripemd160 } from '@noble/hashes/ripemd160'\nimport { keccak_256 } from '@noble/hashes/sha3'\nimport { fromString, toString, concat } from 'uint8arrays'\n\nexport function sha256(payload: string | Uint8Array): Uint8Array {\n const data = typeof payload === 'string' ? fromString(payload) : payload\n return sha256Hash(data)\n}\n\nexport const keccak = keccak_256\n\nexport function toEthereumAddress(hexPublicKey: string): string {\n const hashInput = fromString(hexPublicKey.slice(2), 'base16')\n return `0x${toString(keccak(hashInput).slice(-20), 'base16')}`\n}\n\nfunction writeUint32BE(value: number, array = new Uint8Array(4)): Uint8Array {\n const encoded = fromString(value.toString(), 'base10')\n array.set(encoded, 4 - encoded.length)\n return array\n}\n\nconst lengthAndInput = (input: Uint8Array): Uint8Array => concat([writeUint32BE(input.length), input])\n\n// This implementation of concatKDF was inspired by these two implementations:\n// https://github.com/digitalbazaar/minimal-cipher/blob/master/algorithms/ecdhkdf.js\n// https://github.com/panva/jose/blob/master/lib/jwa/ecdh/derive.js\nexport function concatKDF(\n secret: Uint8Array,\n keyLen: number,\n alg: string,\n producerInfo?: Uint8Array,\n consumerInfo?: Uint8Array\n): Uint8Array {\n if (keyLen !== 256) throw new Error(`Unsupported key length: ${keyLen}`)\n const value = concat([\n lengthAndInput(fromString(alg)),\n lengthAndInput(typeof producerInfo === 'undefined' ? new Uint8Array(0) : producerInfo), // apu\n lengthAndInput(typeof consumerInfo === 'undefined' ? new Uint8Array(0) : consumerInfo), // apv\n writeUint32BE(keyLen),\n ])\n\n // since our key lenght is 256 we only have to do one round\n const roundNumber = 1\n return sha256(concat([writeUint32BE(roundNumber), secret, value]))\n}\n","import { leftpad, toJose } from '../util.js'\nimport { Signer } from '../JWT.js'\nimport { sha256 } from '../Digest.js'\nimport { secp256k1 } from '@noble/curves/secp256k1'\n\n/**\n * Creates a configured signer function for signing data using the ES256K (secp256k1 + sha256) algorithm.\n *\n * The signing function itself takes the data as a `Uint8Array` or `string` and returns a `base64Url`-encoded signature\n *\n * @example\n * ```typescript\n * const sign: Signer = ES256KSigner(process.env.PRIVATE_KEY)\n * const signature: string = await sign(data)\n * ```\n *\n * @param {String} privateKey a private key as `Uint8Array`\n * @param {Boolean} recoverable an optional flag to add the recovery param to the generated signatures\n * @return {Function} a configured signer function `(data: string | Uint8Array): Promise<string>`\n */\nexport function ES256KSigner(privateKey: Uint8Array, recoverable = false): Signer {\n const privateKeyBytes: Uint8Array = privateKey\n if (privateKeyBytes.length !== 32) {\n throw new Error(`bad_key: Invalid private key format. Expecting 32 bytes, but got ${privateKeyBytes.length}`)\n }\n\n return async (data: string | Uint8Array): Promise<string> => {\n const signature = secp256k1.sign(sha256(data), privateKeyBytes)\n return toJose(\n {\n r: leftpad(signature.r.toString(16)),\n s: leftpad(signature.s.toString(16)),\n recoveryParam: signature.recovery,\n },\n recoverable\n )\n }\n}\n","import { fromJose, hexToBytes } from '../util.js'\nimport type { Signer } from '../JWT.js'\nimport { ES256KSigner } from './ES256KSigner.js'\n\n/**\n * @deprecated Please use ES256KSigner\n * The SimpleSigner returns a configured function for signing data.\n *\n * @example\n * const signer = SimpleSigner(process.env.PRIVATE_KEY)\n * signer(data, (err, signature) => {\n * ...\n * })\n *\n * @param {String} hexPrivateKey a hex encoded private key\n * @return {Function} a configured signer function\n */\nfunction SimpleSigner(hexPrivateKey: string): Signer {\n const signer = ES256KSigner(hexToBytes(hexPrivateKey), true)\n return async (data) => {\n const signature = (await signer(data)) as string\n return fromJose(signature)\n }\n}\n\nexport default SimpleSigner\n","import type { Signer } from '../JWT.js'\nimport { hexToBytes } from '../util.js'\nimport { ES256KSigner } from './ES256KSigner.js'\n\n/**\n * @deprecated Please use ES256KSigner\n * The EllipticSigner returns a configured function for signing data.\n *\n * @example\n * ```typescript\n * const signer = EllipticSigner(process.env.PRIVATE_KEY)\n * signer(data).then( (signature: string) => {\n * ...\n * })\n * ```\n *\n * @param {String} hexPrivateKey a hex encoded private key\n * @return {Function} a configured signer function\n */\nfunction EllipticSigner(hexPrivateKey: string): Signer {\n return ES256KSigner(hexToBytes(hexPrivateKey))\n}\n\nexport default EllipticSigner\n","import { ed25519 } from '@noble/curves/ed25519'\nimport type { Signer } from '../JWT.js'\nimport { bytesToBase64url, stringToBytes } from '../util.js'\n\n/**\n * Creates a configured signer function for signing data using the EdDSA (Ed25519) algorithm.\n *\n * The private key is expected to be a `Uint8Array` of 32 bytes, but for compatibility 64 bytes are also acceptable.\n * Users of `@stablelib/ed25519` or `tweetnacl` will be able to use the 64 byte secret keys that library generates.\n * These libraries precompute the public key and append it as the last 32 bytes of the secretKey, to speed up later\n * signing operations.\n *\n * The signing function itself takes the data as a `Uint8Array` or utf8 `string` and returns a `base64Url`-encoded\n * signature\n *\n * @example\n * ```typescript\n * const sign: Signer = EdDSASigner(process.env.PRIVATE_KEY)\n * const signature: string = await sign(data)\n * ```\n *\n * @param {String} secretKey a 32 or 64 byte secret key as `Uint8Array`\n * @return {Function} a configured signer function `(data: string | Uint8Array): Promise<string>`\n */\nexport function EdDSASigner(secretKey: Uint8Array): Signer {\n const privateKeyBytes: Uint8Array = secretKey\n if (![32, 64].includes(privateKeyBytes.length)) {\n throw new Error(`bad_key: Invalid private key format. Expecting 32 or 64 bytes, but got ${privateKeyBytes.length}`)\n }\n return async (data: string | Uint8Array): Promise<string> => {\n const dataBytes: Uint8Array = typeof data === 'string' ? stringToBytes(data) : data\n const signature = ed25519.sign(dataBytes, privateKeyBytes.slice(0, 32))\n return bytesToBase64url(signature)\n }\n}\n","import { EdDSASigner as EdDSASigner } from './EdDSASigner.js'\nimport type { Signer } from '../JWT.js'\nimport { base64ToBytes } from '../util.js'\n\n/**\n * @deprecated Please use EdDSASigner\n *\n * The NaclSigner returns a configured function for signing data using the Ed25519 algorithm.\n *\n * The signing function itself takes the data as a `string` or `Uint8Array` parameter and returns a\n * `base64Url`-encoded signature.\n *\n * @example\n * const signer = NaclSigner(process.env.PRIVATE_KEY)\n * const data: string = '...'\n * signer(data).then( (signature: string) => {\n * ...\n * })\n *\n * @param {String} base64PrivateKey a 64 byte base64 encoded private key\n * @return {Function} a configured signer function\n */\n\nfunction NaclSigner(base64PrivateKey: string): Signer {\n return EdDSASigner(base64ToBytes(base64PrivateKey))\n}\n\nexport default NaclSigner\n","import { leftpad, toJose } from '../util.js'\nimport { Signer } from '../JWT.js'\nimport { sha256 } from '../Digest.js'\nimport { p256 } from '@noble/curves/p256'\n\n/**\n * Creates a configured signer function for signing data using the ES256 (secp256r1 + sha256) algorithm.\n *\n * The signing function itself takes the data as a `Uint8Array` or `string` and returns a `base64Url`-encoded signature\n *\n * @example\n * ```typescript\n * const sign: Signer = ES256Signer(process.env.PRIVATE_KEY)\n * const signature: string = await sign(data)\n * ```\n *\n * @param {String} privateKey a private key as `Uint8Array`\n * @return {Function} a configured signer function `(data: string | Uint8Array): Promise<string>`\n */\nexport function ES256Signer(privateKey: Uint8Array): Signer {\n if (privateKey.length !== 32) {\n throw new Error(`bad_key: Invalid private key format. Expecting 32 bytes, but got ${privateKey.length}`)\n }\n return async (data: string | Uint8Array): Promise<string> => {\n const signature = p256.sign(sha256(data), privateKey)\n return toJose({\n r: leftpad(signature.r.toString(16)),\n s: leftpad(signature.s.toString(16)),\n })\n }\n}\n","import type { Signer, SignerAlgorithm } from './JWT.js'\nimport { type EcdsaSignature, fromJose, toJose } from './util.js'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction instanceOfEcdsaSignature(object: any): object is EcdsaSignature {\n return typeof object === 'object' && 'r' in object && 's' in object\n}\n\nexport function ES256SignerAlg(): SignerAlgorithm {\n return async function sign(payload: string, signer: Signer): Promise<string> {\n const signature: EcdsaSignature | string = await signer(payload)\n if (instanceOfEcdsaSignature(signature)) {\n return toJose(signature)\n } else {\n return signature\n }\n }\n}\n\nexport function ES256KSignerAlg(recoverable?: boolean): SignerAlgorithm {\n return async function sign(payload: string, signer: Signer): Promise<string> {\n const signature: EcdsaSignature | string = await signer(payload)\n if (instanceOfEcdsaSignature(signature)) {\n return toJose(signature, recoverable)\n } else {\n if (recoverable && typeof fromJose(signature).recoveryParam === 'undefined') {\n throw new Error(`not_supported: ES256K-R not supported when signer doesn't provide a recovery param`)\n }\n return signature\n }\n }\n}\n\nexport function Ed25519SignerAlg(): SignerAlgorithm {\n return async function sign(payload: string, signer: Signer): Promise<string> {\n const signature: EcdsaSignature | string = await signer(payload)\n if (!instanceOfEcdsaSignature(signature)) {\n return signature\n } else {\n throw new Error('invalid_config: expected a signer function that returns a string instead of signature object')\n }\n }\n}\n\ninterface SignerAlgorithms {\n [alg: string]: SignerAlgorithm\n}\n\nconst algorithms: SignerAlgorithms = {\n ES256: ES256SignerAlg(),\n ES256K: ES256KSignerAlg(),\n // This is a non-standard algorithm but retained for backwards compatibility\n // see https://github.com/decentralized-identity/did-jwt/issues/146\n 'ES256K-R': ES256KSignerAlg(true),\n // This is actually incorrect but retained for backwards compatibility\n // see https://github.com/decentralized-identity/did-jwt/issues/130\n Ed25519: Ed25519SignerAlg(),\n EdDSA: Ed25519SignerAlg(),\n}\n\nfunction SignerAlg(alg: string): SignerAlgorithm {\n const impl: SignerAlgorithm = algorithms[alg]\n if (!impl) throw new Error(`not_supported: Unsupported algorithm ${alg}`)\n return impl\n}\n\nexport default SignerAlg\n","import { base58ToBytes, bytesToBase58, bytesToHex, hexToBytes } from '../util.js'\nimport { ripemd160, sha256 } from '../Digest.js'\n\nexport function publicKeyToAddress(publicKey: string, otherAddress: string): string {\n // Use the same version/prefix byte as the given address.\n const version = bytesToHex(base58ToBytes(otherAddress).slice(0, 1))\n const publicKeyBuffer = hexToBytes(publicKey)\n const publicKeyHash = ripemd160(sha256(publicKeyBuffer))\n const step1 = version + bytesToHex(publicKeyHash)\n const step2 = sha256(hexToBytes(step1))\n const step3 = sha256(step2)\n const checksum = bytesToHex(step3).substring(0, 8)\n const step4 = step1 + checksum\n return bytesToBase58(hexToBytes(step4))\n}\n","import { secp256k1 } from '@noble/curves/secp256k1'\nimport { bech32 } from '@scure/base'\nimport { sha256, ripemd160 } from '../Digest.js'\n\nexport function publicKeyToAddress(publicKey: string, prefix: string): string {\n const publicKeyBuffer = secp256k1.ProjectivePoint.fromHex(publicKey).toRawBytes()\n const hash = ripemd160(sha256(publicKeyBuffer))\n const words = bech32.toWords(hash)\n return bech32.encode(prefix, words).replace(prefix, '')\n}\n","import { publicKeyToAddress as bip122 } from './bip122.js'\nimport { publicKeyToAddress as cosmos } from './cosmos.js'\nimport { toEthereumAddress } from '../Digest.js'\n\nexport function verifyBlockchainAccountId(publicKey: string, blockchainAccountId: string | undefined): boolean {\n if (blockchainAccountId) {\n const chain = blockchainAccountId.split(':')\n switch (chain[0]) {\n case 'bip122':\n chain[chain.length - 1] = bip122(publicKey, chain[chain.length - 1])\n break\n case 'cosmos':\n chain[chain.length - 1] = cosmos(publicKey, chain[1])\n break\n case 'eip155':\n chain[chain.length - 1] = toEthereumAddress(publicKey)\n break\n default:\n return false\n }\n return chain.join(':').toLowerCase() === blockchainAccountId.toLowerCase()\n }\n return false\n}\n","import { sha256, toEthereumAddress } from './Digest.js'\nimport type { VerificationMethod } from 'did-resolver'\nimport {\n base64ToBytes,\n bytesToHex,\n EcdsaSignature,\n ECDSASignature,\n extractPublicKeyBytes,\n KNOWN_JWA,\n stringToBytes,\n} from './util.js'\nimport { verifyBlockchainAccountId } from './blockchains/index.js'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { p256 } from '@noble/curves/p256'\nimport { ed25519 } from '@noble/curves/ed25519'\n\n// converts a JOSE signature to it's components\nexport function toSignatureObject(signature: string, recoverable = false): EcdsaSignature {\n const rawSig: Uint8Array = base64ToBytes(signature)\n if (rawSig.length !== (recoverable ? 65 : 64)) {\n throw new Error('wrong signature length')\n }\n const r: string = bytesToHex(rawSig.slice(0, 32))\n const s: string = bytesToHex(rawSig.slice(32, 64))\n const sigObj: EcdsaSignature = { r, s }\n if (recoverable) {\n sigObj.recoveryParam = rawSig[64]\n }\n return sigObj\n}\n\nexport function toSignatureObject2(signature: string, recoverable = false): ECDSASignature {\n const bytes = base64ToBytes(signature)\n if (bytes.length !== (recoverable ? 65 : 64)) {\n throw new Error('wrong signature length')\n }\n return {\n compact: bytes.slice(0, 64),\n recovery: bytes[64],\n }\n}\n\nexport function verifyES256(data: string, signature: string, authenticators: VerificationMethod[]): VerificationMethod {\n const hash = sha256(data)\n const sig = p256.Signature.fromCompact(toSignatureObject2(signature).compact)\n const fullPublicKeys = authenticators.filter((a: VerificationMethod) => !a.ethereumAddress && !a.blockchainAccountId)\n\n const signer: VerificationMethod | undefined = fullPublicKeys.find((pk: VerificationMethod) => {\n try {\n const { keyBytes } = extractPublicKeyBytes(pk)\n return p256.verify(sig, hash, keyBytes)\n } catch (err) {\n return false\n }\n })\n\n if (!signer) throw new Error('invalid_signature: Signature invalid for JWT')\n return signer\n}\n\nexport function verifyES256K(\n data: string,\n signature: string,\n authenticators: VerificationMethod[]\n): VerificationMethod {\n const hash = sha256(data)\n const signatureNormalized = secp256k1.Signature.fromCompact(base64ToBytes(signature)).normalizeS()\n const fullPublicKeys = authenticators.filter((a: VerificationMethod) => {\n return !a.ethereumAddress && !a.blockchainAccountId\n })\n const blockchainAddressKeys = authenticators.filter((a: VerificationMethod) => {\n return a.ethereumAddress || a.blockchainAccountId\n })\n\n let signer: VerificationMethod | undefined = fullPublicKeys.find((pk: VerificationMethod) => {\n try {\n const { keyBytes } = extractPublicKeyBytes(pk)\n return secp256k1.verify(signatureNormalized, hash, keyBytes)\n } catch (err) {\n return false\n }\n })\n\n if (!signer && blockchainAddressKeys.length > 0) {\n signer = verifyRecoverableES256K(data, signature, blockchainAddressKeys)\n }\n\n if (!signer) throw new Error('invalid_signature: Signature invalid for JWT')\n return signer\n}\n\nexport function verifyRecoverableES256K(\n data: string,\n signature: string,\n authenticators: VerificationMethod[]\n): VerificationMethod {\n const signatures: ECDSASignature[] = []\n if (signature.length > 86) {\n signatures.push(toSignatureObject2(signature, true))\n } else {\n const so = toSignatureObject2(signature, false)\n signatures.push({ ...so, recovery: 0 })\n signatures.push({ ...so, recovery: 1 })\n }\n const hash = sha256(data)\n\n const checkSignatureAgainstSigner = (sigObj: ECDSASignature): VerificationMethod | undefined => {\n const signature = secp256k1.Signature.fromCompact(sigObj.compact).addRecoveryBit(sigObj.recovery || 0)\n const recoveredPublicKey = signature.recoverPublicKey(hash)\n const recoveredAddress = toEthereumAddress(recoveredPublicKey.toHex(false)).toLowerCase()\n const recoveredPublicKeyHex = recoveredPublicKey.toHex(false)\n const recoveredCompressedPublicKeyHex = recoveredPublicKey.toHex(true)\n\n return authenticators.find((a: VerificationMethod) => {\n const { keyBytes } = extractPublicKeyBytes(a)\n const keyHex = bytesToHex(keyBytes)\n return (\n keyHex === recoveredPublicKeyHex ||\n keyHex === recoveredCompressedPublicKeyHex ||\n a.ethereumAddress?.toLowerCase() === recoveredAddress ||\n a.blockchainAccountId?.split('@eip155')?.[0].toLowerCase() === recoveredAddress || // CAIP-2\n verifyBlockchainAccountId(recoveredPublicKeyHex, a.blockchainAccountId) // CAIP-10\n )\n })\n }\n\n // Find first verification method\n for (const signature of signatures) {\n const verificationMethod = checkSignatureAgainstSigner(signature)\n if (verificationMethod) return verificationMethod\n }\n // If no one found matching\n throw new Error('invalid_signature: Signature invalid for JWT')\n}\n\nexport function verifyEd25519(\n data: string,\n signature: string,\n authenticators: VerificationMethod[]\n): VerificationMethod {\n const clear = stringToBytes(data)\n const signatureBytes = base64ToBytes(signature)\n const signer = authenticators.find((a: VerificationMethod) => {\n const { keyBytes, keyType } = extractPublicKeyBytes(a)\n if (keyType === 'Ed25519') {\n return ed25519.verify(signatureBytes, clear, keyBytes)\n } else {\n return false\n }\n })\n if (!signer) throw new Error('invalid_signature: Signature invalid for JWT')\n return signer\n}\n\ntype Verifier = (data: string, signature: string, authenticators: VerificationMethod[]) => VerificationMethod\n\ntype Algorithms = Record<KNOWN_JWA, Verifier>\n\nconst algorithms: Algorithms = {\n ES256: verifyES256,\n ES256K: verifyES256K,\n // This is a non-standard algorithm but retained for backwards compatibility\n // see https://github.com/decentralized-identity/did-jwt/issues/146\n 'ES256K-R': verifyRecoverableES256K,\n // This is actually incorrect but retained for backwards compatibility\n // see https://github.com/decentralized-identity/did-jwt/issues/130\n Ed25519: verifyEd25519,\n EdDSA: verifyEd25519,\n}\n\nfunction VerifierAlgorithm(alg: string): Verifier {\n const impl: Verifier = algorithms[alg as KNOWN_JWA]\n if (!impl) throw new Error(`not_supported: Unsupported algorithm ${alg}`)\n return impl\n}\n\nVerifierAlgorithm.toSignatureObject = toSignatureObject\n\nexport default VerifierAlgorithm\n","/**\n * Error prefixes used for known verification failure cases.\n *\n * For compatibility, these error prefixes match the existing error messages, but will be adjusted in a future major\n * version update to match the scenarios better.\n *\n * @beta\n */\nexport const JWT_ERROR = {\n /**\n * Thrown when a JWT payload schema is unexpected or when validity period does not match\n */\n INVALID_JWT: 'invalid_jwt',\n /**\n * Thrown when the verifier audience does not match the one set in the JWT payload\n */\n INVALID_AUDIENCE: 'invalid_config',\n /**\n * Thrown when none of the public keys of the issuer match the signature of the JWT.\n *\n * This is equivalent to `NO_SUITABLE_KEYS` when the `proofPurpose` is NOT specified.\n */\n INVALID_SIGNATURE: 'invalid_signature',\n /**\n * Thrown when the DID document of the issuer does not have any keys that match the signature for the given\n * `proofPurpose`.\n *\n * This is equivalent to `invalid_signature`, when a `proofPurpose` is specified.\n */\n NO_SUITABLE_KEYS: 'no_suitable_keys',\n /**\n * Thrown when the `alg` of the JWT or the encoding of the key is not supported\n */\n NOT_SUPPORTED: 'not_supported',\n /**\n * Thrown when the DID resolver is unable to resolve the issuer DID.\n */\n RESOLVER_ERROR: 'resolver_error',\n}\n","import type { VerificationMethod } from 'did-resolver'\nimport { JWT_ERROR } from './Errors.js'\nimport { type JWTDecoded, type JWTVerifyOptions, resolveAuthenticator, verifyJWT, verifyJWTDecoded } from './JWT.js'\n\nexport const CONDITIONAL_PROOF_2022 = 'ConditionalProof2022'\n\nexport async function verifyProof(\n jwt: string,\n { header, payload, signature, data }: JWTDecoded,\n authenticator: VerificationMethod,\n options: JWTVerifyOptions\n): Promise<VerificationMethod> {\n if (authenticator.type === CONDITIONAL_PROOF_2022) {\n return verifyConditionalProof(jwt, { payload, header, signature, data }, authenticator, options)\n } else {\n return verifyJWTDecoded({ header, payload, data, signature }, [authenticator])\n }\n}\n\nexport async function verifyConditionalProof(\n jwt: string,\n { header, payload, signature, data }: JWTDecoded,\n authenticator: VerificationMethod,\n options: JWTVerifyOptions\n): Promise<VerificationMethod> {\n // Validate the condition according to its condition property\n if (authenticator.conditionWeightedThreshold) {\n return verifyConditionWeightedThreshold(jwt, { header, payload, data, signature }, authenticator, options)\n } else if (authenticator.conditionDelegated) {\n return verifyConditionDelegated(jwt, { header, payload, data, signature }, authenticator, options)\n }\n // TODO other conditions\n\n throw new Error(\n `${JWT_ERROR.INVALID_JWT}: conditional proof type did not find condition for authenticator ${authenticator.id}.`\n )\n}\n\nasync function verifyConditionWeightedThreshold(\n jwt: string,\n { header, payload, data, signature }: JWTDecoded,\n authenticator: VerificationMethod,\n options: JWTVerifyOptions\n): Promise<VerificationMethod> {\n if (!authenticator.conditionWeightedThreshold || !authenticator.threshold) {\n throw new Error('Expected conditionWeightedThreshold and threshold')\n }\n\n const issuers: string[] = []\n const threshold = authenticator.threshold\n let weightCount = 0\n\n for (const weightedCondition of authenticator.conditionWeightedThreshold) {\n const currentCondition = weightedCondition.condition\n let foundSigner: VerificationMethod | undefined\n\n try {\n if (currentCondition.type === CONDITIONAL_PROOF_2022) {\n if (!options.didAuthenticator) {\n throw new Error('Expected didAuthenticator')\n }\n\n const newOptions: JWTVerifyOptions = {\n ...options,\n didAuthenticator: {\n didResolutionResult: options.didAuthenticator?.didResolutionResult,\n authenticators: [currentCondition],\n issuer: currentCondition.id,\n },\n }\n const { verified } = await verifyJWT(jwt, newOptions)\n if (verified) {\n foundSigner = currentCondition\n }\n } else {\n foundSigner = await verifyJWTDecoded({ header, payload, data, signature }, currentCondition)\n }\n } catch (e) {\n if (!(e as Error).message.startsWith(JWT_ERROR.INVALID_SIGNATURE)) throw e\n }\n\n if (foundSigner && !issuers.includes(foundSigner.id)) {\n issuers.push(foundSigner.id)\n weightCount += weightedCondition.weight\n\n if (weightCount >= threshold) {\n return authenticator\n }\n }\n }\n throw new Error(`${JWT_ERROR.INVALID_SIGNATURE}: condition for authenticator ${authenticator.id} is not met.`)\n}\n\nasync function verifyConditionDelegated(\n jwt: string,\n { header, payload, data, signature }: JWTDecoded,\n authenticator: VerificationMethod,\n options: JWTVerifyOptions\n): Promise<VerificationMethod> {\n if (!authenticator.conditionDelegated) {\n throw new Error('Expected conditionDelegated')\n }\n if (!options.resolver) {\n throw new Error('Expected resolver')\n }\n\n let foundSigner: VerificationMethod | undefined\n\n const issuer = authenticator.conditionDelegated\n const didAuthenticator = await resolveAuthenticator(options.resolver, header.alg, issuer, options.proofPurpose)\n const didResolutionResult = didAuthenticator.didResolutionResult\n\n if (!didResolutionResult?.didDocument) {\n throw new Error(`${JWT_ERROR.RESOLVER_ERROR}: Could not resolve delegated DID ${issuer}.`)\n }\n\n const delegatedAuthenticator = didAuthenticator.authenticators.find((authenticator) => authenticator.id === issuer)\n if (!delegatedAuthenticator) {\n throw new Error(\n `${JWT_ERROR.NO_SUITABLE_KEYS}: Could not find delegated authenticator ${issuer} in it's DID Document`\n )\n }\n\n if (delegatedAuthenticator.type === CONDITIONAL_PROOF_2022) {\n const { verified } = await verifyJWT(jwt, {\n ...options,\n ...{\n didAuthenticator: {\n didResolutionResult,\n authenticators: [delegatedAuthenticator],\n issuer: delegatedAuthenticator.id,\n },\n },\n })\n if (verified) {\n foundSigner = delegatedAuthenticator\n }\n } else {\n try {\n foundSigner = verifyJWTDecoded({ header, payload, data, signature }, delegatedAuthenticator)\n } catch (e) {\n if (!(e as Error).message.startsWith('invalid_signature:')) throw e\n }\n }\n\n if (foundSigner) {\n return authenticator\n }\n\n throw new Error(`${JWT_ERROR.INVALID_SIGNATURE}: condition for authenticator ${authenticator.id} is not met.`)\n}\n","import canonicalizeData from 'canonicalize'\nimport { DIDDocument, DIDResolutionResult, parse, ParsedDID, Resolvable, VerificationMethod } from 'did-resolver'\nimport SignerAlg from './SignerAlgorithm.js'\nimport { decodeBase64url, EcdsaSignature, encodeBase64url, KNOWN_JWA, SUPPORTED_PUBLIC_KEY_TYPES } from './util.js'\nimport VerifierAlgorithm from './VerifierAlgorithm.js'\nimport { JWT_ERROR } from './Errors.js'\nimport { verifyProof } from './ConditionalAlgorithm.js'\n\nexport type Signer = (data: string | Uint8Array) => Promise<EcdsaSignature | string>\nexport type SignerAlgorithm = (payload: string, signer: Signer) => Promise<string>\n\nexport type ProofPurposeTypes =\n | 'assertionMethod'\n | 'authentication'\n // | 'keyAgreement' // keyAgreement VerificationMethod should not be used for signing\n | 'capabilityDelegation'\n | 'capabilityInvocation'\n\nexport interface JWTOptions {\n issuer: string\n signer: Signer\n /**\n * @deprecated Please use `header.alg` to specify the JWT algorithm.\n */\n alg?: string\n expiresIn?: number\n canonicalize?: boolean\n}\n\nexport interface JWTVerifyOptions {\n /** @deprecated Please use `proofPurpose: 'authentication' instead` */\n auth?: boolean\n audience?: string\n callbackUrl?: string\n resolver?: Resolvable\n skewTime?: number\n /** See https://www.w3.org/TR/did-spec-registries/#verification-relationships */\n proofPurpose?: ProofPurposeTypes\n policies?: JWTVerifyPolicies\n didAuthenticator?: DIDAuthenticator\n}\n\n/**\n * Overrides the different types of checks performed on the JWT besides the signature check\n */\nexport interface JWTVerifyPolicies {\n // overrides the timestamp against which the validity interval is checked\n now?: number\n // when set to false, the timestamp checks ignore the Not Before(`nbf`) property\n nbf?: boolean\n // when set to false, the timestamp checks ignore the Issued At(`iat`) property\n iat?: boolean\n // when set to false, the timestamp checks ignore the Expires At(`exp`) property\n exp?: boolean\n // when set to false, the JWT audience check is skipped\n aud?: boolean\n}\n\nexport interface JWSCreationOptions {\n canonicalize?: boolean\n}\n\nexport interface DIDAuthenticator {\n authenticators: VerificationMethod[]\n issuer: string\n didResolutionResult: DIDResolutionResult\n}\n\nexport interface JWTHeader {\n typ: 'JWT'\n alg: string\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [x: string]: any\n}\n\nexport interface JWTPayload {\n iss?: string\n sub?: string\n aud?: string | string[]\n iat?: number\n nbf?: number\n exp?: number\n rexp?: number\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [x: string]: any\n}\n\nexport interface JWTDecoded {\n header: JWTHeader\n payload: JWTPayload\n signature: string\n data: string\n}\n\nexport interface JWSDecoded {\n header: JWTHeader\n payload: string\n signature: string\n data: string\n}\n\n/**\n * Result object returned by {@link verifyJWT}\n */\nexport interface JWTVerified {\n /**\n * Set to true for a JWT that passes all the required checks minus any verification overrides.\n */\n verified: true\n\n /**\n * The decoded JWT payload\n */\n payload: Partial<JWTPayload>\n\n /**\n * The result of resolving the issuer DID\n */\n didResolutionResult: DIDResolutionResult\n\n /**\n * the issuer DID\n */\n issuer: string\n\n /**\n * The public key of the issuer that matches the JWT signature\n */\n signer: VerificationMethod\n\n /**\n * The original JWT that was verified\n */\n jwt: string\n\n /**\n * Any overrides that were used during verification\n */\n policies?: JWTVerifyPolicies\n}\n\nexport const SELF_ISSUED_V2 = 'https://self-issued.me/v2'\nexport const SELF_ISSUED_V2_VC_INTEROP = 'https://self-issued.me/v2/openid-vc' // https://identity.foundation/jwt-vc-presentation-profile/#id-token-validation\nexport const SELF_ISSUED_V0_1 = 'https://self-issued.me'\n\ntype LegacyVerificationMethod = { publicKey?: string }\n\nconst defaultAlg: KNOWN_JWA = 'ES256K'\nconst DID_JSON = 'application/did+json'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction encodeSection(data: any, shouldCanonicalize = false): string {\n if (shouldCanonicalize) {\n return encodeBase64url(<string>canonicalizeData(data))\n } else {\n return encodeBase64url(JSON.stringify(data))\n }\n}\n\nexport const NBF_SKEW = 300\n\nfunction decodeJWS(jws: string): JWSDecoded {\n const parts = jws.match(/^([a-zA-Z0-9_-]+)\\.([a-zA-Z0-9_-]+)\\.([a-zA-Z0-9_-]+)$/)\n if (parts) {\n return {\n header: JSON.parse(decodeBase64url(parts[1])),\n payload: parts[2],\n signature: parts[3],\n data: `${parts[1]}.${parts[2]}`,\n }\n }\n throw new Error('invalid_argument: Incorrect format JWS')\n}\n\n/**\n * Decodes a JWT and returns an object representing the payload\n *\n * @example\n * decodeJWT('eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE1...')\n *\n * @param {String} jwt a JSON Web Token to verify\n * @param {Object} [recurse] whether to recurse into the payload to decode any nested JWTs\n * @return {Object} a JS object representing the decoded JWT\n */\nexport function decodeJWT(jwt: string, recurse = true): JWTDecoded {\n if (!jwt) throw new Error('invalid_argument: no JWT passed into decodeJWT')\n try {\n const jws = decodeJWS(jwt)\n const decodedJwt: JWTDecoded = Object.assign(jws, { payload: JSON.parse(decodeBase64url(jws.payload)) })\n const iss = decodedJwt.payload.iss\n\n if (decodedJwt.header.cty === 'JWT' && recurse) {\n const innerDecodedJwt = decodeJWT(decodedJwt.payload.jwt)\n\n if (innerDecodedJwt.payload.iss !== iss) throw new Error(`${JWT_ERROR.INVALID_JWT}: multiple issuers`)\n return innerDecodedJwt\n }\n return decodedJwt\n } catch (e) {\n throw new Error(`invalid_argument: ${JWT_ERROR.INVALID_JWT}: ${e}`)\n }\n}\n\n/**\n * Creates a signed JWS given a payload, a signer, and an optional header.\n *\n * @example\n * const signer = ES256KSigner(process.env.PRIVATE_KEY)\n * const jws = await createJWS({ my: 'payload' }, signer)\n *\n * @param {Object} payload payload object\n * @param {Signer} signer a signer, see `ES256KSigner or `EdDSASigner`\n * @param {Object} header optional object to specify or customize the JWS header\n * @param {Object} options can be used to trigger automatic canonicalization of header and\n * payload properties\n * @return {Promise<string>} a Promise which resolves to a JWS string or rejects with an error\n */\nexport async function createJWS(\n payload: string | Partial<JWTPayload>,\n signer: Signer,\n header: Partial<JWTHeader> = {},\n options: JWSCreationOptions = {}\n): Promise<string> {\n if (!header.alg) header.alg = defaultAlg\n const encodedPayload = typeof payload === 'string' ? payload : encodeSection(payload, options.canonicalize)\n const signingInput: string = [encodeSection(header, options.canonicalize), encodedPayload].join('.')\n\n const jwtSigner: SignerAlgorithm = SignerAlg(header.alg)\n const signature: string = await jwtSigner(signingInput, signer)\n\n // JWS Compact Serialization\n // https://www.rfc-editor.org/rfc/rfc7515#section-7.1\n return [signingInput, signature].join('.')\n}\n\n/**\n * Creates a signed JWT given an address which becomes the issuer, a signer, and a payload for which the signature is\n * over.\n *\n * @example\n * const signer = ES256KSigner(process.env.PRIVATE_KEY)\n * createJWT({address: '5A8bRWU3F7j3REx3vkJ...', signer}, {key1: 'value', key2: ..., ... }).then(jwt => {\n * ...\n * })\n *\n * @param {Object}