You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

95 lines
3.1 KiB

from jmbitcoin.secp256k1_main import *
import hmac
import hashlib
import struct
# Below code ASSUMES binary inputs and compressed pubkeys
MAINNET_PRIVATE = b'\x04\x88\xAD\xE4'
MAINNET_PUBLIC = b'\x04\x88\xB2\x1E'
TESTNET_PRIVATE = b'\x04\x35\x83\x94'
TESTNET_PUBLIC = b'\x04\x35\x87\xCF'
PRIVATE = [MAINNET_PRIVATE, TESTNET_PRIVATE]
PUBLIC = [MAINNET_PUBLIC, TESTNET_PUBLIC]
# BIP32 child key derivation
def raw_bip32_ckd(rawtuple, i):
vbytes, depth, fingerprint, oldi, chaincode, key = rawtuple
i = int(i)
if vbytes in PRIVATE:
priv = key
pub = privtopub(key, False)
else:
pub = key
if i >= 2**31:
if vbytes in PUBLIC:
raise Exception("Can't do private derivation on public key!")
I = hmac.new(chaincode, b'\x00' + priv[:32] + encode(i, 256, 4),
hashlib.sha512).digest()
else:
I = hmac.new(chaincode, pub + encode(i, 256, 4),
hashlib.sha512).digest()
if vbytes in PRIVATE:
newkey = add_privkeys(I[:32] + b'\x01', priv, False)
fingerprint = bin_hash160(privtopub(key, False))[:4]
if vbytes in PUBLIC:
newkey = add_pubkeys([privtopub(I[:32] + b'\x01', False), key], False)
fingerprint = bin_hash160(key)[:4]
return (vbytes, depth + 1, fingerprint, i, I[32:], newkey)
def bip32_serialize(rawtuple):
vbytes, depth, fingerprint, i, chaincode, key = rawtuple
if isinstance(i, int):
i = struct.pack(b'>L', i)
chaincode = chaincode
keydata = b'\x00' + key[:-1] if vbytes in PRIVATE else key
bindata = vbytes + from_int_to_byte(
depth % 256) + fingerprint + i + chaincode + keydata
return b58encode(bindata + bin_dbl_sha256(bindata)[:4])
def bip32_deserialize(data):
dbin = b58decode(data)
if bin_dbl_sha256(dbin[:-4])[:4] != dbin[-4:]:
raise Exception("Invalid checksum")
vbytes = dbin[0:4]
depth = dbin[4]
fingerprint = dbin[5:9]
i = decode(dbin[9:13], 256)
chaincode = dbin[13:45]
key = dbin[46:78] + b'\x01' if vbytes in PRIVATE else dbin[45:78]
return (vbytes, depth, fingerprint, i, chaincode, key)
def raw_bip32_privtopub(rawtuple):
vbytes, depth, fingerprint, i, chaincode, key = rawtuple
if vbytes in PUBLIC:
return rawtuple
newvbytes = MAINNET_PUBLIC if vbytes == MAINNET_PRIVATE else TESTNET_PUBLIC
return (newvbytes, depth, fingerprint, i, chaincode, privtopub(key, False))
def bip32_privtopub(data):
return bip32_serialize(raw_bip32_privtopub(bip32_deserialize(data)))
def bip32_ckd(data, i):
return bip32_serialize(raw_bip32_ckd(bip32_deserialize(data), i))
def bip32_master_key(seed, vbytes=MAINNET_PRIVATE):
I = hmac.new(
from_string_to_bytes("Bitcoin seed"), seed, hashlib.sha512).digest()
return bip32_serialize((vbytes, 0, b'\x00' * 4, 0, I[32:], I[:32] + b'\x01'
))
def bip32_extract_key(data):
return safe_hexlify(bip32_deserialize(data)[-1])
def bip32_descend(*args):
if len(args) == 2:
key, path = args
else:
key, path = args[0], map(int, args[1:])
for p in path:
key = bip32_ckd(key, p)
return bip32_extract_key(key)