Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tidy-bools-truthy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fleet-sdk/serializer": patch
---

Fix `SigmaByteReader.readBool()` reading any boolean byte other than `0x01` as false. The reference implementation (sigmastate's `CoreDataSerializer`) reads a boolean as `getUByte() != 0`, so a non-canonical byte such as `0x02` or `0xff` in an `SBool` constant is true; it was previously parsed as false, silently flipping the value.
11 changes: 11 additions & 0 deletions packages/serializer/src/coders/sigmaByteReader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ describe("Sigma byte reader", () => {
expect(reader.match(u8a([0x04, 0x05, 0x06, 0x07]), 3)).toBe(false);
});

it("should read a boolean as false only for a zero byte", () => {
// Reference (sigmastate CoreDataSerializer): `r.getUByte() != 0` —
// any non-zero byte is true, not just 0x01.
expect(new SigmaByteReader(u8a([0x00])).readBool()).toBe(false);
expect(new SigmaByteReader(u8a([0x01])).readBool()).toBe(true);
expect(new SigmaByteReader(u8a([0x02])).readBool()).toBe(true);
expect(new SigmaByteReader(u8a([0x7f])).readBool()).toBe(true);
expect(new SigmaByteReader(u8a([0x80])).readBool()).toBe(true);
expect(new SigmaByteReader(u8a([0xff])).readBool()).toBe(true);
});

it("should read remaining bytes", () => {
const bytes = u8a([0x01, 0x02, 0x03, 0x04]);
const reader = new SigmaByteReader(bytes);
Expand Down
4 changes: 3 additions & 1 deletion packages/serializer/src/coders/sigmaByteReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ export class SigmaByteReader {
}

readBool(): boolean {
return this.readByte() === 0x01;
// Reference (sigmastate CoreDataSerializer): a boolean is `getUByte() != 0`,
// so any non-zero byte is true — not just the canonical 0x01.
return this.readByte() !== 0;
}

readBits(length: number): ArrayLike<boolean> {
Expand Down
10 changes: 10 additions & 0 deletions packages/serializer/src/sigmaConstant.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ describe("Primitive types serialization and parsing", () => {
expect(SConstant.from(tv.hex).data).to.be.equal(tv.value);
});

it("Should parse a non-canonical SBool byte as true, like the reference", () => {
// sigmastate CoreDataSerializer reads SBoolean as `getUByte() != 0`, and
// sigma-rust does the same, so a bool constant byte of 0x02 or 0xff is
// true — only 0x00 is false. Canonical encodings (0x00/0x01) are unchanged.
expect(SConstant.from("0100").data).to.be.equal(false);
expect(SConstant.from("0101").data).to.be.equal(true);
expect(SConstant.from("0102").data).to.be.equal(true);
expect(SConstant.from("01ff").data).to.be.equal(true);
});

it.each(byteVectors)("Should road-trip SByte($value)", (tv) => {
const sconst = SByte(tv.value);

Expand Down