import hashlib from binascii import hexlify, unhexlify import time import struct import hmac from .constants import * from .opcodes import * from .hash import * from .encode import * # Bitcoin keys/ addresses # def create_priv(hex=False): """ :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 bits2target(bits): if type(bits) == str: bits = unhexlify(bits) if type(bits) == bytes: return int.from_bytes(bits[1:], 'big') * (2 ** (8 * (bits[0] - 3))) else: shift = bits >> 24 target = (bits & 0xffffff) * (1 << (8 * (shift - 3))) return target def target2difficulty(target): return 0x00000000FFFF0000000000000000000000000000000000000000000000000000 / target def bits2difficulty(bits): return target2difficulty(bits2target(bits)) def difficulty2target(difficulty): return int(0x00000000FFFF0000000000000000000000000000000000000000000000000000 / difficulty) def rh2s(tthash): return hexlify(tthash[::-1]).decode() def s2rh(hash_string): return unhexlify(hash_string)[::-1] def s2rh_step4(hash_string): h = unhexlify(hash_string) return reverse_hash(h) def reverse_hash(h): return struct.pack('>IIIIIIII', *struct.unpack('>IIIIIIII', h)[::-1])[::-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(0) try: h2 = tx_hash_list.pop(0) except: h2 = h1 new_hash_list.append(double_sha256(h1 + h2)) if len(new_hash_list) > 1: tx_hash_list = new_hash_list else: return new_hash_list[0] def merkle_branches(tx_hash_list): tx_hash_list = list(tx_hash_list) branches = [] if len(tx_hash_list) == 1: return [] tx_hash_list.pop(0) while True: branches.append(tx_hash_list.pop(0)) new_hash_list = list() while tx_hash_list: h1 = tx_hash_list.pop(0) try: h2 = tx_hash_list.pop(0) except: h2 = h1 new_hash_list.append(double_sha256(h1 + h2)) if len(new_hash_list) > 1: tx_hash_list = new_hash_list else: if new_hash_list: branches.append(new_hash_list.pop(0)) return branches def merkleroot_from_branches(merkle_branches, coinbase_hash_bin): merkle_root = coinbase_hash_bin for h in merkle_branches: if type(h) == str: h = unhexlify(h) merkle_root = double_sha256(merkle_root + h) return merkle_root # # # 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) # BIP39 # # # def create_mnemonic(bits=256, language='english'): passphrase = [] wordlist = create_wordlist(language) entropy = os.urandom(bits // 8) entropy_int = int.from_bytes(entropy, byteorder="big") entropy_bit_len = len(entropy) * 8 chk_sum_bit_len = entropy_bit_len // 32 entropy_hash = hashlib.sha256(entropy).hexdigest() fbyte_hash = unhexlify(entropy_hash)[0] entropy_int = add_checksum(entropy) while entropy_int: passphrase.append(wordlist[entropy_int & 0b11111111111]) entropy_int = entropy_int >> 11 return ' '.join(passphrase[::-1]) def create_wordlist(language, wordlist_dir=BIP0039_DIR): f = None path = os.path.join(wordlist_dir, '.'.join((language, 'txt'))) assert os.path.exists(path) f = open(path) content = f.read().rstrip('\n') assert content f.close() return content.split('\n') def add_checksum(data): mask = 0b10000000 data_int = int.from_bytes(data, byteorder="big") data_bit_len = len(data) * 8 // 32 data_hash = hashlib.sha256(data).hexdigest() fbyte_hash = unhexlify(data_hash)[0] while data_bit_len: data_bit_len -= 1 data_int = (data_int << 1) | 1 if fbyte_hash & mask else data_int << 1 mask = mask >> 1 return data_int def mnemonic2bytes(mnemonic, language): wordlist = create_wordlist(language) codes = dict() for code, word in enumerate(wordlist): codes[word] = code word_count = len(mnemonic) entropy_int = None bit_size = word_count * 11 chk_sum_bit_len = word_count * 11 % 32 for word in mnemonic: entropy_int = (entropy_int << 11) | codes[word] if entropy_int else codes[word] chk_sum = entropy_int & (2 ** chk_sum_bit_len - 1) entropy_int = entropy_int >> chk_sum_bit_len entropy = entropy_int.to_bytes((bit_size - chk_sum_bit_len) // 8, byteorder="big") ent_hash = hashlib.sha256(entropy).hexdigest() fb = unhexlify(ent_hash)[0] assert (fb >> (8 - chk_sum_bit_len)) & chk_sum return entropy