Ken Shirriff’s blog post here has an excellent introduction to Bitcoin. One of his code snippets shows a sample python code to generate a private key in WIF format and an address. I tweaked it just a bit to replace usage of python’s random module with os.urandom and stripped it down to just what’s needed to show the exponent, private key and address. Here’s the effort in a gist:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ecdsa | |
import ecdsa.der | |
import ecdsa.util | |
import hashlib | |
import os | |
import re | |
import struct | |
b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' | |
def base58encode(n): | |
result = '' | |
while n > 0: | |
result = b58[n%58] + result | |
n /= 58 | |
return result | |
def base256decode(s): | |
result = 0 | |
for c in s: | |
result = result * 256 + ord(c) | |
return result | |
def countLeadingChars(s, ch): | |
count = 0 | |
for c in s: | |
if c == ch: | |
count += 1 | |
else: | |
break | |
return count | |
# https://en.bitcoin.it/wiki/Base58Check_encoding | |
def base58CheckEncode(version, payload): | |
s = chr(version) + payload | |
checksum = hashlib.sha256(hashlib.sha256(s).digest()).digest()[0:4] | |
result = s + checksum | |
leadingZeros = countLeadingChars(result, '\0') | |
return '1' * leadingZeros + base58encode(base256decode(result)) | |
def privateKeyToWif(key_hex): | |
return base58CheckEncode(0x80, key_hex.decode('hex')) | |
def privateKeyToPublicKey(s): | |
sk = ecdsa.SigningKey.from_string(s.decode('hex'), curve=ecdsa.SECP256k1) | |
vk = sk.verifying_key | |
return ('\04' + sk.verifying_key.to_string()).encode('hex') | |
def pubKeyToAddr(s): | |
ripemd160 = hashlib.new('ripemd160') | |
ripemd160.update(hashlib.sha256(s.decode('hex')).digest()) | |
return base58CheckEncode(0, ripemd160.digest()) | |
def keyToAddr(s): | |
return pubKeyToAddr(privateKeyToPublicKey(s)) | |
# Generate a random private key | |
private_key = os.urandom(32).encode('hex') | |
# You can verify the values on http://brainwallet.org/ | |
print "Secret Exponent (Uncompressed) : %s " % private_key | |
print "Private Key : %s " % privateKeyToWif(private_key) | |
print "Address : %s " % keyToAddr(private_key) |
Leave a comment