This article is the following of Understanding bitcoin addresses (part 1). We took a brief look in this article how to create with openssl a private/public ECDSA secp256k1 key and how to create from this a Bitcoin address and its private key in Wallet Import Format (WIF).
There is still a lot to talk about Bitcoin addresses. This article will cover:
We saw in part-1 that the size of an uncompressed key was 65 bytes, starting by 0x04. A single public key can also have a compressed representation. Its size will be 33 bytes, and will start by either 0x02 or 0x03.
In fact, a public key is composed by a couple of integers, x & y, and in its uncompressed form, the public key is simple [0x04] [X value] [Y value]. In its compressed form, the public key is [0x02 or 0x03 prefix] [X value], because for an X value, the Y value can have only 2 values, an odd one and an even one. Then, the prefix will be 0x02 if Y is even, and 0x03 if it is odd.
Knowing this, the address generation script is very simple to update. We have only the get_public_key function to update:
The complete script is still available on my repository.
Again, the change is light for private addresses. There is no compress form for private key, so the only change is to inform that the address is compressed, by adding a compression flag 0x01 after the private key. The format will then be [prefix] [32 bytes private-key] [compression flag: 0x01] [checksum]. With this form, the private key prefix will change from 5 to L or K, as documented on List of address prefixes.
The change in our python code is a one-liner:
Let’s perform a quick check:
We are good ! Last step: just add this key to Bitcoin Core and check we are still good.
Addresses are correct. Don’t forget the false flag or you’ll have to wait 30 minutes for bitcoind to rescan the whole chain!
Script addresses, or P2SH addresses were introduced in bip-16 to allow transactions to be sent to a script hash instead of a public key hash. The main difference is that we have to provide a script matching the script hash to spend an output, and then, this provides more security that just using a public key/private key, as we can use more than one key to protect our transaction using OP_CHECKMULTISIG, for example. These addresses are starting with the integer 3 (ex: 3G734WzCrphZxN7afnrbwunZjV8MBqWUUV) and their prefix is 0x05, as set in Bitcoin Core:
For information, values for testnet are:
I found out a nice article to understand possibilities using P2SH address.
Creating a P2SH address is not that simple than previous ones. We need a script (that we’ll use to create a hash), and its redeemscript (the script that will allow to unlock the transaction).
Let’s use bitcoin-cli to create our address. We need at least a public key, so we will create a legacy address:
… and then the script address:
We case easily parse the redeemscript generated 512103c09c6ebdebfe02bbbbacd77687e17e5361d07b54efb392e53829edf4f46bd4ee51ae:
51 21 03c09c6ebdebfe02bbbbacd77687e17e5361d07b54efb392e53829edf4f46bd4ee 51 ae
<OP_TRUE> <push 0x21 bytes> <0x21 bytes of public key> <OP_TRUE> <OP_CHECKMULTISIG>
And we’re done, as our address is 2NGAz9ShNSXPWBtg9DPvCjxsx6XEr9pnZHs ! We can now use that address to retrieve bitcoins, and we’ll have to use the redeemscript (and private key of embedded public key) to unlock our coins.
Let’s update our python code:
If you need to spend those, you should refer to this developer example. Also, you can import your private key, and coins will be usable.
Bech32 was introduced by bip173 for segwit transactions. It uses a new hashing format and is supported since Bitcoin Core 0.16.
Like p2sh addresses above, we will use bitcoin-cli to create an address.
The format is simple to understand. It is composed by a prefix (hrp, human readable part, bc for bitcoin’s mainnet, tb for bitcoin’s testnet), a program version and a witness program. for a simple p2wpkh (pay to witness public key hash), the witness program is simply ripemd160(sha160(compressed public key)). In case of more secure p2wsh address, the witness program will be the sha256-hashed (and not ripemd160(sha256())-hashed!) p2sh script (or redeem script), as described in bip141.
We will need a bech32 implementation. There is a lot of samples for multiple languages in this repository. Generating bech32 address will be simple as just calling the encode function:
Other ways to generate private keys
As there are another methods to generate private keys that will need a new post to talk about: