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.

Example 1: A length-prefixed byte sequence
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.

CompactSize encoding ranges
Unsigned valueFirst byteAdditional bytesTotal size
0–252The value itselfNone1 byte
253–65,535fd2, little-endian3 bytes
65,536–4,294,967,295fe4, little-endian5 bytes
4,294,967,296–18,446,744,073,709,551,615ff8, little-endian9 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

Example 2: Encode the integer 253
  1. 253 does not fit the one-byte range, which ends at 252.
  2. Choose the fd marker for a two-byte integer payload.
  3. Write 253 as the two-byte little-endian sequence fd 00.
  4. 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.

Example 3: Encode the integer 65,536

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.

Values around the encoding boundaries
Decimal valueCompactSize hex bytesBytes used
0001
252fc1
253fd fd 003
254fd fe 003
255fd ff 003
65,535fd ff ff3
65,536fe 00 00 01 005
4,294,967,295fe ff ff ff ff5
4,294,967,296ff 00 00 00 00 01 00 00 009
18,446,744,073,709,551,615ff ff ff ff ff ff ff ff ff9

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.

  1. Choose Hex and Endian: Big. Enter fc. Its unsigned value is 252 and its CompactSize result is fc.
  2. Enter fd. Its unsigned value is 253 and its CompactSize result is fdfd00.
  3. Enter 01 00 00. Its big-endian value is 65,536 and its CompactSize result is fe00000100.

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.