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_main.py (14036B)


      1 #!/usr/bin/python
      2 from .py2specials import *
      3 from .py3specials import *
      4 import binascii
      5 import hashlib
      6 import re
      7 import sys
      8 import os
      9 import base64
     10 import time
     11 import random
     12 import hmac
     13 import secp256k1
     14 
     15 ctx = secp256k1.lib.secp256k1_context_create(secp256k1.ALL_FLAGS)
     16 
     17 def privkey_to_address(priv, from_hex=True, magicbyte=0):
     18     return pubkey_to_address(privkey_to_pubkey(priv, from_hex), magicbyte)
     19 
     20 privtoaddr = privkey_to_address
     21 
     22 # Hashes
     23 def bin_hash160(string):
     24     intermed = hashlib.sha256(string).digest()
     25     return hashlib.new('ripemd160', intermed).digest()
     26 
     27 def hash160(string):
     28     return safe_hexlify(bin_hash160(string))
     29 
     30 def bin_sha256(string):
     31     binary_data = string if isinstance(string, bytes) else bytes(string,
     32                                                                  'utf-8')
     33     return hashlib.sha256(binary_data).digest()
     34 
     35 def sha256(string):
     36     return bytes_to_hex_string(bin_sha256(string))
     37 
     38 def bin_dbl_sha256(s):
     39     bytes_to_hash = from_string_to_bytes(s)
     40     return hashlib.sha256(hashlib.sha256(bytes_to_hash).digest()).digest()
     41 
     42 def dbl_sha256(string):
     43     return safe_hexlify(bin_dbl_sha256(string))
     44 
     45 def hash_to_int(x):
     46     if len(x) in [40, 64]:
     47         return decode(x, 16)
     48     return decode(x, 256)
     49 
     50 def num_to_var_int(x):
     51     x = int(x)
     52     if x < 253: return from_int_to_byte(x)
     53     elif x < 65536: return from_int_to_byte(253) + encode(x, 256, 2)[::-1]
     54     elif x < 4294967296: return from_int_to_byte(254) + encode(x, 256, 4)[::-1]
     55     else: return from_int_to_byte(255) + encode(x, 256, 8)[::-1]
     56 
     57 # WTF, Electrum?
     58 def electrum_sig_hash(message):
     59     padded = b"\x18Bitcoin Signed Message:\n" + num_to_var_int(len(
     60         message)) + from_string_to_bytes(message)
     61     return bin_dbl_sha256(padded)
     62 
     63 # Encodings
     64 def b58check_to_bin(inp):
     65     leadingzbytes = len(re.match('^1*', inp).group(0))
     66     data = b'\x00' * leadingzbytes + changebase(inp, 58, 256)
     67     assert bin_dbl_sha256(data[:-4])[:4] == data[-4:]
     68     return data[1:-4]
     69 
     70 def get_version_byte(inp):
     71     leadingzbytes = len(re.match('^1*', inp).group(0))
     72     data = b'\x00' * leadingzbytes + changebase(inp, 58, 256)
     73     assert bin_dbl_sha256(data[:-4])[:4] == data[-4:]
     74     return ord(data[0])
     75 
     76 def hex_to_b58check(inp, magicbyte=0):
     77     return bin_to_b58check(binascii.unhexlify(inp), magicbyte)
     78 
     79 def b58check_to_hex(inp):
     80     return safe_hexlify(b58check_to_bin(inp))
     81 
     82 def pubkey_to_address(pubkey, magicbyte=0):
     83     if len(pubkey) in [66, 130]:
     84         return bin_to_b58check(
     85             bin_hash160(binascii.unhexlify(pubkey)), magicbyte)
     86     return bin_to_b58check(bin_hash160(pubkey), magicbyte)
     87 
     88 pubtoaddr = pubkey_to_address
     89 
     90 def wif_compressed_privkey(priv, vbyte=0):
     91     """Convert privkey in hex compressed to WIF compressed
     92     """
     93     if len(priv) != 66:
     94         raise Exception("Wrong length of compressed private key")
     95     if priv[-2:] != '01':
     96         raise Exception("Private key has wrong compression byte")
     97     return bin_to_b58check(binascii.unhexlify(priv), 128 + int(vbyte))
     98 
     99 
    100 def from_wif_privkey(wif_priv, compressed=True, vbyte=0):
    101     """Convert WIF compressed privkey to hex compressed.
    102     Caller specifies the network version byte (0 for mainnet, 0x6f
    103     for testnet) that the key should correspond to; if there is
    104     a mismatch an error is thrown. WIF encoding uses 128+ this number.
    105     """
    106     bin_key = b58check_to_bin(wif_priv)
    107     claimed_version_byte = get_version_byte(wif_priv)
    108     if not 128+vbyte == claimed_version_byte:
    109         raise Exception(
    110             "WIF key version byte is wrong network (mainnet/testnet?)")
    111     if compressed and not len(bin_key) == 33:
    112         raise Exception("Compressed private key is not 33 bytes")
    113     if compressed and not bin_key[-1] == '\x01':
    114         raise Exception("Private key has incorrect compression byte")
    115     return safe_hexlify(bin_key)
    116 
    117 def ecdsa_sign(msg, priv, usehex=True):
    118     #Compatibility issue: old bots will be confused
    119     #by different msg hashing algo; need to keep electrum_sig_hash, temporarily.
    120     hashed_msg = electrum_sig_hash(msg)
    121     if usehex:
    122         #arguments to raw sign must be consistently hex or bin
    123         hashed_msg = binascii.hexlify(hashed_msg)
    124     dersig = ecdsa_raw_sign(hashed_msg, priv, usehex, rawmsg=True)
    125     #see comments to legacy* functions
    126     #also, note those functions only handles binary, not hex
    127     if usehex:
    128         dersig = binascii.unhexlify(dersig)
    129     sig = legacy_ecdsa_sign_convert(dersig)
    130     return base64.b64encode(sig)
    131 
    132 def ecdsa_verify(msg, sig, pub, usehex=True):
    133     #See note to ecdsa_sign
    134     hashed_msg = electrum_sig_hash(msg)
    135     sig = base64.b64decode(sig)
    136     #see comments to legacy* functions
    137     sig = legacy_ecdsa_verify_convert(sig)
    138     if usehex:
    139         #arguments to raw_verify must be consistently hex or bin
    140         hashed_msg = binascii.hexlify(hashed_msg)
    141         sig = binascii.hexlify(sig)
    142     return ecdsa_raw_verify(hashed_msg, pub, sig, usehex, rawmsg=True)
    143 
    144 #A sadly necessary hack until all joinmarket bots are running secp256k1 code.
    145 #pybitcointools *message* signatures (not transaction signatures) used an old signature
    146 #format, basically: [27+y%2] || 32 byte r || 32 byte s,
    147 #instead of DER. These two functions translate the new version into the old so that
    148 #counterparty bots can verify successfully.
    149 def legacy_ecdsa_sign_convert(dersig):
    150     #note there is no sanity checking of DER format (e.g. leading length byte)
    151     dersig = dersig[2:]  #e.g. 3045
    152     rlen = ord(dersig[1])  #ignore leading 02
    153     #length of r and s: ALWAYS <=33, USUALLY >=32 but can be shorter
    154     if rlen > 33:
    155         raise Exception("Incorrectly formatted DER sig:" + binascii.hexlify(
    156             dersig))
    157     if dersig[2] == '\x00':
    158         r = dersig[3:2 + rlen]
    159         ssig = dersig[2 + rlen:]
    160     else:
    161         r = dersig[2:2 + rlen]
    162         ssig = dersig[2 + rlen:]
    163 
    164     slen = ord(ssig[1])  #ignore leading 02
    165     if slen > 33:
    166         raise Exception("Incorrectly formatted DER sig:" + binascii.hexlify(
    167             dersig))
    168     if len(ssig) != 2 + slen:
    169         raise Exception("Incorrectly formatted DER sig:" + binascii.hexlify(
    170             dersig))
    171     if ssig[2] == '\x00':
    172         s = ssig[3:2 + slen]
    173     else:
    174         s = ssig[2:2 + slen]
    175 
    176         #the legacy version requires padding of r and s to 32 bytes with leading zeros
    177     r = '\x00' * (32 - len(r)) + r
    178     s = '\x00' * (32 - len(s)) + s
    179 
    180     #note: in the original pybitcointools implementation,
    181     #verification ignored the leading byte (it's only needed for pubkey recovery)
    182     #so we just ignore parity here.
    183     return chr(27) + r + s
    184 
    185 def legacy_ecdsa_verify_convert(sig):
    186     sig = sig[1:]  #ignore parity byte
    187     r, s = sig[:32], sig[32:]
    188     if not len(s) == 32:
    189         #signature is invalid.
    190         return False
    191     #legacy code can produce high S. Need to reintroduce N ::cry::
    192     N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
    193     s_int = decode(s, 256)
    194     # note // is integer division operator in both 2.7 and 3
    195     s_int = N - s_int if s_int > N // 2 else s_int  #enforce low S.
    196 
    197     #on re-encoding, don't use the minlen parameter, because
    198     #DER does not used fixed (32 byte) length values, so we
    199     #don't prepend zero bytes to shorter numbers.
    200     s = encode(s_int, 256)
    201 
    202     #as above, remove any front zero padding from r.
    203     r = encode(decode(r, 256), 256)
    204 
    205     #canonicalize r and s
    206     r, s = ['\x00' + x if ord(x[0]) > 127 else x for x in [r, s]]
    207     rlen = chr(len(r))
    208     slen = chr(len(s))
    209     total_len = 2 + len(r) + 2 + len(s)
    210     return '\x30' + chr(total_len) + '\x02' + rlen + r + '\x02' + slen + s
    211 
    212 #Use secp256k1 to handle all EC and ECDSA operations.
    213 #Data types: only hex and binary.
    214 #Compressed and uncompressed private and public keys.
    215 def hexbin(func):
    216     '''To enable each function to 'speak' either hex or binary,
    217     requires that the decorated function's final positional argument
    218     is a boolean flag, True for hex and False for binary.
    219     '''
    220 
    221     def func_wrapper(*args, **kwargs):
    222         if args[-1]:
    223             newargs = []
    224             for arg in args[:-1]:
    225                 if isinstance(arg, (list, tuple)):
    226                     newargs += [[x.decode('hex') for x in arg]]
    227                 else:
    228                     newargs += [arg.decode('hex')]
    229             newargs += [False]
    230             returnval = func(*newargs, **kwargs)
    231             if isinstance(returnval, bool):
    232                 return returnval
    233             else:
    234                 return binascii.hexlify(returnval)
    235         else:
    236             return func(*args, **kwargs)
    237 
    238     return func_wrapper
    239 
    240 def read_privkey(priv):
    241     if len(priv) == 33:
    242         if priv[-1] == '\x01':
    243             compressed = True
    244         else:
    245             raise Exception("Invalid private key")
    246     elif len(priv) == 32:
    247         compressed = False
    248     else:
    249         raise Exception("Invalid private key")
    250     return (compressed, priv[:32])
    251 
    252 @hexbin
    253 def privkey_to_pubkey_inner(priv, usehex):
    254     '''Take 32/33 byte raw private key as input.
    255     If 32 bytes, return compressed (33 byte) raw public key.
    256     If 33 bytes, read the final byte as compression flag,
    257     and return compressed/uncompressed public key as appropriate.'''
    258     compressed, priv = read_privkey(priv)
    259     #secp256k1 checks for validity of key value.
    260     newpriv = secp256k1.PrivateKey(privkey=priv, ctx=ctx)
    261     return newpriv.pubkey.serialize(compressed=compressed)
    262 
    263 def privkey_to_pubkey(priv, usehex=True):
    264     '''To avoid changing the interface from the legacy system,
    265     allow an *optional* hex argument here (called differently from
    266     maker/taker code to how it's called in bip32 code), then
    267     pass to the standard hexbin decorator under the hood.
    268     '''
    269     return privkey_to_pubkey_inner(priv, usehex)
    270 
    271 privtopub = privkey_to_pubkey
    272 
    273 @hexbin
    274 def multiply(s, pub, usehex, rawpub=True):
    275     '''Input binary compressed pubkey P(33 bytes)
    276     and scalar s(32 bytes), return s*P.
    277     The return value is a binary compressed public key.
    278     Note that the called function does the type checking
    279     of the scalar s.
    280     ('raw' options passed in)
    281     '''
    282     newpub = secp256k1.PublicKey(pub, raw=rawpub, ctx=ctx)
    283     res = newpub.tweak_mul(s)
    284     return res.serialize()
    285 
    286 @hexbin
    287 def add_pubkeys(pubkeys, usehex):
    288     '''Input a list of binary compressed pubkeys
    289     and return their sum as a binary compressed pubkey.'''
    290     r = secp256k1.PublicKey(ctx=ctx)  #dummy holding object
    291     pubkey_list = [secp256k1.PublicKey(x,
    292                                        raw=True,
    293                                        ctx=ctx).public_key for x in pubkeys]
    294     r.combine(pubkey_list)
    295     return r.serialize()
    296 
    297 @hexbin
    298 def add_privkeys(priv1, priv2, usehex):
    299     '''Add privkey 1 to privkey 2.
    300     Input keys must be in binary either compressed or not.
    301     Returned key will have the same compression state.
    302     Error if compression state of both input keys is not the same.'''
    303     y, z = [read_privkey(x) for x in [priv1, priv2]]
    304     if y[0] != z[0]:
    305         raise Exception("cannot add privkeys, mixed compression formats")
    306     else:
    307         compressed = y[0]
    308     newpriv1, newpriv2 = (y[1], z[1])
    309     p1 = secp256k1.PrivateKey(newpriv1, raw=True, ctx=ctx)
    310     res = p1.tweak_add(newpriv2)
    311     if compressed:
    312         res += '\x01'
    313     return res
    314 
    315 @hexbin
    316 def ecdsa_raw_sign(msg,
    317                    priv,
    318                    usehex,
    319                    rawpriv=True,
    320                    rawmsg=False,
    321                    usenonce=None):
    322     '''Take the binary message msg and sign it with the private key
    323     priv.
    324     By default priv is just a 32 byte string, if rawpriv is false
    325     it is assumed to be DER encoded.
    326     If rawmsg is True, no sha256 hash is applied to msg before signing.
    327     In this case, msg must be a precalculated hash (256 bit).
    328     If rawmsg is False, the secp256k1 lib will hash the message as part
    329     of the ECDSA-SHA256 signing algo.
    330     If usenonce is not None, its value is passed to the secp256k1 library
    331     sign() function as the ndata value, which is then used in conjunction
    332     with a custom nonce generating function, such that the nonce used in the ECDSA
    333     sign algorithm is exactly that value (ndata there, usenonce here). 32 bytes.
    334     Return value: the calculated signature.'''
    335     if rawmsg and len(msg) != 32:
    336         raise Exception("Invalid hash input to ECDSA raw sign.")
    337     if rawpriv:
    338         compressed, p = read_privkey(priv)
    339         newpriv = secp256k1.PrivateKey(p, raw=True, ctx=ctx)
    340     else:
    341         newpriv = secp256k1.PrivateKey(priv, raw=False, ctx=ctx)
    342     if usenonce and len(usenonce) != 32:
    343         raise ValueError("Invalid nonce passed to ecdsa_sign: " + str(usenonce))
    344 
    345     sig = newpriv.ecdsa_sign(msg, raw=rawmsg)
    346     return newpriv.ecdsa_serialize(sig)
    347 
    348 @hexbin
    349 def ecdsa_raw_verify(msg, pub, sig, usehex, rawmsg=False):
    350     '''Take the binary message msg and binary signature sig,
    351     and verify it against the pubkey pub.
    352     If rawmsg is True, no sha256 hash is applied to msg before verifying.
    353     In this case, msg must be a precalculated hash (256 bit).
    354     If rawmsg is False, the secp256k1 lib will hash the message as part
    355     of the ECDSA-SHA256 verification algo.
    356     Return value: True if the signature is valid for this pubkey, False
    357     otherwise. '''
    358     if rawmsg and len(msg) != 32:
    359         raise Exception("Invalid hash input to ECDSA raw sign.")
    360     newpub = secp256k1.PublicKey(pubkey=pub, raw=True, ctx=ctx)
    361     sigobj = newpub.ecdsa_deserialize(sig)
    362     return newpub.ecdsa_verify(msg, sigobj, raw=rawmsg)
    363 
    364 def estimate_tx_size(ins, outs, txtype='p2pkh'):
    365     '''Estimate transaction size.
    366     Assuming p2pkh:
    367     out: 8+1+3+2+20=34, in: 1+32+4+1+1+~73+1+1+33=147,
    368     ver:4,seq:4, +2 (len in,out)
    369     total ~= 34*len_out + 147*len_in + 10 (sig sizes vary slightly)
    370     '''
    371     if txtype == 'p2pkh':
    372         return 10 + ins * 147 + 34 * outs
    373     else:
    374         raise NotImplementedError("Non p2pkh transaction size estimation not" +
    375                                   "yet implemented")