In this post I’ll show you how I generate bitcoin addresses in python3.6. The purpose of these addresses is to hold bitcoins for long times and not for frequently usage (because if not, you should import the private key to other more complex software you have not fully read).

Why generate my own bitcoin addresses?

Because you should take care about everything that has been in contact with your private keys. Remember that if you don’t hold the private keys needed to spend your Bitcoins, you don’t own any Bitcoin. And if you don’t take care of your private keys, everyone that knows them will own also your Bitcoins.

Address generation

Let’s create an address for a pay to public key hash (P2PKH) payment. You don’t need to import it in any wallet. It’s just for generating an address to receive payments. If you import the private keys to a wallet (a software you has not validated) you should move back to an address you have generated and fully validated as soon as possible.

Generating private keys

A bitcoin private key is a number between 1 and 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140. The critical point is to generate it from a source with the highest entropy possible.

A source with a high entropy, broadly speaking, is good at generating random numbers. Thus, we need a data source with the highest entropy possible to generate our private key. We have several options:

  • A good dice (the best choice in terms of security)
  • Rely on good programming libraries

It’s important to do not trust on human entropy generation. We tend to generate patterns so it’s really a bad idea. For the sake of simplicity, I’ll choice a python3 library named secrets.

import secrets
import binascii

def generatePrivateKey():
	number = int(secrets.randbelow(1 << 256))
	while number < 1 or number > 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140:
	    number = secrets.randbelow(1 << 256)
	return binascii.hexlify(number.to_bytes(32, byteorder='big'))

generatePrivateKey()

Voilà! This code snippet generates the most important thing we have to take care of: private keys.

Generating public keys

Bitcoin uses an algorithm named Elliptic Curve Digital Signature Algorithm (ECDSA) to generate, from the previous random number, a public key. In particular, the properties of the curve used in bitcoin is the curve secp256k1. We have used the following example as the private key: E9873D79C6D87DC0FB6A5778633389F4453213303DA61F20BD67FC233AA33262.

import ecdsa
import binascii

def generatePublicKey(privKey):
	bytes_privKey = binascii.unhexlify(privKey)
	return ecdsa.SigningKey.from_string(bytes_privKey, curve=ecdsa.SECP256k1).get_verifying_key().to_string()

binascii.hexlify(generatePublicKey(b"E9873D79C6D87DC0FB6A5778633389F4453213303DA61F20BD67FC233AA33262"))

Generating bitcoin addresses

The last step in order to be able to receive Bitcoins is to generate from the previous public key your bitcoin address. Bitcoin can perform that in different ways:

  • Base58Check encoding of the hash of the previous public key (P2PKH). Available since first bitcoin 0.1 release
  • Addresses for P2SH payments. Available since BIP-13 activation
  • Addresses for segregate witness payments. Available since BIP-141 activation

The most secure would be generating a 3of5 multisig script for P2PSH or P2WSH and share the keys among secure and different places/persons. However, for the sake of simplicity, we’ll explore P2PKH. In further posts, we will cover multisig address generation. The public key used is 588d202afcc1ee4ab5254c7847ec25b9a135bbda0f2bc69ee1a714749fd77dc9f88ff2a00d7e752d44cbe16e1ebcf0890b76ec7c78886109dee76ccfc844542.

import binascii
import hashlib

def ripemd160(x):
    d = hashlib.new('ripemd160')
    d.update(x)
    return d

def hash160(x):
    return ripemd160(hashlib.sha256(x).digest())

def get_address_for_P2PKH_payments(pubKey, addr_version=0):
	pubkey_hex = binascii.unhexlify(pubKey)
	hashed_key = hash160(pubkey_hex).digest()
	btc_addr = base58.b58encode_check(addr_version.to_bytes(1, byteorder="big") + hashed_key).decode()
	return btc_addr

get_address_for_P2PKH_payments(b"588d202afcc1ee4ab5254c7847ec25b9a135bbda0f2bc69ee1a714749fd77dc9f88ff2a00d7e752d44cbe16e1ebcf0890b76ec7c78886109dee76ccfc8445424")

It will generate the bitcoin address: 17Pe3AFYeqk3Nnneyr7SE3EkSauJkbHqaP

Conclusions

It’s really easy to generate bitcoin addresses trusting the minimum in third-party code (including open source, they are not as secure as you may think). You can master these pieces of code to generate your own addresses and provide an extra security. We have imported only the following libraries:

  • binascii
  • hashlib
  • ecdsa
  • secrets (we’ll see how generate entropy in further posts to avoid this dependency)

In future posts…

  • How to use a dice to generate entropy to avoid secrets or other third-party libraries/systems
  • How to generate a 3of5 multisig address to handle real circumstances: 2 private keys compromised, death, kidnapping or extortion

Leave a comment

Your email address will not be published. Required fields are marked *