@pact-toolbox/crypto
Version:
1 lines • 78.7 kB
Source Map (JSON)
{"version":3,"file":"index.node.mjs","names":["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>","alphabet","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.node.mjs","../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"],"sourcesContent":["import nodeCrypto from 'node:crypto';\n\nconst subtle = nodeCrypto.webcrypto?.subtle || {};\nconst randomUUID = () => {\n return nodeCrypto.randomUUID();\n};\nconst getRandomValues = (array) => {\n return nodeCrypto.webcrypto.getRandomValues(array);\n};\nconst _crypto = {\n randomUUID,\n getRandomValues,\n subtle\n};\n\nexport { _crypto as default, getRandomValues, randomUUID, subtle };\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.fixedSize);\n }\n // Decode the value using the nested decoder.\n const [value] = decoder.read(bytes, 0);\n return [value, offset + fixedBytes];\n },\n });\n}\n\n/**\n * Creates a fixed-size codec from a given codec.\n *\n * @param codec - The codec to wrap into a fixed-size codec.\n * @param fixedBytes - The fixed number of bytes to read/write.\n */\nexport function fixCodecSize<TFrom, TTo extends TFrom, TSize extends number>(\n codec: Codec<TFrom, TTo>,\n fixedBytes: TSize,\n): FixedSizeCodec<TFrom, TTo, TSize> {\n return combineCodec(fixEncoderSize(codec, fixedBytes), fixDecoderSize(codec, fixedBytes));\n}\n","import type { VariableSizeCodec, VariableSizeDecoder, VariableSizeEncoder } from \"../core\";\nimport { combineCodec, createDecoder, createEncoder } from \"../core\";\n\nconst enum HexC {\n ZERO = 48, // 0\n NINE = 57, // 9\n A_UP = 65, // A\n F_UP = 70, // F\n A_LO = 97, // a\n F_LO = 102, // f\n}\n\nfunction charCodeToBase16(char: number) {\n if (char >= HexC.ZERO && char <= HexC.NINE) return char - HexC.ZERO;\n if (char >= HexC.A_UP && char <= HexC.F_UP) return char - (HexC.A_UP - 10);\n if (char >= HexC.A_LO && char <= HexC.F_LO) return char - (HexC.A_LO - 10);\n}\n\n/** Encodes strings in base16. */\nexport function getBase16Encoder(): VariableSizeEncoder<string> {\n return createEncoder({\n getSizeFromValue: (value: string) => Math.ceil(value.length / 2),\n write(value: string, bytes, offset) {\n const len = value.length;\n const al = len / 2;\n if (len === 1) {\n const c = value.charCodeAt(0);\n const n = charCodeToBase16(c);\n if (n === undefined) {\n throw new Error(`Invalid string for base16: ${value}`);\n }\n bytes.set([n], offset);\n return 1 + offset;\n }\n const hexBytes = new Uint8Array(al);\n for (let i = 0, j = 0; i < al; i++) {\n const c1 = value.charCodeAt(j++);\n const c2 = value.charCodeAt(j++);\n\n const n1 = charCodeToBase16(c1);\n const n2 = charCodeToBase16(c2);\n if (n1 === undefined || (n2 === undefined && !Number.isNaN(c2))) {\n throw new Error(`Invalid string for base16: ${value}`);\n }\n hexBytes[i] = !Number.isNaN(c2) ? (n1 << 4) | (n2 ?? 0) : n1;\n }\n\n bytes.set(hexBytes, offset);\n return hexBytes.length + offset;\n },\n });\n}\n\n/** Decodes strings in base16. */\nexport function getBase16Decoder(): VariableSizeDecoder<string> {\n return createDecoder({\n read(bytes, offset) {\n const value = bytes.slice(offset).reduce((str, byte) => str + byte.toString(16).padStart(2, \"0\"), \"\");\n return [value, bytes.length];\n },\n });\n}\n\n/** Encodes and decodes strings in base16. */\nexport function getBase16Codec(): VariableSizeCodec<string> {\n return combineCodec(getBase16Encoder(), getBase16Decoder());\n}\n\nexport const base16: VariableSizeCodec<string> = getBase16Codec();\n","import type { Encoder } from \"../codecs/core\";\nimport type { ReadonlyUint8Array } from \"../codecs/types\";\nimport { assertSigningCapabilityIsAvailable, assertVerificationCapabilityIsAvailable } from \"../assertions\";\nimport { getBase16Encoder } from \"../codecs/strings/base16\";\n\nexport type Signature = string & { readonly __brand: unique symbol };\nexport type SignatureBytes = Uint8Array & { readonly __brand: unique symbol };\n\nlet base16Encoder: Encoder<string> | undefined;\n\nexport function assertIsSignature(putativeSignature: string): asserts putativeSignature is Signature {\n if (!base16Encoder) base16Encoder = getBase16Encoder();\n // Fast-path; see if the input string is of an acceptable length.\n if (\n // Lowest value (64 bytes of zeroes)\n putativeSignature.length < 64 ||\n // Highest value (64 bytes of 255)\n putativeSignature.length > 88\n ) {\n throw new Error(`Invalid signature length: ${putativeSignature.length} out of range`);\n }\n // Slow-path; actually attempt to decode the input string.\n const bytes = base16Encoder.encode(putativeSignature);\n const numBytes = bytes.byteLength;\n if (numBytes !== 64) {\n throw new Error(`Invalid signature length: ${numBytes} bytes`);\n }\n}\n\nexport function isSignature(putativeSignature: string): putativeSignature is Signature {\n if (!base16Encoder) base16Encoder = getBase16Encoder();\n\n // Fast-path; see if the input string is of an acceptable length.\n if (\n // Lowest value (64 bytes of zeroes)\n putativeSignature.length < 64 ||\n // Highest value (64 bytes of 255)\n putativeSignature.length > 88\n ) {\n return false;\n }\n // Slow-path; actually attempt to decode the input string.\n const bytes = base16Encoder.encode(putativeSignature);\n const numBytes = bytes.byteLength;\n if (numBytes !== 64) {\n return false;\n }\n return true;\n}\n\nexport async function signBytes(key: CryptoKey, data: ReadonlyUint8Array): Promise<SignatureBytes> {\n assertSigningCapabilityIsAvailable();\n const signedData = await crypto.subtle.sign(\"Ed25519\", key, data);\n return new Uint8Array(signedData) as SignatureBytes;\n}\n\nexport function signature(putativeSignature: string): Signature {\n assertIsSignature(putativeSignature);\n return putativeSignature;\n}\n\nexport async function verifySignature(\n key: CryptoKey,\n signature: SignatureBytes,\n data: ReadonlyUint8Array | Uint8Array,\n): Promise<boolean> {\n assertVerificationCapabilityIsAvailable();\n return await crypto.subtle.verify(\"Ed25519\", key, signature, data);\n}\n","import crypto from \"uncrypto\";\n\nimport type { ReadonlyUint8Array } from \"../codecs/types\";\nimport { assertKeyExporterIsAvailable, assertKeyGenerationIsAvailable, assertPRNGIsAvailable } from \"../assertions\";\nimport { signBytes, verifySignature } from \"./signatures\";\n\nfunction addPkcs8Header(bytes: ReadonlyUint8Array): ReadonlyUint8Array {\n // prettier-ignore\n return new Uint8Array([\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 ...bytes\n ]);\n}\n\nexport async function createPrivateKeyFromBytes(bytes: ReadonlyUint8Array, extractable?: boolean): Promise<CryptoKey> {\n const actualLength = bytes.byteLength;\n if (actualLength !== 32) {\n throw new Error(`Invalid private key length: ${actualLength}`);\n }\n const privateKeyBytesPkcs8 = addPkcs8Header(bytes);\n return crypto.subtle.importKey(\"pkcs8\", privateKeyBytesPkcs8, \"Ed25519\", extractable ?? false, [\"sign\"]);\n}\n\nexport async function getPublicKeyFromPrivateKey(\n privateKey: CryptoKey,\n extractable: boolean = false,\n): Promise<CryptoKey> {\n assertKeyExporterIsAvailable();\n\n if (privateKey.extractable === false) {\n throw new Error(`Private key ${privateKey} is not extractable`);\n }\n\n // Export private key.\n const jwk = await crypto.subtle.exportKey(\"jwk\", privateKey);\n\n // Import public key.\n return await crypto.subtle.importKey(\n \"jwk\",\n {\n crv /* curve */: \"Ed25519\",\n ext /* extractable */: extractable,\n key_ops /* key operations */: [\"verify\"],\n kty /* key type */: \"OKP\" /* octet key pair */,\n x /* public key x-coordinate */: jwk.x,\n },\n \"Ed25519\",\n extractable,\n [\"verify\"],\n );\n}\n\nexport async function generateKeyPair(): Promise<CryptoKeyPair> {\n await assertKeyGenerationIsAvailable();\n const keyPair = await crypto.subtle.generateKey(\n /* algorithm */ \"Ed25519\", // Native implementation status: https://github.com/WICG/webcrypto-secure-curves/issues/20\n /* extractable */ false, // Prevents the bytes of the private key from being visible to JS.\n /* allowed uses */ [\"sign\", \"verify\"],\n );\n return keyPair as CryptoKeyPair;\n}\n\nexport async function generateExtractableKeyPair(): Promise<CryptoKeyPair> {\n await assertKeyGenerationIsAvailable();\n const keyPair = await crypto.subtle.generateKey(\"Ed25519\", true, [\"sign\", \"verify\"]);\n return keyPair as CryptoKeyPair;\n}\n\nexport async function createKeyPairFromBytes(bytes: ReadonlyUint8Array, extractable?: boolean): Promise<CryptoKeyPair> {\n assertPRNGIsAvailable();\n\n if (bytes.byteLength !== 64) {\n throw new Error(`invalid key pair length: ${bytes.byteLength}`);\n }\n const [publicKey, privateKey] = await Promise.all([\n crypto.subtle.importKey(\"raw\", bytes.slice(32), \"Ed25519\", /* extractable */ true, [\"verify\"]),\n createPrivateKeyFromBytes(bytes.slice(0, 32), extractable),\n ]);\n\n // Verify the key pair\n const randomBytes = new Uint8Array(32);\n crypto.getRandomValues(randomBytes);\n const signedData = await signBytes(privateKey, randomBytes);\n const isValid = await verifySignature(publicKey, signedData, randomBytes);\n if (!isValid) {\n throw new Error(\"public key must match private key\");\n }\n\n return { privateKey, publicKey } as CryptoKeyPair;\n}\n\nexport async function createKeyPairFromPrivateKeyBytes(\n bytes: ReadonlyUint8Array,\n extractable: boolean = false,\n): Promise<CryptoKeyPair> {\n const privateKeyPromise = createPrivateKeyFromBytes(bytes, extractable);\n\n // Here we need the private key to be extractable in order to export\n // it as a public key. Therefore, if the `extractable` parameter\n // is `false`, we need to create two private keys such that:\n // - The extractable one is used to create the public key and\n // - The non-extractable one is the one we will return.\n const [publicKey, privateKey] = await Promise.all([\n // This nested promise makes things efficient by\n // creating the public key in parallel with the\n // second private key creation, if it is needed.\n (extractable ? privateKeyPromise : createPrivateKeyFromBytes(bytes, true /* extractable */)).then(\n async (privateKey) => await getPublicKeyFromPrivateKey(privateKey, true /* extractable */),\n ),\n privateKeyPromise,\n ]);\n\n return { privateKey, publicKey };\n}\n","import type { FixedSizeCodec, FixedSizeDecoder, FixedSizeEncoder } from \"./codecs/core\";\nimport { assertKeyExporterIsAvailable } from \"./assertions\";\nimport { combineCodec, fixDecoderSize, fixEncoderSize, transformEncoder } from \"./codecs/core\";\nimport { base16 } from \"./codecs/strings/base16\";\nimport { generateExtractableKeyPair } from \"./keys/keys\";\n\nexport type Address<TAddress extends string = string> = TAddress & {\n readonly __brand: unique symbol;\n};\n\nexport function isAddress(putativeAddress: string): putativeAddress is Address<typeof putativeAddress> {\n // Fast-path; see if the input string is of an acceptable length.\n if (\n // Lowest address (32 bytes of zeroes)\n putativeAddress.length < 32 ||\n // Highest address (32 bytes of 255)\n putativeAddress.length > 44\n ) {\n return false;\n }\n // Slow-path; actually attempt to decode the input string.\n\n const bytes = base16.encode(putativeAddress);\n const numBytes = bytes.byteLength;\n if (numBytes !== 32) {\n return false;\n }\n return true;\n}\n\nexport function assertIsAddress(putativeAddress: string): asserts putativeAddress is Address<typeof putativeAddress> {\n // Fast-path; see if the input string is of an acceptable length.\n if (\n // Lowest address (32 bytes of zeroes)\n putativeAddress.length < 32 ||\n // Highest address (32 bytes of 255)\n putativeAddress.length > 44\n ) {\n throw new Error(`Invalid address length: ${putativeAddress.length} out of range`);\n }\n // Slow-path; actually attempt to decode the input string.\n const bytes = base16.encode(putativeAddress);\n const numBytes = bytes.byteLength;\n if (numBytes !== 32) {\n throw new Error(`Invalid address length: ${numBytes} bytes`);\n }\n}\n\nexport function address<TAddress extends string = string>(putativeAddress: TAddress): Address<TAddress> {\n assertIsAddress(putativeAddress);\n return putativeAddress as Address<TAddress>;\n}\n\nlet addressEncoder: FixedSizeEncoder<Address, 32> | undefined;\nlet addressDecoder: FixedSizeDecoder<Address, 32> | undefined;\nlet addressCodec: FixedSizeCodec<Address, Address, 32> | undefined;\nexport function getAddressEncoder(): FixedSizeEncoder<Address, 32> {\n return (addressEncoder ??= transformEncoder(fixEncoderSize(base16, 32), (putativeAddress) =>\n address(putativeAddress),\n ));\n}\n\nexport function getAddressDecoder(): FixedSizeDecoder<Address, 32> {\n return (addressDecoder ??= fixDecoderSize(base16, 32) as FixedSizeDecoder<Address, 32>);\n}\n\nexport function getAddressCodec(): FixedSizeCodec<Address, Address, 32> {\n return (addressCodec ??= combineCodec(getAddressEncoder(), getAddressDecoder()));\n}\n\nexport function getAddressComparator(): (x: string, y: string) => number {\n return new Intl.Collator(\"en\", {\n caseFirst: \"lower\",\n ignorePunctuation: false,\n localeMatcher: \"best fit\",\n numeric: false,\n sensitivity: \"variant\",\n usage: \"sort\",\n }).compare;\n}\n\nexport async function exportBase16Key(key: CryptoKey): Promise<string> {\n assertKeyExporterIsAvailable();\n if (!key.extractable || key.algorithm.name !== \"Ed25519\") {\n throw new Error(`Key is not extractable or has an invalid algorithm: ${key.algorithm.name}`);\n }\n const keyBytes = await crypto.subtle.exportKey(\"raw\", key);\n return getAddressDecoder().decode(new Uint8Array(keyBytes));\n}\n\nexport type KAccount = `k:${Address<string>}` & {\n readonly __brand: unique symbol;\n};\n\nexport function isKAccount(putativeAccount: string): putativeAccount is KAccount {\n return putativeAccount.startsWith(\"k:\") && isAddress(putativeAccount.slice(2));\n}\n\nexport function assertIsKAccount(putativeAccount: string): asserts putativeAccount is KAccount {\n if (!isKAccount(putativeAccount)) {\n throw new Error(`Invalid account: ${putativeAccount}`);\n }\n}\n\nexport function kAccount(putativeAccount: string): KAccount {\n assertIsKAccount(putativeAccount);\n return putativeAccount as KAccount;\n}\n\nexport async function getKAccountFromPublicKey(publicKey: CryptoKey): Promise<KAccount> {\n const address = await exportBase16Key(publicKey);\n return kAccount(`k:${address}`);\n}\n\ninterface KeyPair {\n publicKey: string;\n privateKey: string;\n}\nexport async function genKeyPair(): Promise<KeyPair> {\n const keyPair = await generateExtractableKeyPair();\n return {\n publicKey: await exportBase16Key(keyPair.publicKey),\n privateKey: await exportBase16Key(keyPair.privateKey),\n };\n}\n","import type { VariableSizeCodec, VariableSizeDecoder, VariableSizeEncoder } from \"../core\";\nimport { assertValidBaseString } from \"../../assertions\";\nimport { combineCodec, createDecoder, createEncoder } from \"../core\";\n\n/**\n * Encodes a string using a custom alphabet by dividing\n * by the base and handling leading zeroes.\n * @see {@link getBaseXCodec} for a more detailed description.\n */\nexport const getBaseXEncoder = (alphabet: string): VariableSizeEncoder<string> => {\n return createEncoder({\n getSizeFromValue: (value: string): number => {\n const [leadingZeroes, tailChars] = partitionLeadingZeroes(value, alphabet[0]!);\n if (!tailChars) return value.length;\n\n const base10Number = getBigIntFromBaseX(tailChars, alphabet);\n return leadingZeroes.length + Math.ceil(base10Number.toString(16).length / 2);\n },\n write(value: string, bytes, offset) {\n // Check if the value is valid.\n assertValidBaseString(alphabet, value);\n if (value === \"\") return offset;\n\n // Handle leading zeroes.\n const [leadingZeroes, tailChars] = partitionLeadingZeroes(value, alphabet[0]!);\n if (!tailChars) {\n bytes.set(new Uint8Array(leadingZeroes.length).fill(0), offset);\n return offset + leadingZeroes.length;\n }\n\n // From baseX to base10.\n let base10Number = getBigIntFromBaseX(tailChars, alphabet);\n\n // From base10 to bytes.\n const tailBytes: number[] = [];\n while (base10Number > 0n) {\n tailBytes.unshift(Number(base10Number % 256n));\n base10Number /= 256n;\n }\n\n const bytesToAdd = [...Array(leadingZeroes.length).fill(0), ...tailBytes];\n bytes.set(bytesToAdd, offset);\n return offset + bytesToAdd.length;\n },\n });\n};\n\n/**\n * Decodes a string using a custom alphabet by dividing\n * by the base and handling leading zeroes.\n * @see {@link getBaseXCodec} for a more detailed description.\n */\nexport const getBaseXDecoder = (alphabet: string): VariableSizeDecoder<string> => {\n return createDecoder({\n read(rawBytes, offset): [string, number] {\n const bytes = offset === 0 ? rawBytes : rawBytes.slice(offset);\n if (bytes.length === 0) return [\"\", 0];\n\n // Handle leading zeroes.\n let trailIndex = bytes.findIndex((n) => n !== 0);\n trailIndex = trailIndex === -1 ? bytes.length : trailIndex;\n const leadingZeroes = alphabet[0]!.repeat(trailIndex);\n if (trailIndex === bytes.length) return [leadingZeroes, rawBytes.length];\n\n // From bytes to base10.\n const base10Number = bytes.slice(trailIndex).reduce((sum, byte) => sum * 256n + BigInt(byte), 0n);\n\n // From base10 to baseX.\n const tailChars = getBaseXFromBigInt(base10Number, alphabet);\n\n return [leadingZeroes + tailChars, rawBytes.length];\n },\n });\n};\n\n/**\n * A string codec that requires a custom alphabet and uses\n * the length of that alphabet as the base. It then divides\n * the input by the base as many times as necessary to get\n * the output. It also supports leading zeroes by using the\n * first character of the alphabet as the zero character.\n *\n * This can be used to create codecs such as base10 or base58.\n */\nexport const getBaseXCodec = (alphabet: string): VariableSizeCodec<string> =>\n combineCodec(getBaseXEncoder(alphabet), getBaseXDecoder(alphabet));\n\nfunction partitionLeadingZeroes(\n value: string,\n zeroCharacter: string,\n): [leadingZeros: string, tailChars: string | undefined] {\n const [leadingZeros, tailChars] = value.split(new RegExp(`((?!${zeroCharacter}).*)`));\n return [leadingZeros!, tailChars];\n}\n\nfunction getBigIntFromBaseX(value: string, alphabet: string): bigint {\n const base = BigInt(alphabet.length);\n let sum = 0n;\n for (const char of value) {\n sum *= base;\n sum += BigInt(alphabet.indexOf(char));\n }\n return sum;\n}\n\nfunction getBaseXFromBigInt(value: bigint, alphabet: string): string {\n const base = BigInt(alphabet.length);\n const tailChars = [];\n while (value > 0n) {\n tailChars.unshift(alphabet[Number(value % base)]);\n value /= base;\n }\n return tailChars.join(\"\");\n}\n","import type { VariableSizeCodec, VariableSizeDecoder, VariableSizeEncoder } from \"../core\";\nimport { getBaseXCodec, getBaseXDecoder, getBaseXEncoder } from \"./baseX\";\n\nconst alphabet = \"0123456789\";\n\n/** Encodes strings in base10. */\nexport function getBase10Encoder(): VariableSizeEncoder<string> {\n return getBaseXEncoder(alphabet);\n}\n\n/** Decodes strings in base10. */\nexport function getBase10Decoder(): VariableSizeDecoder<string> {\n return getBaseXDecoder(alphabet);\n}\n\n/** Encodes and decodes strings in base10. */\nexport function getBase10Codec(): VariableSizeCodec<string> {\n return getBaseXCodec(alphabet);\n}\n\nexport const base10: VariableSizeCodec<string> = getBase10Codec();\n","import type { VariableSizeCodec, VariableSizeDecoder, VariableSizeEncoder } from \"../core\";\nimport { getBaseXCodec, getBaseXDecoder, getBaseXEncoder } from \"./baseX\";\n\nconst alphabet = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n\n/** Encodes strings in base58. */\nexport function getBase58Encoder(): VariableSizeEncoder<string> {\n return getBaseXEncoder(alphabet);\n}\n\n/** Decodes strings in base58. */\nexport function getBase58Decoder(): VariableSizeDecoder<string> {\n return getBaseXDecoder(alphabet);\n}\n\n/** Encodes and decodes strings in base58. */\nexport function getBase58Codec(): VariableSizeCodec<string> {\n return getBaseXCodec(alphabet);\n}\n\nexport const base58: VariableSizeCodec<string> = getBase58Codec();\n","import type { VariableSizeCodec, VariableSizeDecoder, VariableSizeEncoder } from \"../core\";\nimport { assertValidBaseString } from \"../../assertions\";\nimport { combineCodec, createDecoder, createEncoder } from \"../core\";\n\n/**\n * Encodes a string using a custom alphabet by reslicing the bits of the byte array.\n * @see {@link getBaseXResliceCodec} for a more detailed description.\n */\nexport function getBaseXResliceEncoder(alphabet: string, bits: number): VariableSizeEncoder<string> {\n return createEncoder({\n getSizeFromValue: (value: string) => Math.floor((value.length * bits) / 8),\n write(value: string, bytes, offset) {\n assertValidBaseString(alphabet, value);\n if (value === \"\") return offset;\n const charIndices = [...value].map((c) => alphabet.indexOf(c));\n const reslicedBytes = reslice(charIndices, bits, 8, false);\n bytes.set(reslicedBytes, offset);\n return reslicedBytes.length + offset;\n },\n });\n}\n\n/**\n * Decodes a string using a custom alphabet by reslicing the bits of the byte array.\