CompactSize
CompactSize is Bitcoin’s variable-length encoding for unsigned integers. It commonly records counts and byte lengths, using a short encoding for small values.
Contents
Counts and lengths
A reader of serialized Bitcoin data needs to know where each field ends. A transaction contains input and output counts; a script is preceded by its length in bytes. CompactSize is used for these counts and lengths.
The encoded integer, the number of bytes used to encode it, and the following data are separate things. A one-byte prefix 03 can mean that three bytes follow. Those three bytes are the payload; 03 describes its length.
- Length prefix
03- Following bytes
aa bb cc- Payload length
- 3 bytes
- Total length
- 4 bytes
The complete sequence is 03 aa bb cc. In a count field, the same 03 would instead mean three items, whose individual sizes depend on their format.
The four encoding ranges
Values below 253 occupy one byte. Larger values start with a marker byte: fd, fe, or ff. The marker tells a decoder to read two, four, or eight additional bytes as a little-endian integer.
Scroll sideways to see all columns.
| Unsigned value | First byte | Additional bytes | Total size |
|---|---|---|---|
| 0–252 | The value itself | None | 1 byte |
| 253–65,535 | fd | 2, little-endian | 3 bytes |
| 65,536–4,294,967,295 | fe | 4, little-endian | 5 bytes |
| 4,294,967,296–18,446,744,073,709,551,615 | ff | 8, little-endian | 9 bytes |
The marker contributes to the encoding's byte length. CompactSize uses exactly one, three, five, or nine bytes, not every possible length between one and nine. Its maximum encodable value is 264 − 1; individual Bitcoin fields impose their own, often much smaller, limits.
Hex notation and byte order are explained in Bits, Bytes, and Hexadecimal and Endianness.
Worked encodings
- 253 does not fit the one-byte range, which ends at 252.
- Choose the
fdmarker for a two-byte integer payload. - Write 253 as the two-byte little-endian sequence
fd 00. - Put the marker before the payload:
fd fd 00.
The first fd is a marker. The second fd is the low byte of the value. The result uses three bytes.
65,536 is too large for a two-byte payload, so use fe. Its four-byte little-endian payload is 00 00 01 00. Together they form fe 00 00 01 00, a five-byte encoding.
Scroll sideways to see all columns.
| Decimal value | CompactSize hex bytes | Bytes used |
|---|---|---|
| 0 | 00 | 1 |
| 252 | fc | 1 |
| 253 | fd fd 00 | 3 |
| 254 | fd fe 00 | 3 |
| 255 | fd ff 00 | 3 |
| 65,535 | fd ff ff | 3 |
| 65,536 | fe 00 00 01 00 | 5 |
| 4,294,967,295 | fe ff ff ff ff | 5 |
| 4,294,967,296 | ff 00 00 00 00 01 00 00 00 | 9 |
| 18,446,744,073,709,551,615 | ff ff ff ff ff ff ff ff ff | 9 |
Reading a CompactSize value
Read the first byte. If it is below fd, it is the complete integer. Otherwise, read the number of additional bytes specified by the marker and interpret only those bytes as little-endian.
For fd 02 01, the marker requests two more bytes. The payload 02 01 gives 2 + (1 × 256) = 258. The decoder consumes three bytes in total; any following bytes belong to subsequent data.
Reading CompactSize is an operation on an encoded field. Treating the entire encoding, including its marker, as an ordinary integer produces a different result.
Canonical encoding
A canonical encoding uses the smallest CompactSize form that can represent the value. For example, 1 must be written as 01. The longer sequence fd 01 00 also contains a two-byte payload with value 1, but Bitcoin Core rejects it as noncanonical when reading CompactSize.
Zero is encoded as 00, not as an empty sequence. A marker without its required payload bytes is incomplete: fd 01 is missing the second payload byte. Negative numbers and values above the unsigned 64-bit maximum have no CompactSize encoding.
Other Bitcoin encodings also use the word “compact” or “variable.” Bitcoin Core's internal VARINT encoding and a block header's nBits target encoding are separate formats. Their rules cannot be substituted for CompactSize.
Try the interpreter
Open the Data Interpreter to try these examples.
- Choose Hex and Endian: Big. Enter
fc. Its unsigned value is 252 and its CompactSize result isfc. - Enter
fd. Its unsigned value is 253 and its CompactSize result isfdfd00. - Enter
01 00 00. Its big-endian value is 65,536 and its CompactSize result isfe00000100.
The tool encodes the selected unsigned integer, not the number of input bytes. Changing Endian can change that integer and therefore the CompactSize result; CompactSize's own payload order remains little-endian.
The current interface is an encoder, not a CompactSize decoder. Pasting fd fd 00 makes it interpret those three bytes as ordinary input data; it does not read the marker and return 253. Empty input remains empty rather than encoding zero.