Skip to content

Commit

Permalink
Merge pull request #203 from privacy-scaling-explorations/refactor/co…
Browse files Browse the repository at this point in the history
…nversions-type-checks

Require right types in `conversions` module
  • Loading branch information
cedoor authored Mar 14, 2024
2 parents b9f868c + 3c7badc commit 2dbaa8d
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 44 deletions.
4 changes: 2 additions & 2 deletions packages/eddsa-poseidon/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ export function checkMessage(message: BigNumberish): bigint {
* @param message The input data to hash, provided as a Buffer.
* @returns A Buffer containing the 512-bit hash result.
*/
export function hash(message: Buffer): Buffer {
export function hash(message: Buffer | Uint8Array): Buffer {
const engine = new Blake512()

engine.update(message)
engine.update(Buffer.from(message))

return engine.digest()
}
94 changes: 55 additions & 39 deletions packages/utils/src/conversions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
*/

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

/**
* Converts a bigint to a hexadecimal string.
* @param n The bigint value to convert.
* @param value The bigint value to convert.
* @returns The hexadecimal representation of the bigint.
*/
export function bigIntToHexadecimal(n: bigint): string {
let hex = n.toString(16)
export function bigIntToHexadecimal(value: bigint): string {
requireBigInt(value, "value")

let hex = value.toString(16)

// Ensure even length.
if (hex.length % 2 !== 0) {
Expand All @@ -36,50 +38,60 @@ export function bigIntToHexadecimal(n: bigint): string {
/**
* Converts a hexadecimal string to a bigint. The input is interpreted as hexadecimal
* with or without a '0x' prefix. It uses big-endian byte order.
* @param hex The hexadecimal string to convert.
* @param value The hexadecimal string to convert.
* @returns The bigint representation of the hexadecimal string.
*/
export function beHexadecimalToBigInt(hex: string): bigint {
export function beHexadecimalToBigInt(value: string): bigint {
if (!isHexadecimal(value) && !isHexadecimal(value, false)) {
throw new TypeError(`Parameter 'value' is not a hexadecimal string`)
}

// Ensure the hex string starts with '0x'.
const formattedHexString = hex.startsWith("0x") ? hex : `0x${hex}`
const formattedHexString = value.startsWith("0x") ? value : `0x${value}`

return BigInt(formattedHexString)
}

/**
* Converts a hexadecimal string to a bigint. Alias for beHexadecimalToBigInt.
* @param hex The hexadecimal string to convert.
* @param value The hexadecimal string to convert.
* @returns The bigint representation of the hexadecimal string.
*/
export function hexadecimalToBigInt(hex: string): bigint {
return beHexadecimalToBigInt(hex)
export function hexadecimalToBigInt(value: string): bigint {
return beHexadecimalToBigInt(value)
}

/**
* Converts a buffer of bytes to a bigint using big-endian byte order.
* @param b The buffer to convert.
* It accepts 'Buffer' or 'Uint8Array'.
* @param value The buffer to convert.
* @returns The bigint representation of the buffer's contents.
*/
export function beBufferToBigInt(b: Buffer): bigint {
return BigInt(`0x${b.toString("hex")}`)
export function beBufferToBigInt(value: Buffer | Uint8Array): bigint {
requireTypes(value, "value", ["Buffer", "Uint8Array"])

return BigInt(`0x${Buffer.from(value).toString("hex")}`)
}

/**
* Converts a buffer to a bigint using little-endian byte order.
* @param buffer The buffer to convert.
* It accepts 'Buffer' or 'Uint8Array'.
* @param value The buffer to convert.
* @returns The bigint representation of the buffer's contents in little-endian.
*/
export function leBufferToBigInt(buffer: Buffer): bigint {
return BigInt(`0x${Buffer.from(buffer).reverse().toString("hex")}`)
export function leBufferToBigInt(value: Buffer | Uint8Array): bigint {
requireTypes(value, "value", ["Buffer", "Uint8Array"])

return BigInt(`0x${Buffer.from(value).reverse().toString("hex")}`)
}

/**
* Converts a buffer to a bigint. Alias for beBufferToBigInt.
* @param b The buffer to convert.
* @param value The buffer to convert.
* @returns The bigint representation of the buffer's contents.
*/
export function bufferToBigInt(b: Buffer): bigint {
return beBufferToBigInt(b)
export function bufferToBigInt(value: Buffer | Uint8Array): bigint {
return beBufferToBigInt(value)
}

/**
Expand All @@ -88,12 +100,12 @@ export function bufferToBigInt(b: Buffer): bigint {
* it gets the size from the given bigint. If the specified size is smaller than
* the size of the bigint (i.e. `minSize`), an error is thrown.
* It uses big-endian byte order.
* @param n The bigint to convert.
* @param value The bigint to convert.
* @param size The number of bytes of the buffer to return.
* @returns The buffer representation of the bigint.
*/
export function beBigIntToBuffer(n: bigint, size?: number): Buffer {
const hex = bigIntToHexadecimal(n)
export function beBigIntToBuffer(value: bigint, size?: number): Buffer {
const hex = bigIntToHexadecimal(value)

// Calculate the minimum buffer size required to represent 'n' in bytes.
// Each hexadecimal character represents 4 bits, so 2 characters are 1 byte.
Expand All @@ -120,12 +132,12 @@ export function beBigIntToBuffer(n: bigint, size?: number): Buffer {
* it gets the size from the given bigint. If the specified size is smaller than
* the size of the bigint (i.e. `minSize`), an error is thrown.
* It uses little-endian byte order.
* @param n The bigint to convert.
* @param value The bigint to convert.
* @param size The number of bytes of the buffer to return.
* @returns The buffer representation of the bigint in little-endian.
*/
export function leBigIntToBuffer(n: bigint, size?: number): Buffer {
const hex = bigIntToHexadecimal(n)
export function leBigIntToBuffer(value: bigint, size?: number): Buffer {
const hex = bigIntToHexadecimal(value)

// Calculate the minimum buffer size required to represent 'n' in bytes.
// Each hexadecimal character represents 4 bits, so 2 characters are 1 byte.
Expand All @@ -148,41 +160,45 @@ export function leBigIntToBuffer(n: bigint, size?: number): Buffer {

/**
* Converts a bigint to a buffer. Alias for beBigIntToBuffer.
* @param n The bigint to convert.
* @param value The bigint to convert.
* @returns The buffer representation of the bigint.
*/
export function bigIntToBuffer(n: bigint): Buffer {
return beBigIntToBuffer(n)
export function bigIntToBuffer(value: bigint): Buffer {
return beBigIntToBuffer(value)
}

/**
* Converts a BigNumberish type to a bigint. If the input is already a bigint,
* the return value will be the bigint itself, otherwise it will be converted
* to a bigint using big-endian byte order.
* @param n The BigNumberish value to convert.
* @param value The BigNumberish value to convert.
* @returns The bigint representation of the BigNumberish value.
*/
export function bigNumberishToBigInt(n: BigNumberish): bigint {
if (isNumber(n) || isBigInt(n) || isStringifiedBigInt(n) || isHexadecimal(n)) {
return BigInt(n as BigNumber | number)
export function bigNumberishToBigInt(value: BigNumberish): bigint {
requireBigNumberish(value, "value")

if (isBuffer(value) || isUint8Array(value)) {
return bufferToBigInt(value as Buffer)
}

return bufferToBigInt(n as Buffer)
return BigInt(value as BigNumber | number)
}

/**
* Converts a BigNumberish type to a buffer. If the input is already a buffer,
* the return value will be the buffer itself, otherwise it will be converted
* to a buffer using big-endian byte order.
* @param n The BigNumberish value to convert.
* @param value The BigNumberish value to convert.
* @returns The buffer representation of the BigNumberish value.
*/
export function bigNumberishToBuffer(n: BigNumberish): Buffer {
if (isBuffer(n)) {
return n as Buffer
export function bigNumberishToBuffer(value: BigNumberish): Buffer {
requireBigNumberish(value, "value")

if (isBuffer(value) || isUint8Array(value)) {
return Buffer.from(value as Buffer)
}

return bigIntToBuffer(bigNumberishToBigInt(n))
return bigIntToBuffer(bigNumberishToBigInt(value))
}

/**
Expand Down
15 changes: 13 additions & 2 deletions packages/utils/src/type-checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,11 @@ export function isStringifiedBigInt(value: any): boolean {
* @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, prefix = true) {
export function isHexadecimal(value: any, prefix = true): boolean {
if (!isString(value)) {
return false
}

if (prefix) {
return /^(0x|0X)[0-9a-fA-F]+$/.test(value)
}
Expand All @@ -156,7 +160,14 @@ export function isBigNumber(value: any): boolean {
* @param value The value to check.
*/
export function isBigNumberish(value: any): boolean {
return isNumber(value) || isBigInt(value) || isStringifiedBigInt(value) || isHexadecimal(value) || isBuffer(value)
return (
isNumber(value) ||
isBigInt(value) ||
isStringifiedBigInt(value) ||
isHexadecimal(value) ||
isBuffer(value) ||
isUint8Array(value)
)
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Buffer } from "buffer"

export type BigNumber = bigint | string

export type BigNumberish = BigNumber | number | Buffer
export type BigNumberish = BigNumber | number | Buffer | Uint8Array

export type PackedGroth16Proof = [
NumericString,
Expand Down
24 changes: 24 additions & 0 deletions packages/utils/tests/conversions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ describe("Conversions", () => {

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

it("Should throw an error if the parameter is not a bigint", async () => {
const fun = () => bigIntToHexadecimal(32 as any)

expect(fun).toThrow("Parameter 'value' is not a bigint, received type: number")
})
})

describe("# hexadecimalToBigInt", () => {
Expand All @@ -42,6 +48,12 @@ describe("Conversions", () => {

expect(result).toBe(testBigInt1BE)
})

it("Should throw an error if the parameter is not a valid hexadecimal", async () => {
const fun = () => hexadecimalToBigInt(32 as any)

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

describe("# bigNumberishToBuffer", () => {
Expand Down Expand Up @@ -76,6 +88,12 @@ describe("Conversions", () => {

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

it("Should throw an error if the parameter is not a valid bignumber-ish", async () => {
const fun = () => bigNumberishToBuffer("string" as any)

expect(fun).toThrow("Parameter 'value' is not a bignumber-ish")
})
})

describe("# bigNumberishToBigInt", () => {
Expand Down Expand Up @@ -110,6 +128,12 @@ describe("Conversions", () => {

expect(result).toBe(testBigInt1BE)
})

it("Should throw an error if the parameter is not a valid bignumber-ish", async () => {
const fun = () => bigNumberishToBigInt("string" as any)

expect(fun).toThrow("Parameter 'value' is not a bignumber-ish")
})
})

describe("# bufferToHexadecimal", () => {
Expand Down

0 comments on commit 2dbaa8d

Please sign in to comment.