Let’s look at the complete process of creating a bitcoin address, from a private key, to a public key (a point on the elliptic curve), to a double-hashed address and finally the Base58Check encoding. The C++ code in Example 4-1 shows the complete process, from private key, to Base58Check encoded bitcoin address, step-by-step. The code example uses the libbitcoin library introduced in “Alternative clients, libraries and tool‐
kits” on page 56 for some helper functions:
Example 4-1. Creating a Base58Check encoded bitcoin address from a private key
The code uses a pre-defined private key, so that it produces the same bitcoin address every time it is run:
Example 4-2. Compiling and running the addr code
# Compile the addr.cpp code $ g++ -o addr addr.cpp $(pkg-config –cflags –libs libbitcoin) # Run the addr executable $ ./addr
Public key: 0202a406624211f2abbdc68da3df929f938c3399dd79fac1b51b0e4ad1d26a47aa
Address: 1PRTTaJesdNovgne6Ehcdu1fpEdX7913CK
Key Formats
Private Key Formats
The private key can be represented in a number of different formats, all of which correspond to the same 256-bit number. These formats include:
All of the above representations are different ways of showing the same number, the same private key. They look different, but any one format can easily be converted to any other format.
Decode from Base58Check to Hex
The sx-tools package (See “Libbitcoin and sx tools” on page 56) makes it easy to write shell-scripts and command-line “pipes” that manipulate bitcoin keys, addresses, and transactions. You can use sx-tools to decode the Base58Check format on the command line:
We use the base58check-decode command:
$ sx base58check-decode 5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd 128
The result is the hexadecimal key, followed by the Wallet Import Format (WIF) version
prefix 128.
Encode from Hex to Base58Check
To encode into Base58Check (the opposite of the previous command), we provide the hex private key, followed by the Wallet Import Format (WIF) version prefix 128:
$ sx base58check-encode 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd 128
5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
Encode from Hex (Compressed Key) to Base58Check encoding
To encode into Base58Check as a “compressed” private key (see “Compressed Private Keys” on page 80), we add the suffix 01 to the end of the hex key and then encode as above:
$ sx base58check-encode 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd01 128
KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
The resulting WIF-compressed format, starts with a “K”. This denotes that the private key within has a suffix of “01” and will be used to produce compressed public keys only (See “Compressed Public Keys” on page 78 below).
Public Key Formats
Public keys are also presented in different ways, most importantly as either compressed or uncompressed public keys. As we saw previously, the public key is a point on the elliptic curve consisting of a pair
of coordinates (x,y). It is usually presented with the prefix 04 followed by two 256-bit numbers, one for the x-coordinate of the point, the other for the y-coordinate. The prefix 04 is used to distinguish uncompressed public keys from compressed public keys that begin with a 02 or a 03.
Here’s the public key generated by the private key we created above, shown as the co‐
ordinates x and y.
Public Key K defined as a point K = (x,y).
x = F028892BAD…DC341A
y = 07CF33DA18…505BDB
Here’s the same public key shown as a 520-bit number (130 hex digits) with the prefix 04 followed by x and then y coordinates, as 04 x y:
Uncompressed Public Key K shown in hex (130 hex digits) as 04xy.
K = 04F028892BAD…505BDB
Compressed Public Keys
Compressed public keys were introduced to bitcoin to reduce the size of transactions and conserve disk space on nodes that store the bitcoin blockchain database. Most transactions include the public key, required to validate the owner’s credentials and spend the bitcoin. Each public key requires 520 bits (prefix + x + y), which when multiplied by several hundred transactions per block, or tens of thousands of transactions per day, adds a significant amount of data to the blockchain.
As we saw in the section “Public Keys” on page 65 above, a public key is a point (x,y) on an elliptic curve. Since the curve expresses a mathematical function, a point on the curve represents a solution to the equation and therefore if we know the x-coordinate we can calculate the y-coordinate by solving the equation y2 mod p = (X^3+7) mod p. That allows us to store only the x-coordinate of the public key point, omitting the y-coordinate and reducing the size of the key and the space required to store it by 256 bits. An almost 50% reduction in size in every transaction adds up to a lot of data saved over time!
Whereas uncompressed public keys have a prefix of 04, compressed public keys start with either a 02 or a 03 prefix. Let’s look at why there are two possible prefixes: since the left side of the equation is y2, that means the solution for y is a square root, which can have a positive or negative value. Visually, this means that the resulting y-coordinate can be above the x-axis or below the x-axis. As you can see from the graph of the elliptic curve, the curve is symmetric, meaning it is reflected like a mirror by the x-axis. So,
while we can omit the y-coordinate we have to store the sign of y (positive or negative), or in other words we have to remember if it was above or below the x-axis, as each of those options represents a different point and a different public key. When calculating the elliptic curve in binary arithmetic on the finite field of prime order p, the y coordinate is either even or odd, which corresponds to the positive/negative sign as explained above. Therefore, to distinguish between the two possible values of y, we store a com
pressed public key with the prefix 02 if the y is even, and 03 if it is odd, allowing the software to correctly deduce the y-coordinate from the x-coordinate and uncompress the public key to the full coordinates of the point.
Here’s the same public key generated previously, shown as a compressed public key stored in 264-bits (66 hex digits) with the prefix 03 indicating the y coordinate is odd:
Compressed Public Key K shown in hex (66 hex digits) as K = {02 or 03} x.
K = 03F028892BAD…DC341A
The compressed public key, above, corresponds to the same private key, meaning that it is generated from the same private key. However it looks different from the uncompressed public key. More importantly, if we convert this compressed public key to a bitcoin address using the double-hash function (RIPEMD160(SHA256(K))) it will pro‐duce a different bitcoin address. This can be confusing, because it means that a single private key can produce a public key expressed in two different formats (compressed
and uncompressed) which produce two different bitcoin addresses. However, the private key is identical for both bitcoin addresses.
Compressed public keys are gradually becoming the default across bitcoin clients, which is having a significant impact on reducing the size of transactions and therefore the blockchain. However, not all clients support compressed public keys yet. Newer clients that support compressed public keys have to account for transactions from older clients which do not support compressed public keys. This is especially important when a wallet application is importing private keys from another bitcoin wallet application, because the new wallet needs to scan the blockchain to find transactions corresponding to these
imported keys. Which bitcoin addresses should the bitcoin wallet scan for? The bitcoin addresses produced by uncompressed public keys, or the bitcoin addresses produced by compressed public keys? Both are valid bitcoin addresses, and can be signed for by the private key, but they are different addresses!
To resolve this issue, when private keys are exported from a wallet, the Wallet Import Format that is used to represent them is implemented differently in newer bitcoin wallets, to indicate that these private keys have been used to produce compressed public keys and therefore compressed bitcoin addresses. This allows the importing wallet to distinguish between private keys originating from older or newer wallets and search the blockchain for transactions with bitcoin addresses corresponding to the uncompressed, or the compressed public keys respectively. Let’s look at how this works in more detail, in the next section.
Compressed Private Keys
Ironically, the name “compressed private key” is misleading, because when a private key is exported as WIF-compressed it is actually one byte longer than an “uncompressed” private key. That is because it has the added 01 suffix which signifies it comes from a newer wallet and should only be used to produce compressed public keys. Private keys are not compressed and cannot be compressed. The term “compressed private key” really means “private key from which compressed public keys should be derived”,
whereas “uncompressed private key” really means “private key from which uncompressed public keys should be derived”. You should only refer to the export format as “WIF-compressed” or “WIF” and not refer to the private key as “compressed” to avoid further confusion.
Remember, these formats are not used interchangeably. In a newer wallet that implements compressed public keys, the private keys will only ever be exported as WIF-compressed (with a K or L prefix). If the wallet is an older implementation and does not use compressed public keys, the private keys will only ever be exported as WIF (5 prefix).
The goal here is to signal to the wallet importing these private keys whether it must search the blockchain for compressed or uncompressed public keys and addresses.
If a bitcoin wallet is able to implement compressed public keys, then it will use those in all transactions. The private keys in the wallet will be used to derive the public key points on the curve, which will be compressed. The compressed public keys will be used to produce bitcoin addresses and those will be used in transactions. When exporting private keys from a new wallet that implements compressed public keys, the Wallet Import Format is modified, with the addition of a one-byte suffix +01+to the private key. The
resulting base58check encoded private key is called a “Compressed WIF” and starts with the letter K or L, instead of starting with “5” as is the case with WIF encoded (non-compressed) keys from older wallets.
Here’s the same key, encoded in WIF and WIF-compressed formats
“Compressed private keys” is a misnomer! They are not compressed, rather the WIF-compressed format signifies that they should only be used to derive compressed public keys and their corresponding bitcoin addresses. Ironically, a “WIF-compressed” encoded private key is one byte longer because it has the added 01 suffix to distinguish it from an “uncompressed” one.