Skip to content

consensus: Add CompactSize range check to deserialization#5697

Merged
apoelstra merged 1 commit into
rust-bitcoin:masterfrom
erickcestari:add-max-size-compactsize
Mar 14, 2026
Merged

consensus: Add CompactSize range check to deserialization#5697
apoelstra merged 1 commit into
rust-bitcoin:masterfrom
erickcestari:add-max-size-compactsize

Conversation

@erickcestari

Copy link
Copy Markdown
Contributor

Reject CompactSize values exceeding MAX_COMPACT_SIZE (0x02000000) during deserialization, matching Bitcoin Core's serialize.h limit.

Extract read_compact_size logic into a private free function to allow tests to bypass the range check when validating non-minimal encoding.

Add test for the new OversizedCompactSize error at the boundary.

Update bip152 error test to expect failure at deserialization rather than at index computation, since the range check now triggers earlier.

Found by differential fuzzing using bitcoinfuzz.

@github-actions github-actions Bot added C-bitcoin PRs modifying the bitcoin crate C-p2p labels Feb 18, 2026
Reject CompactSize values exceeding MAX_COMPACT_SIZE (0x02000000) during
deserialization, matching Bitcoin Core's serialize.h limit.

Extract read_compact_size logic into a private free function to allow
tests to bypass the range check when validating non-minimal encoding.

Add test for the new SizeTooLargeCompactSize error at the boundary.

Update bip152 error test to expect failure at deserialization rather
than at index computation, since the range check now triggers earlier.
@erickcestari erickcestari force-pushed the add-max-size-compactsize branch from 3f3f5ec to 1dd1d92 Compare February 18, 2026 17:16
@tcharding

Copy link
Copy Markdown
Member

Thanks man! Good work on the fuzzing.

A couple of comments/questions for the project more than just for you.

  • The patched code is more or less on its way out so if we need this fix we likely need it consensus_enocding as well.
  • We have done a fair bit of work with compact sizes and we don't have this check, that makes me think we discussed it and I can't remember? If not how did we miss this?

@erickcestari

Copy link
Copy Markdown
Contributor Author

Thanks man! Good work on the fuzzing.

A couple of comments/questions for the project more than just for you.

  • The patched code is more or less on its way out so if we need this fix we likely need it consensus_enocding as well.
  • We have done a fair bit of work with compact sizes and we don't have this check, that makes me think we discussed it and I can't remember? If not how did we miss this?

More context:

I found this while doing differential fuzzing in the PSBT parser. Bitcoin Core always checks if the compact_size value is greater than 33,554,432 to throw an exception. While debugging, I found that the PSBT key has a type value that is the compact size encoded, which Bitcoin Core checks against the upper bound limit, but rust-bitcoin does not. Making rust-bitcoin accepting the PSBT and Bitcoin Core rejects it.

@tcharding

Copy link
Copy Markdown
Member

Ha! Interesting timing then. I only recently raised this issue: #5622 which is around the key type and its usage of a CompactSize encoding. Note in the associated PR the code comment 'the protocol abuses ...' (which I suggested). Amusing that its not the only bug we have on this data field and I"m now not surprised we missed it.

@tcharding

tcharding commented Feb 19, 2026

Copy link
Copy Markdown
Member

BTW we are trying to move PSBT dev over to rust-psbt. Would be mad if you fuzzed against that too if its not too much additional work. Would give us more confidence as we migrate dev that we don't make any mistakes. ref: #5700

@jrakibi

jrakibi commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

We have done a fair bit of work with compact sizes and we don't have this check, that makes me think we discussed it and I can't remember? If not how did we miss this?

we previously had MAX_ENCODABLE_VALUE constant for this, but it was removed in 460976939 because it wasn’t enforced anywhere.

this was discussed here: #5057 (comment)

@tcharding

Copy link
Copy Markdown
Member

Ouch so I removed it. Thanks @jrakibi!

@erickcestari

Copy link
Copy Markdown
Contributor Author

BTW we are trying to move PSBT dev over to rust-psbt. Would be mad if you fuzzed against that too if its not too much additional work. Would give us more confidence as we migrate dev that we don't make any mistakes. ref: #5700

Yes, adding the rust-psbt is already on the plan.

bitcoinfuzz/bitcoinfuzz#419

I'll check to see if it gets done this week and report any issues I find.

@tcharding

Copy link
Copy Markdown
Member

Boss!

@apoelstra

Copy link
Copy Markdown
Member

I'm gonna go ahead and ACK/merge this. But

  • Does this need to be backported to 0.32.x to be picked up by your fuzzer?
  • Do we want to move any of this PR to rust-psbt?

@apoelstra apoelstra left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 1dd1d92; successfully ran local tests

@tcharding

tcharding commented Mar 2, 2026

Copy link
Copy Markdown
Member

I created rust-bitcoin/rust-psbt#74 to track it over in rust-psbt and added the backport label (after checking we can backport the changes). And #5752 to track fixing it in consensus_encoding.

@erickcestari

Copy link
Copy Markdown
Contributor Author

I'm gonna go ahead and ACK/merge this. But

  • Does this need to be backported to 0.32.x to be picked up by your fuzzer?
  • Do we want to move any of this PR to rust-psbt?
  • Does this need to be backported to 0.32.x to be picked up by your fuzzer?

No, We can do fuzzing in any commit/branch.

  • Do we want to move any of this PR to rust-psbt?

Yes, I've tested with rust-psbt and it has the same issue as rust-bitcoin. Since rust-psbt v0 uses the Key from rust-bitcoin it also will accept a key type that core doesn't accept.

@apoelstra apoelstra merged commit 9129379 into rust-bitcoin:master Mar 14, 2026
28 checks passed
tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request Mar 29, 2026
Manually backport rust-bitcoin#5697. On `master` the `VarInt` type is gone but the
deserialization bug fixed by 5697 exists here none the less.

Add the same range check to `Decodable for VarInt`.
@tcharding

Copy link
Copy Markdown
Member

Backported in #5921

tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request Apr 8, 2026
Manually backport rust-bitcoin#5697. On `master` the `VarInt` type is gone but the
deserialization bug fixed by 5697 exists here none the less.

Add the same range check to `Decodable for VarInt`.
tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request Apr 8, 2026
Manually backport rust-bitcoin#5697. On `master` the `VarInt` type is gone but the
deserialization bug fixed by 5697 exists here none the less.

Add the same range check to `Decodable for VarInt`.
tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request Apr 9, 2026
Manually backport rust-bitcoin#5697. On `master` the `VarInt` type is gone but the
deserialization bug fixed by 5697 exists here none the less.

Add the same range check to `Decodable for VarInt`.
tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request Apr 9, 2026
Manually backport rust-bitcoin#5697. On `master` the `VarInt` type is gone but the
deserialization bug fixed by 5697 exists here none the less.

Add the same range check to `Decodable for VarInt`.
apoelstra added a commit that referenced this pull request Apr 9, 2026
11bb6a8 bitcoin: update CompactSize Kani proofs (Ismail Daif)

Pull request description:

  There were 2 existing Kani proofs, checking a CompactSize serialization/deserialization roundtrip for all `u32` values and `u64` values greater than `0xffffffff`.
  
  These proofs no longer succeeded after #5697 implemented a range-check on CompactSize deserialization.
  
  This PR updates the proofs such that a roundtrip is tested for all values in the enforced range, and values outside that range are rejected with `ParseError::OversizedCompactSize`.
  
  Closes #5954


ACKs for top commit:
  tcharding:
    ACK 11bb6a8
  apoelstra:
    ACK 11bb6a8; successfully ran local tests; nice! We will try to be more conscientious about the Kani tests in future..


Tree-SHA512: 94c0a702a79d7154a3e8452df2292ac1773515780d78e8c1f28f53c0620f6643c8a9c520b629c3dbefd59228380a7329deb04fd14b49319a538775443ece503e
tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request Apr 14, 2026
Manually backport rust-bitcoin#5697. On `master` the `VarInt` type is gone but the
deserialization bug fixed by 5697 exists here none the less.

Add the same range check to `Decodable for VarInt`.
apoelstra added a commit that referenced this pull request Apr 17, 2026
…rialization

4a71193 Remove doc_auto_cfg (Tobin C. Harding)
91a6e64 consensus: Add CompactSize range check to deserialization (Tobin C. Harding)
48ac68d Update nightly toolchain version (Tobin C. Harding)

Pull request description:

  Manually backport #5697. On `master` the `VarInt` type is gone but the deserialization bug fixed by 5697 exists here none the less.
      
  Add the same range check to `Decodable for VarInt`.


ACKs for top commit:
  apoelstra:
    ACK 4a71193; successfully ran local tests


Tree-SHA512: c46ed1b90f0d44c994302b69f7051388308a40939631f4542459abd58908913adbcf0f406f0b04111ae7bb74ad2ad603fb769eab3e1470a1e4fece1667fef6c5
tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request May 14, 2026
    
Manually revert 91a6e64
    
(`git revert` didn't work.)
    
This was a backport of rust-bitcoin#5697 which added range checking to the
`VarInt` type. On master we did this then realized there are
legitimate use cases for the full range of a `u64`. We then added
`u64` support to compact size (rust-bitcoin#5784).

Note that we cannot break the API so the new stuff introduced in
`0.32.9` has to stay in there. Comment the code as such.

NB: 'compact size' is the new name for varint.
    
This backport then broke downstream users.
tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request May 14, 2026
    
Manually revert 91a6e64

Note that we cannot break the API so the new stuff introduced in
`0.32.9` has to stay in there. Comment the code as such.
    
This was a backport of rust-bitcoin#5697 which added range checking to the
`VarInt` type. On master we did this then realized there are
legitimate use cases for the full range of a `u64`. We then added
`u64` support to compact size (rust-bitcoin#5784).

NB: 'compact size' is the new name for varint.
    
This backport then broke downstream users.
tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request May 14, 2026
    
Manually revert 91a6e64

Note that we cannot break the API so the new stuff introduced in
`0.32.9` has to stay in there. Comment the code as such.
    
This was a backport of rust-bitcoin#5697 which added range checking to the
`VarInt` type. On master we did this then realized there are
legitimate use cases for the full range of a `u64`. We then added
`u64` support to compact size (rust-bitcoin#5784).

NB: 'compact size' is the new name for varint.
    
This backport then broke downstream users.
tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request May 17, 2026
    
Manually revert 91a6e64

Note that we cannot break the API so the new stuff introduced in
`0.32.9` has to stay in there. Comment the code as such.
    
This was a backport of rust-bitcoin#5697 which added range checking to the
`VarInt` type. On master we did this then realized there are
legitimate use cases for the full range of a `u64`. We then added
`u64` support to compact size (rust-bitcoin#5784).

NB: 'compact size' is the new name for varint.
    
This backport then broke downstream users.
apoelstra pushed a commit that referenced this pull request May 24, 2026
    
Manually revert 91a6e64

Note that we cannot break the API so the new stuff introduced in
`0.32.9` has to stay in there. Comment the code as such.
    
This was a backport of #5697 which added range checking to the
`VarInt` type. On master we did this then realized there are
legitimate use cases for the full range of a `u64`. We then added
`u64` support to compact size (#5784).

NB: 'compact size' is the new name for varint.
    
This backport then broke downstream users.
apoelstra added a commit that referenced this pull request May 24, 2026
3bcd7c9 Manually revert VarInt range check (Tobin C. Harding)

Pull request description:

  Manually revert 91a6e64
  
  Note that we cannot break the API so the new stuff introduced in `0.32.9` has to stay in there. Comment the code as such.
  
  This was a backport of #5697 which added range checking to the `VarInt` type. On master we did this then realized there are legitimate use cases for the full range of a `u64`. We then added `u64` support to compact size (#5784).
  
  NB: 'compact size' is the new name for varint.
  
  This backport then broke downstream users.
  
  Close: #6138


ACKs for top commit:
  apoelstra:
    ACK 3bcd7c9; successfully ran local tests


Tree-SHA512: d01078f4f8fae59c439fd404a643abfb353bcec1757ebfbcabde487ff8620d927387f91d0e749a7bbd36163f2386290d301f17c0cff9e628e37585329daf116b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug C-bitcoin PRs modifying the bitcoin crate C-p2p Needs Backport

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants