Skip to content

fix(ergotree-ir): reject ErgoTree headers with version > 0 and no size bit - #975

Open
Kshot3000 wants to merge 1 commit into
ergoplatform:developfrom
Kshot3000:fix/ergotree-header-size-bit
Open

Kshot3000 wants to merge 1 commit into
ergoplatform:developfrom
Kshot3000:fix/ergotree-header-size-bit

Conversation

@Kshot3000

Copy link
Copy Markdown
Contributor

Fixes #974.

The gap

The sigmastate-interpreter serializer runs CheckHeaderSizeBit (validation rule 1012) on the ErgoTree header byte during deserialization: for version > 0 the size bit must be set, otherwise a ValidationException is thrown — and because a tree without a size cannot be skipped, it escalates to a SerializerException and the whole parse fails. sigma-rust's ErgoTreeHeader::new accepted every version/flag combination, so ErgoTree::sigma_parse took the un-sized path for version 1/2/3 headers and interpreted the following bytes directly as constants + root. A trivial proof: take the canonical v0 serialization of a SigmaProp(true) tree and flip the header byte to 0x01 — it parsed as a valid v1 tree here, while the reference rejects it at the header byte.

The fix

ErgoTreeHeader::new now rejects version > 0 headers without the size bit with a new ErgoTreeHeaderError::MissingSizeBit(header_byte) variant. Putting the check in the header constructor means it covers both ErgoTreeHeader::sigma_parse and the full ErgoTree::sigma_parse path (which converts the error via the existing #[from] into SigmaParsingError), and it matches where the reference performs the check — on the header, before the body is read.

Behaviour matrix (all pinned by the new test):

  • v0, no size bit: parses (canonical legacy form) — unchanged
  • v0, size bit set: parses — unchanged (rule 1012 only fires for version != 0)
  • v1..=v3, size bit set: parses (canonical sized form) — unchanged
  • v1..=v3, no size bit: rejected (previously parsed under the wrong framing)
  • v1 + constant segregation, no size bit (0x11): rejected as well

Tests

  • Fail-first on pristine develop: the new test parse_header_version_without_size_bit_is_rejected failed at the first rejection assertion (header 0x01 accepted); the v0/v1-sized acceptance pins passed pre-fix, so in-range behaviour is pinned as unchanged, not just the new rejections.
  • cargo test -p ergotree-ir --all-features: 265 passed (+2 doc/integration) — one new test over the 264 baseline.
  • Downstream: cargo test -p ergo-lib --all-features --lib 121/121, cargo test -p ergotree-interpreter --all-features --lib 339/339 (the interpreter's own header construction in tests uses 0x0b — v3 with the size bit set — so it is unaffected).
  • cargo clippy -p ergotree-ir --all-features --all-targets -- -D warnings clean; cargo fmt --check clean.

Deliberate non-changes

  • The reserved header bits (5–7) are still ignored on parse, exactly as in the reference, which stores the raw header byte and only interprets version/segregation/size. This PR changes acceptance of version/size combinations only.
  • ErgoTreeHeader::v0(..) / v1(..) constructors are untouched: they build valid combinations by construction (v1 always sets the size bit).

Built by @Kshot9000 — donations (Ergo): 9fcM5RWnAjmP4vx5bnW6yohB6H9bLq8sJbaPLHtwZLtQPB32Pvy

…e bit

The sigmastate-interpreter serializer runs CheckHeaderSizeBit
(validation rule 1012) on the header byte during deserialization:
for version > 0 the size bit must be set, otherwise the parse fails
(without a size the tree body cannot be skipped, so the reference
throws a SerializerException instead of producing a tree).

sigma-rust accepted such headers and parsed the following bytes as
an un-sized body, so a tree the reference rejects outright could
parse successfully here under the wrong framing (e.g. header 0x01
followed by a plain SigmaProp constant root).

ErgoTreeHeader::new now returns the new
ErgoTreeHeaderError::MissingSizeBit variant for version > 0 headers
without the size bit. Version 0 headers are unaffected either way,
matching the reference rule, which only fires for version != 0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ErgoTree parsing accepts version > 0 headers without the size bit, which the reference rejects (CheckHeaderSizeBit, rule 1012)

1 participant