bitcoinbegins.com
How the original Bitcoin client created keys — live generator and full step-by-step walkthrough.
This is NOT where you should generate keypairs for real life use. Please be careful.
Every time the original Bitcoin client (v0.1, released January 2009) needed a new address — whether for a coinbase reward or to receive a payment — it generated a fresh keypair automatically, using the following process:
wallet.dat on disk — unencrypted until Bitcoin 0.4.0 in September 2011The early client pre-generated a pool of 100 keypairs at startup, topping it up as keys were used. Each coinbase output in those first blocks used a fresh key drawn from this pool — which is why every early block has a distinct public key in its coinbase output.
Click the button to generate a genuine Bitcoin keypair in your browser, using real secp256k1 elliptic curve cryptography — the exact curve and algorithm used by Satoshi's original client. Every value shown is mathematically valid and correctly derived.
0x00 prepended (mainnet)The following uses a fixed, well-known example keypair (from the Bitcoin developer documentation) so every intermediate value can be explained precisely. The same process applies to every keypair generated above.
The private key is a random integer between 1 and n — the order of the secp256k1 curve. It must be exactly 256 bits (32 bytes). In the original Bitcoin client, this was generated by OpenSSL's RAND_bytes(), a cryptographically secure random number generator. In modern browsers, crypto.getRandomValues() serves the same purpose.
The only constraints: it must not be zero, and must be less than n (a number just slightly below 2²⁵⁶). Any valid 256-bit random number satisfies this in practice.
Example private key:
0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d
This is a standard example private key used in Bitcoin developer documentation. The corresponding address is known and publicly documented.
The public key is computed as K = k × G, where k is the private key and G is the secp256k1 generator point — a fixed, well-known point on the curve that every Bitcoin implementation uses.
This "multiplication" is not ordinary arithmetic. It is a sequence of point additions and point doublings on the elliptic curve y² = x³ + 7 (over a finite field of ~2²⁵⁶ elements). The result is a new point on the curve with coordinates (x, y). The key property is that this is a one-way function: given the result and G, you cannot work backwards to find k. This is the mathematical foundation of Bitcoin's security.
In the early Bitcoin client, the result was encoded in uncompressed format: a 04 prefix byte followed by the 32-byte x and 32-byte y coordinates (65 bytes total).
Resulting public key (uncompressed, 65 bytes):
04d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645cd85228a6fb29940e858e7e55842ae2bd115d1ed7cc0e82d934e929c97648cb0a
Compressed format (introduced later, not used in the very earliest blocks): Because the secp256k1 curve is symmetric around the x-axis, the y coordinate can always be reconstructed from x. So only x needs to be stored, with prefix 02 if y is even, or 03 if y is odd — saving 32 bytes per key.
03d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c
The prefix is 03 here because the y coordinate (d852…cb0a) is odd.
The full 65-byte uncompressed public key is hashed using SHA-256. This is a one-way cryptographic function that always produces exactly 32 bytes of output, regardless of input size. It is not possible to reconstruct the public key from its hash.
Input: the 65-byte uncompressed public key above
SHA-256 result (32 bytes):
58618fffe27f39d1f68d8d4eb5d496ab6925d1c0e981a522720495a9720552ef
The 32-byte SHA-256 output is hashed again using RIPEMD-160, producing a 20-byte (160-bit) result. This two-step combination — SHA-256 followed by RIPEMD-160 — is called Hash160 in Bitcoin terminology, and is also referred to as the pubkey hash.
Using two independent algorithms means that breaking either one alone is not enough to reverse the process. It also produces a shorter, more practical address.
RIPEMD-160 result — the Hash160 (20 bytes):
a65d1a239d4ec666643d350c7bb8fc44d2881128
This 20-byte value is the core of the Bitcoin address. Everything else that follows is just formatting and error-checking around it.
A single byte is prepended to identify which Bitcoin network this address belongs to:
0x00 — Bitcoin mainnet (the live network)0x6f — Bitcoin testnetThe original client always used 0x00. This gives a 21-byte payload.
After prepending version byte:
00a65d1a239d4ec666643d350c7bb8fc44d2881128
A 4-byte checksum is appended to catch transcription errors. It is computed by running the 21-byte payload through SHA-256 twice (double-SHA256), then taking the first 4 bytes of the result.
First SHA-256:
dd1cd208877a6a835fa0cee5095de605a7bc6f15efaa4bf977f733c35b050934
Second SHA-256:
268e839baa663479bad676b100524229ca219ffacd44681f472e210792b2622c
First 4 bytes — the checksum:
268e839b
If you type an address incorrectly, the checksum will not match and the wallet software will reject it before any funds are sent to an invalid address. This is why Bitcoin addresses have built-in typo detection.
The final address is formed by concatenating version byte + hash160 + checksum (25 bytes total), then encoding in Base58Check.
Full 25-byte payload:
00a65d1a239d4ec666643d350c7bb8fc44d2881128268e839b
Base58 is similar to Base64 but with characters removed that are easily confused when written by hand: no 0 (zero), O (capital-o), I (capital-i), or l (lowercase-L). The full Bitcoin Base58 alphabet is:
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
The 25-byte payload is treated as one large integer and converted to this base-58 number system. Any leading zero bytes in the payload each become a leading 1 character — which is why all legacy Bitcoin addresses start with 1 (the version byte 0x00 always encodes to 1 in Base58).
Final Bitcoin address:
1GAehh7TsJAHuUAeKZcXf5CnwuGuGgyX2S
This is the address corresponding to our example private key, using the uncompressed public key format used by the early Bitcoin client. It can be verified at any block explorer.
Internally, wallet.dat stored private keys as raw bytes. But when a key needed to be exported, backed up as text, or shared between wallets, Bitcoin uses WIF (Wallet Import Format) — the same Base58Check process applied to the private key rather than the address.
The process mirrors address derivation:
0x80 (mainnet private key)0x01 if the corresponding public key is compressed (not done in early client)WIF breakdown for our example:
Encoded WIF key:
5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ
WIF keys for uncompressed public keys always start with 5. Keys for compressed public keys start with K or L. Since the early Bitcoin client used only uncompressed keys, all early WIF exports begin with 5.
Every generated keypair was written into wallet.dat — a Berkeley DB database file in the Bitcoin data directory. The file held the raw private key bytes, the corresponding public key, and metadata such as creation time and optional labels.
| File | wallet.datBerkeley DB 4.x format. A widely-used embedded database library from the early 2000s, used by many applications of the era. |
| Encryption | None — Bitcoin v0.1 through v0.3Wallet encryption was added in Bitcoin 0.4.0, September 2011 — over two and a half years after launch. Before this, anyone with access to wallet.dat had immediate, complete access to all private keys and therefore all funds. |
| Key pool | 100 pre-generated keypairsGenerated at startup and maintained as a pool. New keys were generated to replace used ones. This meant a backup taken today might not contain keys generated tomorrow — leading to loss of funds if a stale backup was later restored. |
| Key generation | OpenSSL EC_KEY_generate_key()The original client delegated key generation entirely to OpenSSL, which uses the operating system's cryptographically secure random number generator internally. |
| Windows location | %APPDATA%\Bitcoin\wallet.dat |
| Linux / Mac location | ~/.bitcoin/wallet.dat |
wallet.dat today and continued using the wallet, new keypairs would be drawn from the pool and eventually exhausted — after which the client would generate entirely new keys that were not in your backup. Any funds received to those new addresses would be permanently unrecoverable if you ever restored from the old backup. Satoshi's advice was to back up after every few transactions. This caused real losses for many early users.
The keypair generation process — unchanged in its fundamentals from those first blocks to today — involves just a handful of steps. Private key → elliptic curve multiplication → public key → double hash → address. Each step is a one-way operation, so the chain cannot be reversed: an address doesn't reveal the public key it came from, and the public key doesn't reveal the private key.
Every coinbase transaction in those first Bitcoin blocks — each with its own fresh key drawn from Satoshi's 100-key pool — was generated exactly this way, written to an unencrypted file on disk, and treated as the sole record of ownership of those 50 BTC.