UNPKG

@pact-toolbox/crypto

Version:
1 lines 110 kB
{"version":3,"file":"index.browser.mjs","names":["data: BufferSource","storageKeyBySecretKey_INTERNAL_ONLY_DO_NOT_EXPORT: WeakMap<CryptoKey, Uint8Array> | undefined","publicKeyBytesStore: WeakMap<CryptoKey, Uint8Array> | undefined","createKeyPairFromBytes","bytes: Uint8Array","extractable: boolean","keyUsages: readonly KeyUsage[]","key: CryptoKey","value: string","format: KeyFormat","signature","signature: BufferSource","type: \"private\" | \"public\"","keyData: BufferSource | JsonWebKey","cachedEd25519Decision: PromiseLike<boolean> | boolean | undefined","subtle: SubtleCrypto","crypto","codecDescription: string","bytes: ReadonlyUint8Array | Uint8Array","expected: number","offset: number","bytesLength: number","alphabet: string","testValue: string","givenValue: string","alphabet","value: TFrom","encoder: { fixedSize: number } | { getSizeFromValue: (value: TFrom) => number }","encoder: Omit<FixedSizeEncoder<TFrom>, \"encode\"> | Omit<VariableSizeEncoder<TFrom>, \"encode\">","decoder: Omit<FixedSizeDecoder<TTo>, \"decode\"> | Omit<VariableSizeDecoder<TTo>, \"decode\">","codec:\n | Omit<FixedSizeCodec<TFrom, TTo>, \"decode\" | \"encode\">\n | Omit<VariableSizeCodec<TFrom, TTo>, \"decode\" | \"encode\">","codec: { fixedSize: number } | { maxSize?: number }","encoder: Encoder<TOldFrom>","unmap: (value: TNewFrom) => TOldFrom","value: TNewFrom","decoder: Decoder<TOldTo>","map: (value: TOldTo, bytes: ReadonlyUint8Array | Uint8Array, offset: number) => TNewTo","bytes: ReadonlyUint8Array | Uint8Array","encoder: Encoder<TFrom>","decoder: Decoder<TTo>","codec: Codec<TOldFrom, TOldTo>","map?: (value: TOldTo, bytes: ReadonlyUint8Array | Uint8Array, offset: number) => TNewTo","byteArrays: Uint8Array[]","length: number","data: ReadonlyUint8Array | Uint8Array","offset: number","fixedBytes: TSize","bytes: Uint8Array","offset: Offset","codec: Codec<TFrom, TTo>","char: number","value: string","base16: VariableSizeCodec<string>","base16Encoder: Encoder<string> | undefined","putativeSignature: string","key: CryptoKey","data: ReadonlyUint8Array","signature: SignatureBytes","data: ReadonlyUint8Array | Uint8Array","signature","bytes: ReadonlyUint8Array","extractable?: boolean","privateKey: CryptoKey","extractable: boolean","privateKey","putativeAddress: string","putativeAddress: TAddress","addressEncoder: FixedSizeEncoder<Address, 32> | undefined","addressDecoder: FixedSizeDecoder<Address, 32> | undefined","addressCodec: FixedSizeCodec<Address, Address, 32> | undefined","key: CryptoKey","putativeAccount: string","publicKey: CryptoKey","address","alphabet: string","value: string","alphabet","tailBytes: number[]","zeroCharacter: string","value: bigint","alphabet","base10: VariableSizeCodec<string>","base58: VariableSizeCodec<string>","alphabet: string","bits: number","value: string","alphabet","input: number[]","inputBits: number","outputBits: number","useRemainder: boolean","value: string","value: string","base64Url: VariableSizeCodec<string>","value: string","chars: number","textEncoder: TextEncoder","value: string","textDecoder: TextDecoder","utf8: VariableSizeCodec<string>","input: string | Uint8Array","val: unknown","isArrayProp: boolean"],"sources":["../../../node_modules/.pnpm/uncrypto@0.1.3/node_modules/uncrypto/dist/crypto.web.mjs","../src/polyfill/secrets.ts","../src/polyfill/install.ts","../src/assertions.ts","../src/codecs/core.ts","../src/codecs/strings/base16.ts","../src/keys/signatures.ts","../src/keys/keys.ts","../src/address.ts","../src/codecs/strings/baseX.ts","../src/codecs/strings/base10.ts","../src/codecs/strings/base58.ts","../src/codecs/strings/baseX-reslice.ts","../src/codecs/strings/base64.ts","../src/codecs/strings/base64-url.ts","../src/codecs/strings/null.ts","../src/codecs/text.ts","../src/codecs/strings/utf-8.ts","../src/hash/base64-url-blake2b.ts","../src/stringify.ts","../src/index.ts"],"sourcesContent":["const webCrypto = globalThis.crypto;\nconst subtle = webCrypto.subtle;\nconst randomUUID = () => {\n return webCrypto.randomUUID();\n};\nconst getRandomValues = (array) => {\n return webCrypto.getRandomValues(array);\n};\nconst _crypto = {\n randomUUID,\n getRandomValues,\n subtle\n};\n\nexport { _crypto as default, getRandomValues, randomUUID, subtle };\n","/**\n * HEY! <== SECRET KEY KOALA\n * |/ <== WOULD LIKE YOUR\n * ʕ·͡ᴥ·ʔ <== ATTENTION PLEASE\n *\n * Key material generated in this module must stay in this module. So long as the secrets cache and\n * the methods that interact with it are not exported from `@solana/webcrypto-ed25519-polyfill`,\n * accidental logging of the actual bytes of a secret key (eg. to the console, or to a remote\n * server) should not be possible.\n *\n * WARNING: This does not imply that the secrets cache is secure against supply-chain attacks.\n * Untrusted code in your JavaScript context can easily override `WeakMap.prototype.set` to steal\n * private keys as they are written to the cache, without alerting you to its presence or affecting\n * the regular operation of the cache.\n */\nimport { getPublicKeyAsync, signAsync, utils, verifyAsync } from \"@noble/ed25519\";\n\nconst PROHIBITED_KEY_USAGES = new Set<KeyUsage>([\n \"decrypt\",\n \"deriveBits\",\n \"deriveKey\",\n \"encrypt\",\n \"unwrapKey\",\n \"wrapKey\",\n]);\n\nconst ED25519_PKCS8_HEADER =\n // prettier-ignore\n [\n /**\n * PKCS#8 header\n */\n 0x30, // ASN.1 sequence tag\n 0x2e, // Length of sequence (46 more bytes)\n\n 0x02, // ASN.1 integer tag\n 0x01, // Length of integer\n 0x00, // Version number\n\n 0x30, // ASN.1 sequence tag\n 0x05, // Length of sequence\n 0x06, // ASN.1 object identifier tag\n 0x03, // Length of object identifier\n // Edwards curve algorithms identifier https://oid-rep.orange-labs.fr/get/1.3.101.112\n 0x2b, // iso(1) / identified-organization(3) (The first node is multiplied by the decimal 40 and the result is added to the value of the second node)\n 0x65, // thawte(101)\n // Ed25519 identifier\n 0x70, // id-Ed25519(112)\n\n /**\n * Private key payload\n */\n 0x04, // ASN.1 octet string tag\n 0x22, // String length (34 more bytes)\n\n // Private key bytes as octet string\n 0x04, // ASN.1 octet string tag\n 0x20, // String length (32 bytes)\n ];\n\nfunction bufferSourceToUint8Array(data: BufferSource): Uint8Array {\n return data instanceof Uint8Array ? data : new Uint8Array(ArrayBuffer.isView(data) ? data.buffer : data);\n}\n\nlet storageKeyBySecretKey_INTERNAL_ONLY_DO_NOT_EXPORT: WeakMap<CryptoKey, Uint8Array> | undefined;\n\n// Map of public key bytes. These are the result of calling `getPublicKey`\nlet publicKeyBytesStore: WeakMap<CryptoKey, Uint8Array> | undefined;\n\nfunction createKeyPairFromBytes(\n bytes: Uint8Array,\n extractable: boolean,\n keyUsages: readonly KeyUsage[],\n): CryptoKeyPair {\n const keyPair = createKeyPair_INTERNAL_ONLY_DO_NOT_EXPORT(extractable, keyUsages);\n const cache = (storageKeyBySecretKey_INTERNAL_ONLY_DO_NOT_EXPORT ||= new WeakMap());\n cache.set(keyPair.privateKey, bytes);\n cache.set(keyPair.publicKey, bytes);\n return keyPair;\n}\n\nfunction createKeyPair_INTERNAL_ONLY_DO_NOT_EXPORT(\n extractable: boolean,\n keyUsages: readonly KeyUsage[],\n): CryptoKeyPair {\n if (keyUsages.length === 0) {\n throw new DOMException(\"Usages cannot be empty when creating a key.\", \"SyntaxError\");\n }\n if (keyUsages.some((usage) => PROHIBITED_KEY_USAGES.has(usage))) {\n throw new DOMException(\"Unsupported key usage for an Ed25519 key.\", \"SyntaxError\");\n }\n const base = {\n [Symbol.toStringTag]: \"CryptoKey\",\n algorithm: Object.freeze({ name: \"Ed25519\" }),\n };\n const privateKey = {\n ...base,\n extractable,\n type: \"private\",\n usages: Object.freeze(keyUsages.filter((usage) => usage === \"sign\")) as KeyUsage[],\n } as CryptoKey;\n const publicKey = {\n ...base,\n extractable: true,\n type: \"public\",\n usages: Object.freeze(keyUsages.filter((usage) => usage === \"verify\")) as KeyUsage[],\n } as CryptoKey;\n return Object.freeze({\n privateKey: Object.freeze(privateKey),\n publicKey: Object.freeze(publicKey),\n });\n}\n\nfunction getSecretKeyBytes_INTERNAL_ONLY_DO_NOT_EXPORT(key: CryptoKey): Uint8Array {\n const secretKeyBytes = storageKeyBySecretKey_INTERNAL_ONLY_DO_NOT_EXPORT?.get(key);\n if (secretKeyBytes === undefined) {\n throw new Error(\"Could not find secret key material associated with this `CryptoKey`\");\n }\n return secretKeyBytes;\n}\n\nasync function getPublicKeyBytes(key: CryptoKey): Promise<Uint8Array> {\n // Try to find the key in the public key store first\n const publicKeyStore = (publicKeyBytesStore ||= new WeakMap());\n const fromPublicStore = publicKeyStore.get(key);\n if (fromPublicStore) return fromPublicStore;\n\n // If not available, get the key from the secrets store instead\n const publicKeyBytes = await getPublicKeyAsync(getSecretKeyBytes_INTERNAL_ONLY_DO_NOT_EXPORT(key));\n\n // Store the public key bytes in the public key store for next time\n publicKeyStore.set(key, publicKeyBytes);\n return publicKeyBytes;\n}\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n return btoa(Array.from(bytes, (b) => String.fromCharCode(b)).join(\"\"))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nfunction base64UrlDecode(value: string): Uint8Array {\n const m = value.length % 4;\n const base64Value = value\n .replace(/-/g, \"+\")\n .replace(/_/g, \"/\")\n .padEnd(value.length + (m === 0 ? 0 : 4 - m), \"=\");\n return Uint8Array.from(atob(base64Value), (c) => c.charCodeAt(0));\n}\n\nexport async function exportKeyPolyfill(format: \"jwk\", key: CryptoKey): Promise<JsonWebKey>;\nexport async function exportKeyPolyfill(format: KeyFormat, key: CryptoKey): Promise<ArrayBuffer>;\nexport async function exportKeyPolyfill(format: KeyFormat, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey> {\n if (key.extractable === false) {\n throw new DOMException(\"key is not extractable\", \"InvalidAccessException\");\n }\n switch (format) {\n case \"raw\": {\n if (key.type !== \"public\") {\n throw new DOMException(`Unable to export a raw Ed25519 ${key.type} key`, \"InvalidAccessError\");\n }\n const publicKeyBytes = await getPublicKeyBytes(key);\n // @ts-expect-error\n return publicKeyBytes;\n }\n case \"pkcs8\": {\n if (key.type !== \"private\") {\n throw new DOMException(`Unable to export a pkcs8 Ed25519 ${key.type} key`, \"InvalidAccessError\");\n }\n const secretKeyBytes = getSecretKeyBytes_INTERNAL_ONLY_DO_NOT_EXPORT(key);\n // @ts-expect-error\n return new Uint8Array([...ED25519_PKCS8_HEADER, ...secretKeyBytes]);\n }\n case \"jwk\": {\n const publicKeyBytes = await getPublicKeyBytes(key);\n const base = {\n crv /* curve */: \"Ed25519\",\n ext /* extractable */: key.extractable,\n key_ops /* key operations */: key.usages,\n kty /* key type */: \"OKP\" /* octet key pair */,\n x /* public key x-coordinate (base64-URL encoded) */: base64UrlEncode(publicKeyBytes),\n };\n if (key.type === \"private\") {\n const secretKeyBytes = getSecretKeyBytes_INTERNAL_ONLY_DO_NOT_EXPORT(key);\n return Object.freeze({\n ...base,\n d /* private key (base64-URL encoded) */: base64UrlEncode(secretKeyBytes),\n });\n }\n return Object.freeze({ ...base });\n }\n default:\n throw new Error(`Exporting polyfilled Ed25519 keys in the \"${format}\" format is unimplemented`);\n }\n}\n\n/**\n * This function generates a key pair and stores the secret bytes associated with it in a\n * module-private cache. Instead of vending the actual secret bytes, it returns a `CryptoKeyPair`\n * that you can use with other methods in this package to produce signatures and derive public keys\n * associated with the secret.\n */\nexport function generateKeyPolyfill(extractable: boolean, keyUsages: readonly KeyUsage[]): CryptoKeyPair {\n const privateKeyBytes = utils.randomPrivateKey();\n const keyPair = createKeyPairFromBytes(privateKeyBytes, extractable, keyUsages);\n return keyPair;\n}\n\nexport function isPolyfilledKey(key: CryptoKey): boolean {\n return !!storageKeyBySecretKey_INTERNAL_ONLY_DO_NOT_EXPORT?.has(key) || !!publicKeyBytesStore?.has(key);\n}\n\nexport async function signPolyfill(key: CryptoKey, data: BufferSource): Promise<ArrayBuffer> {\n if (key.type !== \"private\" || !key.usages.includes(\"sign\")) {\n throw new DOMException(\"Unable to use this key to sign\", \"InvalidAccessError\");\n }\n const privateKeyBytes = getSecretKeyBytes_INTERNAL_ONLY_DO_NOT_EXPORT(key);\n const payload = bufferSourceToUint8Array(data);\n const signature = await signAsync(payload, privateKeyBytes);\n // @ts-expect-error\n return signature;\n}\n\nexport async function verifyPolyfill(key: CryptoKey, signature: BufferSource, data: BufferSource): Promise<boolean> {\n if (key.type !== \"public\" || !key.usages.includes(\"verify\")) {\n throw new DOMException(\"Unable to use this key to verify\", \"InvalidAccessError\");\n }\n const publicKeyBytes = await getPublicKeyBytes(key);\n try {\n return await verifyAsync(bufferSourceToUint8Array(signature), bufferSourceToUint8Array(data), publicKeyBytes);\n } catch {\n return false;\n }\n}\n\nfunction assertValidKeyUsages(keyUsages: readonly KeyUsage[], type: \"private\" | \"public\") {\n const prohibitedKeyUses = new Set<KeyUsage>([\n ...((type === \"private\" ? [\"verify\"] : [\"sign\"]) as KeyUsage[]),\n ...PROHIBITED_KEY_USAGES,\n ]);\n if (keyUsages.some((usage) => prohibitedKeyUses.has(usage))) {\n throw new DOMException(\"Unsupported key usage for a Ed25519 key\", \"SyntaxError\");\n }\n}\n\nexport function importKeyPolyfill(\n format: \"jwk\",\n keyData: JsonWebKey,\n extractable: boolean,\n keyUsages: readonly KeyUsage[],\n): CryptoKey;\nexport function importKeyPolyfill(\n format: Exclude<KeyFormat, \"jwk\">,\n keyData: BufferSource,\n extractable: boolean,\n keyUsages: readonly KeyUsage[],\n): CryptoKey;\nexport function importKeyPolyfill(\n format: KeyFormat,\n keyData: BufferSource | JsonWebKey,\n extractable: boolean,\n keyUsages: readonly KeyUsage[],\n): CryptoKey {\n if (format === \"raw\") {\n const bytes = bufferSourceToUint8Array(keyData as BufferSource);\n assertValidKeyUsages(keyUsages, \"public\");\n if (bytes.length !== 32) {\n throw new DOMException(\"Ed25519 raw keys must be exactly 32-bytes\", \"DataError\");\n }\n const publicKey = {\n [Symbol.toStringTag]: \"CryptoKey\",\n algorithm: Object.freeze({ name: \"Ed25519\" }),\n extractable,\n type: \"public\",\n usages: Object.freeze(keyUsages.filter((usage) => usage === \"verify\")) as KeyUsage[],\n } as CryptoKey;\n\n const cache = (publicKeyBytesStore ||= new WeakMap());\n cache.set(publicKey, bytes);\n\n return publicKey;\n }\n\n if (format === \"pkcs8\") {\n const bytes = bufferSourceToUint8Array(keyData as BufferSource);\n assertValidKeyUsages(keyUsages, \"private\");\n // 48 bytes: 16-byte PKCS8 header + 32 byte secret key\n if (bytes.length !== 48) {\n throw new DOMException(\"Invalid keyData\", \"DataError\");\n }\n // Must start with exactly the Ed25519 pkcs8 header\n const header = bytes.slice(0, 16);\n if (!header.every((val, i) => val === ED25519_PKCS8_HEADER[i])) {\n throw new DOMException(\"Invalid keyData\", \"DataError\");\n }\n const secretKeyBytes = bytes.slice(16);\n\n const privateKey = {\n [Symbol.toStringTag]: \"CryptoKey\",\n algorithm: Object.freeze({ name: \"Ed25519\" }),\n extractable,\n type: \"private\",\n usages: Object.freeze(keyUsages.filter((usage) => usage === \"sign\")) as KeyUsage[],\n } as CryptoKey;\n\n const cache = (storageKeyBySecretKey_INTERNAL_ONLY_DO_NOT_EXPORT ||= new WeakMap());\n cache.set(privateKey, secretKeyBytes);\n\n return privateKey;\n }\n\n if (format === \"jwk\") {\n const jwk = keyData as JsonWebKey;\n const type = \"d\" in jwk ? \"private\" : \"public\";\n assertValidKeyUsages(keyUsages, type);\n const keyOps = new Set(jwk.key_ops ?? []);\n const sameKeyUsages = keyUsages.length === keyOps.size && [...keyUsages].every((x) => keyOps.has(x));\n if (jwk.kty !== \"OKP\" || jwk.crv !== \"Ed25519\" || jwk.ext !== extractable || !sameKeyUsages) {\n throw new DOMException(\"Invalid Ed25519 JWK\", \"DataError\");\n }\n if (type === \"public\" && !jwk.x) {\n throw new DOMException(\"Ed25519 JWK is missing public key coordinates\", \"DataError\");\n }\n if (type === \"private\" && !jwk.d) {\n throw new DOMException(\"Ed25519 JWK is missing private key coordinates\", \"DataError\");\n }\n const usageToKeep = type === \"public\" ? \"verify\" : \"sign\";\n const key = Object.freeze({\n [Symbol.toStringTag]: \"CryptoKey\",\n algorithm: Object.freeze({ name: \"Ed25519\" }),\n extractable,\n type,\n usages: Object.freeze(keyUsages.filter((usage) => usage === usageToKeep)) as KeyUsage[],\n }) as CryptoKey;\n\n if (type === \"public\") {\n const cache = (publicKeyBytesStore ||= new WeakMap());\n cache.set(key, base64UrlDecode(jwk.x!));\n } else {\n const cache = (storageKeyBySecretKey_INTERNAL_ONLY_DO_NOT_EXPORT ||= new WeakMap());\n cache.set(key, base64UrlDecode(jwk.d!));\n }\n\n return key;\n }\n\n throw new Error(`Importing Ed25519 keys in the \"${format}\" format is unimplemented`);\n}\n","import cryptoImpl from \"uncrypto\";\n\nimport {\n exportKeyPolyfill,\n generateKeyPolyfill,\n importKeyPolyfill,\n isPolyfilledKey,\n signPolyfill,\n verifyPolyfill,\n} from \"./secrets\";\n\nexport function install(): void {\n if (__NODEJS__) {\n /**\n * Node only sets the `crypto` global variable when run with `--experimental-global-webcrypto`.\n * Let's set it unconditionally here.\n */\n globalThis.crypto ||= cryptoImpl;\n }\n\n if (!__BROWSER__ || globalThis.isSecureContext) {\n /**\n * Create `crypto.subtle` if it doesn't exist.\n */\n const originalCryptoObject = (globalThis.crypto ||= {} as Crypto);\n const originalSubtleCrypto = ((originalCryptoObject as Crypto & { subtle: SubtleCrypto }).subtle ||=\n {} as SubtleCrypto);\n\n /**\n * Override `SubtleCrypto#exportKey`\n */\n const originalExportKey = originalSubtleCrypto.exportKey as SubtleCrypto[\"exportKey\"] | undefined;\n originalSubtleCrypto.exportKey = (async (...args: Parameters<SubtleCrypto[\"exportKey\"]>) => {\n const [_, key] = args;\n if (isPolyfilledKey(key)) {\n return await exportKeyPolyfill(...args);\n } else if (originalExportKey) {\n return await originalExportKey.apply(originalSubtleCrypto, args);\n } else {\n throw new TypeError(\"No native `exportKey` function exists to handle this call\");\n }\n }) as SubtleCrypto[\"exportKey\"];\n\n /**\n * Override `SubtleCrypto#generateKey`\n */\n const originalGenerateKey = originalSubtleCrypto.generateKey as SubtleCrypto[\"generateKey\"] | undefined;\n let originalGenerateKeySupportsEd25519: Promise<boolean> | boolean | undefined;\n originalSubtleCrypto.generateKey = (async (...args: Parameters<SubtleCrypto[\"generateKey\"]>) => {\n const [algorithm] = args;\n if (algorithm !== \"Ed25519\") {\n if (originalGenerateKey) {\n return await originalGenerateKey.apply(originalSubtleCrypto, args);\n } else {\n throw new TypeError(\"No native `generateKey` function exists to handle this call\");\n }\n }\n let optimisticallyGeneratedKeyPair;\n if (originalGenerateKeySupportsEd25519 === undefined) {\n originalGenerateKeySupportsEd25519 = new Promise((resolve) => {\n if (!originalGenerateKey) {\n resolve((originalGenerateKeySupportsEd25519 = false));\n return;\n }\n originalGenerateKey\n .apply(originalSubtleCrypto, args)\n .then((keyPair) => {\n if (__DEV__) {\n console.warn(\n \"`webcrypto-ed25519-polyfill` was installed in an \" +\n \"environment that supports Ed25519 key manipulation \" +\n \"natively. Falling back to the native implementation. \" +\n \"Consider installing this polyfill only in environments where \" +\n \"Ed25519 is not supported.\",\n );\n }\n if (originalSubtleCrypto.generateKey !== originalGenerateKey) {\n originalSubtleCrypto.generateKey = originalGenerateKey;\n }\n optimisticallyGeneratedKeyPair = keyPair;\n resolve((originalGenerateKeySupportsEd25519 = true));\n })\n .catch(() => {\n resolve((originalGenerateKeySupportsEd25519 = false));\n });\n });\n }\n if (\n typeof originalGenerateKeySupportsEd25519 === \"boolean\"\n ? originalGenerateKeySupportsEd25519\n : await originalGenerateKeySupportsEd25519\n ) {\n if (optimisticallyGeneratedKeyPair) {\n return optimisticallyGeneratedKeyPair;\n } else if (originalGenerateKey) {\n return await originalGenerateKey.apply(originalSubtleCrypto, args);\n } else {\n throw new TypeError(\"No native `generateKey` function exists to handle this call\");\n }\n } else {\n const [_, extractable, keyUsages] = args;\n return generateKeyPolyfill(extractable, keyUsages);\n }\n }) as SubtleCrypto[\"generateKey\"];\n\n /**\n * Override `SubtleCrypto#sign`\n */\n const originalSign = originalSubtleCrypto.sign as SubtleCrypto[\"sign\"] | undefined;\n originalSubtleCrypto.sign = (async (...args: Parameters<SubtleCrypto[\"sign\"]>) => {\n const [_, key] = args;\n if (isPolyfilledKey(key)) {\n const [_, ...rest] = args;\n return await signPolyfill(...rest);\n } else if (originalSign) {\n return await originalSign.apply(originalSubtleCrypto, args);\n } else {\n throw new TypeError(\"No native `sign` function exists to handle this call\");\n }\n }) as SubtleCrypto[\"sign\"];\n\n /**\n * Override `SubtleCrypto#verify`\n */\n const originalVerify = originalSubtleCrypto.verify as SubtleCrypto[\"verify\"] | undefined;\n originalSubtleCrypto.verify = (async (...args: Parameters<SubtleCrypto[\"verify\"]>) => {\n const [_, key] = args;\n if (isPolyfilledKey(key)) {\n const [_, ...rest] = args;\n return await verifyPolyfill(...rest);\n } else if (originalVerify) {\n return await originalVerify.apply(originalSubtleCrypto, args);\n } else {\n throw new TypeError(\"No native `verify` function exists to handle this call\");\n }\n }) as SubtleCrypto[\"verify\"];\n\n /**\n * Override `SubtleCrypto#importKey`\n */\n const originalImportKey = originalSubtleCrypto.importKey as SubtleCrypto[\"importKey\"] | undefined;\n let originalImportKeySupportsEd25519: Promise<boolean> | boolean | undefined;\n originalSubtleCrypto.importKey = (async (...args: Parameters<SubtleCrypto[\"importKey\"]>) => {\n const [format, keyData, algorithm] = args;\n if (algorithm !== \"Ed25519\") {\n if (originalImportKey) {\n return await originalImportKey.apply(originalSubtleCrypto, args);\n } else {\n throw new TypeError(\"No native `importKey` function exists to handle this call\");\n }\n }\n let optimisticallyImportedKey;\n if (originalImportKeySupportsEd25519 === undefined) {\n originalImportKeySupportsEd25519 = new Promise((resolve) => {\n if (!originalImportKey) {\n resolve((originalImportKeySupportsEd25519 = false));\n return;\n }\n originalImportKey\n .apply(originalSubtleCrypto, args)\n .then((key) => {\n if (__DEV__) {\n console.warn(\n \"`webcrypto-ed25519-polyfill` was included in an \" +\n \"environment that supports Ed25519 key manipulation \" +\n \"natively. Falling back to the native implementation. \" +\n \"Consider including this polyfill only in environments where \" +\n \"Ed25519 is not supported.\",\n );\n }\n if (originalSubtleCrypto.importKey !== originalImportKey) {\n originalSubtleCrypto.importKey = originalImportKey;\n }\n optimisticallyImportedKey = key;\n resolve((originalImportKeySupportsEd25519 = true));\n })\n .catch(() => {\n resolve((originalImportKeySupportsEd25519 = false));\n });\n });\n }\n if (\n typeof originalImportKey === \"boolean\"\n ? originalImportKeySupportsEd25519\n : await originalImportKeySupportsEd25519\n ) {\n if (optimisticallyImportedKey) {\n return optimisticallyImportedKey;\n } else if (originalImportKey) {\n return await originalImportKey.apply(originalSubtleCrypto, args);\n } else {\n throw new TypeError(\"No native `importKey` function exists to handle this call\");\n }\n } else {\n const [_format, _keyData, _algorithm, extractable, keyUsages] = args;\n return importKeyPolyfill(format, keyData, extractable, keyUsages);\n }\n }) as SubtleCrypto[\"importKey\"];\n }\n}\n","import crypto from \"uncrypto\";\n\nimport type { ReadonlyUint8Array } from \"./codecs/types\";\n\nfunction assertIsSecureContext() {\n if (!__NODEJS__ && __BROWSER__ && !globalThis.isSecureContext) {\n throw new Error(\"Must be in a secure context (HTTPS, localhost, file://)\");\n }\n}\n\nlet cachedEd25519Decision: PromiseLike<boolean> | boolean | undefined;\nasync function isEd25519CurveSupported(subtle: SubtleCrypto): Promise<boolean> {\n if (cachedEd25519Decision === undefined) {\n cachedEd25519Decision = new Promise((resolve) => {\n subtle\n .generateKey(\"Ed25519\", /* extractable */ false, [\"sign\", \"verify\"])\n .catch(() => {\n resolve((cachedEd25519Decision = false));\n })\n .then(() => {\n resolve((cachedEd25519Decision = true));\n });\n });\n }\n if (typeof cachedEd25519Decision === \"boolean\") {\n return cachedEd25519Decision;\n } else {\n return await cachedEd25519Decision;\n }\n}\n\nexport function assertDigestCapabilityIsAvailable(): void {\n assertIsSecureContext();\n if (typeof crypto === \"undefined\" || typeof crypto.subtle?.digest !== \"function\") {\n throw new Error(\"SubtleCrypto.digest is not available\");\n }\n}\n\nexport async function assertKeyGenerationIsAvailable(): Promise<void> {\n assertIsSecureContext();\n if (typeof crypto === \"undefined\" || typeof crypto.subtle?.generateKey !== \"function\") {\n throw new Error(\"SubtleCrypto.generateKey is not available\");\n }\n if (!(await isEd25519CurveSupported(crypto.subtle))) {\n throw new Error(\"Ed25519 curve is not supported\");\n }\n}\n\nexport function assertKeyExporterIsAvailable(): void {\n assertIsSecureContext();\n if (typeof crypto === \"undefined\" || typeof crypto.subtle?.exportKey !== \"function\") {\n throw new Error(\"SubtleCrypto.exportKey is not available\");\n }\n}\n\nexport function assertSigningCapabilityIsAvailable(): void {\n assertIsSecureContext();\n if (typeof crypto === \"undefined\" || typeof crypto.subtle?.sign !== \"function\") {\n throw new Error(\"SubtleCrypto.sign is not available\");\n }\n}\n\nexport function assertVerificationCapabilityIsAvailable(): void {\n assertIsSecureContext();\n if (typeof crypto === \"undefined\" || typeof crypto.subtle?.verify !== \"function\") {\n throw new Error(\"SubtleCrypto.verify is not available\");\n }\n}\n\nexport function assertPRNGIsAvailable(): void {\n if (typeof crypto === \"undefined\" || typeof crypto.getRandomValues !== \"function\") {\n throw new Error(\"Crypto.getRandomValues is not available\");\n }\n}\n\n/**\n * Asserts that a given byte array is not empty.\n */\nexport function assertByteArrayIsNotEmptyForCodec(\n codecDescription: string,\n bytes: ReadonlyUint8Array | Uint8Array,\n offset = 0,\n): void {\n if (bytes.length - offset <= 0) {\n throw new Error(`Empty byte array for ${codecDescription}`);\n }\n}\n\n/**\n * Asserts that a given byte array has enough bytes to decode.\n */\nexport function assertByteArrayHasEnoughBytesForCodec(\n codecDescription: string,\n expected: number,\n bytes: ReadonlyUint8Array | Uint8Array,\n offset = 0,\n): void {\n const bytesLength = bytes.length - offset;\n if (bytesLength < expected) {\n throw new Error(`Not enough bytes to decode ${codecDescription}. Expected: ${expected}, Actual: ${bytesLength}`);\n }\n}\n\n/**\n * Asserts that a given offset is within the byte array bounds.\n * This range is between 0 and the byte array length and is inclusive.\n * An offset equals to the byte array length is considered a valid offset\n * as it allows the post-offset of codecs to signal the end of the byte array.\n */\nexport function assertByteArrayOffsetIsNotOutOfRange(\n codecDescription: string,\n offset: number,\n bytesLength: number,\n): void {\n if (offset < 0 || offset > bytesLength) {\n throw new Error(`Offset is out of range for ${codecDescription}: ${offset}`);\n }\n}\n\n/**\n * Asserts that a given string matches a given alphabet.\n */\nexport function assertValidBaseString(alphabet: string, testValue: string, givenValue: string = testValue): void {\n if (!testValue.match(new RegExp(`^[${alphabet}]*$`))) {\n throw new Error(`Invalid base${alphabet.length} string: ${givenValue}`);\n }\n}\n","import type { ReadonlyUint8Array } from \"./types\";\nimport { assertByteArrayHasEnoughBytesForCodec } from \"../assertions\";\n\n/**\n * Defines an offset in bytes.\n */\nexport type Offset = number;\n\ntype BaseEncoder<TFrom> = {\n /** Encode the provided value and return the encoded bytes directly. */\n readonly encode: (value: TFrom) => ReadonlyUint8Array;\n /**\n * Writes the encoded value into the provided byte array at the given offset.\n * Returns the offset of the next byte after the encoded value.\n */\n readonly write: (value: TFrom, bytes: Uint8Array, offset: Offset) => Offset;\n};\n\nexport type FixedSizeEncoder<TFrom, TSize extends number = number> = BaseEncoder<TFrom> & {\n /** The fixed size of the encoded value in bytes. */\n readonly fixedSize: TSize;\n};\n\nexport type VariableSizeEncoder<TFrom> = BaseEncoder<TFrom> & {\n /** The total size of the encoded value in bytes. */\n readonly getSizeFromValue: (value: TFrom) => number;\n /** The maximum size an encoded value can be in bytes, if applicable. */\n readonly maxSize?: number;\n};\n\n/**\n * An object that can encode a value to a `Uint8Array`.\n */\nexport type Encoder<TFrom> = FixedSizeEncoder<TFrom> | VariableSizeEncoder<TFrom>;\n\ntype BaseDecoder<TTo> = {\n /** Decodes the provided byte array at the given offset (or zero) and returns the value directly. */\n readonly decode: (bytes: ReadonlyUint8Array | Uint8Array, offset?: Offset) => TTo;\n /**\n * Reads the encoded value from the provided byte array at the given offset.\n * Returns the decoded value and the offset of the next byte after the encoded value.\n */\n readonly read: (bytes: ReadonlyUint8Array | Uint8Array, offset: Offset) => [TTo, Offset];\n};\n\nexport type FixedSizeDecoder<TTo, TSize extends number = number> = BaseDecoder<TTo> & {\n /** The fixed size of the encoded value in bytes. */\n readonly fixedSize: TSize;\n};\n\nexport type VariableSizeDecoder<TTo> = BaseDecoder<TTo> & {\n /** The maximum size an encoded value can be in bytes, if applicable. */\n readonly maxSize?: number;\n};\n\n/**\n * An object that can decode a value from a `Uint8Array`.\n */\nexport type Decoder<TTo> = FixedSizeDecoder<TTo> | VariableSizeDecoder<TTo>;\n\nexport type FixedSizeCodec<TFrom, TTo extends TFrom = TFrom, TSize extends number = number> = FixedSizeDecoder<\n TTo,\n TSize\n> &\n FixedSizeEncoder<TFrom, TSize>;\n\nexport type VariableSizeCodec<TFrom, TTo extends TFrom = TFrom> = VariableSizeDecoder<TTo> & VariableSizeEncoder<TFrom>;\n\n/**\n * An object that can encode and decode a value to and from a `Uint8Array`.\n * It supports encoding looser types than it decodes for convenience.\n * For example, a `bigint` encoder will always decode to a `bigint`\n * but can be used to encode a `number`.\n *\n * @typeParam TFrom - The type of the value to encode.\n * @typeParam TTo - The type of the decoded value. Defaults to `TFrom`.\n */\nexport type Codec<TFrom, TTo extends TFrom = TFrom> = FixedSizeCodec<TFrom, TTo> | VariableSizeCodec<TFrom, TTo>;\n\n/**\n * Get the encoded size of a given value in bytes.\n */\nexport function getEncodedSize<TFrom>(\n value: TFrom,\n encoder: { fixedSize: number } | { getSizeFromValue: (value: TFrom) => number },\n): number {\n return \"fixedSize\" in encoder ? encoder.fixedSize : encoder.getSizeFromValue(value);\n}\n\n/** Fills the missing `encode` function using the existing `write` function. */\nexport function createEncoder<TFrom, TSize extends number>(\n encoder: Omit<FixedSizeEncoder<TFrom, TSize>, \"encode\">,\n): FixedSizeEncoder<TFrom, TSize>;\nexport function createEncoder<TFrom>(encoder: Omit<VariableSizeEncoder<TFrom>, \"encode\">): VariableSizeEncoder<TFrom>;\nexport function createEncoder<TFrom>(\n encoder: Omit<FixedSizeEncoder<TFrom>, \"encode\"> | Omit<VariableSizeEncoder<TFrom>, \"encode\">,\n): Encoder<TFrom>;\nexport function createEncoder<TFrom>(\n encoder: Omit<FixedSizeEncoder<TFrom>, \"encode\"> | Omit<VariableSizeEncoder<TFrom>, \"encode\">,\n): Encoder<TFrom> {\n return Object.freeze({\n ...encoder,\n encode: (value) => {\n const bytes = new Uint8Array(getEncodedSize(value, encoder));\n encoder.write(value, bytes, 0);\n return bytes;\n },\n });\n}\n\n/** Fills the missing `decode` function using the existing `read` function. */\nexport function createDecoder<TTo, TSize extends number>(\n decoder: Omit<FixedSizeDecoder<TTo, TSize>, \"decode\">,\n): FixedSizeDecoder<TTo, TSize>;\nexport function createDecoder<TTo>(decoder: Omit<VariableSizeDecoder<TTo>, \"decode\">): VariableSizeDecoder<TTo>;\nexport function createDecoder<TTo>(\n decoder: Omit<FixedSizeDecoder<TTo>, \"decode\"> | Omit<VariableSizeDecoder<TTo>, \"decode\">,\n): Decoder<TTo>;\nexport function createDecoder<TTo>(\n decoder: Omit<FixedSizeDecoder<TTo>, \"decode\"> | Omit<VariableSizeDecoder<TTo>, \"decode\">,\n): Decoder<TTo> {\n return Object.freeze({\n ...decoder,\n decode: (bytes, offset = 0) => decoder.read(bytes, offset)[0],\n });\n}\n\n/** Fills the missing `encode` and `decode` function using the existing `write` and `read` functions. */\nexport function createCodec<TFrom, TTo extends TFrom = TFrom, TSize extends number = number>(\n codec: Omit<FixedSizeCodec<TFrom, TTo, TSize>, \"decode\" | \"encode\">,\n): FixedSizeCodec<TFrom, TTo, TSize>;\nexport function createCodec<TFrom, TTo extends TFrom = TFrom>(\n codec: Omit<VariableSizeCodec<TFrom, TTo>, \"decode\" | \"encode\">,\n): VariableSizeCodec<TFrom, TTo>;\nexport function createCodec<TFrom, TTo extends TFrom = TFrom>(\n codec:\n | Omit<FixedSizeCodec<TFrom, TTo>, \"decode\" | \"encode\">\n | Omit<VariableSizeCodec<TFrom, TTo>, \"decode\" | \"encode\">,\n): Codec<TFrom, TTo>;\nexport function createCodec<TFrom, TTo extends TFrom = TFrom>(\n codec:\n | Omit<FixedSizeCodec<TFrom, TTo>, \"decode\" | \"encode\">\n | Omit<VariableSizeCodec<TFrom, TTo>, \"decode\" | \"encode\">,\n): Codec<TFrom, TTo> {\n return Object.freeze({\n ...codec,\n decode: (bytes, offset = 0) => codec.read(bytes, offset)[0],\n encode: (value) => {\n const bytes = new Uint8Array(getEncodedSize(value, codec));\n codec.write(value, bytes, 0);\n return bytes;\n },\n });\n}\n\nexport function isFixedSize<TFrom, TSize extends number>(\n encoder: FixedSizeEncoder<TFrom, TSize> | VariableSizeEncoder<TFrom>,\n): encoder is FixedSizeEncoder<TFrom, TSize>;\nexport function isFixedSize<TTo, TSize extends number>(\n decoder: FixedSizeDecoder<TTo, TSize> | VariableSizeDecoder<TTo>,\n): decoder is FixedSizeDecoder<TTo, TSize>;\nexport function isFixedSize<TFrom, TTo extends TFrom, TSize extends number>(\n codec: FixedSizeCodec<TFrom, TTo, TSize> | VariableSizeCodec<TFrom, TTo>,\n): codec is FixedSizeCodec<TFrom, TTo, TSize>;\nexport function isFixedSize<TSize extends number>(\n codec: { fixedSize: TSize } | { maxSize?: number },\n): codec is { fixedSize: TSize };\nexport function isFixedSize(codec: { fixedSize: number } | { maxSize?: number }): codec is { fixedSize: number } {\n return \"fixedSize\" in codec && typeof codec.fixedSize === \"number\";\n}\n\nexport function assertIsFixedSize<TFrom, TSize extends number>(\n encoder: FixedSizeEncoder<TFrom, TSize> | VariableSizeEncoder<TFrom>,\n): asserts encoder is FixedSizeEncoder<TFrom, TSize>;\nexport function assertIsFixedSize<TTo, TSize extends number>(\n decoder: FixedSizeDecoder<TTo, TSize> | VariableSizeDecoder<TTo>,\n): asserts decoder is FixedSizeDecoder<TTo, TSize>;\nexport function assertIsFixedSize<TFrom, TTo extends TFrom, TSize extends number>(\n codec: FixedSizeCodec<TFrom, TTo, TSize> | VariableSizeCodec<TFrom, TTo>,\n): asserts codec is FixedSizeCodec<TFrom, TTo, TSize>;\nexport function assertIsFixedSize<TSize extends number>(\n codec: { fixedSize: TSize } | { maxSize?: number },\n): asserts codec is { fixedSize: TSize };\nexport function assertIsFixedSize(\n codec: { fixedSize: number } | { maxSize?: number },\n): asserts codec is { fixedSize: number } {\n if (!isFixedSize(codec)) {\n throw new Error(\"expected a fixed size codec\");\n }\n}\n\nexport function isVariableSize<TFrom>(encoder: Encoder<TFrom>): encoder is VariableSizeEncoder<TFrom>;\nexport function isVariableSize<TTo>(decoder: Decoder<TTo>): decoder is VariableSizeDecoder<TTo>;\nexport function isVariableSize<TFrom, TTo extends TFrom>(\n codec: Codec<TFrom, TTo>,\n): codec is VariableSizeCodec<TFrom, TTo>;\nexport function isVariableSize(codec: { fixedSize: number } | { maxSize?: number }): codec is { maxSize?: number };\nexport function isVariableSize(codec: { fixedSize: number } | { maxSize?: number }): codec is { maxSize?: number } {\n return !isFixedSize(codec);\n}\n\nexport function assertIsVariableSize<T>(encoder: Encoder<T>): asserts encoder is VariableSizeEncoder<T>;\nexport function assertIsVariableSize<T>(decoder: Decoder<T>): asserts decoder is VariableSizeDecoder<T>;\nexport function assertIsVariableSize<TFrom, TTo extends TFrom>(\n codec: Codec<TFrom, TTo>,\n): asserts codec is VariableSizeCodec<TFrom, TTo>;\nexport function assertIsVariableSize(\n codec: { fixedSize: number } | { maxSize?: number },\n): asserts codec is { maxSize?: number };\nexport function assertIsVariableSize(\n codec: { fixedSize: number } | { maxSize?: number },\n): asserts codec is { maxSize?: number } {\n if (!isVariableSize(codec)) {\n throw new Error(\"expected a variable size codec\");\n }\n}\n\n/**\n * Converts an encoder A to a encoder B by mapping their values.\n */\nexport function transformEncoder<TOldFrom, TNewFrom, TSize extends number>(\n encoder: FixedSizeEncoder<TOldFrom, TSize>,\n unmap: (value: TNewFrom) => TOldFrom,\n): FixedSizeEncoder<TNewFrom, TSize>;\nexport function transformEncoder<TOldFrom, TNewFrom>(\n encoder: VariableSizeEncoder<TOldFrom>,\n unmap: (value: TNewFrom) => TOldFrom,\n): VariableSizeEncoder<TNewFrom>;\nexport function transformEncoder<TOldFrom, TNewFrom>(\n encoder: Encoder<TOldFrom>,\n unmap: (value: TNewFrom) => TOldFrom,\n): Encoder<TNewFrom>;\nexport function transformEncoder<TOldFrom, TNewFrom>(\n encoder: Encoder<TOldFrom>,\n unmap: (value: TNewFrom) => TOldFrom,\n): Encoder<TNewFrom> {\n return createEncoder({\n ...(isVariableSize(encoder)\n ? { ...encoder, getSizeFromValue: (value: TNewFrom) => encoder.getSizeFromValue(unmap(value)) }\n : encoder),\n write: (value: TNewFrom, bytes, offset) => encoder.write(unmap(value), bytes, offset),\n });\n}\n\n/**\n * Converts an decoder A to a decoder B by mapping their values.\n */\nexport function transformDecoder<TOldTo, TNewTo, TSize extends number>(\n decoder: FixedSizeDecoder<TOldTo, TSize>,\n map: (value: TOldTo, bytes: ReadonlyUint8Array | Uint8Array, offset: number) => TNewTo,\n): FixedSizeDecoder<TNewTo, TSize>;\nexport function transformDecoder<TOldTo, TNewTo>(\n decoder: VariableSizeDecoder<TOldTo>,\n map: (value: TOldTo, bytes: ReadonlyUint8Array | Uint8Array, offset: number) => TNewTo,\n): VariableSizeDecoder<TNewTo>;\nexport function transformDecoder<TOldTo, TNewTo>(\n decoder: Decoder<TOldTo>,\n map: (value: TOldTo, bytes: ReadonlyUint8Array | Uint8Array, offset: number) => TNewTo,\n): Decoder<TNewTo>;\nexport function transformDecoder<TOldTo, TNewTo>(\n decoder: Decoder<TOldTo>,\n map: (value: TOldTo, bytes: ReadonlyUint8Array | Uint8Array, offset: number) => TNewTo,\n): Decoder<TNewTo> {\n return createDecoder({\n ...decoder,\n read: (bytes: ReadonlyUint8Array | Uint8Array, offset) => {\n const [value, newOffset] = decoder.read(bytes, offset);\n return [map(value, bytes, offset), newOffset];\n },\n });\n}\n\n/**\n * Combines an encoder and a decoder into a codec.\n * The encoder and decoder must have the same fixed size, max size and description.\n * If a description is provided, it will override the encoder and decoder descriptions.\n */\nexport function combineCodec<TFrom, TTo extends TFrom, TSize extends number>(\n encoder: FixedSizeEncoder<TFrom, TSize>,\n decoder: FixedSizeDecoder<TTo, TSize>,\n): FixedSizeCodec<TFrom, TTo, TSize>;\nexport function combineCodec<TFrom, TTo extends TFrom>(\n encoder: VariableSizeEncoder<TFrom>,\n decoder: VariableSizeDecoder<TTo>,\n): VariableSizeCodec<TFrom, TTo>;\nexport function combineCodec<TFrom, TTo extends TFrom>(\n encoder: Encoder<TFrom>,\n decoder: Decoder<TTo>,\n): Codec<TFrom, TTo>;\nexport function combineCodec<TFrom, TTo extends TFrom>(\n encoder: Encoder<TFrom>,\n decoder: Decoder<TTo>,\n): Codec<TFrom, TTo> {\n if (isFixedSize(encoder) !== isFixedSize(decoder)) {\n throw new Error(\"encoder and decoder size compatibility mismatch\");\n }\n\n if (isFixedSize(encoder) && isFixedSize(decoder) && encoder.fixedSize !== decoder.fixedSize) {\n throw new Error(`encoder and decoder fixed size mismatch ${encoder.fixedSize} !== ${decoder.fixedSize}`);\n }\n\n if (!isFixedSize(encoder) && !isFixedSize(decoder) && encoder.maxSize !== decoder.maxSize) {\n throw new Error(`encoder and decoder max size mismatch ${encoder.maxSize} !== ${decoder.maxSize}`);\n }\n\n return {\n ...decoder,\n ...encoder,\n decode: decoder.decode,\n encode: encoder.encode,\n read: decoder.read,\n write: encoder.write,\n };\n}\n\n/**\n * Converts a codec A to a codec B by mapping their values.\n */\nexport function transformCodec<TOldFrom, TNewFrom, TTo extends TNewFrom & TOldFrom, TSize extends number>(\n codec: FixedSizeCodec<TOldFrom, TTo, TSize>,\n unmap: (value: TNewFrom) => TOldFrom,\n): FixedSizeCodec<TNewFrom, TTo, TSize>;\nexport function transformCodec<TOldFrom, TNewFrom, TTo extends TNewFrom & TOldFrom>(\n codec: VariableSizeCodec<TOldFrom, TTo>,\n unmap: (value: TNewFrom) => TOldFrom,\n): VariableSizeCodec<TNewFrom, TTo>;\nexport function transformCodec<TOldFrom, TNewFrom, TTo extends TNewFrom & TOldFrom>(\n codec: Codec<TOldFrom, TTo>,\n unmap: (value: TNewFrom) => TOldFrom,\n): Codec<TNewFrom, TTo>;\nexport function transformCodec<\n TOldFrom,\n TNewFrom,\n TOldTo extends TOldFrom,\n TNewTo extends TNewFrom,\n TSize extends number,\n>(\n codec: FixedSizeCodec<TOldFrom, TOldTo, TSize>,\n unmap: (value: TNewFrom) => TOldFrom,\n map: (value: TOldTo, bytes: ReadonlyUint8Array | Uint8Array, offset: number) => TNewTo,\n): FixedSizeCodec<TNewFrom, TNewTo, TSize>;\nexport function transformCodec<TOldFrom, TNewFrom, TOldTo extends TOldFrom, TNewTo extends TNewFrom>(\n codec: VariableSizeCodec<TOldFrom, TOldTo>,\n unmap: (value: TNewFrom) => TOldFrom,\n map: (value: TOldTo, bytes: ReadonlyUint8Array | Uint8Array, offset: number) => TNewTo,\n): VariableSizeCodec<TNewFrom, TNewTo>;\nexport function transformCodec<TOldFrom, TNewFrom, TOldTo extends TOldFrom, TNewTo extends TNewFrom>(\n codec: Codec<TOldFrom, TOldTo>,\n unmap: (value: TNewFrom) => TOldFrom,\n map: (value: TOldTo, bytes: ReadonlyUint8Array | Uint8Array, offset: number) => TNewTo,\n): Codec<TNewFrom, TNewTo>;\nexport function transformCodec<TOldFrom, TNewFrom, TOldTo extends TOldFrom, TNewTo extends TNewFrom>(\n codec: Codec<TOldFrom, TOldTo>,\n unmap: (value: TNewFrom) => TOldFrom,\n map?: (value: TOldTo, bytes: ReadonlyUint8Array | Uint8Array, offset: number) => TNewTo,\n): Codec<TNewFrom, TNewTo> {\n return createCodec({\n ...transformEncoder(codec, unmap),\n read: map ? transformDecoder(codec, map).read : (codec.read as unknown as Decoder<TNewTo>[\"read\"]),\n });\n}\n\n/**\n * Concatenates an array of `Uint8Array`s into a single `Uint8Array`.\n * Reuses the original byte array when applicable.\n */\nexport const mergeBytes = (byteArrays: Uint8Array[]): Uint8Array => {\n const nonEmptyByteArrays = byteArrays.filter((arr) => arr.length);\n if (nonEmptyByteArrays.length === 0) {\n return byteArrays.length ? byteArrays[0]! : new Uint8Array();\n }\n\n if (nonEmptyByteArrays.length === 1) {\n return nonEmptyByteArrays[0]!;\n }\n\n const totalLength = nonEmptyByteArrays.reduce((total, arr) => total + arr.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n nonEmptyByteArrays.forEach((arr) => {\n result.set(arr, offset);\n offset += arr.length;\n });\n return result;\n};\n\n/**\n * Pads a `Uint8Array` with zeroes to the specified length.\n * If the array is longer than the specified length, it is returned as-is.\n */\nexport const padBytes = (bytes: ReadonlyUint8Array | Uint8Array, length: number): ReadonlyUint8Array | Uint8Array => {\n if (bytes.length >= length) return bytes;\n const paddedBytes = new Uint8Array(length).fill(0);\n paddedBytes.set(bytes);\n return paddedBytes;\n};\n\n/**\n * Fixes a `Uint8Array` to the specified length.\n * If the array is longer than the specified length, it is truncated.\n * If the array is shorter than the specified length, it is padded with zeroes.\n */\nexport const fixBytes = (bytes: ReadonlyUint8Array | Uint8Array, length: number): ReadonlyUint8Array | Uint8Array =>\n padBytes(bytes.length <= length ? bytes : bytes.slice(0, length), length);\n\n/**\n * Returns true if and only if the provided `data` byte array contains\n * the provided `bytes` byte array at the specified `offset`.\n */\nexport function containsBytes(\n data: ReadonlyUint8Array | Uint8Array,\n bytes: ReadonlyUint8Array | Uint8Array,\n offset: number,\n): boolean {\n const slice = offset === 0 && data.length === bytes.length ? data : data.slice(offset, offset + bytes.length);\n if (slice.length !== bytes.length) return false;\n return bytes.every((b, i) => b === slice[i]);\n}\n\n/**\n * Creates a fixed-size encoder from a given encoder.\n *\n * @param encoder - The encoder to wrap into a fixed-size encoder.\n * @param fixedBytes - The fixed number of bytes to write.\n */\nexport function fixEncoderSize<TFrom, TSize extends number>(\n encoder: Encoder<TFrom>,\n fixedBytes: TSize,\n): FixedSizeEncoder<TFrom, TSize> {\n return createEncoder({\n fixedSize: fixedBytes,\n write: (value: TFrom, bytes: Uint8Array, offset: Offset) => {\n // Here we exceptionally use the `encode` function instead of the `write`\n // function as using the nested `write` function on a fixed-sized byte\n // array may result in a out-of-bounds error on the nested encoder.\n const variableByteArray = encoder.encode(value);\n const fixedByteArray =\n variableByteArray.length > fixedBytes ? variableByteArray.slice(0, fixedBytes) : variableByteArray;\n bytes.set(fixedByteArray, offset);\n return offset + fixedBytes;\n },\n });\n}\n\n/**\n * Creates a fixed-size decoder from a given decoder.\n *\n * @param decoder - The decoder to wrap into a fixed-size decoder.\n * @param fixedBytes - The fixed number of bytes to read.\n */\nexport function fixDecoderSize<TTo, TSize extends number>(\n decoder: Decoder<TTo>,\n fixedBytes: TSize,\n): FixedSizeDecoder<TTo, TSize> {\n return createDecoder({\n fixedSize: fixedBytes,\n read: (bytes, offset) => {\n assertByteArrayHasEnoughBytesForCodec(\"fixCodecSize\", fixedBytes, bytes, offset);\n // Slice the byte array to the fixed size if necessary.\n if (offset > 0 || bytes.length > fixedBytes) {\n bytes = bytes.slice(offset, offset + fixedBytes);\n }\n // If the nested decoder is fixed-size, pad and truncate the byte array accordingly.\n if (isFixedSize(decoder)) {\n bytes = fixBytes(bytes, decoder.f