Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
311 views

Bitcoin Address Generation in Pure Python - OPSXCQ Blog

This document discusses bitcoin address generation in Python. It describes the 4 main steps: 1) generating a private key, 2) calculating the public key from the private key, 3) encoding the public key as a bitcoin address, and 4) encoding the private key in the WIF format. Code examples are provided to generate an address and WIF from a random private key. The code uses elliptic curve cryptography over the secp256k1 curve to perform the key generation and address encoding.

Uploaded by

Megan Kos
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
311 views

Bitcoin Address Generation in Pure Python - OPSXCQ Blog

This document discusses bitcoin address generation in Python. It describes the 4 main steps: 1) generating a private key, 2) calculating the public key from the private key, 3) encoding the public key as a bitcoin address, and 4) encoding the private key in the WIF format. Code examples are provided to generate an address and WIF from a random private key. The code uses elliptic curve cryptography over the secp256k1 curve to perform the key generation and address encoding.

Uploaded by

Megan Kos
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1

[OPSXCQ Blog] # _

published on September 14, 2018


tags: cryptography eliptic curves bitcoin python

Bitcoin address generation


in pure python

Bitcoin address generation can be split in 4 steps listed


bellow:

Generating a secure private key.


Calculate the public key from the private key.
Encode the public key as a bitcoin address.
Encode the private key in the WIF format.

Step 1: Generate ECDSA Keypair


The very first step is to select a good and secure number,
for this example we won’t use one, instead we will simply
get the random from the system. An example why is important
a good and secure random number is written in this post
about cracking some bitcoin private keys, the bug isn’t
located in the key generation, but in the random used to
sign the transactions, but the point is the same, weak PRNG
(Pseudo-random number generators) can put everything in
risk.

Using this PRNG can be done with:

randomBytes = os.urandom(32)

Step 2: Calculate the public key


Since bitcoin uses spec256k1 the only thing that we need to
do is multiply it by the initial point in the curve by the
private key to obtain the public key.

Next step is to convert the key to a byte array and hash it,
first with SHA-256 then with RIPEMD-160. Then we prepend
the hashed public key with 0x00 if the target network is
the mainnet, if the address generated meant to be used in
the testnet 0x6f must be prepended.

SPEC256k1 = Point()
pk = int.from_bytes(privkey, "big")
hash160 = ripemd160(sha256((SPEC256k1 * pk).toBytes()))
address = b"\x00" + hash160

Checksum
Then the only thing left to add in the address it the
checksum, it is appended to the address and is the last 4
bytes of the double SHA-256 of the address calculated above.

address = b58(address + sha256(sha256(address))[:4])

Then just encode the key bytes to base58 and you have your
Bitcoin address !

Public key compression


When representing the public key as a number is possible to
compress it considering that the key is x and y in the
eliptic curve and since we have the equation, and given an
x value, there is only two values for y possible. So to

compress a public key, if y is odd, 0x03 is appended to


the x value, else, 0x02 is appended.

Step 4: Encode the private key


in the WIF format
To create a WIF () key from the private key bytes is far
simples than the previous steps, first prepend the byte
0x80 to the wif, then append the private key bytes. After,
append the checksum, that is the last 4 bytes of the double
SHA-256 of the partial wif key that we already have
calculated.

wif = b"\x80" + privkey


wif = b58(wif + sha256(sha256(wif))[:4])
return wif

Source code
This is a reference script, it depends on Python 3 to run
and is self contained, it means no external dependencies are
required to run it. One example of its output:

$ ./bitcoin-address-generator.py
Address: 18jJh1kSPJqbXtMB51SyczgcHL1drkDgxV
Privkey: 5JTEF3GHpDAin1caVqfznHU8T1jscHVVD5SMFALBTC4no2J4DqX

import os
import hashlib

def sha256(data):
digest = hashlib.new("sha256")
digest.update(data)
return digest.digest()

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

def b58(data):
B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

if data[0] == 0:
return "1" + b58(data[1:])

x = sum([v * (256 ** i) for i, v in enumerate(data[::-1])])


ret = ""
while x > 0:
ret = B58[x % 58] + ret
x = x // 58

return ret

class Point:
def __init__(self,
x=0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
y=0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8,
p=2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1):
self.x = x
self.y = y
self.p = p

def __add__(self, other):


return self.__radd__(other)

def __mul__(self, other):


return self.__rmul__(other)

def __rmul__(self, other):


n = self
q = None

for i in range(256):
if other & (1 << i):
q = q + n
n = n + n

return q

def __radd__(self, other):


if other is None:
return self
x1 = other.x
y1 = other.y
x2 = self.x
y2 = self.y
p = self.p

if self == other:
l = pow(2 * y2 % p, p-2, p) * (3 * x2 * x2) % p
else:
l = pow(x1 - x2, p-2, p) * (y1 - y2) % p

newX = (l ** 2 - x2 - x1) % p
newY = (l * x2 - l * newX - y2) % p

return Point(newX, newY)

def toBytes(self):
x = self.x.to_bytes(32, "big")
y = self.y.to_bytes(32, "big")
return b"\x04" + x + y

def getPublicKey(privkey):
SPEC256k1 = Point()
pk = int.from_bytes(privkey, "big")
hash160 = ripemd160(sha256((SPEC256k1 * pk).toBytes()))
address = b"\x00" + hash160

address = b58(address + sha256(sha256(address))[:4])


return address

def getWif(privkey):
wif = b"\x80" + privkey
wif = b58(wif + sha256(sha256(wif))[:4])
return wif

if __name__ == "__main__":
randomBytes = os.urandom(32)
print("Address: " + getPublicKey(randomBytes))
print("Privkey: " + getWif(randomBytes))

References
Eliptic curves in cryptography
Bitcoin Address documentation

© 2019 OPSXCQ Blog - CC BY 4.0

You might also like