Skip to content

Commit

Permalink
prevent u256 and u512 deserialization modifying the original ser arra…
Browse files Browse the repository at this point in the history
…y when passed as Buffer
  • Loading branch information
marcus-pousette committed Jan 17, 2023
1 parent ada6ef6 commit 1fc6566
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 13 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dao-xyz/borsh",
"version": "5.1.2",
"version": "5.1.3",
"readme": "README.md",
"homepage": "https://github.com/dao-xyz/borsh-ts#README",
"description": "Binary Object Representation Serializer for Hashing simplified with decorators",
Expand Down
100 changes: 94 additions & 6 deletions src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,46 @@ describe("arrays", () => {
expect(new Uint8Array(deserialized.a)).toEqual(new Uint8Array([1, 2, 3]));
});

test("byte array should deserialize zero-copy from Uint8array", () => {
class TestStruct {
@field({ type: fixedArray("u8", 3) })
public a: Uint8Array | number[];

constructor(properties?: { a: number[] }) {
if (properties) {
this.a = properties.a;
}
}
}

validate(TestStruct);
const buf = new Uint8Array(serialize(new TestStruct({ a: [1, 2, 3] })));
expect(new Uint8Array(buf)).toEqual(new Uint8Array([1, 2, 3]));
const deserialized = deserialize(buf, TestStruct);
deserialized.a[0] = 123;
expect(buf[0]).toEqual(123);
});

test("byte array should deserialize zero-copy from Buffer", () => {
class TestStruct {
@field({ type: fixedArray("u8", 3) })
public a: Uint8Array | number[];

constructor(properties?: { a: number[] }) {
if (properties) {
this.a = properties.a;
}
}
}

validate(TestStruct);
const buf = serialize(new TestStruct({ a: [1, 2, 3] }));
expect(new Uint8Array(buf)).toEqual(new Uint8Array([1, 2, 3]));
const deserialized = deserialize(buf, TestStruct);
deserialized.a[0] = 123;
expect(buf[0]).toEqual(123);
});

test("fixed array wrong length serialize", () => {
class TestStruct {
@field({ type: fixedArray("u8", 3) })
Expand Down Expand Up @@ -540,11 +580,37 @@ describe("number", () => {
const n = BigInt(123);
const instance = new Struct(n);
const buf = serialize(instance);
expect(new Uint8Array(buf)).toEqual(
new Uint8Array([123, ...new Array(31).fill(0)])
);
const serializedExpected = new Uint8Array([123, ...new Array(31).fill(0)]);

expect(new Uint8Array(buf)).toEqual(serializedExpected);
const deserialized = deserialize(buf, Struct);
expect(deserialized.a).toEqual(n);

// check that the original array has not been modified
expect(new Uint8Array(buf)).toEqual(serializedExpected);
});

test("u256 with Uin8array", () => {
class Struct {
@field({ type: "u256" })
public a: bigint;

constructor(a: bigint) {
this.a = a;
}
}
const n = BigInt(123);
const instance = new Struct(n);
const buf = new Uint8Array(serialize(instance));

const serializedExpected = new Uint8Array([123, ...new Array(31).fill(0)]);

expect(new Uint8Array(buf)).toEqual(serializedExpected);
const deserialized = deserialize(buf, Struct);
expect(deserialized.a).toEqual(n);

// check that the original array has not been modified
expect(new Uint8Array(buf)).toEqual(serializedExpected);
});

test("u512 is le", () => {
Expand All @@ -558,11 +624,33 @@ describe("number", () => {
}
const instance = new Struct(BigInt(3));
const buf = serialize(instance);
expect(new Uint8Array(buf)).toEqual(
new Uint8Array([3, ...new Array(63).fill(0)])
);
const serializedExpected = new Uint8Array([3, ...new Array(63).fill(0)]);
expect(new Uint8Array(buf)).toEqual(serializedExpected);
const deserialized = deserialize(buf, Struct);
expect(deserialized.a).toEqual(BigInt(3));

// check that the original array has not been modified
expect(new Uint8Array(buf)).toEqual(serializedExpected);
});

test("u512 with 8int8array", () => {
class Struct {
@field({ type: "u512" })
public a: bigint;

constructor(a: bigint) {
this.a = a;
}
}
const instance = new Struct(BigInt(3));
const buf = new Uint8Array(serialize(instance));
const serializedExpected = new Uint8Array([3, ...new Array(63).fill(0)]);
expect(new Uint8Array(buf)).toEqual(serializedExpected);
const deserialized = deserialize(buf, Struct);
expect(deserialized.a).toEqual(BigInt(3));

// check that the original array has not been modified
expect(new Uint8Array(buf)).toEqual(serializedExpected);
});

test("u512 max", () => {
Expand Down
10 changes: 4 additions & 6 deletions src/bigint.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
function arrayToHex(arr: Uint8Array): string {
return [...new Uint8Array(arr)]
function arrayToHex(arr: Uint8Array, reverse: boolean = false): string {
return [...(reverse ? new Uint8Array(arr).reverse() : new Uint8Array(arr))]
.map(b => b.toString(16).padStart(2, "0"))
.join("");
}

export function toBigIntLE(buf: Uint8Array): bigint {
const reversed = buf.reverse();
const hex = arrayToHex(reversed);
const hex = arrayToHex(buf, true);
if (hex.length === 0) {
return BigInt(0);
}
Expand Down Expand Up @@ -91,8 +90,7 @@ export const readBigUInt64LE = (buf: Uint8Array, offset: number) => {
}

export function readUIntLE(buf: Uint8Array, offset: number, width: number): bigint {
const reversed = buf.slice(offset, offset + width).reverse();
const hex = arrayToHex(reversed);
const hex = arrayToHex(buf.subarray(offset, offset + width), true);
if (hex.length === 0) {
return BigInt(0);
}
Expand Down

0 comments on commit 1fc6566

Please sign in to comment.