Skip to content

Commit

Permalink
Merge pull request #149 from artwyman/artwyman/number-conversions
Browse files Browse the repository at this point in the history
fix(utils): input mutations and small-number padding in BigInt <-> Buffer conversions
  • Loading branch information
cedoor committed Feb 9, 2024
2 parents 6002137 + 87ebf8d commit b7ae09c
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 2 deletions.
1 change: 1 addition & 0 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"access": "public"
},
"devDependencies": {
"@types/chai": "^4.2.0",
"rollup-plugin-cleanup": "^3.2.1",
"rollup-plugin-polyfill-node": "^0.13.0",
"rollup-plugin-terser": "^7.0.2",
Expand Down
17 changes: 15 additions & 2 deletions packages/utils/src/number-conversions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ export function bufferToBigint(buffer: Buffer): bigint {
return BigInt(`0x${buffer.toString("hex")}`)
}

export function bigintToBuffer(n: bigint): Buffer {
const hex = bigintToHexadecimal(n)

// Allocate buffer of the desired size, filled with zeros.
const buffer = Buffer.alloc(32, 0)

const fromHex = Buffer.from(hex, "hex")
fromHex.copy(buffer, 32 - fromHex.length)

return buffer
}

export function bigNumberishToBigint(value: BigNumberish): bigint {
if (
typeof value === "number" ||
Expand All @@ -44,7 +56,7 @@ export function bigNumberishToBigint(value: BigNumberish): bigint {
}

export function leBufferToBigint(buffer: Buffer): bigint {
return BigInt(`0x${buffer.reverse().toString("hex")}`)
return BigInt(`0x${Buffer.from(buffer).reverse().toString("hex")}`)
}

export function leBigintToBuffer(n: bigint): Buffer {
Expand All @@ -53,7 +65,8 @@ export function leBigintToBuffer(n: bigint): Buffer {
// Allocate buffer of the desired size, filled with zeros.
const buffer = Buffer.alloc(32, 0)

Buffer.from(hex, "hex").reverse().copy(buffer)
const fromHex = Buffer.from(hex, "hex").reverse()
fromHex.copy(buffer, 0)

return buffer
}
58 changes: 58 additions & 0 deletions packages/utils/tests/number-conversions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { expect } from "chai"
import { bufferToBigint, bigintToBuffer, leBigintToBuffer, leBufferToBigint } from "../src/number-conversions"

describe("Number Conversions", () => {
describe("Bigint to/from Buffer Conversions", () => {
const tesetBytes1 = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
]
const testNum1LE = BigInt("0x1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100");
const testNum1BE = BigInt("0x000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");

it("Should support little-endian conversions", async () => {
const in1 = Buffer.from(tesetBytes1)
const n1 = leBufferToBigint(in1)
expect(n1).to.be.eq(testNum1LE)
const out1 = leBigintToBuffer(n1)
expect(out1.length).to.eq(32)
expect(out1).to.deep.eq(Buffer.from(tesetBytes1))
})

it("Should support big-endian conversions", async () => {
const in1 = Buffer.from(tesetBytes1)
const n1 = bufferToBigint(in1)
expect(n1).to.be.eq(testNum1BE)
const out1 = bigintToBuffer(n1)
expect(out1.length).to.eq(32)
expect(out1).to.deep.eq(Buffer.from(tesetBytes1))
})

it("Should pad small numbers", async () => {
const smallBufLE = leBigintToBuffer(BigInt(0x020100))
expect(smallBufLE).to.have.length(32)
const smallOutLE = leBufferToBigint(smallBufLE)
expect(smallOutLE).to.eq(BigInt(0x020100))

const smallBufBE = bigintToBuffer(BigInt(0x020100))
expect(smallBufBE).to.have.length(32)
const smallOutBE = bufferToBigint(smallBufBE)
expect(smallOutBE).to.eq(BigInt(0x020100))
})

it("Should not mutate input buffers", async () => {
const in1 = Buffer.from(tesetBytes1)
expect(in1).to.deep.eq(Buffer.from(tesetBytes1))

const n1LE = leBufferToBigint(in1)
expect(n1LE).to.eq(testNum1LE)
expect(in1).to.deep.eq(Buffer.from(tesetBytes1))

const n1BE = bufferToBigint(in1)
expect(n1BE).to.eq(testNum1BE)
expect(in1).to.deep.eq(Buffer.from(tesetBytes1))
})
})
})
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4642,6 +4642,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@zk-kit/utils@workspace:packages/utils"
dependencies:
"@types/chai": ^4.2.0
rollup-plugin-cleanup: ^3.2.1
rollup-plugin-polyfill-node: ^0.13.0
rollup-plugin-terser: ^7.0.2
Expand Down

0 comments on commit b7ae09c

Please sign in to comment.