Skip to content

Commit

Permalink
Merge pull request #194 from privacy-scaling-explorations/feat/hex-to…
Browse files Browse the repository at this point in the history
…-buffer

Add new utility functions to convert hex and buffers
  • Loading branch information
cedoor committed Mar 8, 2024
2 parents e18dd6a + 5126ddd commit 8071815
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 16 deletions.
31 changes: 28 additions & 3 deletions packages/utils/src/conversions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
* the order of bytes is always big-endian.
*/

import { isBigInt, isHexadecimal, isNumber, isStringifiedBigInt } from "./type-checks"
import { requireHexadecimal, requireTypes } from "./error-handlers"
import { isBigInt, isBuffer, isHexadecimal, isNumber, isStringifiedBigInt } from "./type-checks"
import { BigNumber, BigNumberish } from "./types"

/**
Expand Down Expand Up @@ -176,9 +177,33 @@ export function bigNumberishToBigInt(n: BigNumberish): bigint {
* @returns The buffer representation of the BigNumberish value.
*/
export function bigNumberishToBuffer(n: BigNumberish): Buffer {
if (n instanceof Buffer) {
return n
if (isBuffer(n)) {
return n as Buffer
}

return bigIntToBuffer(bigNumberishToBigInt(n))
}

/**
* Converts an hexadecimal string to a buffer. The hexadecimal string
* should not start with '0x' or '0X'. It keeps the bytes in the same order.
* @param value The hexadecimal string to convert.
* @returns The buffer representation of the hexadecimal string.
*/
export function hexadecimalToBuffer(value: string): Buffer {
requireHexadecimal(value, "value", false)

return Buffer.from(value, "hex")
}

/**
* Converts a buffer to a hexadecimal string. It accepts 'Buffer' or 'Uint8Array'.
* The hexadecimal string will not start with '0x' or '0X'. It keeps the bytes in the same order.
* @param value The buffer to convert.
* @returns The converted hexadecimal string.
*/
export function bufferToHexadecimal(value: Buffer | Uint8Array): string {
requireTypes(value, "value", ["Buffer", "Uint8Array"])

return Buffer.from(value).toString("hex")
}
20 changes: 18 additions & 2 deletions packages/utils/src/error-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
isArray,
isBigInt,
isBigNumberish,
isBuffer,
isDefined,
isFunction,
isHexadecimal,
Expand Down Expand Up @@ -91,6 +92,17 @@ export function requireUint8Array(parameterValue: Uint8Array, parameterName: str
}
}

/**
* @throws Throws a type error if the parameter value is not a Buffer.
* @param parameterValue The parameter value.
* @param parameterName The parameter name.
*/
export function requireBuffer(parameterValue: Buffer, parameterName: string) {
if (!isBuffer(parameterValue)) {
throw new TypeError(`Parameter '${parameterName}' is not a Buffer instance`)
}
}

/**
* @throws Throws a type error if the parameter value is not an object.
* Please, note that arrays are also objects in JavaScript.
Expand Down Expand Up @@ -127,11 +139,15 @@ export function requireStringifiedBigInt(parameterValue: string, parameterName:

/**
* @throws Throws a type error if the parameter value is not a hexadecimal string.
* If 'prefix' is 'true', the string must start with '0x' or '0X' followed by one or more
* hexadecimal digits (0-9, a-f, A-F), otherwise no prefix is expected. 'prefix' is optional and
* if its value it is not explicitly defined it will be set to 'true' by default.
* @param parameterValue The parameter value.
* @param parameterName The parameter name.
* @param prefix A boolean to include or not a '0x' or '0X' prefix.
*/
export function requireHexadecimal(parameterValue: string, parameterName: string) {
if (!isHexadecimal(parameterValue)) {
export function requireHexadecimal(parameterValue: string, parameterName: string, prefix = true) {
if (!isHexadecimal(parameterValue, prefix)) {
throw new TypeError(`Parameter '${parameterName}' is not a hexadecimal string`)
}
}
Expand Down
32 changes: 22 additions & 10 deletions packages/utils/src/type-checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const supportedTypes = [
"function",
"Array",
"Uint8Array",
"Buffer",
"object",
"bigint",
"stringified-bigint",
Expand Down Expand Up @@ -81,6 +82,14 @@ export function isUint8Array(value: any): boolean {
return value instanceof Uint8Array
}

/**
* Returns true if the value is a Buffer instance, false otherwise.
* @param value The value to be checked.
*/
export function isBuffer(value: any): boolean {
return Buffer.isBuffer(value)
}

/**
* Returns true if the value is a bigint, false otherwise.
* @param value The value to be checked.
Expand Down Expand Up @@ -111,11 +120,18 @@ export function isStringifiedBigInt(value: any): boolean {

/**
* Checks if a string is a valid hexadecimal string representation.
* The string must start with '0x' or '0X' followed by one or more hexadecimal digits (0-9, a-f, A-F).
* If 'prefix' is 'true', the string must start with '0x' or '0X' followed by one or more
* hexadecimal digits (0-9, a-f, A-F), otherwise no prefix is expected. 'prefix' is optional and
* if its value it is not explicitly defined it will be set to 'true' by default.
* @param value The string to be tested.
* @param prefix A boolean to include or not a '0x' or '0X' prefix.
*/
export function isHexadecimal(value: any) {
return /^(0x|0X)[0-9a-fA-F]+$/.test(value)
export function isHexadecimal(value: any, prefix = true) {
if (prefix) {
return /^(0x|0X)[0-9a-fA-F]+$/.test(value)
}

return /^[0-9a-fA-F]+$/.test(value)
}

/**
Expand All @@ -127,13 +143,7 @@ export function isHexadecimal(value: any) {
* @param value The value to check.
*/
export function isBigNumberish(value: any): boolean {
return (
isNumber(value) ||
isBigInt(value) ||
isStringifiedBigInt(value) ||
isHexadecimal(value) ||
Buffer.isBuffer(value)
)
return isNumber(value) || isBigInt(value) || isStringifiedBigInt(value) || isHexadecimal(value) || isBuffer(value)
}

/**
Expand All @@ -153,6 +163,8 @@ export function isType(value: any, type: SupportedType): boolean {
return isArray(value)
case "Uint8Array":
return isUint8Array(value)
case "Buffer":
return isBuffer(value)
case "object":
return isObject(value)
case "bigint":
Expand Down
30 changes: 30 additions & 0 deletions packages/utils/tests/conversions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {
bigIntToHexadecimal,
bigNumberishToBigInt,
bigNumberishToBuffer,
bufferToHexadecimal,
hexadecimalToBigInt,
hexadecimalToBuffer,
leBigIntToBuffer,
leBufferToBigInt
} from "../src/conversions"
Expand Down Expand Up @@ -103,6 +105,34 @@ describe("Conversions", () => {
})
})

describe("# bufferToHexadecimal", () => {
it("Should convert a BE buffer to a hexadecimal string", async () => {
const result = bufferToHexadecimal(Buffer.from(testBytes1))

expect(result).toBe(testHex1BE.slice(2))
})

it("Should throw an error if the input is not a valid buffer (BE)", async () => {
const fun = () => bufferToHexadecimal(1 as any)

expect(fun).toThrow("Parameter 'value' is none of the following types: Buffer, Uint8Array")
})
})

describe("# hexadecimalToBuffer", () => {
it("Should convert a BE hexadecimal string to a buffer", async () => {
const result = hexadecimalToBuffer(testHex1BE.slice(2))

expect(result).toStrictEqual(Buffer.from(testBytes1))
})

it("Should throw an error if the input is not a valid hexadecimal (BE)", async () => {
const fun = () => hexadecimalToBuffer("0x12")

expect(fun).toThrow("Parameter 'value' is not a hexadecimal string")
})
})

describe("BigInt to/from Buffer Conversions", () => {
it("Should support little-endian conversions", async () => {
const in1 = Buffer.from(testBytes1)
Expand Down
13 changes: 13 additions & 0 deletions packages/utils/tests/error-handlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
requireArray,
requireBigInt,
requireBigNumberish,
requireBuffer,
requireDefined,
requireFunction,
requireHexadecimal,
Expand Down Expand Up @@ -74,6 +75,18 @@ describe("# error-handlers", () => {
expect(fun).not.toThrow()
})

it("Should throw an error if the parameter is not a Buffer", () => {
const fun = () => requireBuffer([] as any, "parameter")

expect(fun).toThrow("Parameter 'parameter' is not a Buffer instance")
})

it("Should not throw an error if the parameter is a Buffer", () => {
const fun = () => requireBuffer(Buffer.from("buffer"), "parameter")

expect(fun).not.toThrow()
})

it("Should throw an error if the parameter is not a function", () => {
const fun = () => requireFunction(1 as any, "parameter")

Expand Down
13 changes: 12 additions & 1 deletion packages/utils/tests/type-checks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
isArray,
isBigInt,
isBigNumberish,
isBuffer,
isFunction,
isHexadecimal,
isNumber,
Expand Down Expand Up @@ -46,14 +47,22 @@ describe("# type-checks", () => {
expect(isArray(1)).toBeFalsy()
})

it("Should return true if the value is a Uint8Array instance", () => {
it("Should return true if the value is a Uint8Array", () => {
expect(isUint8Array(new Uint8Array([]))).toBeTruthy()
})

it("Should return false if the value is not a Uint8Array", () => {
expect(isUint8Array(1)).toBeFalsy()
})

it("Should return true if the value is a Buffer", () => {
expect(isBuffer(Buffer.from("buffer"))).toBeTruthy()
})

it("Should return false if the value is not a Buffer", () => {
expect(isBuffer(1)).toBeFalsy()
})

it("Should return true if the value is an object", () => {
expect(isObject({})).toBeTruthy()
})
Expand Down Expand Up @@ -105,6 +114,7 @@ describe("# type-checks", () => {
expect(isType(() => true, "function")).toBeTruthy()
expect(isType([], "Array")).toBeTruthy()
expect(isType(new Uint8Array([]), "Uint8Array")).toBeTruthy()
expect(isType(Buffer.from("buffer"), "Buffer")).toBeTruthy()
expect(isType({}, "object")).toBeTruthy()
expect(isType(BigInt(1), "bigint")).toBeTruthy()
expect(isType("1242342342342342", "stringified-bigint")).toBeTruthy()
Expand All @@ -118,6 +128,7 @@ describe("# type-checks", () => {
expect(isType(1, "function")).toBeFalsy()
expect(isType(1, "Array")).toBeFalsy()
expect(isType(1, "Uint8Array")).toBeFalsy()
expect(isType(1, "Buffer")).toBeFalsy()
expect(isType(1, "object")).toBeFalsy()
expect(isType(1, "bigint")).toBeFalsy()
expect(isType(1, "stringified-bigint")).toBeFalsy()
Expand Down

0 comments on commit 8071815

Please sign in to comment.