From 93cbb5187e1a0a308fe3a5614cf73eb84ed19501 Mon Sep 17 00:00:00 2001 From: Brian Faust Date: Wed, 7 Sep 2022 06:26:46 +0300 Subject: [PATCH] feat(util): implement `assertIsUint8Array` --- packages/util/src/account.ts | 44 ++++++++++++++++++---------------- packages/util/src/address.ts | 10 ++++---- packages/util/src/bytes.ts | 39 +++++++++++++++--------------- packages/util/src/helpers.ts | 11 +++++++++ packages/util/src/signature.ts | 4 ++-- packages/util/src/types.ts | 1 - 6 files changed, 61 insertions(+), 48 deletions(-) diff --git a/packages/util/src/account.ts b/packages/util/src/account.ts index 0c811af408..92b0343b66 100644 --- a/packages/util/src/account.ts +++ b/packages/util/src/account.ts @@ -13,7 +13,7 @@ import { zeros, } from './bytes' import { KECCAK256_NULL, KECCAK256_RLP } from './constants' -import { assertIsBuffer, assertIsHexString, assertIsString } from './helpers' +import { assertIsHexString, assertIsString, assertIsUint8Array } from './helpers' import { stripHexPrefix } from './internal' import type { BigIntLike, BufferLike } from './types' @@ -44,8 +44,8 @@ export class Account { ) } - public static fromRlpSerializedAccount(serialized: Buffer) { - const values = arrToBufArr(RLP.decode(Uint8Array.from(serialized)) as Uint8Array[]) as Buffer[] + public static fromRlpSerializedAccount(serialized: Uint8Array) { + const values = arrToBufArr(RLP.decode(serialized) as Uint8Array[]) as Buffer[] if (!Array.isArray(values)) { throw new Error('Invalid serialized account input. Must be array') @@ -194,9 +194,9 @@ export const isValidChecksumAddress = function ( * @param from The address which is creating this new address * @param nonce The nonce of the from account */ -export const generateAddress = function (from: Buffer, nonce: Buffer): Buffer { - assertIsBuffer(from) - assertIsBuffer(nonce) +export const generateAddress = function (from: Buffer, nonce: Uint8Array): Buffer { + assertIsUint8Array(from) + assertIsUint8Array(nonce) if (bufferToBigInt(nonce) === BigInt(0)) { // in RLP we want to encode null in the case of zero nonce @@ -214,10 +214,14 @@ export const generateAddress = function (from: Buffer, nonce: Buffer): Buffer { * @param salt A salt * @param initCode The init code of the contract being created */ -export const generateAddress2 = function (from: Buffer, salt: Buffer, initCode: Buffer): Buffer { - assertIsBuffer(from) - assertIsBuffer(salt) - assertIsBuffer(initCode) +export const generateAddress2 = function ( + from: Uint8Array, + salt: Uint8Array, + initCode: Uint8Array +): Buffer { + assertIsUint8Array(from) + assertIsUint8Array(salt) + assertIsUint8Array(initCode) if (from.length !== 20) { throw new Error('Expected from to be of length 20') @@ -236,7 +240,7 @@ export const generateAddress2 = function (from: Buffer, salt: Buffer, initCode: /** * Checks if the private key satisfies the rules of the curve secp256k1. */ -export const isValidPrivate = function (privateKey: Buffer): boolean { +export const isValidPrivate = function (privateKey: Uint8Array): boolean { return utils.isValidPrivateKey(privateKey) } @@ -247,7 +251,7 @@ export const isValidPrivate = function (privateKey: Buffer): boolean { * @param sanitize Accept public keys in other formats */ export const isValidPublic = function (publicKey: Buffer, sanitize: boolean = false): boolean { - assertIsBuffer(publicKey) + assertIsUint8Array(publicKey) if (publicKey.length === 64) { // Convert to SEC1 for secp256k1 // Automatically checks whether point is on curve @@ -278,7 +282,7 @@ export const isValidPublic = function (publicKey: Buffer, sanitize: boolean = fa * @param sanitize Accept public keys in other formats */ export const pubToAddress = function (pubKey: Buffer, sanitize: boolean = false): Buffer { - assertIsBuffer(pubKey) + assertIsUint8Array(pubKey) if (sanitize && pubKey.length !== 64) { pubKey = Buffer.from(Point.fromHex(pubKey).toRawBytes(false).slice(1)) } @@ -286,7 +290,7 @@ export const pubToAddress = function (pubKey: Buffer, sanitize: boolean = false) throw new Error('Expected pubKey to be of length 64') } // Only take the lower 160bits of the hash - return Buffer.from(keccak256(pubKey)).slice(-20) + return Buffer.from(keccak256(pubKey).slice(-20)) } export const publicToAddress = pubToAddress @@ -294,8 +298,8 @@ export const publicToAddress = pubToAddress * Returns the ethereum public key of a given private key. * @param privateKey A private key must be 256 bits wide */ -export const privateToPublic = function (privateKey: Buffer): Buffer { - assertIsBuffer(privateKey) +export const privateToPublic = function (privateKey: Uint8Array): Buffer { + assertIsUint8Array(privateKey) // skip the type flag and use the X, Y points return Buffer.from(Point.fromPrivateKey(privateKey).toRawBytes(false).slice(1)) } @@ -304,19 +308,19 @@ export const privateToPublic = function (privateKey: Buffer): Buffer { * Returns the ethereum address of a given private key. * @param privateKey A private key must be 256 bits wide */ -export const privateToAddress = function (privateKey: Buffer): Buffer { +export const privateToAddress = function (privateKey: Uint8Array): Buffer { return publicToAddress(privateToPublic(privateKey)) } /** * Converts a public key to the Ethereum format. */ -export const importPublic = function (publicKey: Buffer): Buffer { - assertIsBuffer(publicKey) +export const importPublic = function (publicKey: Uint8Array): Buffer { + assertIsUint8Array(publicKey) if (publicKey.length !== 64) { publicKey = Buffer.from(Point.fromHex(publicKey).toRawBytes(false).slice(1)) } - return publicKey + return toBuffer(publicKey) } /** diff --git a/packages/util/src/address.ts b/packages/util/src/address.ts index a70532e875..3542cd7a55 100644 --- a/packages/util/src/address.ts +++ b/packages/util/src/address.ts @@ -10,11 +10,11 @@ import { bigIntToBuffer, bufferToBigInt, toBuffer, zeros } from './bytes' export class Address { public readonly buf: Buffer - constructor(buf: Buffer) { + constructor(buf: Uint8Array) { if (buf.length !== 20) { throw new Error('Invalid address length') } - this.buf = buf + this.buf = toBuffer(buf) } /** @@ -39,7 +39,7 @@ export class Address { * Returns an address for a given public key. * @param pubKey The two points of an uncompressed key */ - static fromPublicKey(pubKey: Buffer): Address { + static fromPublicKey(pubKey: Uint8Array): Address { if (!Buffer.isBuffer(pubKey)) { throw new Error('Public key should be Buffer') } @@ -51,7 +51,7 @@ export class Address { * Returns an address for a given private key. * @param privateKey A private key must be 256 bits wide */ - static fromPrivateKey(privateKey: Buffer): Address { + static fromPrivateKey(privateKey: Uint8Array): Address { if (!Buffer.isBuffer(privateKey)) { throw new Error('Private key should be Buffer') } @@ -77,7 +77,7 @@ export class Address { * @param salt A salt * @param initCode The init code of the contract being created */ - static generate2(from: Address, salt: Buffer, initCode: Buffer): Address { + static generate2(from: Address, salt: Buffer, initCode: Uint8Array): Address { if (!Buffer.isBuffer(salt)) { throw new Error('Expected salt to be a Buffer') } diff --git a/packages/util/src/bytes.ts b/packages/util/src/bytes.ts index cd19851c47..f01791d9f1 100644 --- a/packages/util/src/bytes.ts +++ b/packages/util/src/bytes.ts @@ -1,8 +1,7 @@ -import { assertIsArray, assertIsBuffer, assertIsHexString } from './helpers' +import { assertIsArray, assertIsHexString, assertIsUint8Array } from './helpers' import { isHexPrefixed, isHexString, padToEven, stripHexPrefix } from './internal' import type { - NestedBufferArray, NestedUint8Array, PrefixedHexString, TransformableToArray, @@ -72,7 +71,7 @@ const setLength = function (msg: Buffer, length: number, right: boolean) { * @return (Buffer) */ export const setLengthLeft = function (msg: Buffer, length: number) { - assertIsBuffer(msg) + assertIsUint8Array(msg) return setLength(msg, length, false) } @@ -84,7 +83,7 @@ export const setLengthLeft = function (msg: Buffer, length: number) { * @return (Buffer) */ export const setLengthRight = function (msg: Buffer, length: number) { - assertIsBuffer(msg) + assertIsUint8Array(msg) return setLength(msg, length, true) } @@ -107,8 +106,8 @@ const stripZeros = function (a: any): Buffer | number[] | string { * @param a (Buffer) * @return (Buffer) */ -export const unpadBuffer = function (a: Buffer): Buffer { - assertIsBuffer(a) +export const unpadBuffer = function (a: Uint8Array): Buffer { + assertIsUint8Array(a) return stripZeros(a) as Buffer } @@ -202,15 +201,15 @@ export const toBuffer = function (v: ToBufferInputTypes): Buffer { * Converts a `Buffer` into a `0x`-prefixed hex `String`. * @param buf `Buffer` object to convert */ -export const bufferToHex = function (buf: Buffer): string { +export const bufferToHex = function (buf: Uint8Array): string { buf = toBuffer(buf) - return '0x' + buf.toString('hex') + return '0x' + Buffer.from(buf).toString('hex') } /** * Converts a {@link Buffer} to a {@link bigint} */ -export function bufferToBigInt(buf: Buffer) { +export function bufferToBigInt(buf: Uint8Array) { const hex = bufferToHex(buf) if (hex === '0x') { return BigInt(0) @@ -230,7 +229,7 @@ export function bigIntToBuffer(num: bigint) { * @param buf `Buffer` object to convert * @throws If the input number exceeds 53 bits. */ -export const bufferToInt = function (buf: Buffer): number { +export const bufferToInt = function (buf: Uint8Array): number { const res = Number(bufferToBigInt(buf)) if (!Number.isSafeInteger(res)) throw new Error('Number exceeds 53 bits') return res @@ -240,7 +239,7 @@ export const bufferToInt = function (buf: Buffer): number { * Interprets a `Buffer` as a signed integer and returns a `BigInt`. Assumes 256-bit numbers. * @param num Signed integer value */ -export const fromSigned = function (num: Buffer): bigint { +export const fromSigned = function (num: Uint8Array): bigint { return BigInt.asIntN(256, bufferToBigInt(num)) } @@ -346,12 +345,12 @@ export const validateNoLeadingZeroes = function (values: { [key: string]: Buffer } /** - * Converts a {@link Uint8Array} or {@link NestedUint8Array} to {@link Buffer} or {@link NestedBufferArray} + * Converts a {@link Uint8Array} or {@link NestedUint8Array} to {@link Buffer} or {@link NestedUint8Array} */ export function arrToBufArr(arr: Uint8Array): Buffer -export function arrToBufArr(arr: NestedUint8Array): NestedBufferArray -export function arrToBufArr(arr: Uint8Array | NestedUint8Array): Buffer | NestedBufferArray -export function arrToBufArr(arr: Uint8Array | NestedUint8Array): Buffer | NestedBufferArray { +export function arrToBufArr(arr: NestedUint8Array): NestedUint8Array +export function arrToBufArr(arr: Uint8Array | NestedUint8Array): Buffer | NestedUint8Array +export function arrToBufArr(arr: Uint8Array | NestedUint8Array): Buffer | NestedUint8Array { if (!Array.isArray(arr)) { return Buffer.from(arr) } @@ -359,12 +358,12 @@ export function arrToBufArr(arr: Uint8Array | NestedUint8Array): Buffer | Nested } /** - * Converts a {@link Buffer} or {@link NestedBufferArray} to {@link Uint8Array} or {@link NestedUint8Array} + * Converts a {@link Buffer} or {@link NestedUint8Array} to {@link Uint8Array} or {@link NestedUint8Array} */ -export function bufArrToArr(arr: Buffer): Uint8Array -export function bufArrToArr(arr: NestedBufferArray): NestedUint8Array -export function bufArrToArr(arr: Buffer | NestedBufferArray): Uint8Array | NestedUint8Array -export function bufArrToArr(arr: Buffer | NestedBufferArray): Uint8Array | NestedUint8Array { +export function bufArrToArr(arr: Uint8Array): Uint8Array +export function bufArrToArr(arr: NestedUint8Array): NestedUint8Array +export function bufArrToArr(arr: Uint8Array | NestedUint8Array): Uint8Array | NestedUint8Array +export function bufArrToArr(arr: Uint8Array | NestedUint8Array): Uint8Array | NestedUint8Array { if (!Array.isArray(arr)) { return Uint8Array.from(arr ?? []) } diff --git a/packages/util/src/helpers.ts b/packages/util/src/helpers.ts index 297dbb0f8c..ead6e94ec8 100644 --- a/packages/util/src/helpers.ts +++ b/packages/util/src/helpers.ts @@ -22,6 +22,17 @@ export const assertIsBuffer = function (input: Buffer): void { } } +/** + * Throws if input is not a `Uint8Array` + * @param {Buffer} input value to check + */ +export const assertIsUint8Array = function (input: Uint8Array): void { + if (!(input instanceof Uint8Array)) { + const msg = `This method only supports Buffer but input was: ${input}` + throw new Error(msg) + } +} + /** * Throws if input is not an array * @param {number[]} input value to check diff --git a/packages/util/src/signature.ts b/packages/util/src/signature.ts index 6294b1656a..63529b8f7f 100644 --- a/packages/util/src/signature.ts +++ b/packages/util/src/signature.ts @@ -3,7 +3,7 @@ import { recoverPublicKey, signSync } from 'ethereum-cryptography/secp256k1' import { bufferToBigInt, bufferToHex, bufferToInt, setLengthLeft, toBuffer } from './bytes' import { SECP256K1_ORDER, SECP256K1_ORDER_DIV_2 } from './constants' -import { assertIsBuffer } from './helpers' +import { assertIsUint8Array } from './helpers' export interface ECDSASignature { v: bigint @@ -187,7 +187,7 @@ export const isValidSignature = function ( * used to produce the signature. */ export const hashPersonalMessage = function (message: Buffer): Buffer { - assertIsBuffer(message) + assertIsUint8Array(message) const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${message.length}`, 'utf-8') return Buffer.from(keccak256(Buffer.concat([prefix, message]))) } diff --git a/packages/util/src/types.ts b/packages/util/src/types.ts index 6c007c0fe2..0867a4c9e3 100644 --- a/packages/util/src/types.ts +++ b/packages/util/src/types.ts @@ -48,7 +48,6 @@ export interface TransformableToBuffer { } export type NestedUint8Array = Array -export type NestedBufferArray = Array /** * Type output options