import hashlib from binascii import hexlify, unhexlify import time import random import struct import hmac from secp256k1 import lib as secp256k1 from secp256k1 import ffi SIGHASH_ALL = 0x00000001 SIGHASH_NONE = 0x00000002 SIGHASH_SINGLE = 0x00000003 SIGHASH_ANYONECANPAY = 0x00000080 MAX_INT_PRIVATE_KEY = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 EC_COMPRESSED = secp256k1.SECP256K1_EC_COMPRESSED EC_UNCOMPRESSED = secp256k1.SECP256K1_EC_UNCOMPRESSED FLAG_SIGN = secp256k1.SECP256K1_CONTEXT_SIGN FLAG_VERIFY = secp256k1.SECP256K1_CONTEXT_VERIFY ALL_FLAGS = FLAG_SIGN | FLAG_VERIFY NO_FLAGS = secp256k1.SECP256K1_CONTEXT_NONE HAS_RECOVERABLE = hasattr(secp256k1, 'secp256k1_ecdsa_sign_recoverable') HAS_SCHNORR = hasattr(secp256k1, 'secp256k1_schnorr_sign') HAS_ECDH = hasattr(secp256k1, 'secp256k1_ecdh') ECDSA_CONTEXT_SIGN = secp256k1.secp256k1_context_create(FLAG_SIGN) ECDSA_CONTEXT_VERIFY = secp256k1.secp256k1_context_create(FLAG_VERIFY) ECDSA_CONTEXT_ALL = secp256k1.secp256k1_context_create(ALL_FLAGS) secp256k1.secp256k1_context_randomize(ECDSA_CONTEXT_SIGN, random.SystemRandom().randint(0,MAX_INT_PRIVATE_KEY).to_bytes(32,byteorder="big")) SCRIPT_TYPES = { "P2PKH": 0, "P2SH" : 1, "PUBKEY": 2, "NULL_DATA": 3, "MULTISIG": 4, "NON_STANDART": 5, "SP2PKH": 6 } b58_digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' # # Encoding functions # def encode_base58(b): """Encode bytes to a base58-encoded string""" # Convert big-endian bytes to integer n = int('0x0' + hexlify(b).decode('utf8'), 16) # Divide that integer into bas58 res = [] while n > 0: n, r = divmod(n, 58) res.append(b58_digits[r]) res = ''.join(res[::-1]) # Encode leading zeros as base58 zeros czero = 0 pad = 0 for c in b: if c == czero: pad += 1 else: break return b58_digits[0] * pad + res def decode_base58(s): """Decode a base58-encoding string, returning bytes""" if not s: return b'' # Convert the string to an integer n = 0 for c in s: n *= 58 if c not in b58_digits: raise Exception('Character %r is not a valid base58 character' % c) digit = b58_digits.index(c) n += digit # Convert the integer to bytes h = '%x' % n if len(h) % 2: h = '0' + h res = unhexlify(h.encode('utf8')) # Add padding back. pad = 0 for c in s[:-1]: if c == b58_digits[0]: pad += 1 else: break return b'\x00' * pad + res # # Hash functions # def sha256(bytes): return hashlib.sha256(bytes).digest() def double_sha256(bytes): return sha256(sha256(bytes)) def hmac_sha512(key, data): return hmac.new(key, data, hashlib.sha512).digest() def ripemd160(bytes): h = hashlib.new('ripemd160') h.update(bytes) return h.digest() def hash160(bytes): return ripemd160(sha256(bytes)) # # Bitcoin keys/ addresses # def create_priv(): """ :return: 32 bytes private key """ q = time.time() rnd = random.SystemRandom() a = rnd.randint(0,MAX_INT_PRIVATE_KEY) i = int((time.time()%0.01)*100000) h = a.to_bytes(32,byteorder="big") while True: h = hashlib.sha256(h).digest() if i>1: i -= 1 else: if int.from_bytes(h,byteorder="big") 73): return False # A signature is of type 0x30 (compound). if sig[0] != 0x30: return False # Make sure the length covers the entire signature. if sig[1] != (length - 3): return False # Extract the length of the R element. lenR = sig[3] # Make sure the length of the S element is still inside the signature. if (5 + lenR) >= length: return False # Extract the length of the S element. lenS = sig[5 + lenR] # Verify that the length of the signature matches the sum of the length # of the elements. if (lenR + lenS + 7) != length: return False # Check whether the R element is an integer. if sig[2] != 0x02: return False # Zero-length integers are not allowed for R. if lenR == 0: return False # Negative numbers are not allowed for R. if sig[4] & 0x80: return False # Null bytes at the start of R are not allowed, unless R would # otherwise be interpreted as a negative number. if (lenR > 1) and (sig[4] == 0x00) and (not sig[5] & 0x80): return False # Check whether the S element is an integer. if sig[lenR + 4] != 0x02: return False # Zero-length integers are not allowed for S. if lenS == 0: return False # Negative numbers are not allowed for S. if sig[lenR + 6] & 0x80: return False # Null bytes at the start of S are not allowed, unless S would otherwise be # interpreted as a negative number. if (lenS > 1) and (sig[lenR + 6] == 0x00) and (not sig[lenR + 7] & 0x80): return False return True # # Transaction encoding # def rh2s(tthash): return hexlify(tthash[::-1]).decode() def s2rh(hash_string): return unhexlify(hash_string)[::-1] def merkleroot(tx_hash_list): tx_hash_list = list(tx_hash_list) if len(tx_hash_list) == 1: return tx_hash_list[0] while True: new_hash_list = list() while tx_hash_list: h1 = tx_hash_list.pop() try: h2 = tx_hash_list.pop() except: h2 = h1 new_hash_list.insert(0, double_sha256(h1 + h2)) if len(new_hash_list) > 1: tx_hash_list = new_hash_list else: return new_hash_list[0] # # # def var_int(data): e, s = 1, 0 if data[:1] == b'\xfd': s, e = 1, 3 elif data[:1] == b'\xfe': s = 1 e = 5 elif data[:1] == b'\xff': s = 1 e = 9 i = int.from_bytes(data[s:e], byteorder='little', signed=False) return (i, e) def from_var_int(data): # retrun e = 1 s = 0 if data[:1] == b'\xfd': s = 1 e = 3 elif data[:1] == b'\xfe': s = 1 e = 5 elif data[:1] == b'\xff': s = 1 e = 9 i = int.from_bytes(data[s:e], byteorder='little', signed=False) return i def var_int_len(byte): e = 1 if byte == 253: e = 3 elif byte == 254: e = 5 elif byte == 255: e = 9 return e def to_var_int(i): if i < 253: return i.to_bytes(1, byteorder='little') if i <= 0xffff: return b'\xfd' + i.to_bytes(2, byteorder='little') if i <= 0xffffffff: return b'\xfe' + i.to_bytes(4, byteorder='little') return b'\xff' + i.to_bytes(8, byteorder='little') def read_var_int(stream): l = stream.read(1) bytes_length = var_int_len(l[0]) return l + stream.read(bytes_length - 1) def read_var_list(stream, data_type): count = from_var_int(read_var_int(stream)) return [data_type.deserialize(stream) for i in range(count)] # generic big endian MPI format def bn_bytes(v, have_ext=False): ext = 0 if have_ext: ext = 1 return ((v.bit_length() + 7) // 8) + ext def bn2bin(v): s = bytearray() i = bn_bytes(v) while i > 0: s.append((v >> ((i - 1) * 8)) & 0xff) i -= 1 return s def bin2bn(s): l = 0 for ch in s: l = (l << 8) | ch return l def bn2mpi(v): have_ext = False if v.bit_length() > 0: have_ext = (v.bit_length() & 0x07) == 0 neg = False if v < 0: neg = True v = -v s = struct.pack(b">I", bn_bytes(v, have_ext)) ext = bytearray() if have_ext: ext.append(0) v_bin = bn2bin(v) if neg: if have_ext: ext[0] |= 0x80 else: v_bin[0] |= 0x80 return s + ext + v_bin def mpi2bn(s): if len(s) < 4: return None s_size = bytes(s[:4]) v_len = struct.unpack(b">I", s_size)[0] if len(s) != (v_len + 4): return None if v_len == 0: return 0 v_str = bytearray(s[4:]) neg = False i = v_str[0] if i & 0x80: neg = True i &= ~0x80 v_str[0] = i v = bin2bn(v_str) if neg: return -v return v # bitcoin-specific little endian format, with implicit size def mpi2vch(s): r = s[4:] # strip size # if r: r = r[::-1] # reverse string, converting BE->LE # else: r=b'\x00' return r def bn2vch(v): return bytes(mpi2vch(bn2mpi(v))) def vch2mpi(s): r = struct.pack(b">I", len(s)) # size r += s[::-1] # reverse string, converting LE->BE return r def vch2bn(s): return mpi2bn(vch2mpi(s)) def i2b(i): return bn2vch(i) def b2i(b): return vch2bn(b)