Digital Archaeology: Bitcoin’s 21 Million

Everyone knows the number. Almost nobody knows where it comes from.

The 21 million coin limit is not in Satoshi’s whitepaper. It is not explained in any early public communication. It appears in the code, implied rather than stated, and its origin is easier to read from the implementation than from any document of intent.

The 32-bit Constraint

Bitcoin’s internal representation uses integers, not floating point. Floating-point arithmetic introduces rounding errors that compound unpredictably; currency requires exact arithmetic. The base unit is the satoshi: one hundred-millionth of a bitcoin, encoded in the early source as COIN = 100000000, along with CENT = 1000000, or one hundredth of a bitcoin.

The CENT constant implies a western decimal currency model: coins and cents. The minimum transaction fee was set at 1 * CENT in the original code, and later halved.

One aside: many researchers believe Satoshi was in London, based on email and forum post timestamps. A British programmer would almost certainly have named that constant PENCE!

The int32-to-int64 Migration (Speculation)

What follows is speculative, but the engineering logic is coherent.

A C programmer working quickly uses int and takes the platform default. On 32-bit Windows (which other parts of the codebase indicate) that default is a signed 32-bit integer.

We may also speculate that in an int32 environment COIN = 100 and CENT = 1 expressed bitcoin more like a traditional pound/pence or dollar/cent system with two decimal places rather than eight.

A 32-bit signed integer has a maximum value of 2^31, which is 2,147,483,648. If you count the total money supply in cents, one cent being one hundredth of a bitcoin, the maximum that fits is 2,147,483,648 cents, which, divided by 100, converts to 21,474,836.48 bitcoins. Exactly the same way that 2^31 pence is nearly £21.5M.

At some point before the initial public commit, Satoshi migrated value types to int64. This was a Visual Studio extension to C, not yet standardised as int64_t in C99.

The migration matters because of what it changed about overflow behaviour.

In an int32 world, with values counted in cents, the maximum representable transaction value is 2^31 cents. An integer overflow in that environment produces a wrong value, but cannot exceed the type’s ceiling. The supply limit is self-bounding: there is no reason to add a runtime check for values exceeding 21 million because it is impossible.

After the move to int64 the ceiling is no longer self-bounding.

The Exploit

On 15 August 2010, block 74,638 contained a transaction that created 184B bitcoins across three addresses. Two of them received 92B btc each.

The transaction was deliberate. The attacker constructed outputs with values of 0x7ffffffffff85ee0 – just below the maximum value of a signed 64-bit integer. The original CheckTransaction() tested each output individually for a negative value. Both outputs were positive and passed the check.

The code did not check the sum of outputs - which overflowed the integer type. Two values near the 64-bit signed maximum, added together, produce a result approaching 2^64, which wraps in a signed 64-bit integer by using the sign bit. The sum appeared to the validator as a small value within range and the transaction was accepted.

(The original discussion is preserved at bitcointalk.org, topic 823. The fix is at github.com/bitcoin/bitcoin/commit/d4c6b90 – the repository lived on SourceForge SVN at the time; the GitHub presence is a later mirror, as the commit’s svn id confirms: svn://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@132.)

The Patch

Satoshi coordinated the response within hours. The fix added checks to CheckTransaction() and ConnectInputs(): each individual output must be non-negative and must not exceed MAX_MONEY; the cumulative output total must also not exceed MAX_MONEY. The constant was defined in the same commit as 21000000 * COIN. This was written in the same style as the existing CENT = 1000000, suggesting the same hand that defined the original constants came back to name the one that had been left implicit.

This was the first time the limit appeared in the codebase as a named value.

What the Archaeology Shows

The sequence: a 32-bit ceiling on the cent-denominated supply produced a round number; the type that enforced it was later widened to 64 bits; the widening removed the structural bound that had made an explicit check unnecessary; an anonymous attacker found the gap between the implied limit and the absent runtime check; the patch closed it by making the implied explicit.

What remains is the number 21,000,000: derived from a hardware constraint that no longer appears in the code, enforced by a constant added under pressure and now treated as foundational.

Interestingly, when asked in emails why the 21 million limit exists, Satoshi gives a rambling response about balancing scarcity against global utility. In my opinion, this is not the same person that wrote and updated the code. The origins of the limits are very clear to any C developer.