diff --git a/src/abstract/utils.ts b/src/abstract/utils.ts index bf8a09f..0647295 100644 --- a/src/abstract/utils.ts +++ b/src/abstract/utils.ts @@ -33,15 +33,34 @@ export function abool(title: string, value: boolean): void { if (typeof value !== 'boolean') throw new Error(title + ' boolean expected, got ' + value); } +export function numberToHexUnpadded(num: number | bigint): string { + const hex = num.toString(16); + return hex.length & 1 ? '0' + hex : hex; +} + +export function hexToNumber(hex: string): bigint { + if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex); + return hex === '' ? _0n : BigInt('0x' + hex); // Big Endian +} + +// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex +const hasHexBuiltin: boolean = + // @ts-ignore + typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function'; + // Array where index 0xf0 (240) is mapped to string 'f0' const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0') ); + /** + * Convert byte array to hex string. Uses built-in function, when available. * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123' */ export function bytesToHex(bytes: Uint8Array): string { abytes(bytes); + // @ts-ignore + if (hasHexBuiltin) return bytes.toHex(); // pre-caching improves the speed 6x let hex = ''; for (let i = 0; i < bytes.length; i++) { @@ -50,16 +69,6 @@ export function bytesToHex(bytes: Uint8Array): string { return hex; } -export function numberToHexUnpadded(num: number | bigint): string { - const hex = num.toString(16); - return hex.length & 1 ? '0' + hex : hex; -} - -export function hexToNumber(hex: string): bigint { - if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex); - return hex === '' ? _0n : BigInt('0x' + hex); // Big Endian -} - // We use optimized technique to convert hex string to byte array const asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const; function asciiToBase16(ch: number): number | undefined { @@ -70,10 +79,13 @@ function asciiToBase16(ch: number): number | undefined { } /** + * Convert hex string to byte array. Uses built-in function, when available. * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23]) */ export function hexToBytes(hex: string): Uint8Array { if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex); + // @ts-ignore + if (hasHexBuiltin) return Uint8Array.fromHex(hex); const hl = hex.length; const al = hl / 2; if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);