implemented function xprivate_to_xpublic_key (BIP0032/BIP0044)

This commit is contained in:
Alexey Karyabkin 2018-06-19 17:18:34 +04:00
parent 4ad4fea4b5
commit 6a48f8965c

View File

@ -95,18 +95,18 @@ def mnemonic_to_seed(passphrase, password):
# #
# создание родительского приватного ключа # создание родительского приватного ключа
def create_master_key_hdwallet(seed, testnet=False): def create_xmaster_key(seed, testnet=False):
if testnet: if testnet:
version = TESTNET_PRIVATE_WALLET_VERSION version = TESTNET_PRIVATE_WALLET_VERSION
else: else:
version = MAINNET_PRIVATE_WALLET_VERSION version = MAINNET_PRIVATE_WALLET_VERSION
key = b'Bitcoin seed' key = b'Bitcoin seed'
intermediary = hmac_sha512(key, seed) intermediary = hmac_sha512(key, seed)
master_key = intermediary[:32] mkey = intermediary[:32]
chain_code = intermediary[32:] chain_code = intermediary[32:]
if validate_private_key(master_key) and validate_private_key(chain_code): if validate_private_key(mkey) and validate_private_key(chain_code):
return dict(version=version, return dict(version=version,
key=master_key, key=mkey,
depth=0, depth=0,
child=0, child=0,
finger_print=b'\x00\x00\x00\x00', finger_print=b'\x00\x00\x00\x00',
@ -116,19 +116,36 @@ def create_master_key_hdwallet(seed, testnet=False):
return None return None
def create_xpublic_key(key):
if key['is_private']:
if key['version'] == TESTNET_PRIVATE_WALLET_VERSION:
version = TESTNET_PUBLIC_WALLET_VERSION
else:
version = MAINNET_PUBLIC_WALLET_VERSION
pubkey = private_to_public_key(key['key'], True)
return dict(version=version,
key=pubkey,
depth=key['depth'],
child=key['child'],
finger_print=key['finger_print'],
chain_code=key['chain_code'],
is_private=False)
return None
def derive_xkey(seed, *path_level, bip44=True, testnet=True, wif=True): def derive_xkey(seed, *path_level, bip44=True, testnet=True, wif=True):
if not bip44: if not bip44:
if not len(path_level): if not len(path_level):
raise TypeError("not specified path levels") raise TypeError("not specified path levels")
mkey = create_master_key_hdwallet(seed, testnet) mkey = create_xmaster_key(seed, testnet)
xkey = create_child_privkey(mkey, path_level[0]) xkey = create_child_privkey(mkey, path_level[0])
for idx in path_level[1:]: for idx in path_level[1:]:
xkey = create_child_privkey(xkey, idx) xkey = create_child_privkey(xkey, idx)
# сериализация и кодирование ключа # сериализация и кодирование ключа
if wif: if wif:
result = encode_base58(serialize_key_hdwallet(xkey)) result = encode_base58(serialize_xkey(xkey))
else: else:
result = serialize_key_hdwallet(xkey) result = serialize_xkey(xkey)
return result return result
else: else:
if not validate_path_level(path_level, testnet): if not validate_path_level(path_level, testnet):
@ -138,34 +155,27 @@ def derive_xkey(seed, *path_level, bip44=True, testnet=True, wif=True):
path_level = TESTNET_PATH_LEVEL_BIP0044 path_level = TESTNET_PATH_LEVEL_BIP0044
else: else:
path_level = PATH_LEVEL_BIP0044 path_level = PATH_LEVEL_BIP0044
mkey = create_master_key_hdwallet(seed, testnet) mkey = create_xmaster_key(seed, testnet)
xkey = create_child_privkey(mkey, path_level[0]) xkey = create_child_privkey(mkey, path_level[0])
for idx in path_level[1:]: for idx in path_level[1:]:
xkey = create_child_privkey(xkey, idx) xkey = create_child_privkey(xkey, idx)
# сериализация и кодирование ключа # сериализация и кодирование ключа
if wif: if wif:
result = encode_base58(serialize_key_hdwallet(xkey)) result = encode_base58(serialize_xkey(xkey))
else: else:
result = serialize_key_hdwallet(xkey) result = serialize_xkey(xkey)
return result return result
def xprivate_to_xpublic_key(xprv, encode_b58=True):
## Надо удалить в будущем как дублирование. И добавить в реализации ООП как метод if validate_private_key(xprv):
def create_parent_pubkey_hdwallet(master_key): xprivkey = deserialize_xkey(xprv)
if master_key['is_private']: xpubkey = create_xpublic_key(xprivkey)
if master_key['version'] == TESTNET_PRIVATE_WALLET_VERSION: if encode_b58:
version = TESTNET_PUBLIC_WALLET_VERSION return encode_base58(serialize_xkey(xpubkey))
else: return serialize_xkey(xpubkey)
version = MAINNET_PUBLIC_WALLET_VERSION else:
pubkey = private_to_public_key(master_key['key'], True) raise TypeError("Private key must be serialized according to BIP-0032 - " \
return dict(version=version, "https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format")
key=pubkey,
depth=master_key['depth'],
child=master_key['child'],
finger_print=master_key['finger_print'],
chain_code=master_key['chain_code'],
is_private=False)
return None
# Создание дочернего приватного ключа # Создание дочернего приватного ключа
@ -252,9 +262,13 @@ def add_public_keys(ext_value, key):
def validate_private_key(key): def validate_private_key(key):
key_int = int.from_bytes(key, byteorder="big") if isinstance(key, bytes):
if key_int > 0 and key_int < MAX_INT_PRIVATE_KEY and len(key) == 32: key_int = int.from_bytes(key, byteorder="big")
return True if key_int > 0 and key_int < MAX_INT_PRIVATE_KEY and len(key) == 32:
return True
elif isinstance(key, str):
if len(key) == 111 and key[:4] in ['xprv', 'tprv']:
return True
return False return False
@ -275,7 +289,7 @@ def validate_path_level(path_level, testnet):
return False return False
def serialize_key_hdwallet(key): def serialize_xkey(key):
try: try:
key_bytes = key['key'] key_bytes = key['key']
if key.get('is_private'): if key.get('is_private'):
@ -293,7 +307,7 @@ def serialize_key_hdwallet(key):
raise Exception('Serialization error') raise Exception('Serialization error')
def deserialize_key_hdwallet(encode_key): def deserialize_xkey(encode_key):
raw_key = decode_base58(encode_key) raw_key = decode_base58(encode_key)
decode_key = dict() decode_key = dict()
if raw_key[:4] in [MAINNET_PUBLIC_WALLET_VERSION, MAINNET_PRIVATE_WALLET_VERSION]: if raw_key[:4] in [MAINNET_PUBLIC_WALLET_VERSION, MAINNET_PRIVATE_WALLET_VERSION]: