secp256k1_deterministic.py (3240B)
1 from electrumpersonalserver.bitcoin.secp256k1_main import * 2 import hmac 3 import hashlib 4 from binascii import hexlify 5 6 # Below code ASSUMES binary inputs and compressed pubkeys 7 MAINNET_PRIVATE = b'\x04\x88\xAD\xE4' 8 MAINNET_PUBLIC = b'\x04\x88\xB2\x1E' 9 TESTNET_PRIVATE = b'\x04\x35\x83\x94' 10 TESTNET_PUBLIC = b'\x04\x35\x87\xCF' 11 PRIVATE = [MAINNET_PRIVATE, TESTNET_PRIVATE] 12 PUBLIC = [MAINNET_PUBLIC, TESTNET_PUBLIC] 13 14 # BIP32 child key derivation 15 16 def raw_bip32_ckd(rawtuple, i): 17 vbytes, depth, fingerprint, oldi, chaincode, key = rawtuple 18 i = int(i) 19 20 if vbytes in PRIVATE: 21 priv = key 22 pub = privtopub(key, False) 23 else: 24 pub = key 25 26 if i >= 2**31: 27 if vbytes in PUBLIC: 28 raise Exception("Can't do private derivation on public key!") 29 I = hmac.new(chaincode, b'\x00' + priv[:32] + encode(i, 256, 4), 30 hashlib.sha512).digest() 31 else: 32 I = hmac.new(chaincode, pub + encode(i, 256, 4), 33 hashlib.sha512).digest() 34 35 if vbytes in PRIVATE: 36 newkey = add_privkeys(I[:32] + B'\x01', priv, False) 37 fingerprint = bin_hash160(privtopub(key, False))[:4] 38 if vbytes in PUBLIC: 39 newkey = add_pubkeys([privtopub(I[:32] + '\x01', False), key], False) 40 fingerprint = bin_hash160(key)[:4] 41 42 return (vbytes, depth + 1, fingerprint, i, I[32:], newkey) 43 44 def bip32_serialize(rawtuple): 45 vbytes, depth, fingerprint, i, chaincode, key = rawtuple 46 i = encode(i, 256, 4) 47 chaincode = encode(hash_to_int(chaincode), 256, 32) 48 keydata = b'\x00' + key[:-1] if vbytes in PRIVATE else key 49 bindata = vbytes + from_int_to_byte( 50 depth % 256) + fingerprint + i + chaincode + keydata 51 return changebase(bindata + bin_dbl_sha256(bindata)[:4], 256, 58) 52 53 def bip32_deserialize(data): 54 dbin = changebase(data, 58, 256) 55 if bin_dbl_sha256(dbin[:-4])[:4] != dbin[-4:]: 56 raise Exception("Invalid checksum") 57 vbytes = dbin[0:4] 58 depth = from_byte_to_int(dbin[4]) 59 fingerprint = dbin[5:9] 60 i = decode(dbin[9:13], 256) 61 chaincode = dbin[13:45] 62 key = dbin[46:78] + b'\x01' if vbytes in PRIVATE else dbin[45:78] 63 return (vbytes, depth, fingerprint, i, chaincode, key) 64 65 def raw_bip32_privtopub(rawtuple): 66 vbytes, depth, fingerprint, i, chaincode, key = rawtuple 67 newvbytes = MAINNET_PUBLIC if vbytes == MAINNET_PRIVATE else TESTNET_PUBLIC 68 return (newvbytes, depth, fingerprint, i, chaincode, privtopub(key, False)) 69 70 def bip32_privtopub(data): 71 return bip32_serialize(raw_bip32_privtopub(bip32_deserialize(data))) 72 73 def bip32_ckd(data, i): 74 return bip32_serialize(raw_bip32_ckd(bip32_deserialize(data), i)) 75 76 def bip32_master_key(seed, vbytes=MAINNET_PRIVATE): 77 I = hmac.new( 78 from_string_to_bytes("Bitcoin seed"), seed, hashlib.sha512).digest() 79 return bip32_serialize((vbytes, 0, b'\x00' * 4, 0, I[32:], I[:32] + b'\x01' 80 )) 81 82 def bip32_extract_key(data): 83 return safe_hexlify(bip32_deserialize(data)[-1]) 84 85 def bip32_descend(*args): 86 if len(args) == 2: 87 key, path = args 88 else: 89 key, path = args[0], map(int, args[1:]) 90 for p in path: 91 key = bip32_ckd(key, p) 92 return bip32_extract_key(key)