Made bip32 extended key serialization functions more generic and allow passing params, with default params for master keys. Simplified some of the main.py test code.

This commit is contained in:
Josh K 2019-07-26 02:31:46 -04:00
parent fc0bb21e7f
commit f41b566576
3 changed files with 35 additions and 34 deletions

View File

@ -21,25 +21,21 @@ PRV_VER = bytes.fromhex( '02fac398' if DOGE_MODE else '0488ADE4' )
# 0488B21E - bitcoin pub # 0488B21E - bitcoin pub
# 02facafd - dogecoin pub # 02facafd - dogecoin pub
PUB_VER = bytes.fromhex( '02facafd' if DOGE_MODE else '0488B21E' ) PUB_VER = bytes.fromhex( '02facafd' if DOGE_MODE else '0488B21E' )
# return serialized master private key string from master private (key, chain) bytes pair
def serializeMasterPrvKey( master ):
depth = 0
parFP = intBytes( 0, 4 ) # parent fingerprint
childNum = 0
prvroot = base58.encodeCheck( PRV_VER, intBytes( depth, 1 ) +
parFP + intBytes( childNum, 4 ) + master[1] +
b'\x00' + master[0] )
return prvroot
# return serialized master public key string from master private (key, chain) bytes pair # serialize an extended private key (key, chain)
def serializeMasterPubKey( master ): # parfp is the 4byte parent fingerprint
depth = 0 # default parameters assume master key
parFP = intBytes( 0, 4 ) # parent fingerprint def serializeExtPrvKey( key, depth=0, parfp=b'\x00\x00\x00\x00', child=0 ):
childNum = 0 return base58.encodeCheck( PRV_VER, intBytes( depth, 1 ) +
pubroot = base58.encodeCheck( PUB_VER, intBytes( depth, 1 ) + parfp + intBytes( child, 4 ) + key[1] + b'\x00' + key[0] )
parFP + intBytes( childNum, 4 ) + master[1] +
keys.getPubKey( master[0] ) ) # serialize an extended public key (key, chain)
return pubroot # key is compressed public point bytes
# parfp is the 4byte parent fingerprint
# default parameters assume master key
def serializeExtPubKey( key, depth=0, parfp=b'\x00\x00\x00\x00', child=0 ):
return base58.encodeCheck( PUB_VER, intBytes( depth, 1 ) +
parfp + intBytes( child, 4 ) + key[1] + key[0] )
# public parent -> public child. # public parent -> public child.
# pub is (key, chain) where key is the compressed pubkey bytes # pub is (key, chain) where key is the compressed pubkey bytes

13
keys.py
View File

@ -4,7 +4,7 @@
from hashlib import new as newhash from hashlib import new as newhash
from hashlib import sha256 from hashlib import sha256
from random import getrandbits from os import urandom
import base58 import base58
import ecdsa import ecdsa
@ -20,15 +20,12 @@ WIF_VER = b'\x9e' if DOGE_MODE else b'\x80'
# 0x1e - dogecoin # 0x1e - dogecoin
ADDR_VER = b'\x1e' if DOGE_MODE else b'\x00' ADDR_VER = b'\x1e' if DOGE_MODE else b'\x00'
# gen random 256bit privkey as bytes # gen random 256bit prvkey bytes
def genRandPrvKey(): def genRandPrvKey(): return urandom( 32 )
# replace with os.urandom for the real deal
rawpk = intBytes( getrandbits( 256 ) )
return rawpk
# get base58 wif privkey from raw privkey bytes # get base58 wif privkey from raw privkey bytes
def getPrvKeyWIF( rawpk ): def getPrvKeyWIF( prv ):
return base58.encodeCheck( WIF_VER, rawpk + b'\x01' ) return base58.encodeCheck( WIF_VER, prv + b'\x01' )
# get hash160 bytes of pubkey bytes. base58Check this for addr # get hash160 bytes of pubkey bytes. base58Check this for addr
# also used for bip32 ext key identifier. first 32bits of id is the fingerprint # also used for bip32 ext key identifier. first 32bits of id is the fingerprint

24
main.py
View File

@ -18,20 +18,28 @@ if __name__ == '__main__':
b39seed = bip39.genSeed( b39phrase ) b39seed = bip39.genSeed( b39phrase )
# test bip32 # test bip32
# master (key, chain) bytes # master private (key, chain) bytes
b32master = bip32.getMaster( b39seed ) b32master = bip32.getMaster( b39seed )
# serialize root master prv and pub key # serialize master ext prv and pub key
b32masterxprv = bip32.serializeMasterPrvKey( b32master ) b32masterxprv = bip32.serializeExtPrvKey( b32master )
b32masterxpub = bip32.serializeMasterPubKey( b32master ) b32masterxpub = bip32.serializeExtPubKey( (keys.getPubKey( b32master[0] ), b32master[1]) )
print( 'BIP39\n', b39phrase + '\n', b39seed.hex() + '\nBIP32\n' + print( 'BIP39 phrase, seed\n\t', b39phrase + '\n\t', b39seed.hex() +
f'{b32masterxprv}\n{b32masterxpub}\n{base58.decodeCheck( b32masterxprv ).hex()}\n{base58.decodeCheck( b32masterxpub ).hex()}' ) '\nBIP32 master\n' + f'\t{b32masterxprv}\n\t{b32masterxpub}' )
print() print()
prvmaster = (b32master[0], b32master[1]) prvmaster = (b32master[0], b32master[1])
prvroot0 = bip32.ckdPrv( prvmaster, 0 ) # m/0 prvroot0 = bip32.ckdPrv( prvmaster, 0 ) # m/0
parfp = keys.getPubKeyHash( keys.getPubKey( prvmaster[0] ) )[:4] # parent fingerprint
prvroot0ext = bip32.serializeExtPrvKey(
prvroot0, 1, parfp, 0 )
pubroot0ext = bip32.serializeExtPubKey(
(keys.getPubKey( prvroot0[0] ), prvroot0[1]), 1, parfp, 0 )
print( f'm/0 derived ext keys:\n\t{prvroot0ext}\n\t{pubroot0ext}' )
for i in range( 20 ): for i in range( 20 ):
# pubkeys # pubkey - prvkey
pk = bip32.ckdPrv( prvroot0, i )[0] pk = bip32.ckdPrv( prvroot0, i )[0]
print( 'm/0/{}: {} - {}'.format( i, keys.getPubKey( pk ).hex(), keys.getPrvKeyWIF( pk ) ) ) print( 'm/0/{}: {} - {}'.format( i, keys.getPubKey( pk ).hex(), keys.getPrvKeyWIF( pk ) ) )
@ -42,6 +50,6 @@ if __name__ == '__main__':
pubaddr = keys.getPubKeyAddr( pubkey ) pubaddr = keys.getPubKeyAddr( pubkey )
print( f'prvkey hex: {prvkey.hex()}' ) print( f'prvkey hex: {prvkey.hex()}' )
print( f'b58 wif pk: {keys.getPrvKeyWIF( prvkey )}' ) print( f'b58 wif pk: {keys.getPrvKeyWIF( prvkey )}' )
print( f'pubkey: {pubkey.hex()}\n\thash: {keys.getPubKeyHash( pubkey ).hex()}\n\taddr: {pubaddr}\n\tdecoded: {base58.decodeCheck( pubaddr ).hex()}' ) print( f'pubkey: {pubkey.hex()}\n\thash: {keys.getPubKeyHash( pubkey ).hex()}\n\taddr: {pubaddr}' )
""" """