1#!/usr/bin/env python3 2 3# This software is Copyright (c) 2018, Dhiru Kholia <dhiru at openwall.com> and 4# it is hereby released to the general public under the following terms: 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted. 8# 9# Special thanks goes to https://github.com/NODESPLIT/tz-brute and Michael Senn 10# (@MikeSenn on Telegram) for helping me bootstrap this project. 11 12import re 13import os 14import sys 15import json 16import hashlib 17import binascii 18 19PY3 = sys.version_info[0] == 3 20 21if not PY3: 22 print("This program requires Python 3.6+ to run.") 23 sys.exit(0) 24 25### Borrowed code starts, The MIT License (MIT), Copyright (c) 2013 Vitalik Buterin, https://github.com/vbuterin/pybitcointools ### 26 27def bytes_to_hex_string(b): 28 if isinstance(b, str): 29 return b 30 31 return ''.join('{:02x}'.format(y) for y in b) 32 33def safe_from_hex(s): 34 return bytes.fromhex(s) 35 36def from_int_representation_to_bytes(a): 37 return bytes(str(a), 'utf-8') 38 39def from_int_to_byte(a): 40 return bytes([a]) 41 42def from_byte_to_int(a): 43 return a 44 45def from_string_to_bytes(a): 46 return a if isinstance(a, bytes) else bytes(a, 'utf-8') 47 48def safe_hexlify(a): 49 return str(binascii.hexlify(a), 'utf-8') 50 51 52string_types = (str) 53string_or_bytes_types = (str, bytes) 54int_types = (int, float) 55# Base switching 56code_strings = { 57 2: '01', 58 10: '0123456789', 59 16: '0123456789abcdef', 60 32: 'abcdefghijklmnopqrstuvwxyz234567', 61 58: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz', 62 256: ''.join([chr(x) for x in range(256)]) 63} 64 65def encode(val, base, minlen=0): 66 base, minlen = int(base), int(minlen) 67 code_string = get_code_string(base) 68 result_bytes = bytes() 69 while val > 0: 70 curcode = code_string[val % base] 71 result_bytes = bytes([ord(curcode)]) + result_bytes 72 val //= base 73 74 pad_size = minlen - len(result_bytes) 75 76 padding_element = b'\x00' if base == 256 else b'1' \ 77 if base == 58 else b'0' 78 if (pad_size > 0): 79 result_bytes = padding_element*pad_size + result_bytes 80 81 result_string = ''.join([chr(y) for y in result_bytes]) 82 result = result_bytes if base == 256 else result_string 83 84 return result 85 86def decode(string, base): 87 if base == 256 and isinstance(string, str): 88 string = bytes(bytearray.fromhex(string)) 89 base = int(base) 90 code_string = get_code_string(base) 91 result = 0 92 if base == 256: 93 def extract(d, cs): 94 return d 95 else: 96 def extract(d, cs): 97 return cs.find(d if isinstance(d, str) else chr(d)) 98 99 if base == 16: 100 string = string.lower() 101 while len(string) > 0: 102 result *= base 103 result += extract(string[0], code_string) 104 string = string[1:] 105 return result 106 107 108 109def bin_dbl_sha256(s): 110 bytes_to_hash = from_string_to_bytes(s) 111 return hashlib.sha256(hashlib.sha256(bytes_to_hash).digest()).digest() 112 113def lpad(msg, symbol, length): 114 if len(msg) >= length: 115 return msg 116 return symbol * (length - len(msg)) + msg 117 118def get_code_string(base): 119 if base in code_strings: 120 return code_strings[base] 121 else: 122 raise ValueError("Invalid base!") 123 124def changebase(string, frm, to, minlen=0): 125 if frm == to: 126 return lpad(string, get_code_string(frm)[0], minlen) 127 return encode(decode(string, frm), to, minlen) 128 129def b58check_to_bin(inp): 130 leadingzbytes = len(re.match('^1*', inp).group(0)) 131 data = b'\x00' * leadingzbytes + changebase(inp, 58, 256) 132 assert bin_dbl_sha256(data[:-4])[:4] == data[-4:] 133 return data[1:-4] 134 135### Borrowed code ends #### 136 137if __name__ == "__main__": 138 if len(sys.argv) == 2: # internal https://faucet.tzalpha.net/ files testing mode 139 filename = sys.argv[1] 140 data = open(filename).read() 141 data = json.loads(data) 142 mnemonic, email, address = (" ".join(data["mnemonic"]), data["email"], data["pkh"]) 143 raw_address = binascii.hexlify(b58check_to_bin(address)).decode("ascii") 144 print("%s:$tezos$1*%s*%s*%s*%s*%s" % ("dummy", 2048, mnemonic, email, address, raw_address)) 145 sys.exit(0) 146 if len(sys.argv) < 4: 147 sys.stderr.write("Usage: %s \'mnemonic data (15 words)\' \'email\' \'public key\'\n" % 148 sys.argv[0]) 149 sys.stderr.write("""\nExample: %s 'put guide flat machine express cave hello connect stay local spike ski romance express brass' 'jbzbdybr.vpbdbxnn@tezos.example.org' 'tz1eTjPtwYjdcBMStwVdEcwY2YE3th1bXyMR'\n""" % sys.argv[0]) 150 sys.exit(-1) 151 152 mnemonic, email, address = sys.argv[1:4] 153 if len(email) > 51: 154 sys.stderr.write("[WARNING] Very large salt (email address) found, which is unsupported by tezos-opencl format!\n") 155 156 raw_address = binascii.hexlify(b58check_to_bin(address)).decode("ascii") 157 158 print("%s:$tezos$1*%s*%s*%s*%s*%s" % ("dummy", 2048, mnemonic, email, address, raw_address)) 159