electrum-personal-server

Maximally lightweight electrum server for a single user
git clone https://git.parazyd.org/electrum-personal-server
Log | Files | Refs | README

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)