def decrypt(type, domain, secret): transport = get_transport() client = TrezorClient(transport, ClickUI()) dom = type.upper() + ": " + domain dec = decrypt_keyvalue(client, BIP32_PATH, dom, secret, False, True) client.close() return dec
def main(): # List all connected TREZORs on USB devices = HidTransport.enumerate() # Check whether we found any if len(devices) == 0: print 'No TREZOR found' return # Use first connected device transport = HidTransport(devices[0]) # Creates object for manipulating TREZOR client = TrezorClient(transport) # Print out TREZOR's features and settings print client.features # Get the first address of first BIP44 account # (should be the same address as shown in mytrezor.com) bip32_path = client.expand_path("44'/0'/0'/0/0") address = client.get_address('Bitcoin', bip32_path) print 'Bitcoin address:', address client.close()
def choose_device(devices): if not len(devices): raise RuntimeError("No Trezor connected!") if len(devices) == 1: try: return devices[0] except IOError: raise RuntimeError("Device is currently in use") i = 0 sys.stderr.write("----------------------------\n") sys.stderr.write("Available devices:\n") for d in devices: try: client = TrezorClient(d, ui=ClickUI()) except IOError: sys.stderr.write("[-] <device is currently in use>\n") continue if client.features.label: sys.stderr.write("[%d] %s\n" % (i, client.features.label)) else: sys.stderr.write("[%d] <no label>\n" % i) client.close() i += 1 sys.stderr.write("----------------------------\n") sys.stderr.write("Please choose device to use:") try: device_id = int(input()) return devices[device_id] except Exception: raise ValueError("Invalid choice, exiting...")
def encrypt(type, domain, secret): transport = get_transport() client = TrezorClient(transport, ClickUI()) dom = type.upper() + ": " + domain enc = encrypt_keyvalue(client, BIP32_PATH, dom, secret.encode(), False, True) client.close() return enc.hex()
def main(): try: # List all connected TREZORs on USB devices = HidTransport.enumerate() # Check whether we found any if len(devices) == 0: input('No TREZOR found. Press any key...') return # Use first connected device transport = HidTransport(devices[0]) # Creates object for manipulating TREZOR client = TrezorClient(transport) # Print out TREZOR's features and settings print(client.features) # # Get the first address of first BIP44 account # # (should be the same address as shown in wallet.trezor.io) bip32_path = client.expand_path("m/44'/49344'/0'/0/0") address = client.get_address('Stash', bip32_path) print('Stash address:', address) client.close() except Exception as e: print(str(e)) traceback.print_exc(file=sys.stdout) input('Press any key...')
def main(): # List all debuggable TREZORs devices = [ device for device in enumerate_devices() if hasattr(device, 'find_debug') ] # Check whether we found any if len(devices) == 0: print('No TREZOR found') return # Use first connected device transport = devices[0] debug_transport = devices[0].find_debug() # Creates object for manipulating TREZOR client = TrezorClient(transport) debug = DebugLink(debug_transport) sector = int(sys.argv[1]) f = open(sys.argv[2], "rb") content = f.read(sectorlens[sector]) if (len(content) != sectorlens[sector]): print("Not enough bytes in file") return debug.flash_erase(sector) step = 0x400 for offset in range(0, sectorlens[sector], step): debug.memory_write(sectoraddrs[sector] + offset, content[offset:offset + step], flash=True) client.close()
def main(): # List all connected TREZORs on USB devices = HidTransport.enumerate() # Check whether we found any if len(devices) == 0: print('No TREZOR found') return # Use first connected device transport = devices[0] debug_transport = devices[0].find_debug() # Creates object for manipulating TREZOR client = TrezorClient(transport) debug = DebugLink(debug_transport) arg1 = int(sys.argv[1], 16) arg2 = int(sys.argv[2], 16) step = 0x400 if arg2 >= 0x400 else arg2 f = open('memory.dat', 'w') for addr in range(arg1, arg1 + arg2, step): mem = debug.memory_read(addr, step) f.write(mem) f.close() client.close()
def choose_device(devices): if not len(devices): raise RuntimeError("No TREZOR connected!") if len(devices) == 1: try: return devices[0] except IOError: raise RuntimeError("Device is currently in use") i = 0 sys.stderr.write("----------------------------\n") sys.stderr.write("Available devices:\n") for d in devices: try: client = TrezorClient(d, ui=ClickUI()) except IOError: sys.stderr.write("[-] <device is currently in use>\n") continue if client.features.label: sys.stderr.write("[%d] %s\n" % (i, client.features.label)) else: sys.stderr.write("[%d] <no label>\n" % i) client.close() i += 1 sys.stderr.write("----------------------------\n") sys.stderr.write("Please choose device to use:") try: device_id = int(input()) return devices[device_id] except Exception: raise ValueError("Invalid choice, exiting...")
def main(): # List all connected TREZORs on USB/UDP devices = TrezorDevice.enumerate() # Check whether we found any if len(devices) == 0: print('No TREZOR found') return # Use first connected device transport = devices[0] # Creates object for manipulating TREZOR client = TrezorClient(transport) # Print out TREZOR's features and settings print(client.features) # Get the first address of first BIP44 account # (should be the same address as shown in wallet.trezor.io) bip32_path = client.expand_path("44'/0'/0'/0/0") address = client.get_address('Bitcoin', bip32_path) print('Bitcoin address:', address) client.close()
class TrezorTest(unittest.TestCase): def setUp(self): transport = config.TRANSPORT(*config.TRANSPORT_ARGS, **config.TRANSPORT_KWARGS) if hasattr(config, 'DEBUG_TRANSPORT'): debug_transport = config.DEBUG_TRANSPORT( *config.DEBUG_TRANSPORT_ARGS, **config.DEBUG_TRANSPORT_KWARGS) self.client = TrezorDebugClient(transport) self.client.set_debuglink(debug_transport) else: self.client = TrezorClient(transport) self.client.set_tx_api(tx_api.TxApiBitcoin) # self.client.set_buttonwait(3) # 1 2 3 4 5 6 7 8 9 10 11 12 self.mnemonic12 = 'alcohol woman abuse must during monitor noble actual mixed trade anger aisle' self.mnemonic18 = 'owner little vague addict embark decide pink prosper true fork panda embody mixture exchange choose canoe electric jewel' self.mnemonic24 = 'dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic' self.mnemonic_all = ' '.join(['all'] * 12) self.pin4 = '1234' self.pin6 = '789456' self.pin8 = '45678978' self.client.wipe_device() print("Setup finished") print("--------------") def setup_mnemonic_allallall(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic_all, pin='', passphrase_protection=False, label='test', language='english') def setup_mnemonic_nopin_nopassphrase(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin='', passphrase_protection=False, label='test', language='english') def setup_mnemonic_pin_nopassphrase(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin=self.pin4, passphrase_protection=False, label='test', language='english') def setup_mnemonic_pin_passphrase(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin=self.pin4, passphrase_protection=True, label='test', language='english') def tearDown(self): self.client.close()
def encrypt(type, domain, secret): transport = get_transport() client = TrezorClient(transport, ClickUI()) dom = type.upper() + ": " + domain enc = encrypt_keyvalue(client, BIP32_PATH, dom, secret.encode(), False, True) client.close() return enc.hex()
def main(): try: client = TrezorClient(get_transport()) except Exception as e: print(e) return arg1 = sys.argv[1] # output file arg2 = int(sys.argv[2], 10) # total number of how many bytes of entropy to read step = 1024 if arg2 >= 1024 else arg2 # trezor will only return 1KB at a time with io.open(arg1, 'wb') as f: for i in range(0, arg2, step): entropy = client.get_entropy(step) f.write(entropy) client.close()
def main(): try: client = TrezorClient(get_transport(), ui=ui.ClickUI()) except Exception as e: print(e) return arg1 = sys.argv[1] # output file arg2 = int(sys.argv[2], 10) # total number of how many bytes of entropy to read step = 1024 if arg2 >= 1024 else arg2 # trezor will only return 1KB at a time with io.open(arg1, 'wb') as f: for i in range(0, arg2, step): entropy = misc.get_entropy(client, step) f.write(entropy) client.close()
def main(): # Use first connected device transport = get_transport() # Creates object for manipulating TREZOR client = TrezorClient(transport) # Print out TREZOR's features and settings print(client.features) # Get the first address of first BIP44 account # (should be the same address as shown in wallet.trezor.io) bip32_path = client.expand_path("44'/0'/0'/0/0") address = client.get_address('Bitcoin', bip32_path) print('Bitcoin address:', address) client.close()
def main(): # List all connected TREZORs on USB devices = HidTransport.enumerate() # Check whether we found any if len(devices) == 0: print('No TREZOR found') return # Use first connected device transport = devices[0] debug_transport = devices[0].find_debug() # Creates object for manipulating TREZOR client = TrezorClient(transport) debug = DebugLink(debug_transport) debug.memory_write(int(sys.argv[1], 16), binascii.unhexlify(sys.argv[2]), flash=True) client.close()
def main(): # List all connected TREZORs on USB devices = HidTransport.enumerate() # Check whether we found any if len(devices) == 0: print('No TREZOR found') return # Use first connected device transport = HidTransport(devices[0]) # Creates object for manipulating TREZOR debug_transport = HidTransport(devices[0], **{'debug_link': True}) client = TrezorClient(transport) debug = DebugLink(debug_transport) mem = debug.memory_write(int(sys.argv[1],16), binascii.unhexlify(sys.argv[2]), flash=True) client.close()
class TrezorTest(unittest.TestCase): def setUp(self): transport = config.TRANSPORT(*config.TRANSPORT_ARGS, **config.TRANSPORT_KWARGS) if hasattr(config, 'DEBUG_TRANSPORT'): debug_transport = config.DEBUG_TRANSPORT(*config.DEBUG_TRANSPORT_ARGS, **config.DEBUG_TRANSPORT_KWARGS) self.client = TrezorDebugClient(transport) self.client.set_debuglink(debug_transport) else: self.client = TrezorClient(transport) self.client.set_tx_api(tx_api.TxApiBitcoin) # self.client.set_buttonwait(3) # 1 2 3 4 5 6 7 8 9 10 11 12 self.mnemonic12 = 'alcohol woman abuse must during monitor noble actual mixed trade anger aisle' self.mnemonic18 = 'owner little vague addict embark decide pink prosper true fork panda embody mixture exchange choose canoe electric jewel' self.mnemonic24 = 'dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic' self.mnemonic_all = ' '.join(['all'] * 12) self.pin4 = '1234' self.pin6 = '789456' self.pin8 = '45678978' self.client.wipe_device() print("Setup finished") print("--------------") def setup_mnemonic_allallall(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic_all, pin='', passphrase_protection=False, label='test', language='english') def setup_mnemonic_nopin_nopassphrase(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin='', passphrase_protection=False, label='test', language='english') def setup_mnemonic_pin_nopassphrase(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin=self.pin4, passphrase_protection=False, label='test', language='english') def setup_mnemonic_pin_passphrase(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin=self.pin4, passphrase_protection=True, label='test', language='english') def tearDown(self): self.client.close()
def main(): # List all connected TREZORs on USB devices = HidTransport.enumerate() # Check whether we found any if len(devices) == 0: print('No TREZOR found') return # Use first connected device transport = HidTransport(devices[0]) # Creates object for manipulating TREZOR debug_transport = HidTransport(devices[0], **{'debug_link': True}) client = TrezorClient(transport) debug = DebugLink(debug_transport) mem = debug.memory_read(int(sys.argv[1],16), int(sys.argv[2],16)) f = open('memory.dat', 'w') f.write(mem) f.close() client.close()
def main(): # List all connected TREZORs on USB devices = HidTransport.enumerate() # Check whether we found any if len(devices) == 0: print('No TREZOR found') return # Use first connected device transport = HidTransport(devices[0]) # Creates object for manipulating TREZOR debug_transport = HidTransport(devices[0], **{'debug_link': True}) client = TrezorClient(transport) debug = DebugLink(debug_transport) mem = debug.memory_read(int(sys.argv[1], 16), int(sys.argv[2], 16)) f = open('memory.dat', 'w') f.write(mem) f.close() client.close()
def main(): # List all debuggable TREZORs devices = [ device for device in enumerate_devices() if hasattr(device, 'find_debug') ] # Check whether we found any if len(devices) == 0: print('No TREZOR found') return # Use first connected device transport = devices[0] debug_transport = devices[0].find_debug() # Creates object for manipulating TREZOR client = TrezorClient(transport) debug = DebugLink(debug_transport) debug.memory_write(int(sys.argv[1], 16), bytes.fromhex(sys.argv[2]), flash=True) client.close()
devices = HidTransport.enumerate() # Check whether we found any if len(devices) == 0: print('No TREZOR found') sys.exit() # Use first connected device transport = devices[0] # Creates object for manipulating TREZOR client = TrezorClient(transport) adrs = [] for i in tqdm(range(ADRS_TOTAL)): bip32_path = client.expand_path("49'/2'/0'/0/{0}".format(i)) adrs.append( client.get_address('Litecoin', bip32_path, script_type=proto.InputScriptType.SPENDP2SHWITNESS)) client.close() #print(adrs) pickle.dump(adrs, open('LTC.pickle', 'wb')) # SPENDWITNESS # SPENDP2SHWITNESS # SAMPLE ADR: MKVW8NewajMWijvKg7td2e7aUq8cyFYtPB # (trezorfeb) sbassi@Us-IT00354:~/projects/takocoin/takomisc/trezorfeb$ trezorctl get_address --coin Bitcoin --script-type segwit --address "m/49'/0'/0'/0/0" # bc1qrwl055767s26920eq7tfpaa4m97m302cnkh6w4 #
class TrezorClient(HardwareWalletClient): def __init__(self, path, password=''): super(TrezorClient, self).__init__(path, password) if path.startswith('udp'): logging.debug('Simulator found, using DebugLink') transport = get_transport(path) self.client = TrezorClientDebugLink(transport=transport) else: self.client = Trezor(transport=get_transport(path), ui=ClickUI()) # if it wasn't able to find a client, throw an error if not self.client: raise IOError("no Device") self.password = password os.environ['PASSPHRASE'] = password # Must return a dict with the xpub # Retrieves the public key at the specified BIP 32 derivation path def get_pubkey_at_path(self, path): expanded_path = tools.parse_path(path) output = btc.get_public_node(self.client, expanded_path) if self.is_testnet: return {'xpub': xpub_main_2_test(output.xpub)} else: return {'xpub': output.xpub} # Must return a hex string with the signed transaction # The tx must be in the psbt format def sign_tx(self, tx): # Get this devices master key fingerprint master_key = btc.get_public_node(self.client, [0]) master_fp = get_xpub_fingerprint(master_key.xpub) # Do multiple passes for multisig passes = 1 p = 0 while p < passes: # Prepare inputs inputs = [] to_ignore = [ ] # Note down which inputs whose signatures we're going to ignore for input_num, (psbt_in, txin) in py_enumerate( list(zip(tx.inputs, tx.tx.vin))): txinputtype = proto.TxInputType() # Set the input stuff txinputtype.prev_hash = ser_uint256(txin.prevout.hash)[::-1] txinputtype.prev_index = txin.prevout.n txinputtype.sequence = txin.nSequence # Detrermine spend type scriptcode = b'' if psbt_in.non_witness_utxo: utxo = psbt_in.non_witness_utxo.vout[txin.prevout.n] txinputtype.script_type = proto.InputScriptType.SPENDADDRESS scriptcode = utxo.scriptPubKey txinputtype.amount = psbt_in.non_witness_utxo.vout[ txin.prevout.n].nValue elif psbt_in.witness_utxo: utxo = psbt_in.witness_utxo # Check if the output is p2sh if psbt_in.witness_utxo.is_p2sh(): txinputtype.script_type = proto.InputScriptType.SPENDP2SHWITNESS else: txinputtype.script_type = proto.InputScriptType.SPENDWITNESS scriptcode = psbt_in.witness_utxo.scriptPubKey txinputtype.amount = psbt_in.witness_utxo.nValue # Set the script if psbt_in.witness_script: scriptcode = psbt_in.witness_script elif psbt_in.redeem_script: scriptcode = psbt_in.redeem_script def ignore_input(): txinputtype.address_n = [0x80000000] inputs.append(txinputtype) to_ignore.append(input_num) # Check for multisig is_ms, multisig = parse_multisig(scriptcode) if is_ms: # Add to txinputtype txinputtype.multisig = multisig if psbt_in.non_witness_utxo: if utxo.is_p2sh: txinputtype.script_type = proto.InputScriptType.SPENDMULTISIG else: # Cannot sign bare multisig, ignore it ignore_input() continue elif not is_ms and psbt_in.non_witness_utxo and not utxo.is_p2pkh: # Cannot sign unknown spk, ignore it ignore_input() continue elif not is_ms and psbt_in.witness_utxo and psbt_in.witness_script: # Cannot sign unknown witness script, ignore it ignore_input() continue # Find key to sign with found = False our_keys = 0 for key in psbt_in.hd_keypaths.keys(): keypath = psbt_in.hd_keypaths[key] if keypath[ 0] == master_fp and key not in psbt_in.partial_sigs: if not found: txinputtype.address_n = keypath[1:] found = True our_keys += 1 # Determine if we need to do more passes to sign everything if our_keys > passes: passes = our_keys if not found: # This input is not one of ours ignore_input() continue # append to inputs inputs.append(txinputtype) # address version byte if self.is_testnet: p2pkh_version = b'\x6f' p2sh_version = b'\xc4' bech32_hrp = 'tb' else: p2pkh_version = b'\x00' p2sh_version = b'\x05' bech32_hrp = 'bc' # prepare outputs outputs = [] for out in tx.tx.vout: txoutput = proto.TxOutputType() txoutput.amount = out.nValue txoutput.script_type = proto.OutputScriptType.PAYTOADDRESS if out.is_p2pkh(): txoutput.address = to_address(out.scriptPubKey[3:23], p2pkh_version) elif out.is_p2sh(): txoutput.address = to_address(out.scriptPubKey[2:22], p2sh_version) else: wit, ver, prog = out.is_witness() if wit: txoutput.address = bech32.encode(bech32_hrp, ver, prog) else: raise TypeError("Output is not an address") # append to outputs outputs.append(txoutput) # Prepare prev txs prevtxs = {} for psbt_in in tx.inputs: if psbt_in.non_witness_utxo: prev = psbt_in.non_witness_utxo t = proto.TransactionType() t.version = prev.nVersion t.lock_time = prev.nLockTime for vin in prev.vin: i = proto.TxInputType() i.prev_hash = ser_uint256(vin.prevout.hash)[::-1] i.prev_index = vin.prevout.n i.script_sig = vin.scriptSig i.sequence = vin.nSequence t.inputs.append(i) for vout in prev.vout: o = proto.TxOutputBinType() o.amount = vout.nValue o.script_pubkey = vout.scriptPubKey t.bin_outputs.append(o) logging.debug(psbt_in.non_witness_utxo.hash) prevtxs[ser_uint256( psbt_in.non_witness_utxo.sha256)[::-1]] = t # Sign the transaction tx_details = proto.SignTx() tx_details.version = tx.tx.nVersion tx_details.lock_time = tx.tx.nLockTime if self.is_testnet: signed_tx = btc.sign_tx(self.client, "Testnet", inputs, outputs, tx_details, prevtxs) else: signed_tx = btc.sign_tx(self.client, "Bitcoin", inputs, outputs, tx_details, prevtxs) # Each input has one signature for input_num, (psbt_in, sig) in py_enumerate( list(zip(tx.inputs, signed_tx[0]))): if input_num in to_ignore: continue for pubkey in psbt_in.hd_keypaths.keys(): fp = psbt_in.hd_keypaths[pubkey][0] if fp == master_fp and pubkey not in psbt_in.partial_sigs: psbt_in.partial_sigs[pubkey] = sig + b'\x01' break p += 1 return {'psbt': tx.serialize()} # Must return a base64 encoded string with the signed message # The message can be any string def sign_message(self, message, keypath): path = tools.parse_path(keypath) result = btc.sign_message(self.client, 'Bitcoin', path, message) return { 'signature': base64.b64encode(result.signature).decode('utf-8') } # Display address of specified type on the device. Only supports single-key based addresses. def display_address(self, keypath, p2sh_p2wpkh, bech32): expanded_path = tools.parse_path(keypath) address = btc.get_address( self.client, "Testnet" if self.is_testnet else "Bitcoin", expanded_path, show_display=True, script_type=proto.InputScriptType.SPENDWITNESS if bech32 else (proto.InputScriptType.SPENDP2SHWITNESS if p2sh_p2wpkh else proto.InputScriptType.SPENDADDRESS)) return {'address': address} # Setup a new device def setup_device(self, label='', passphrase=''): if self.client.features.initialized: raise DeviceAlreadyInitError( 'Device is already initialized. Use wipe first and try again') passphrase_enabled = False if self.password: passphrase_enabled = True device.reset(self.client, passphrase_protection=bool(self.password)) return {'success': True} # Wipe this device def wipe_device(self): device.wipe(self.client) return {'success': True} # Restore device from mnemonic or xprv def restore_device(self, label=''): passphrase_enabled = False device.recover(self.client, label=label, input_callback=mnemonic_words, passphrase_protection=bool(self.password)) return {'success': True} # Begin backup process def backup_device(self, label='', passphrase=''): raise UnavailableActionError( 'The Trezor does not support creating a backup via software') # Close the device def close(self): self.client.close()
def main(): numinputs = 100 sizeinputtx = 10 # Use first connected device try: transport = get_transport() except Exception as e: print(e) return print(transport) txstore = MyTxApiBitcoin() # Creates object for manipulating TREZOR client = TrezorClient(transport) # client.set_tx_api(TxApiTestnet) txstore.set_client(client) txstore.set_publickey( client.get_public_node(client.expand_path("44'/0'/0'"))) print("creating input txs") txstore.create_inputs(numinputs, sizeinputtx) print("go") client.set_tx_api(txstore) # client.set_tx_api(MyTxApiBitcoin()) # Print out TREZOR's features and settings print(client.features) # Get the first address of first BIP44 account # (should be the same address as shown in wallet.trezor.io) outputs = [ proto_types.TxOutputType( amount=0, script_type=proto_types.PAYTOADDRESS, address='p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm' # op_return_data=binascii.unhexlify('2890770995194662774cd192ee383b805e9a066e6a456be037727649228fb7f6') # address_n=client.expand_path("44'/0'/0'/0/35"), # address='3PUxV6Cc4udQZQsJhArVUzvvVoKC8ohkAj', ), # proto_types.TxOutputType( # amount=0, # script_type=proto_types.PAYTOOPRETURN, # op_return_data=binascii.unhexlify('2890770995194662774cd192ee383b805e9a066e6a456be037727649228fb7f6') # ), # proto_types.TxOutputType( # amount= 8120, # script_type=proto_types.PAYTOADDRESS, # address_n=client.expand_path("44'/1'/0'/1/0"), # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ', # address='14KRxYgFc7Se8j7MDdrK5PTNv8meq4GivK', # ), # proto_types.TxOutputType( # amount= 18684 - 2000, # script_type=proto_types.PAYTOADDRESS, # address_n=client.expand_path("44'/0'/0'/0/7"), # # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ', # # address='1s9TSqr3PHZdXGrYws59Uaf5SPqavH43z', # ), # proto_types.TxOutputType( # amount= 1000, # script_type=proto_types.PAYTOADDRESS, # # address_n=client.expand_path("44'/0'/0'/0/18"), # # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ', # # address='1NcMqUvyWv1K3Zxwmx5sqfj7ZEmPCSdJFM', # ), ] # (signatures, serialized_tx) = client.sign_tx('Testnet', inputs, outputs) (signatures, serialized_tx) = client.sign_tx('Bitcoin', txstore.get_inputs(), txstore.get_outputs()) print('Transaction:', binascii.hexlify(serialized_tx)) client.close()
def sign(addr, msg, tx): # List all connected Trezors on USB devices = HidTransport.enumerate() # Check whether we found any trezor devices if len(devices) == 0: print 'No TREZOR found' return # Use first connected device transport = devices[0] # Determine coin/address type corresponding to signing addresses addr_prefix = addr[0] coin = PREFIX_TO_COIN[addr_prefix] # TODO: Remove this to enable mainnet addresses. Currently temporarily disabled for safety. if coin == 'Bitcoin': raise ValueError( 'Mainnet addresses currently not supported for safety') # Creates object for manipulating trezor client = TrezorClient(transport) if coin == 'Testnet': TxApi = TxApiBlockCypher(coin, 'https://api.blockcypher.com/v1/btc/test3/') print('Making testnet api') if coin == 'Bitcoin': TxApi = TxApiBlockCypher(coin, 'https://api.blockcypher.com/v1/btc/main/') print("Making bitcoin api") # Set the api for trezor client client.set_tx_api(TxApi) # Find the bip32 path of the address we are signing a message or tx from found_path = find_path(target_address=addr, client=client, coin=coin) if found_path is None: raise ValueError( 'The address {} was not found on the connected trezor {} in search for its bip32 path' .format(addr, transport)) else: print('Found bip32 path for: {} - signing from this address'.format( client.get_address(coin, found_path))) # Sign the specified message from the specified source address. Signature is in base64 if msg is not None: print('Signing message: "{}"\nFrom address: {}'.format(msg, addr)) res = client.sign_message( coin_name=coin, n=found_path, message=msg, script_type=PREFIX_TO_INPUT_SCRIPT[addr_prefix]) print('Verify signing action on your trezor') print('Signature:', str(base64.b64encode(res.signature), 'ascii')) if tx is not None: # In this basic implementation, remember that tx data comes in the format: # <PREV HASH> <PREV INDEX> <DESTINATION ADDRESS> <AMOUNT> <FEE> prev_hash = tx[0] prev_index = int(tx[1]) dest_address = tx[2] send_amount = int(tx[3]) fee = int(tx[4]) # Uses blockcypher API to get the amount (satoshi) of the UTXO. Amount is in satoshis utxo_amount = TxApi.get_tx(prev_hash).bin_outputs[prev_index].amount if send_amount + fee > utxo_amount: raise ValueError( 'UTXO amount of {} is too small for sending {} satoshi with {} satoshi fee' .format(utxo_amount, send_amount, fee)) print('Using UTXO: {} and index {} to send {} {} coins to: {}'.format( prev_hash, prev_index, send_amount / 100000000, coin, dest_address)) # Prepare the inputs of the transaction input_type = get_input_script_type(api=TxApi, txhash=prev_hash, index=prev_index) inputs = [ proto_types.TxInputType( address_n=found_path, prev_hash=binascii.unhexlify(prev_hash), prev_index=prev_index, script_type=input_type, amount=utxo_amount # Amount is in satoshis ), ] # Prepare the outputs of the transaction outputs = [ proto_types.TxOutputType( amount=send_amount, # Amount is in satoshis script_type=PREFIX_TO_OUTPUT_SCRIPT[dest_address[0]], address=dest_address), ] # Determine amount to send to change address. Amount is in satoshis change = utxo_amount - send_amount - fee # Add change output, which is change address on the bip32 path of the sending address if change > 0: change_path = found_path[:] change_path[3] = 1 change_address = client.get_address(coin, change_path) outputs.append( proto_types.TxOutputType( amount=change, # Amount is in satoshis script_type=PREFIX_TO_OUTPUT_SCRIPT[change_address[0]], address=change_address)) print('Sending change amount of {} {} coins to change address: {}'. format(change / 100000000, coin, change_address)) # All information is ready, sign transaction and print it print('Verify transaction on your trezor') (signatures, serialized_tx) = client.sign_tx(coin, inputs, outputs) # print('Signatures:', signatures) print('Signed transaction:', serialized_tx.hex()) client.close()
class TrezorClient(HardwareWalletClient): # device is an HID device that has already been opened. def __init__(self, device, path): super(TrezorClient, self).__init__(device) device.close() self.client = Trezor(transport=get_transport("hid:" + path.decode())) # if it wasn't able to find a client, throw an error if not self.client: raise IOError("no Device") # Must return a dict with the xpub # Retrieves the public key at the specified BIP 32 derivation path def get_pubkey_at_path(self, path): expanded_path = tools.parse_path(path) output = self.client.get_public_node(expanded_path) if self.is_testnet: return {'xpub': xpub_main_2_test(output.xpub)} else: return {'xpub': output.xpub} # Must return a hex string with the signed transaction # The tx must be in the psbt format def sign_tx(self, tx): # Get this devices master key fingerprint master_key = self.client.get_public_node([0]) master_fp = get_xpub_fingerprint(master_key.xpub) # Prepare inputs inputs = [] for psbt_in, txin in zip(tx.inputs, tx.tx.vin): txinputtype = proto.TxInputType() # Set the input stuff txinputtype.prev_hash = ser_uint256(txin.prevout.hash)[::-1] txinputtype.prev_index = txin.prevout.n txinputtype.sequence = txin.nSequence # Detrermine spend type if psbt_in.non_witness_utxo: txinputtype.script_type = proto.InputScriptType.SPENDADDRESS elif psbt_in.witness_utxo: # Check if the output is p2sh if psbt_in.witness_utxo.is_p2sh(): txinputtype.script_type = proto.InputScriptType.SPENDP2SHWITNESS else: txinputtype.script_type = proto.InputScriptType.SPENDWITNESS # Check for 1 key if len(psbt_in.hd_keypaths) == 1: # Is this key ours pubkey = list(psbt_in.hd_keypaths.keys())[0] fp = psbt_in.hd_keypaths[pubkey][0] keypath = list(psbt_in.hd_keypaths[pubkey][1:]) if fp == master_fp: # Set the keypath txinputtype.address_n = keypath # Check for multisig (more than 1 key) elif len(psbt_in.hd_keypaths) > 1: raise TypeError("Cannot sign multisig yet") else: raise TypeError("All inputs must have a key for this device") # Set the amount if psbt_in.non_witness_utxo: txinputtype.amount = psbt_in.non_witness_utxo.vout[ txin.prevout.n].nValue elif psbt_in.witness_utxo: txinputtype.amount = psbt_in.witness_utxo.nValue # append to inputs inputs.append(txinputtype) # address version byte if self.is_testnet: p2pkh_version = b'\x6f' p2sh_version = b'\xc4' bech32_hrp = 'tb' else: p2pkh_version = b'\x00' p2sh_version = b'\x05' bech32_hrp = 'bc' # prepare outputs outputs = [] for out in tx.tx.vout: txoutput = proto.TxOutputType() txoutput.amount = out.nValue txoutput.script_type = proto.OutputScriptType.PAYTOADDRESS if out.is_p2pkh(): txoutput.address = to_address(out.scriptPubKey[3:23], p2pkh_version) elif out.is_p2sh(): txoutput.address = to_address(out.scriptPubKey[2:22], p2sh_version) else: wit, ver, prog = out.is_witness() if wit: txoutput.address = bech32.encode(bech32_hrp, ver, prog) else: raise TypeError("Output is not an address") # append to outputs outputs.append(txoutput) # Sign the transaction self.client.set_tx_api(TxAPIPSBT(tx)) if self.is_testnet: signed_tx = self.client.sign_tx("Testnet", inputs, outputs, tx.tx.nVersion, tx.tx.nLockTime) else: signed_tx = self.client.sign_tx("Bitcoin", inputs, outputs, tx.tx.nVersion, tx.tx.nLockTime) signatures = signed_tx[0] for psbt_in in tx.inputs: for pubkey, sig in zip(psbt_in.hd_keypaths.keys(), signatures): fp = psbt_in.hd_keypaths[pubkey][0] keypath = psbt_in.hd_keypaths[pubkey][1:] if fp == master_fp: psbt_in.partial_sigs[pubkey] = sig + b'\x01' break signatures.remove(sig) return {'psbt': tx.serialize()} # Must return a base64 encoded string with the signed message # The message can be any string def sign_message(self, message): raise NotImplementedError( 'The HardwareWalletClient base class does not ' 'implement this method') # Display address of specified type on the device. Only supports single-key based addresses. def display_address(self, keypath, p2sh_p2wpkh, bech32): raise NotImplementedError( 'The HardwareWalletClient base class does not ' 'implement this method') # Setup a new device def setup_device(self): raise NotImplementedError( 'The HardwareWalletClient base class does not ' 'implement this method') # Wipe this device def wipe_device(self): raise NotImplementedError( 'The HardwareWalletClient base class does not ' 'implement this method') # Close the device def close(self): self.client.close()
def main(): numinputs = 600 sizeinputtx = 10 # List all connected TREZORs on USB devices = HidTransport.enumerate() # Check whether we found any if len(devices) == 0: print('No TREZOR found') return # Use first connected device print(devices[0][0]) # transport = BridgeTransport(devices[0][0]) transport = HidTransport(devices[0]) txstore = MyTXAPIBitcoin() # Creates object for manipulating TREZOR client = TrezorClient(transport) # client.set_tx_api(TXAPITestnet()) txstore.set_client(client) txstore.set_publickey(client.get_public_node(client.expand_path("44'/0'/0'"))) print("creating input txs") txstore.create_inputs(numinputs, sizeinputtx) print("go") client.set_tx_api(txstore) # client.set_tx_api(MyTXAPIBitcoin()) # Print out TREZOR's features and settings print(client.features) # Get the first address of first BIP44 account # (should be the same address as shown in mytrezor.com) outputs = [ proto_types.TxOutputType( amount=0, script_type=proto_types.PAYTOADDRESS, address='p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm' # op_return_data=binascii.unhexlify('2890770995194662774cd192ee383b805e9a066e6a456be037727649228fb7f6') # address_n=client.expand_path("44'/0'/0'/0/35"), # address='3PUxV6Cc4udQZQsJhArVUzvvVoKC8ohkAj', ), # proto_types.TxOutputType( # amount=0, # script_type=proto_types.PAYTOOPRETURN, # op_return_data=binascii.unhexlify('2890770995194662774cd192ee383b805e9a066e6a456be037727649228fb7f6') # ), # proto_types.TxOutputType( # amount= 8120, # script_type=proto_types.PAYTOADDRESS, # address_n=client.expand_path("44'/1'/0'/1/0"), # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ', # address='14KRxYgFc7Se8j7MDdrK5PTNv8meq4GivK', # ), # proto_types.TxOutputType( # amount= 18684 - 2000, # script_type=proto_types.PAYTOADDRESS, # address_n=client.expand_path("44'/0'/0'/0/7"), # # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ', # # address='1s9TSqr3PHZdXGrYws59Uaf5SPqavH43z', # ), # proto_types.TxOutputType( # amount= 1000, # script_type=proto_types.PAYTOADDRESS, # # address_n=client.expand_path("44'/0'/0'/0/18"), # # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ', # address='1NcMqUvyWv1K3Zxwmx5sqfj7ZEmPCSdJFM', # ), ] # (signatures, serialized_tx) = client.sign_tx('Testnet', inputs, outputs) (signatures, serialized_tx) = client.sign_tx('Bitcoin', txstore.get_inputs(), txstore.get_outputs()) print('Transaction:', binascii.hexlify(serialized_tx)) client.close()