# v0.1.0 → v0.1.3 — what Satoshi changed in the four days after the first release

*A source-level diff of the second and third surviving Bitcoin codebases, hash-anchored end to end.*

The lab's earlier work compares the 15 November 2008 pre-release with the 9 January 2009 v0.1.0. This
continues that line forward by one step, to the next artifact that survives: **v0.1.3**, dated
13 January 2009. **No v0.1.1 or v0.1.2 archive survives to us** — the jump we can execute is
0.1.0 → 0.1.3, and the Satoshi Nakamoto Institute marks even the 0.1.3 date with a question mark.

> **⚠️ CORRECTED 9 August 2026.** This paragraph previously read *"There is no public v0.1.1 or
> v0.1.2."* **That is false as to v0.1.2.** SourceForge's own file listing, captured 2 November 2010,
> records **`bitcoin-0.1.2.rar`, released 11 January 2009, downloaded 52 times** — and released a day
> *before* the archive named `bitcoin-0.1.0.rar`. **It was public; it is simply not preserved.** The
> distinction matters: *"never released"* and *"released and lost"* are different facts, and only the
> second is true. **Nothing in this document's finding depends on it** — the diff is between the two
> codebases we hold. Established from the SourceForge file listing; the working note is internal and not published.
>
> *(v0.1.1 does not appear in that listing either, so the claim survives for v0.1.1 alone.)*

> **★ ADDED 9 August 2026 — v0.1.3 was not the end of the line.** bitcoin.org's own homepage,
> captured by the Internet Archive, advertised **`bitcoin-0.1.3.rar` on 31 January 2009** and
> **`bitcoin-0.1.5.rar` by 3 March 2009**. So **v0.1.4 and v0.1.5 were both released, and neither
> survives to us** — the same *"released and lost"* category as v0.1.2, reached by a different
> source. **This dates availability, never release:** a capture shows what was on offer that day, not
> when it shipped. **And it corroborates the 0.1.3 date SNI marks with a question mark** — whatever
> day it shipped, 0.1.3 was still the current release on 31 January 2009. Full 19-point series,
> 0.1.3 → 0.3.19, in `archives/bitcoin-org-2009/SOURCES.md`;
> established from an exhaustive CDX sweep of bitcoin.org; the working note is internal and not published.

**The finding, in one line: v0.1.3 changes no consensus rule.** Every file that decides whether a
block or a script is valid is byte-identical to v0.1.0. What changed is networking, IRC bootstrap,
shutdown, and logging — plus the protocol version number.

---

## Provenance

The archive is not hosted by any project; it survives because people mirrored it. Two independent
sources agree on it, which is the whole of its chain of custody:

| | |
|---|---|
| Retrieved | `https://cdn.nakamotoinstitute.org/code/bitcoin-0.1.3.rar`, 4 August 2026 |
| Size | 2,127,418 bytes |
| MD5 | `9a73e0826d5c069091600ca295c6d224` |
| SHA1 | `294c684fbaa13ae2662e612e98d288bde0ba2b88` |
| SHA256 | `3d73b1a80ce775e0cec7f9476644a6bf9b361e99567fd143807ad1d1c81b1756` |

The MD5 matches the one posted by *deepceleron* to bitcointalk on 22 March 2012
([topic 68121, msg 814283](https://bitcointalk.org/index.php?topic=68121.msg814283#msg814283)) —
the thread in which Gavin Andresen explains that he had deleted every pre-0.3.24 binary from
SourceForge because the release list had grown unwieldy. The SHA1 matches the value published by
[SNI](https://satoshi.nakamotoinstitute.org/code/), which that page notes it calculated itself.

**The SHA256 above appears to be new.** Neither source publishes one; both predate the habit. It is
recorded here so the artifact has a modern digest that does not depend on MD5 or SHA1, both of which
are now unsafe for the one job a provenance hash has.

A caution worth stating plainly: two mirrors agreeing establishes that this is *the file that has
been circulating since at least 2012*. It does not establish that Satoshi released exactly these
bytes. Nothing available can establish that — there is no contemporaneous signature over any of
these archives. This is the same honest boundary the lab draws around the `satoshin@gmx.com` PGP
key: period-plausible and consistently attested is not the same as cryptographically bound.

## Method

Both trees were compared with line endings normalised (`\r\n` → `\n`) before hashing, because the
archives differ in that respect and it is not a difference Satoshi made. Files were compared
pairwise by SHA256; only where digests differed was a line diff taken. Every figure below is
reproducible from the two archives with nothing but `sha256sum` and `diff`.

## The diff

26 source files. **8 changed, 18 byte-identical.** Net +156 / −75 lines.

| file | | + | − | what changed |
|---|---|---:|---:|---|
| `net.cpp` | changed | 96 | 49 | `GetMyExternalIP`, `ConnectSocket`, `ConnectNode`, `ThreadSocketHandler2`, `ThreadOpenConnections2`, `StopNode` |
| `irc.cpp` | changed | 44 | 21 | reconnect with growing backoff, clean shutdown, input validation |
| `util.cpp` | changed | 7 | 1 | timestamp prefixed to a `printf` |
| `db.cpp` | changed | 4 | 0 | a GCC workaround |
| `net.h` | changed | 2 | 2 | `CAddress` default port; `IsRoutable` |
| `serialize.h` | changed | 1 | 1 | **`VERSION` 101 → 103** |
| `main.cpp` | changed | 1 | 1 | one `printf` |
| `ui.h` | changed | 1 | 0 | `extern void Shutdown(void*)` |
| `base58.h` `bignum.h` `db.h` `headers.h` `irc.h` `key.h` `main.h` `market.cpp` `market.h` `script.cpp` `script.h` `sha.cpp` `sha.h` `ui.cpp` `uibase.cpp` `uibase.h` `uint256.h` `util.h` | identical | 0 | 0 | — |

### The protocol version

```diff
- static const int VERSION = 101;
+ static const int VERSION = 103;
```

That is the entire `serialize.h` change. It is the number a node puts on the wire, and it moved with
the release number: 0.1.0 carries 101, 0.1.3 carries 103. Worth noting because it means the version
in the filename and the version on the wire are the same fact, not two conventions that happen to
agree — a release that did not change the protocol would not have moved it.

### Networking

`GetMyExternalIP` — the routine that asks an outside host what your address looks like from the
internet — accounts for most of `net.cpp`'s churn. `ConnectSocket`, `ConnectNode` and the two
connection threads are reworked around timeouts and shutdown; `StopNode` gains the ordering that
lets threads exit rather than be abandoned.

`net.h` is two small lines with a real consequence each:

```diff
- CAddress(unsigned int ipIn, unsigned short portIn, uint64 nServicesIn=0)
+ CAddress(unsigned int ipIn, unsigned short portIn=DEFAULT_PORT, uint64 nServicesIn=0)

- return !(GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168));
+ return !(GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168) || GetByte(3) == 127 || GetByte(3) == 0);
```

The second widens `IsRoutable` to reject loopback and `0.x`. That matters more than it looks: a node
whose own address is not routable falls back to a random IRC nickname instead of publishing its
address, so this quietly stops a class of nodes from advertising an address nobody can reach.

### IRC

The bootstrap thread is rebuilt around surviving failure. Where v0.1.0 returns from
`ThreadIRCSeed` on any error — ending peer discovery for the rest of the session — v0.1.3 waits and
retries with a backoff that grows by 60 seconds each time, and re-enters the loop. It also gains
`fShutdown` checks throughout, a 900-character cap on input lines, and a guard on malformed `JOIN`
lines.

**What it does not change is how a node identifies itself.** The nickname is still
`EncodeAddress(addrLocalHost)` — the node's own routable address, base58-encoded — announced into a
public channel. Whatever one makes of that as a privacy property, it was not something the four days
after the first release were spent revising.

### The rest

`db.cpp` gains four lines that are their own commentary:

```cpp
// Fix for possible GCC bug that manifests in mapAddresses.count in irc.cpp,
// just need to call count here and it doesn't happen there, do not delete this!
mapAddresses.count(vector<unsigned char>(18));
```

`util.cpp` puts a timestamp on a log line; `main.cpp` widens one `printf` from `addrMe` to the
peer's address and version; `ui.h` declares `Shutdown`. These are the marks of someone reading their
own logs while the thing runs.

## What it adds up to

Four days after publishing, the work was **keeping nodes connected**, not changing what a node
believes. Every rule that decides validity — `script.cpp`, `script.h`, `main.h`, `uint256.h`,
`bignum.h`, `key.h`, `sha.cpp`, `base58.h` — is untouched, and `serialize.h` moves only the version
number. A v0.1.0 node and a v0.1.3 node agree on every block.

That is a small fact with a large implication for how the earliest period is usually described. The
first release was not followed by a scramble to fix consensus. It was followed by a scramble to stop
the network dropping its own peers.

## Verifying this yourself

Fetch the archive, check it against the digests above, extract, and compare against the
R0-verified v0.1.0 tree in `extracted/`. Per-file SHA256 of the v0.1.3 sources as shipped
(before any line-ending normalisation):

| file | sha256 |
|---|---|
| `base58.h` | `f74d61273812f0966968f4bdf5e42ff8cc28837f0df463fe09980065e84209eb` |
| `bignum.h` | `c946d2678051772a771ec2ba9c33fee64d8c1d0c92b6a791d6637ba673b36fc0` |
| `db.cpp` | `d30fa51dedf951e2a36abf7a2096be87c8e0b16bc82fb710de776b754ecd9bf5` |
| `db.h` | `6f0abeb8ae108f9823783a71ef214824e9f6ab72e93990bc70838cd55a433eda` |
| `headers.h` | `dac61d922a9cdce5f6f6a8acd0e5628721d865ce9bb54ded32b5fa9a7a6e202f` |
| `irc.cpp` | `24eab76785cfd889ffbf80cee1c5674e1bee81064544a60f5bf79ed250a6180e` |
| `irc.h` | `f3c40402a7809562de6cc659e099ba9ccfee6f119958b7811ba82414edc42e7a` |
| `key.h` | `f631451db96081b0eeb4ca74d2f9c221de934f1079b166077055f4d0cea63e68` |
| `main.cpp` | `c7357a9bece0a9efc19de966f6a2c1c6a708918359b27a9c992a7a2873b2057a` |
| `main.h` | `f134c66c90c9ee054573a4f3199a0231b95c9e7a26e1ee45a73748ff4ac3511e` |
| `market.cpp` | `81c15691f9ca4c0a0d66b4a4a95e631caf3f31af26575e5ab49f8db838fa6e39` |
| `market.h` | `85aa4b054d749e094e641d41233384c1e7b58c84696b7be145ab53e6c0fbdbc4` |
| `net.cpp` | `8fadb290c8ff9245fbbda7e246ea283be14438156e9935894d53a830889568a3` |
| `net.h` | `46e9974eaa9b4182381131db12e4ed42d80fd0932ce96251cac78efbd624e43a` |
| `script.cpp` | `347c7526932d42a4d10ae487150b709e2ead737aa4b05f50aa9e2eefeb05a5b5` |
| `script.h` | `f905858b5d6d4593a3051b593c45fb5a8dd4cd38b5636c5e4456060b034fa218` |
| `serialize.h` | `6b4bf47d96a73d53b396b5d19940dba3cc7eb21db46f2f13555ff533ceb72a9c` |
| `sha.cpp` | `e99fec6d660bf7b06f7455f41567c5454b04c63e0ad0ee16b51ef421110cd0b5` |
| `sha.h` | `8b4c2faf5156b67491aa78ead117870999c807f7627afc6d223194416df02ede` |
| `ui.cpp` | `bec80418526c9fe45f3b83c99c0a708363942df271d3f048c18fec6ebff8fa63` |
| `ui.h` | `a99010147ea081ecbf22f6c3ce80954f1fe7fec72e26cc15a11f246dd6a271c4` |
| `uibase.cpp` | `a6270e7d73012541cd086a5ca1d9b06ad8ec3422e2e3ce1c9ce0a064f0c350da` |
| `uibase.h` | `945c2abf4280518a6d1ede7319e835fb3df82674e8a907ec4a2d1e8c74674eab` |
| `uint256.h` | `54818c679957094352ca5a6d7b7d131cfa7052ee54d8481053f87f57217b0c59` |
| `util.cpp` | `9fff6bc6eb125a2afffc7cde2643dfb054ddc0d9d71c3e87c5b3f238b3bfb054` |
| `util.h` | `1411b8f3ff7c712ea80f98587e3b8a9cf05b81a1dc8c45021bbf491de6292534` |

`sha.cpp` is worth spotting in that list: `e99fec6d…`, the same digest it carries in v0.1.0 and in
`derivatives/build-reconstruction/MANIFEST.sha256`. The SHA-256 implementation that validates the
chain did not move.

## What is not claimed

That these bytes are what Satoshi released — see *Provenance*. That the archive is complete: it is
what the mirrors carry, and `obj/` and `rc/` differ in incidental build residue not analysed here.
That the changes are exhaustively explained: `net.cpp`'s 96 added lines are summarised by function,
not annotated line by line. The per-file digests are the durable part; the prose is a reading of
them, and the diff is the thing to check.

**NOT money.**
