AI-generated analysisPublished automatically and not human-verified. Validated context appears in community notes below.
← Watch feed
Moderate 62 Bitcoin

Merge rust-bitcoin/rust-bitcoin#6954: units: serialize unsigned amounts as u64

Public commit record

What the developer wrote

Authored by Andrew Poelstra

100/100 · Strong
Merge rust-bitcoin/rust-bitcoin#6954: units: serialize unsigned amounts as u64

256ad0137832ac2bbbfb4053f570675fb1c72003 units: test amount varint serde round-trip (satsfy (Renato Britto))
ce1e998db1290a1d8da83d1a4c4a1393b41dd983 units: serialize unsigned amounts as u64 (satsfy (Renato Britto))

Pull request description:

A follow up of https://github.com/rust-bitcoin/rust-bitcoin/pull/6061#issuecomment-5751334257

`deserialize()` hinted u64 for unsigned amounts, but `serialize()` only ever wrote i64, so the two sides disagreed on the encoding. As a result, 100 sats became 200 sats in varint serialization format formats like postcard.

This state came about because we wanted serde errors to show each type's real range, and unsigned amounts to use a u64 hint so deserializers wouldn't be confused because the old errors complained about i64 first and only then about the real range, so users hit two failures. An unsigned amount should hint u64.

The problem is that, in varint formats like postcard, every amount reads back doubled. The zigzag encoding formula is `zigzag(n) = (n << 1) ^ (n >> 63)` for integer n in 64 bit representation. When n>0, (n>>63) is 0 and (n<<1) becomes n*2, so the number gets doubled on encoding, and then read as the doubled number directly on decoding. Also Amount::MAX fails because values ]10.5M,21M] BTC get doubled, surpassing the total bitcoin cap, then when range check looks at it on decoder, it rejects the input.

Serialization output format has changed, now matches the hint, and the `as_sat` token tests expect U64 for unsigned amounts.


ACKs for top commit:
apoelstra:
ACK 256ad0137832ac2bbbfb4053f570675fb1c72003; successfully ran local tests
tcharding:
ACK 256ad0137832ac2bbbfb4053f570675fb1c72003
Kixunil:
ACK 256ad0137832ac2bbbfb4053f570675fb1c72003


Tree-SHA512: 9c6ff0c7fac4ed2f6f356eba0f59cc903eb6adc89382b343ceae79fbbff2e26268ea8c77c62cd2c9447f543dfc08bb060ad2eb943771e8af361585123af9a053
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification✓ Links an issue, advisory, or supporting reference
The short version

What changed, and why it matters

This commit fixes a mismatch in how unsigned Bitcoin amounts were serialized versus deserialized when using certain compact binary formats. Previously, an unsigned amount (like 100 satoshis) was written as a signed number, which caused formats such as postcard/bincode with varint encoding to silently double the value on read-back and to reject very large amounts near the Bitcoin supply cap. The fix makes serialization use the same unsigned 64-bit hint that deserialization already expected, so round-trips now produce the same value.

Recommended action

Review any persisted binary serde data produced by `Amount`/`as_sat` serialization in varint formats (bincode, postcard, etc.) before this fix; such data may decode to doubled values or fail validation. Upgrade to the patched version for new data and consider migration/re-encoding of existing stored amounts.

Security signals we found

01

Data integrity bug: serialized values decode to different numeric values in varint binary formats

02

Range-check failure: Amount::MAX and large values near the cap fail deserialization after round-trip

03

Serde serialize/deserialize hint mismatch for unsigned amount types

04

Fix includes regression test for varint round-trip and token-type expectations

Risk score

Why this scored 62/100

Our methodology →
Potential impact 18/30
Exploitability 12/25
Stealth signal 10/15
Affected reach 10/15
Confidence 8/10
Evidence quality 4/5
Human-validated context

Community notes

Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.

No validated notes yet.

The AI analysis stands alone for now. Submit a note if you can add evidence or important context.