diff --git a/.flake8 b/.flake8 index a89b939558..5fd5447939 100644 --- a/.flake8 +++ b/.flake8 @@ -10,18 +10,12 @@ exclude = ignore = # F401: module imported but unused F401, - # F403: used import * - F403, - # F405 'foo' may be undefined, or defined from star imports - F405, # E241: multiple spaces after ':' E241, # E402: module level import not at top of file E402, # E501: line too long E501, - # E721: do not compare types, use 'isinstance()' - E721, # E722: do not use bare except E722, # E741: ambiguous variable name diff --git a/tools/helloworld.py b/tools/helloworld.py index c91e5d392a..c851baca36 100755 --- a/tools/helloworld.py +++ b/tools/helloworld.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from trezorlib.client import TrezorClient from trezorlib.transport import get_transport +from trezorlib.tools import parse_path def main(): @@ -15,7 +16,7 @@ def main(): # 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") + bip32_path = parse_path("44'/0'/0'/0/0") address = client.get_address('Bitcoin', bip32_path) print('Bitcoin address:', address) diff --git a/tools/pwd_reader.py b/tools/pwd_reader.py index a979bd5279..58c9b5fe45 100755 --- a/tools/pwd_reader.py +++ b/tools/pwd_reader.py @@ -10,16 +10,16 @@ from urllib.parse import urlparse from trezorlib.client import TrezorClient from trezorlib.transport import get_transport +from trezorlib.tools import parse_path # Return path by BIP-32 -def getPath(client): - return client.expand_path("10016'/0") +BIP32_PATH = parse_path("10016h/0") # Deriving master key def getMasterKey(client): - bip32_path = getPath(client) + bip32_path = BIP32_PATH ENC_KEY = 'Activate TREZOR Password Manager?' ENC_VALUE = unhexlify('2d650551248d792eabf628f451200d7f51cb63e46aadcbb1038aacb05e8c8aee2d650551248d792eabf628f451200d7f51cb63e46aadcbb1038aacb05e8c8aee') key = hexlify(client.encrypt_keyvalue( @@ -99,7 +99,7 @@ def getDecryptedNonce(client, entry): ENC_KEY = 'Unlock %s for user %s?' % (item, entry['username']) ENC_VALUE = entry['nonce'] decrypted_nonce = hexlify(client.decrypt_keyvalue( - getPath(client), + BIP32_PATH, ENC_KEY, unhexlify(ENC_VALUE), False, diff --git a/tools/signtest.py b/tools/signtest.py index 547c3c6953..90feb7a4aa 100755 --- a/tools/signtest.py +++ b/tools/signtest.py @@ -14,6 +14,13 @@ from trezorlib.tx_api import TxApiBitcoin from trezorlib.transport import get_transport +# This script has survived unmodified through several significant changes +# of the trezorlib library. While we want to have something like this, +# we're waiting on a couple more changes in order to implement this a little more cleanly. +# Wait for trezorlib v1.0. +raise Exception("This code is too old to run. Sorry.") + + def hash160(x): h = hashlib.new("ripemd160") h.update(hashlib.sha256(x).digest()) @@ -110,7 +117,7 @@ class MyTxApiBitcoin(object): o.script_pubkey = b'\x76\xa9\x14' + pubkey + b'\x88\xac' txser = self.serialize_tx(t) - txhash = tools.Hash(txser)[::-1] + txhash = tools.btc_hash(txser)[::-1] self.inputs.append( proto_types.TxInputType( address_n=self.client.expand_path("44'/0'/0'/0/%d" % idx), diff --git a/trezorctl b/trezorctl index 7b436700d5..8b09e3d8fb 100755 --- a/trezorctl +++ b/trezorctl @@ -23,18 +23,19 @@ import base64 import binascii import click -import functools import json +import logging import os import sys -from trezorlib.client import TrezorClient, TrezorClientVerbose, CallException, format_protobuf -from trezorlib.transport import get_transport, enumerate_devices, TransportException +from trezorlib.client import TrezorClient, CallException +from trezorlib.transport import get_transport, enumerate_devices from trezorlib import coins +from trezorlib import log from trezorlib import messages as proto from trezorlib import protobuf -from trezorlib.ckd_public import PRIME_DERIVATION_FLAG from trezorlib import stellar +from trezorlib import tools class ChoiceType(click.Choice): @@ -65,32 +66,34 @@ CHOICE_OUTPUT_SCRIPT_TYPE = ChoiceType({ }) +def enable_logging(): + log.enable_debug_output() + log.OMITTED_MESSAGES.add(proto.Features) + + @click.group(context_settings={'max_content_width': 400}) @click.option('-p', '--path', help='Select device by specific path.', default=os.environ.get('TREZOR_PATH')) @click.option('-v', '--verbose', is_flag=True, help='Show communication messages.') @click.option('-j', '--json', 'is_json', is_flag=True, help='Print result as JSON object') @click.pass_context def cli(ctx, path, verbose, is_json): - if ctx.invoked_subcommand != 'list': - if verbose: - cls = TrezorClientVerbose - else: - cls = TrezorClient + if verbose: + enable_logging() - def get_device(): + def get_device(): + try: + device = get_transport(path, prefix_search=False) + except: try: - device = get_transport(path, prefix_search=False) + device = get_transport(path, prefix_search=True) except: - try: - device = get_transport(path, prefix_search=True) - except: - click.echo("Failed to find a TREZOR device.") - if path is not None: - click.echo("Using path: {}".format(path)) - sys.exit(1) - return cls(transport=device) + click.echo("Failed to find a TREZOR device.") + if path is not None: + click.echo("Using path: {}".format(path)) + sys.exit(1) + return TrezorClient(transport=device) - ctx.obj = get_device + ctx.obj = get_device @cli.resultcallback() @@ -112,7 +115,7 @@ def print_result(res, path, verbose, is_json): else: click.echo('%s: %s' % (k, v)) elif isinstance(res, protobuf.MessageType): - click.echo(format_protobuf(res)) + click.echo(protobuf.format_message(res)) else: click.echo(res) @@ -449,7 +452,7 @@ def self_test(connect): @click.pass_obj def get_address(connect, coin, address, script_type, show_display): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) return client.get_address(coin, address_n, show_display, script_type=script_type) @@ -461,7 +464,7 @@ def get_address(connect, coin, address, script_type, show_display): @click.pass_obj def get_public_node(connect, coin, address, curve, show_display): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) result = client.get_public_node(address_n, ecdsa_curve_name=curve, show_display=show_display, coin_name=coin) return { 'node': { @@ -502,7 +505,7 @@ def sign_tx(connect, coin): if address_n is None: pass - elif address_n[0] == (49 | PRIME_DERIVATION_FLAG): + elif address_n[0] == tools.H_(49): script_type = 'p2shsegwit' return script_type @@ -518,7 +521,7 @@ def sign_tx(connect, coin): if not prev: break prev_hash, prev_index = prev - address_n = click.prompt('BIP-32 path to derive the key', type=client.expand_path) + address_n = click.prompt('BIP-32 path to derive the key', type=tools.parse_path) amount = click.prompt('Input amount (satoshis)', type=int, default=0) sequence = click.prompt('Sequence Number to use (RBF opt-in enabled by default)', type=int, default=0xfffffffd) script_type = click.prompt('Input type', type=CHOICE_INPUT_SCRIPT_TYPE, default=default_script_type(address_n)) @@ -540,7 +543,7 @@ def sign_tx(connect, coin): address_n = None else: address = None - address_n = click.prompt('BIP-32 path (for change output)', type=client.expand_path, default='') + address_n = click.prompt('BIP-32 path (for change output)', type=tools.parse_path, default='') if not address_n: break amount = click.prompt('Amount to spend (satoshis)', type=int) @@ -581,7 +584,7 @@ def sign_tx(connect, coin): @click.pass_obj def sign_message(connect, coin, address, message, script_type): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) typemap = { 'address': proto.InputScriptType.SPENDADDRESS, 'segwit': proto.InputScriptType.SPENDWITNESS, @@ -613,7 +616,7 @@ def verify_message(connect, coin, address, signature, message): @click.pass_obj def ethereum_sign_message(connect, address, message): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) ret = client.ethereum_sign_message(address_n, message) output = { 'message': message, @@ -648,7 +651,7 @@ def ethereum_verify_message(connect, address, signature, message): @click.pass_obj def encrypt_keyvalue(connect, address, key, value): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) res = client.encrypt_keyvalue(address_n, key, value.encode()) return binascii.hexlify(res) @@ -660,7 +663,7 @@ def encrypt_keyvalue(connect, address, key, value): @click.pass_obj def decrypt_keyvalue(connect, address, key, value): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) return client.decrypt_keyvalue(address_n, key, binascii.unhexlify(value)) @@ -674,7 +677,7 @@ def decrypt_keyvalue(connect, address, key, value): def encrypt_message(connect, coin, display_only, address, pubkey, message): client = connect() pubkey = binascii.unhexlify(pubkey) - address_n = client.expand_path(address) + address_n = tools.parse_path(address) res = client.encrypt_message(pubkey, message, display_only, coin, address_n) return { 'nonce': binascii.hexlify(res.nonce), @@ -690,7 +693,7 @@ def encrypt_message(connect, coin, display_only, address, pubkey, message): @click.pass_obj def decrypt_message(connect, address, payload): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) payload = base64.b64decode(payload) nonce, message, msg_hmac = payload[:33], payload[33:-8], payload[-8:] return client.decrypt_message(address_n, nonce, message, msg_hmac) @@ -707,7 +710,7 @@ def decrypt_message(connect, address, payload): @click.pass_obj def ethereum_get_address(connect, address, show_display): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) address = client.ethereum_get_address(address_n, show_display) return '0x%s' % binascii.hexlify(address).decode() @@ -774,7 +777,7 @@ def ethereum_sign_tx(connect, host, chain_id, address, value, gas_limit, gas_pri to_address = ethereum_decode_hex(to) client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) address = '0x%s' % (binascii.hexlify(client.ethereum_get_address(address_n)).decode()) if gas_price is None or gas_limit is None or nonce is None or publish: @@ -836,7 +839,7 @@ def ethereum_sign_tx(connect, host, chain_id, address, value, gas_limit, gas_pri @click.pass_obj def nem_get_address(connect, address, network, show_display): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) return client.nem_get_address(address_n, network, show_display) @@ -847,7 +850,7 @@ def nem_get_address(connect, address, network, show_display): @click.pass_obj def nem_sign_tx(connect, address, file, broadcast): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) transaction = client.nem_sign_tx(address_n, json.load(file)) payload = { @@ -873,7 +876,7 @@ def nem_sign_tx(connect, address, file, broadcast): @click.pass_obj def lisk_get_address(connect, address, show_display): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) return client.lisk_get_address(address_n, show_display) @@ -883,7 +886,7 @@ def lisk_get_address(connect, address, show_display): @click.pass_obj def lisk_get_public_key(connect, address, show_display): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) res = client.lisk_get_public_key(address_n, show_display) output = { "public_key": binascii.hexlify(res.public_key).decode() @@ -898,7 +901,7 @@ def lisk_get_public_key(connect, address, show_display): @click.pass_obj def lisk_sign_tx(connect, address, file): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) transaction = client.lisk_sign_tx(address_n, json.load(file)) payload = { @@ -919,7 +922,7 @@ def lisk_sign_tx(connect, address, file): @click.pass_obj def cosi_commit(connect, address, data): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) return client.cosi_commit(address_n, binascii.unhexlify(data)) @@ -931,7 +934,7 @@ def cosi_commit(connect, address, data): @click.pass_obj def cosi_sign(connect, address, data, global_commitment, global_pubkey): client = connect() - address_n = client.expand_path(address) + address_n = tools.parse_path(address) return client.cosi_sign(address_n, binascii.unhexlify(data), binascii.unhexlify(global_commitment), binascii.unhexlify(global_pubkey)) @@ -939,25 +942,24 @@ def cosi_sign(connect, address, data, global_commitment, global_pubkey): # Stellar functions # @cli.command(help='Get Stellar public address') -@click.option('-n', '--address', required=False, help="BIP32 path. Default primary account is m/44'/148'/0'. Always use hardened paths and the m/44'/148'/ prefix") +@click.option('-n', '--address', required=False, help="BIP32 path. Always use hardened paths and the m/44'/148'/ prefix", default=stellar.DEFAULT_BIP32_PATH) @click.pass_obj def stellar_get_address(connect, address): client = connect() - address_n = stellar.expand_path_or_default(client, address) + address_n = tools.parse_path(address) # StellarPublicKey response response = client.stellar_get_public_key(address_n) return stellar.address_from_public_key(response.public_key) @cli.command(help='Sign a base64-encoded transaction envelope') -@click.option('-n', '--address', required=False, help="BIP32 path. Default primary account is m/44'/148'/0'. Always use hardened paths and the m/44'/148'/ prefix") +@click.option('-n', '--address', required=False, help="BIP32 path. Always use hardened paths and the m/44'/148'/ prefix", default=stellar.DEFAULT_BIP32_PATH) @click.option('-n', '--network-passphrase', default='Public Global Stellar Network ; September 2015', required=False, help="Network passphrase (blank for public network). Testnet is: 'Test SDF Network ; September 2015'") @click.argument('b64envelope') @click.pass_obj def stellar_sign_transaction(connect, b64envelope, address, network_passphrase): client = connect() - - address_n = stellar.expand_path_or_default(client, address) + address_n = tools.parse_path(address) tx, operations = stellar.parse_transaction_bytes(base64.b64decode(b64envelope)) resp = client.stellar_sign_transaction(tx, operations, address_n, network_passphrase) diff --git a/trezorlib/ed25519raw.py b/trezorlib/_ed25519.py similarity index 77% rename from trezorlib/ed25519raw.py rename to trezorlib/_ed25519.py index 81476396e9..7470dea1a4 100644 --- a/trezorlib/ed25519raw.py +++ b/trezorlib/_ed25519.py @@ -1,19 +1,21 @@ # orignal version downloaded from https://ed25519.cr.yp.to/python/ed25519.py # modified for Python 3 by Jochen Hoenicke -import sys import hashlib +from typing import Tuple, NewType + +Point = NewType("Point", Tuple[int, int]) b = 256 q = 2 ** 255 - 19 l = 2 ** 252 + 27742317777372353535851937790883648493 -def H(m): +def H(m: bytes) -> bytes: return hashlib.sha512(m).digest() -def expmod(b, e, m): +def expmod(b: int, e: int, m: int) -> int: if e < 0: raise ValueError('negative exponent') if e == 0: @@ -24,7 +26,7 @@ def expmod(b, e, m): return t -def inv(x): +def inv(x: int) -> int: return expmod(x, q - 2, q) @@ -32,7 +34,7 @@ d = -121665 * inv(121666) I = expmod(2, (q - 1) >> 2, q) -def xrecover(y): +def xrecover(y: int) -> int: xx = (y * y - 1) * inv(d * y * y + 1) x = expmod(xx, (q + 3) >> 3, q) if (x * x - xx) % q != 0: @@ -44,22 +46,22 @@ def xrecover(y): By = 4 * inv(5) Bx = xrecover(By) -B = [Bx % q, By % q] +B = Point((Bx % q, By % q)) -def edwards(P, Q): +def edwards(P: Point, Q: Point) -> Point: x1 = P[0] y1 = P[1] x2 = Q[0] y2 = Q[1] x3 = (x1 * y2 + x2 * y1) * inv(1 + d * x1 * x2 * y1 * y2) y3 = (y1 * y2 + x1 * x2) * inv(1 - d * x1 * x2 * y1 * y2) - return [x3 % q, y3 % q] + return Point((x3 % q, y3 % q)) -def scalarmult(P, e): +def scalarmult(P: Point, e: int) -> Point: if e == 0: - return [0, 1] + return Point((0, 1)) Q = scalarmult(P, e >> 1) Q = edwards(Q, Q) if e & 1: @@ -67,35 +69,35 @@ def scalarmult(P, e): return Q -def encodeint(y): +def encodeint(y: int) -> bytes: bits = [(y >> i) & 1 for i in range(b)] return bytes([sum([bits[i * 8 + j] << j for j in range(8)]) for i in range(b >> 3)]) -def encodepoint(P): +def encodepoint(P: Point) -> bytes: x = P[0] y = P[1] bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1] return bytes([sum([bits[i * 8 + j] << j for j in range(8)]) for i in range(b >> 3)]) -def bit(h, i): +def bit(h: bytes, i: int) -> int: return (h[i >> 3] >> (i & 7)) & 1 -def publickey(sk): +def publickey(sk: bytes) -> bytes: h = H(sk) a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2)) A = scalarmult(B, a) return encodepoint(A) -def Hint(m): +def Hint(m: bytes) -> int: h = H(m) return sum(2 ** i * bit(h, i) for i in range(2 * b)) -def signature(m, sk, pk): +def signature(m: bytes, sk: bytes, pk: bytes) -> bytes: h = H(sk) a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2)) r = Hint(bytes([h[i] for i in range(b >> 3, b >> 2)]) + m) @@ -104,28 +106,28 @@ def signature(m, sk, pk): return encodepoint(R) + encodeint(S) -def isoncurve(P): +def isoncurve(P: Point) -> bool: x = P[0] y = P[1] return (-x * x + y * y - 1 - d * x * x * y * y) % q == 0 -def decodeint(s): +def decodeint(s: bytes) -> int: return sum(2 ** i * bit(s, i) for i in range(0, b)) -def decodepoint(s): +def decodepoint(s: bytes) -> Point: y = sum(2 ** i * bit(s, i) for i in range(0, b - 1)) x = xrecover(y) if x & 1 != bit(s, b - 1): x = q - x - P = [x, y] + P = Point((x, y)) if not isoncurve(P): raise ValueError('decoding point that is not on curve') return P -def checkvalid(s, m, pk): +def checkvalid(s: bytes, m: bytes, pk: bytes) -> None: if len(s) != b >> 2: raise ValueError('signature length is wrong') if len(pk) != b >> 3: diff --git a/trezorlib/client.py b/trezorlib/client.py index 837bbe3e10..a654c25a15 100644 --- a/trezorlib/client.py +++ b/trezorlib/client.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from __future__ import print_function, absolute_import - +import functools +import logging import os import sys import time @@ -34,18 +34,16 @@ from . import messages as proto from . import tools from . import mapping from . import nem -from .coins import slip44 +from . import protobuf from . import stellar from .debuglink import DebugLink -from .protobuf import MessageType - if sys.version_info.major < 3: raise Exception("Trezorlib does not support Python 2 anymore.") SCREENSHOT = False - +LOG = logging.getLogger(__name__) # make a getch function try: @@ -84,70 +82,15 @@ def get_buttonrequest_value(code): return [k for k in dir(proto.ButtonRequestType) if getattr(proto.ButtonRequestType, k) == code][0] -def format_protobuf(pb, indent=0, sep=' ' * 4): - def pformat_value(value, indent): - level = sep * indent - leadin = sep * (indent + 1) - if isinstance(value, MessageType): - return format_protobuf(value, indent, sep) - if isinstance(value, list): - lines = [] - lines.append('[') - lines += [leadin + pformat_value(x, indent + 1) + ',' for x in value] - lines.append(level + ']') - return '\n'.join(lines) - if isinstance(value, dict): - lines = [] - lines.append('{') - for key, val in sorted(value.items()): - if val is None or val == []: - continue - if key == 'address_n' and isinstance(val, list): - lines.append(leadin + key + ': ' + repr(val) + ',') - else: - lines.append(leadin + key + ': ' + pformat_value(val, indent + 1) + ',') - lines.append(level + '}') - return '\n'.join(lines) - if isinstance(value, bytearray): - return 'bytearray(0x{})'.format(binascii.hexlify(value).decode('ascii')) - - return repr(value) - - return pb.__class__.__name__ + ' ' + pformat_value(pb.__dict__, indent) - - -def pprint(msg): - msg_class = msg.__class__.__name__ - msg_size = msg.ByteSize() - if isinstance(msg, proto.FirmwareUpload) or isinstance(msg, proto.SelfTest) \ - or isinstance(msg, proto.Features): - return "<%s> (%d bytes)" % (msg_class, msg_size) - else: - return "<%s> (%d bytes):\n%s" % (msg_class, msg_size, format_protobuf(msg)) - - -def log(msg): - sys.stderr.write(msg) - sys.stderr.write('\n') - sys.stderr.flush() - - class CallException(Exception): - def __init__(self, code, message): - super(CallException, self).__init__() - self.args = [code, message] - - -class AssertionException(Exception): - def __init__(self, code, message): - self.args = [code, message] + pass class PinException(CallException): pass -class field(object): +class field: # Decorator extracts single value from # protobuf object. If the field is not # present, raises an exception. @@ -155,13 +98,14 @@ class field(object): self.field = field def __call__(self, f): + @functools.wraps(f) def wrapped_f(*args, **kwargs): ret = f(*args, **kwargs) return getattr(ret, self.field) return wrapped_f -class expect(object): +class expect: # Decorator checks if the method # returned one of expected protobuf messages # or raises an exception @@ -169,6 +113,7 @@ class expect(object): self.expected = expected def __call__(self, f): + @functools.wraps(f) def wrapped_f(*args, **kwargs): ret = f(*args, **kwargs) if not isinstance(ret, self.expected): @@ -180,7 +125,9 @@ class expect(object): def session(f): # Decorator wraps a BaseClient method # with session activation / deactivation + @functools.wraps(f) def wrapped_f(*args, **kwargs): + __tracebackhide__ = True # pytest traceback hiding - this function won't appear in tracebacks client = args[0] client.transport.session_begin() try: @@ -204,6 +151,7 @@ class BaseClient(object): # Implements very basic layer of sending raw protobuf # messages to device and getting its response back. def __init__(self, transport, **kwargs): + LOG.info("creating client instance for device: {}".format(transport.get_path())) self.transport = transport super(BaseClient, self).__init__() # *args, **kwargs) @@ -215,6 +163,7 @@ class BaseClient(object): @session def call_raw(self, msg): + __tracebackhide__ = True # pytest traceback hiding - this function won't appear in tracebacks self.transport.write(msg) return self.transport.read() @@ -244,14 +193,6 @@ class BaseClient(object): mapping.register_message(msg) -class VerboseWireMixin(object): - def call_raw(self, msg): - log("SENDING " + pprint(msg)) - resp = super(VerboseWireMixin, self).call_raw(msg) - log("RECEIVED " + pprint(resp)) - return resp - - class TextUIMixin(object): # This class demonstrates easy test-based UI # integration between the device and wallet. @@ -262,6 +203,10 @@ class TextUIMixin(object): def __init__(self, *args, **kwargs): super(TextUIMixin, self).__init__(*args, **kwargs) + @staticmethod + def print(text): + print(text, file=sys.stderr) + def callback_ButtonRequest(self, msg): # log("Sending ButtonAck for %s " % get_buttonrequest_value(msg.code)) return proto.ButtonAck() @@ -269,11 +214,11 @@ class TextUIMixin(object): def callback_RecoveryMatrix(self, msg): if self.recovery_matrix_first_pass: self.recovery_matrix_first_pass = False - log("Use the numeric keypad to describe positions. For the word list use only left and right keys.") - log("Use backspace to correct an entry. The keypad layout is:") - log(" 7 8 9 7 | 9") - log(" 4 5 6 4 | 6") - log(" 1 2 3 1 | 3") + self.print("Use the numeric keypad to describe positions. For the word list use only left and right keys.") + self.print("Use backspace to correct an entry. The keypad layout is:") + self.print(" 7 8 9 7 | 9") + self.print(" 4 5 6 4 | 6") + self.print(" 1 2 3 1 | 3") while True: character = getch() if character in ('\x03', '\x04'): @@ -299,11 +244,11 @@ class TextUIMixin(object): else: desc = 'PIN' - log("Use the numeric keypad to describe number positions. The layout is:") - log(" 7 8 9") - log(" 4 5 6") - log(" 1 2 3") - log("Please enter %s: " % desc) + self.print("Use the numeric keypad to describe number positions. The layout is:") + self.print(" 7 8 9") + self.print(" 4 5 6") + self.print(" 1 2 3") + self.print("Please enter %s: " % desc) pin = getpass.getpass('') if not pin.isdigit(): raise ValueError('Non-numerical PIN provided') @@ -314,18 +259,18 @@ class TextUIMixin(object): return proto.PassphraseAck() if os.getenv("PASSPHRASE") is not None: - log("Passphrase required. Using PASSPHRASE environment variable.") + self.print("Passphrase required. Using PASSPHRASE environment variable.") passphrase = Mnemonic.normalize_string(os.getenv("PASSPHRASE")) return proto.PassphraseAck(passphrase=passphrase) - log("Passphrase required: ") + self.print("Passphrase required: ") passphrase = getpass.getpass('') - log("Confirm your Passphrase: ") + self.print("Confirm your Passphrase: ") if passphrase == getpass.getpass(''): passphrase = Mnemonic.normalize_string(passphrase) return proto.PassphraseAck(passphrase=passphrase) else: - log("Passphrase did not match! ") + self.print("Passphrase did not match! ") exit() def callback_PassphraseStateRequest(self, msg): @@ -335,7 +280,7 @@ class TextUIMixin(object): if msg.type in (proto.WordRequestType.Matrix9, proto.WordRequestType.Matrix6): return self.callback_RecoveryMatrix(msg) - log("Enter one word of mnemonic: ") + self.print("Enter one word of mnemonic: ") word = input() if self.expand: word = self.mnemonic_wordlist.expand_word(word) @@ -352,6 +297,7 @@ class DebugLinkMixin(object): # of unit testing, because it will fail to work # without special DebugLink interface provided # by the device. + DEBUG = LOG.getChild('debug_link').debug def __init__(self, *args, **kwargs): super(DebugLinkMixin, self).__init__(*args, **kwargs) @@ -396,7 +342,7 @@ class DebugLinkMixin(object): # Evaluate missed responses in 'with' statement if self.expected_responses is not None and len(self.expected_responses): raise RuntimeError("Some of expected responses didn't come from device: %s" % - [pprint(x) for x in self.expected_responses]) + [repr(x) for x in self.expected_responses]) # Cleanup self.expected_responses = None @@ -418,6 +364,7 @@ class DebugLinkMixin(object): self.mnemonic = Mnemonic.normalize_string(mnemonic).split(' ') def call_raw(self, msg): + __tracebackhide__ = True # pytest traceback hiding - this function won't appear in tracebacks if SCREENSHOT and self.debug: from PIL import Image @@ -437,30 +384,32 @@ class DebugLinkMixin(object): return resp def _check_request(self, msg): + __tracebackhide__ = True # pytest traceback hiding - this function won't appear in tracebacks + if self.expected_responses is not None: try: expected = self.expected_responses.pop(0) except IndexError: - raise AssertionException(proto.FailureType.UnexpectedMessage, - "Got %s, but no message has been expected" % pprint(msg)) + raise AssertionError(proto.FailureType.UnexpectedMessage, + "Got %s, but no message has been expected" % repr(msg)) if msg.__class__ != expected.__class__: - raise AssertionException(proto.FailureType.UnexpectedMessage, - "Expected %s, got %s" % (pprint(expected), pprint(msg))) + raise AssertionError(proto.FailureType.UnexpectedMessage, + "Expected %s, got %s" % (repr(expected), repr(msg))) for field, value in expected.__dict__.items(): if value is None or value == []: continue if getattr(msg, field) != value: - raise AssertionException(proto.FailureType.UnexpectedMessage, - "Expected %s, got %s" % (pprint(expected), pprint(msg))) + raise AssertionError(proto.FailureType.UnexpectedMessage, + "Expected %s, got %s" % (repr(expected), repr(msg))) def callback_ButtonRequest(self, msg): - log("ButtonRequest code: " + get_buttonrequest_value(msg.code)) + self.DEBUG("ButtonRequest code: " + get_buttonrequest_value(msg.code)) - log("Pressing button " + str(self.button)) + self.DEBUG("Pressing button " + str(self.button)) if self.button_wait: - log("Waiting %d seconds " % self.button_wait) + self.DEBUG("Waiting %d seconds " % self.button_wait) time.sleep(self.button_wait) self.debug.press_button(self.button) return proto.ButtonAck() @@ -473,7 +422,7 @@ class DebugLinkMixin(object): return proto.PinMatrixAck(pin=pin) def callback_PassphraseRequest(self, msg): - log("Provided passphrase: '%s'" % self.passphrase) + self.DEBUG("Provided passphrase: '%s'" % self.passphrase) return proto.PassphraseAck(passphrase=self.passphrase) def callback_PassphraseStateRequest(self, msg): @@ -490,7 +439,6 @@ class DebugLinkMixin(object): class ProtocolMixin(object): - PRIME_DERIVATION_FLAG = 0x80000000 VENDORS = ('bitcointrezor.com', 'trezor.io') def __init__(self, state=None, *args, **kwargs): @@ -513,44 +461,15 @@ class ProtocolMixin(object): def _get_local_entropy(self): return os.urandom(32) - def _convert_prime(self, n): + @staticmethod + def _convert_prime(n: tools.Address) -> tools.Address: # Convert minus signs to uint32 with flag - return [int(abs(x) | self.PRIME_DERIVATION_FLAG) if x < 0 else x for x in n] + return [tools.H_(int(abs(x))) if x < 0 else x for x in n] @staticmethod def expand_path(n): - # Convert string of bip32 path to list of uint32 integers with prime flags - # 0/-1/1' -> [0, 0x80000001, 0x80000001] - if not n: - return [] - - n = n.split('/') - - # m/a/b/c => a/b/c - if n[0] == 'm': - n = n[1:] - - # coin_name/a/b/c => 44'/SLIP44_constant'/a/b/c - if n[0] in slip44: - n = ["44'", "%d'" % slip44[n[0]]] + n[1:] - - path = [] - for x in n: - prime = False - if x.endswith("'"): - x = x.replace('\'', '') - prime = True - if x.startswith('-'): - prime = True - - x = abs(int(x)) - - if prime: - x |= ProtocolMixin.PRIME_DERIVATION_FLAG - - path.append(x) - - return path + warnings.warn('expand_path is deprecated, use tools.parse_path', DeprecationWarning) + return tools.parse_path(n) @expect(proto.PublicKey) def get_public_node(self, n, ecdsa_curve_name=None, show_display=False, coin_name=None): @@ -1031,7 +950,7 @@ class ProtocolMixin(object): raise RuntimeError("Invalid response, expected EntropyRequest") external_entropy = self._get_local_entropy() - log("Computer generated entropy: " + binascii.hexlify(external_entropy).decode()) + LOG.debug("Computer generated entropy: " + binascii.hexlify(external_entropy).decode()) ret = self.call(proto.EntropyAck(entropy=external_entropy)) self.init_device() return ret @@ -1079,7 +998,7 @@ class ProtocolMixin(object): if xprv[0:4] not in ('xprv', 'tprv'): raise ValueError("Unknown type of xprv") - if len(xprv) < 100 and len(xprv) > 112: + if not 100 < len(xprv) < 112: # yes this is correct in Python raise ValueError("Invalid length of xprv") node = proto.HDNodeType() @@ -1088,7 +1007,7 @@ class ProtocolMixin(object): if data[90:92] != b'00': raise ValueError("Contain invalid private key") - checksum = binascii.hexlify(hashlib.sha256(hashlib.sha256(binascii.unhexlify(data[:156])).digest()).digest()[:4]) + checksum = binascii.hexlify(tools.btc_hash(binascii.unhexlify(data[:156]))[:4]) if checksum != data[156:]: raise ValueError("Checksum doesn't match") @@ -1128,7 +1047,7 @@ class ProtocolMixin(object): # TREZORv1 method if isinstance(resp, proto.Success): fingerprint = hashlib.sha256(data[256:]).hexdigest() - log("Firmware fingerprint: " + fingerprint) + LOG.debug("Firmware fingerprint: " + fingerprint) resp = self.call(proto.FirmwareUpload(payload=data)) if isinstance(resp, proto.Success): return True @@ -1204,11 +1123,6 @@ class TrezorClient(ProtocolMixin, TextUIMixin, BaseClient): super().__init__(transport=transport, *args, **kwargs) -class TrezorClientVerbose(ProtocolMixin, TextUIMixin, VerboseWireMixin, BaseClient): - def __init__(self, transport, *args, **kwargs): - super().__init__(transport=transport, *args, **kwargs) - - -class TrezorClientDebugLink(ProtocolMixin, DebugLinkMixin, VerboseWireMixin, BaseClient): +class TrezorClientDebugLink(ProtocolMixin, DebugLinkMixin, BaseClient): def __init__(self, transport, *args, **kwargs): super().__init__(transport=transport, *args, **kwargs) diff --git a/trezorlib/cosi.py b/trezorlib/cosi.py new file mode 100644 index 0000000000..71e2899de1 --- /dev/null +++ b/trezorlib/cosi.py @@ -0,0 +1,72 @@ +import sys +from functools import reduce +import binascii +from typing import Iterable, Tuple + +from trezorlib import _ed25519 + +# XXX, these could be NewType's, but that would infect users of the cosi module with these types as well. +# Unsure if we want that. +Ed25519PrivateKey = bytes +Ed25519PublicPoint = bytes +Ed25519Signature = bytes + + +def combine_keys(pks: Iterable[Ed25519PublicPoint]) -> Ed25519PublicPoint: + """Combine a list of Ed25519 points into a "global" CoSi key.""" + P = [_ed25519.decodepoint(pk) for pk in pks] + combine = reduce(_ed25519.edwards, P) + return Ed25519PublicPoint(_ed25519.encodepoint(combine)) + + +def combine_sig(global_R: Ed25519PublicPoint, sigs: Iterable[Ed25519Signature]) -> Ed25519Signature: + """Combine a list of signatures into a single CoSi signature.""" + S = [_ed25519.decodeint(si) for si in sigs] + s = sum(S) % _ed25519.l + sig = global_R + _ed25519.encodeint(s) + return Ed25519Signature(sig) + + +def get_nonce(sk: Ed25519PrivateKey, data: bytes, ctr: int = 0) -> Tuple[int, Ed25519PublicPoint]: + """Calculate CoSi nonces for given data. + These differ from Ed25519 deterministic nonces in that there is a counter appended at end. + + Returns both the private point `r` and the partial signature `R`. + `r` is returned for performance reasons: :func:`sign_with_privkey` + takes it as its `nonce` argument so that it doesn't repeat the `get_nonce` call. + + `R` should be combined with other partial signatures through :func:`combine_keys` + to obtain a "global commitment". + """ + h = _ed25519.H(sk) + b = _ed25519.b + r = _ed25519.Hint(bytes([h[i] for i in range(b >> 3, b >> 2)]) + data + binascii.unhexlify('%08x' % ctr)) + R = _ed25519.scalarmult(_ed25519.B, r) + return r, Ed25519PublicPoint(_ed25519.encodepoint(R)) + + +def verify(signature: Ed25519Signature, digest: bytes, pub_key: Ed25519PublicPoint) -> None: + """Verify Ed25519 signature. Raise exception if the signature is invalid.""" + # XXX this *might* change to bool function + _ed25519.checkvalid(signature, digest, pub_key) + + +def pubkey_from_privkey(privkey: Ed25519PrivateKey) -> Ed25519PublicPoint: + """Interpret 32 bytes of data as an Ed25519 private key. + Calculate and return the corresponding public key. + """ + return Ed25519PublicPoint(_ed25519.publickey(privkey)) + + +def sign_with_privkey(digest: bytes, privkey: Ed25519PrivateKey, + global_pubkey: Ed25519PublicPoint, + nonce: int, + global_commit: Ed25519PublicPoint) -> Ed25519Signature: + """Create a CoSi signature of `digest` with the supplied private key. + This function needs to know the global public key and global commitment. + """ + h = _ed25519.H(privkey) + b = _ed25519.b + a = 2 ** (b - 2) + sum(2 ** i * _ed25519.bit(h, i) for i in range(3, b - 2)) + S = (nonce + _ed25519.Hint(global_commit + global_pubkey + digest) * a) % _ed25519.l + return Ed25519Signature(_ed25519.encodeint(S)) diff --git a/trezorlib/debuglink.py b/trezorlib/debuglink.py index af130f8690..bfe44c1c3d 100644 --- a/trezorlib/debuglink.py +++ b/trezorlib/debuglink.py @@ -29,10 +29,6 @@ def button_press(yes_no): print("User pressed", '"y"' if yes_no else '"n"') -def pprint(msg): - return "<%s> (%d bytes):\n%s" % (msg.__class__.__name__, msg.ByteSize(), msg) - - class DebugLink(object): def __init__(self, transport, pin_func=pin_info, button_func=button_press): self.transport = transport @@ -45,12 +41,10 @@ class DebugLink(object): self.transport.session_end() def _call(self, msg, nowait=False): - print("DEBUGLINK SEND", pprint(msg)) self.transport.write(msg) if nowait: - return + return None ret = self.transport.read() - print("DEBUGLINK RECV", pprint(ret)) return ret def read_pin(self): diff --git a/trezorlib/ed25519cosi.py b/trezorlib/ed25519cosi.py deleted file mode 100644 index 530718a109..0000000000 --- a/trezorlib/ed25519cosi.py +++ /dev/null @@ -1,89 +0,0 @@ -import sys -from functools import reduce -import binascii - -from . import ed25519raw - - -def combine_keys(pks): - P = [ed25519raw.decodepoint(pk) for pk in pks] - combine = reduce(ed25519raw.edwards, P) - return ed25519raw.encodepoint(combine) - - -def combine_sig(R, sigs): - S = [ed25519raw.decodeint(si) for si in sigs] - s = sum(S) % ed25519raw.l - sig = R + ed25519raw.encodeint(s) - return sig - - -def get_nonce(sk, data, ctr): - h = ed25519raw.H(sk) - b = ed25519raw.b - r = ed25519raw.Hint(bytes([h[i] for i in range(b >> 3, b >> 2)]) + data + binascii.unhexlify('%08x' % ctr)) - R = ed25519raw.scalarmult(ed25519raw.B, r) - return r, ed25519raw.encodepoint(R) - - -def self_test(digest): - - def to_hex(by): - return binascii.hexlify(by).decode() - - N = 3 - keyset = [0, 2] - - digest = binascii.unhexlify(digest) - print('Digest: %s' % to_hex(digest)) - sks = [] - pks = [] - nonces = [] - commits = [] - sigs = [] - for i in range(0, N): - print('----- Key %d ------' % (i + 1)) - seckey = (chr(0x41 + i) * 32).encode() - pubkey = ed25519raw.publickey(seckey) - print('Secret Key: %s' % to_hex(seckey)) - print('Public Key: %s' % to_hex(pubkey)) - sks.append(seckey) - pks.append(pubkey) - ctr = 0 - r, R = get_nonce(seckey, digest, ctr) - print('Local nonce: %s' % to_hex(ed25519raw.encodeint(r))) - print('Local commit: %s' % to_hex(R)) - nonces.append(r) - commits.append(R) - - global_pk = combine_keys([pks[i] for i in keyset]) - global_R = combine_keys([commits[i] for i in keyset]) - print('-----------------') - print('Global pubkey: %s' % to_hex(global_pk)) - print('Global commit: %s' % to_hex(global_R)) - print('-----------------') - - for i in range(0, N): - seckey = sks[i] - pubkey = pks[i] - r = nonces[i] - R = commits[i] - h = ed25519raw.H(seckey) - b = ed25519raw.b - a = 2**(b - 2) + sum(2**i * ed25519raw.bit(h, i) for i in range(3, b - 2)) - S = (r + ed25519raw.Hint(global_R + global_pk + digest) * a) % ed25519raw.l - print('Local sig %d: %s' % (i + 1, to_hex(ed25519raw.encodeint(S)))) - sigs.append(ed25519raw.encodeint(S)) - - print('-----------------') - sig = combine_sig(global_R, [sigs[i] for i in keyset]) - print('Global sig: %s' % to_hex(sig)) - ed25519raw.checkvalid(sig, digest, global_pk) - print('Valid Signature!') - - -if __name__ == '__main__': - if len(sys.argv) > 1: - self_test(digest=sys.argv[1]) - else: - self_test(digest='4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b') diff --git a/trezorlib/log.py b/trezorlib/log.py new file mode 100644 index 0000000000..89abd17cfd --- /dev/null +++ b/trezorlib/log.py @@ -0,0 +1,34 @@ +import logging +from typing import Set, Type, Optional + +from . import protobuf + +OMITTED_MESSAGES = set() # type: Set[Type[protobuf.MessageType]] + + +class PrettyProtobufFormatter(logging.Formatter): + + def format(self, record: logging.LogRecord) -> str: + time = self.formatTime(record) + message = '[{time}] {source} {level}: {msg}'.format( + time=time, level=record.levelname.upper(), + source=record.name, + msg=super().format(record)) + if hasattr(record, 'protobuf'): + if type(record.protobuf) in OMITTED_MESSAGES: + message += " ({} bytes)".format(record.protobuf.ByteSize()) + else: + message += "\n" + protobuf.format_message(record.protobuf) + return message + + +def enable_debug_output(handler: Optional[logging.Handler] = None): + if handler is None: + handler = logging.StreamHandler() + + formatter = PrettyProtobufFormatter() + handler.setFormatter(formatter) + + logger = logging.getLogger('trezorlib') + logger.setLevel(logging.DEBUG) + logger.addHandler(handler) diff --git a/trezorlib/protobuf.py b/trezorlib/protobuf.py index 287d7dabf6..866f5e9b2c 100644 --- a/trezorlib/protobuf.py +++ b/trezorlib/protobuf.py @@ -39,7 +39,9 @@ required: >>> """ ''' +import binascii from io import BytesIO +from typing import Any, Optional _UVARINT_BUFFER = bytearray(1) @@ -344,3 +346,58 @@ def dump_message(writer, msg): else: raise TypeError + + +def format_message(pb: MessageType, + indent: int = 0, + sep: str = ' ' * 4, + truncate_after: Optional[int] = 256, + truncate_to: Optional[int] = 64) -> str: + + def mostly_printable(bytes): + if not bytes: + return True + printable = sum(1 for byte in bytes if 0x20 <= byte <= 0x7e) + return printable / len(bytes) > 0.8 + + def pformat_value(value: Any, indent: int) -> str: + level = sep * indent + leadin = sep * (indent + 1) + if isinstance(value, MessageType): + return format_message(value, indent, sep) + if isinstance(value, list): + # short list of simple values + if not value or not isinstance(value[0], MessageType): + return repr(value) + + # long list, one line per entry + lines = ['[', level + ']'] + lines[1:1] = [leadin + pformat_value(x, indent + 1) + ',' for x in value] + return '\n'.join(lines) + if isinstance(value, dict): + lines = ['{'] + for key, val in sorted(value.items()): + if val is None or val == []: + continue + lines.append(leadin + key + ': ' + pformat_value(val, indent + 1) + ',') + lines.append(level + '}') + return '\n'.join(lines) + if isinstance(value, (bytes, bytearray)): + length = len(value) + suffix = '' + if truncate_after and length > truncate_after: + suffix = '...' + value = value[:truncate_to or 0] + if mostly_printable(value): + output = repr(value) + else: + output = '0x' + binascii.hexlify(value).decode('ascii') + return '{} bytes {}{}'.format(length, output, suffix) + + return repr(value) + + return '{name} ({size} bytes) {content}'.format( + name=pb.__class__.__name__, + size=pb.ByteSize(), + content=pformat_value(pb.__dict__, indent) + ) diff --git a/trezorlib/protocol_v1.py b/trezorlib/protocol_v1.py index 6c04af3251..cd263e7d7e 100644 --- a/trezorlib/protocol_v1.py +++ b/trezorlib/protocol_v1.py @@ -19,22 +19,30 @@ from __future__ import absolute_import from io import BytesIO +import logging import struct +from typing import Tuple, Type + from . import mapping from . import protobuf +from .transport import Transport REPLEN = 64 +LOG = logging.getLogger(__name__) -class ProtocolV1(object): - def session_begin(self, transport): +class ProtocolV1: + + def session_begin(self, transport: Transport) -> None: pass - def session_end(self, transport): + def session_end(self, transport: Transport) -> None: pass - def write(self, transport, msg): + def write(self, transport: Transport, msg: protobuf.MessageType) -> None: + LOG.debug("sending message: {}".format(msg.__class__.__name__), + extra={'protobuf': msg}) data = BytesIO() protobuf.dump_message(data, msg) ser = data.getvalue() @@ -48,10 +56,10 @@ class ProtocolV1(object): transport.write_chunk(chunk) data = data[63:] - def read(self, transport): + def read(self, transport: Transport) -> protobuf.MessageType: # Read header with first part of message data chunk = transport.read_chunk() - (msg_type, datalen, data) = self.parse_first(chunk) + msg_type, datalen, data = self.parse_first(chunk) # Read the rest of the message while len(data) < datalen: @@ -63,21 +71,23 @@ class ProtocolV1(object): # Parse to protobuf msg = protobuf.load_message(data, mapping.get_class(msg_type)) + LOG.debug("received message: {}".format(msg.__class__.__name__), + extra={'protobuf': msg}) return msg - def parse_first(self, chunk): + def parse_first(self, chunk: bytes) -> Tuple[int, int, bytes]: if chunk[:3] != b'?##': raise RuntimeError('Unexpected magic characters') try: headerlen = struct.calcsize('>HL') - (msg_type, datalen) = struct.unpack('>HL', chunk[3:3 + headerlen]) + msg_type, datalen = struct.unpack('>HL', chunk[3:3 + headerlen]) except: raise RuntimeError('Cannot parse header') data = chunk[3 + headerlen:] - return (msg_type, datalen, data) + return msg_type, datalen, data - def parse_next(self, chunk): + def parse_next(self, chunk: bytes) -> bytes: if chunk[:1] != b'?': raise RuntimeError('Unexpected magic characters') return chunk[1:] diff --git a/trezorlib/protocol_v2.py b/trezorlib/protocol_v2.py index fd33c96a7c..ba0c4f02d4 100644 --- a/trezorlib/protocol_v2.py +++ b/trezorlib/protocol_v2.py @@ -18,28 +18,34 @@ from __future__ import absolute_import -import struct from io import BytesIO -from . import messages as proto +import logging +import struct +from typing import Tuple + from . import mapping from . import protobuf +from .transport import Transport REPLEN = 64 +LOG = logging.getLogger(__name__) -class ProtocolV2(object): - def __init__(self): +class ProtocolV2: + + def __init__(self) -> None: self.session = None - def session_begin(self, transport): + def session_begin(self, transport: Transport) -> None: chunk = struct.pack('>B', 0x03) chunk = chunk.ljust(REPLEN, b'\x00') transport.write_chunk(chunk) resp = transport.read_chunk() self.session = self.parse_session_open(resp) + LOG.debug("[session {}] session started".format(self.session)) - def session_end(self, transport): + def session_end(self, transport: Transport) -> None: if not self.session: return chunk = struct.pack('>BL', 0x04, self.session) @@ -49,12 +55,15 @@ class ProtocolV2(object): (magic, ) = struct.unpack('>B', resp[:1]) if magic != 0x04: raise RuntimeError('Expected session close') + LOG.debug("[session {}] session ended".format(self.session)) self.session = None - def write(self, transport, msg): + def write(self, transport: Transport, msg: protobuf.MessageType) -> None: if not self.session: raise RuntimeError('Missing session for v2 protocol') + LOG.debug("[session {}] sending message: {}".format(self.session, msg.__class__.__name__), + extra={'protobuf': msg}) # Serialize whole message data = BytesIO() protobuf.dump_message(data, msg) @@ -76,7 +85,7 @@ class ProtocolV2(object): data = data[datalen:] seq += 1 - def read(self, transport): + def read(self, transport: Transport) -> protobuf.MessageType: if not self.session: raise RuntimeError('Missing session for v2 protocol') @@ -95,12 +104,14 @@ class ProtocolV2(object): # Parse to protobuf msg = protobuf.load_message(data, mapping.get_class(msg_type)) + LOG.debug("[session {}] received message: {}".format(self.session, msg.__class__.__name__), + extra={'protobuf': msg}) return msg - def parse_first(self, chunk): + def parse_first(self, chunk: bytes) -> Tuple[int, int, bytes]: try: headerlen = struct.calcsize('>BLLL') - (magic, session, msg_type, datalen) = struct.unpack('>BLLL', chunk[:headerlen]) + magic, session, msg_type, datalen = struct.unpack('>BLLL', chunk[:headerlen]) except: raise RuntimeError('Cannot parse header') if magic != 0x01: @@ -109,10 +120,10 @@ class ProtocolV2(object): raise RuntimeError('Session id mismatch') return msg_type, datalen, chunk[headerlen:] - def parse_next(self, chunk): + def parse_next(self, chunk: bytes) -> bytes: try: headerlen = struct.calcsize('>BLL') - (magic, session, sequence) = struct.unpack('>BLL', chunk[:headerlen]) + magic, session, sequence = struct.unpack('>BLL', chunk[:headerlen]) except: raise RuntimeError('Cannot parse header') if magic != 0x02: @@ -121,10 +132,10 @@ class ProtocolV2(object): raise RuntimeError('Session id mismatch') return chunk[headerlen:] - def parse_session_open(self, chunk): + def parse_session_open(self, chunk: bytes) -> int: try: headerlen = struct.calcsize('>BL') - (magic, session) = struct.unpack('>BL', chunk[:headerlen]) + magic, session = struct.unpack('>BL', chunk[:headerlen]) except: raise RuntimeError('Cannot parse header') if magic != 0x03: diff --git a/trezorlib/stellar.py b/trezorlib/stellar.py index 292dae7c77..3c7c9e2cb9 100644 --- a/trezorlib/stellar.py +++ b/trezorlib/stellar.py @@ -30,14 +30,7 @@ OP_MANAGE_DATA = 10 OP_BUMP_SEQUENCE = 11 -def expand_path_or_default(client, address): - """Uses client to parse address and returns an array of integers - If no address is specified, the default of m/44'/148'/0' is used - """ - if address: - return client.expand_path(address) - else: - return client.expand_path("m/44'/148'/0'") +DEFAULT_BIP32_PATH = "m/44h/148h/0h" def address_from_public_key(pk_bytes): diff --git a/trezorlib/tests/device_tests/common.py b/trezorlib/tests/device_tests/common.py index 8681d947f6..5e925b7afa 100644 --- a/trezorlib/tests/device_tests/common.py +++ b/trezorlib/tests/device_tests/common.py @@ -18,13 +18,11 @@ from __future__ import print_function -from binascii import hexlify, unhexlify -import pytest import os from trezorlib import coins from trezorlib import tx_api -from trezorlib.client import TrezorClient, TrezorClientDebugLink +from trezorlib.client import TrezorClientDebugLink from trezorlib.transport import get_transport tests_dir = os.path.dirname(os.path.abspath(__file__)) diff --git a/trezorlib/tests/device_tests/conftest.py b/trezorlib/tests/device_tests/conftest.py index 3e3c732f86..5f56afe6e8 100644 --- a/trezorlib/tests/device_tests/conftest.py +++ b/trezorlib/tests/device_tests/conftest.py @@ -2,6 +2,7 @@ import pytest from . import common from trezorlib.client import TrezorClient +from trezorlib import log def device_version(): @@ -22,6 +23,11 @@ except: TREZOR_VERSION = None +def pytest_configure(config): + if config.getoption('verbose'): + log.enable_debug_output() + + def pytest_addoption(parser): parser.addini("run_xfail", "List of markers that will run even if marked as xfail", "args", []) diff --git a/trezorlib/tests/device_tests/test_basic.py b/trezorlib/tests/device_tests/test_basic.py index 902b385351..fbba93212e 100644 --- a/trezorlib/tests/device_tests/test_basic.py +++ b/trezorlib/tests/device_tests/test_basic.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +from .common import TrezorTest from trezorlib import messages diff --git a/trezorlib/tests/device_tests/test_bip32_speed.py b/trezorlib/tests/device_tests/test_bip32_speed.py index fdd8c450bd..6f06e705b9 100644 --- a/trezorlib/tests/device_tests/test_bip32_speed.py +++ b/trezorlib/tests/device_tests/test_bip32_speed.py @@ -15,11 +15,10 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . - -from __future__ import print_function - -from .common import * import time +import pytest + +from .common import TrezorTest class TestBip32Speed(TrezorTest): diff --git a/trezorlib/tests/device_tests/test_cosi.py b/trezorlib/tests/device_tests/test_cosi.py index d5d9c1790d..46ec9eb4d6 100644 --- a/trezorlib/tests/device_tests/test_cosi.py +++ b/trezorlib/tests/device_tests/test_cosi.py @@ -16,10 +16,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * - +import pytest from hashlib import sha256 -from trezorlib import ed25519raw, ed25519cosi + +from .common import TrezorTest +from trezorlib import cosi + +from trezorlib.tools import parse_path @pytest.mark.skip_t2 @@ -30,9 +33,9 @@ class TestCosi(TrezorTest): digest = sha256(b'this is a message').digest() - c0 = self.client.cosi_commit(self.client.expand_path("10018'/0'"), digest) - c1 = self.client.cosi_commit(self.client.expand_path("10018'/1'"), digest) - c2 = self.client.cosi_commit(self.client.expand_path("10018'/2'"), digest) + c0 = self.client.cosi_commit(parse_path("10018'/0'"), digest) + c1 = self.client.cosi_commit(parse_path("10018'/1'"), digest) + c2 = self.client.cosi_commit(parse_path("10018'/2'"), digest) assert c0.pubkey != c1.pubkey assert c0.pubkey != c2.pubkey @@ -44,9 +47,9 @@ class TestCosi(TrezorTest): digestb = sha256(b'this is a different message').digest() - c0b = self.client.cosi_commit(self.client.expand_path("10018'/0'"), digestb) - c1b = self.client.cosi_commit(self.client.expand_path("10018'/1'"), digestb) - c2b = self.client.cosi_commit(self.client.expand_path("10018'/2'"), digestb) + c0b = self.client.cosi_commit(parse_path("10018'/0'"), digestb) + c1b = self.client.cosi_commit(parse_path("10018'/1'"), digestb) + c2b = self.client.cosi_commit(parse_path("10018'/2'"), digestb) assert c0.pubkey == c0b.pubkey assert c1.pubkey == c1b.pubkey @@ -61,17 +64,36 @@ class TestCosi(TrezorTest): digest = sha256(b'this is a message').digest() - c0 = self.client.cosi_commit(self.client.expand_path("10018'/0'"), digest) - c1 = self.client.cosi_commit(self.client.expand_path("10018'/1'"), digest) - c2 = self.client.cosi_commit(self.client.expand_path("10018'/2'"), digest) + c0 = self.client.cosi_commit(parse_path("10018'/0'"), digest) + c1 = self.client.cosi_commit(parse_path("10018'/1'"), digest) + c2 = self.client.cosi_commit(parse_path("10018'/2'"), digest) - global_pk = ed25519cosi.combine_keys([c0.pubkey, c1.pubkey, c2.pubkey]) - global_R = ed25519cosi.combine_keys([c0.commitment, c1.commitment, c2.commitment]) + global_pk = cosi.combine_keys([c0.pubkey, c1.pubkey, c2.pubkey]) + global_R = cosi.combine_keys([c0.commitment, c1.commitment, c2.commitment]) - sig0 = self.client.cosi_sign(self.client.expand_path("10018'/0'"), digest, global_R, global_pk) - sig1 = self.client.cosi_sign(self.client.expand_path("10018'/1'"), digest, global_R, global_pk) - sig2 = self.client.cosi_sign(self.client.expand_path("10018'/2'"), digest, global_R, global_pk) + sig0 = self.client.cosi_sign(parse_path("10018'/0'"), digest, global_R, global_pk) + sig1 = self.client.cosi_sign(parse_path("10018'/1'"), digest, global_R, global_pk) + sig2 = self.client.cosi_sign(parse_path("10018'/2'"), digest, global_R, global_pk) - sig = ed25519cosi.combine_sig(global_R, [sig0.signature, sig1.signature, sig2.signature]) + sig = cosi.combine_sig(global_R, [sig0.signature, sig1.signature, sig2.signature]) - ed25519raw.checkvalid(sig, digest, global_pk) + cosi.verify(sig, digest, global_pk) + + def test_cosi_compat(self): + self.setup_mnemonic_pin_passphrase() + + digest = sha256(b'this is not a pipe').digest() + remote_commit = self.client.cosi_commit(parse_path("10018'/0'"), digest) + + local_privkey = sha256(b'private key').digest()[:32] + local_pubkey = cosi.pubkey_from_privkey(local_privkey) + local_nonce, local_commitment = cosi.get_nonce(local_privkey, digest, 42) + + global_pk = cosi.combine_keys([remote_commit.pubkey, local_pubkey]) + global_R = cosi.combine_keys([remote_commit.commitment, local_commitment]) + + remote_sig = self.client.cosi_sign(parse_path("10018'/0'"), digest, global_R, global_pk) + local_sig = cosi.sign_with_privkey(digest, local_privkey, global_pk, local_nonce, global_R) + sig = cosi.combine_sig(global_R, [remote_sig.signature, local_sig]) + + cosi.verify(sig, digest, global_pk) diff --git a/trezorlib/tests/device_tests/test_debuglink.py b/trezorlib/tests/device_tests/test_debuglink.py index 795d2f9668..ab9dc91776 100644 --- a/trezorlib/tests/device_tests/test_debuglink.py +++ b/trezorlib/tests/device_tests/test_debuglink.py @@ -15,9 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import pytest -from .common import * - +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_applysettings.py b/trezorlib/tests/device_tests/test_msg_applysettings.py index 07bf805d47..c5511658c9 100644 --- a/trezorlib/tests/device_tests/test_msg_applysettings.py +++ b/trezorlib/tests/device_tests/test_msg_applysettings.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import pytest -from .common import * +from .common import TrezorTest import time from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_changepin.py b/trezorlib/tests/device_tests/test_msg_changepin.py index bab268044c..3d40bbafbb 100644 --- a/trezorlib/tests/device_tests/test_msg_changepin.py +++ b/trezorlib/tests/device_tests/test_msg_changepin.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import pytest -from .common import * +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_cipherkeyvalue.py b/trezorlib/tests/device_tests/test_msg_cipherkeyvalue.py index de01f1e141..174145a3e2 100644 --- a/trezorlib/tests/device_tests/test_msg_cipherkeyvalue.py +++ b/trezorlib/tests/device_tests/test_msg_cipherkeyvalue.py @@ -15,8 +15,10 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import hexlify, unhexlify +import pytest -from .common import * +from .common import TrezorTest class TestMsgCipherkeyvalue(TrezorTest): diff --git a/trezorlib/tests/device_tests/test_msg_clearsession.py b/trezorlib/tests/device_tests/test_msg_clearsession.py index 4452fd12bc..64c90db976 100644 --- a/trezorlib/tests/device_tests/test_msg_clearsession.py +++ b/trezorlib/tests/device_tests/test_msg_clearsession.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import pytest -from .common import * +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_ethereum_getaddress.py b/trezorlib/tests/device_tests/test_msg_ethereum_getaddress.py index 636fce9c4d..61f2e7b465 100644 --- a/trezorlib/tests/device_tests/test_msg_ethereum_getaddress.py +++ b/trezorlib/tests/device_tests/test_msg_ethereum_getaddress.py @@ -15,9 +15,10 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import hexlify import pytest -from .common import * +from .common import TrezorTest @pytest.mark.ethereum diff --git a/trezorlib/tests/device_tests/test_msg_ethereum_signmessage.py b/trezorlib/tests/device_tests/test_msg_ethereum_signmessage.py index ecb9b457c5..464f0e0173 100644 --- a/trezorlib/tests/device_tests/test_msg_ethereum_signmessage.py +++ b/trezorlib/tests/device_tests/test_msg_ethereum_signmessage.py @@ -14,8 +14,10 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import hexlify +import pytest -from .common import * +from .common import TrezorTest @pytest.mark.ethereum diff --git a/trezorlib/tests/device_tests/test_msg_ethereum_signtx.py b/trezorlib/tests/device_tests/test_msg_ethereum_signtx.py index aa3dfbca8a..4744002335 100644 --- a/trezorlib/tests/device_tests/test_msg_ethereum_signtx.py +++ b/trezorlib/tests/device_tests/test_msg_ethereum_signtx.py @@ -15,9 +15,10 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import unhexlify, hexlify import pytest -from .common import * +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_ethereum_verifymessage.py b/trezorlib/tests/device_tests/test_msg_ethereum_verifymessage.py index 5685837fd7..c49a9dda64 100644 --- a/trezorlib/tests/device_tests/test_msg_ethereum_verifymessage.py +++ b/trezorlib/tests/device_tests/test_msg_ethereum_verifymessage.py @@ -14,8 +14,11 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import unhexlify -from .common import * +import pytest + +from .common import TrezorTest @pytest.mark.ethereum diff --git a/trezorlib/tests/device_tests/test_msg_getaddress.py b/trezorlib/tests/device_tests/test_msg_getaddress.py index 69a656a282..8ae556bb61 100644 --- a/trezorlib/tests/device_tests/test_msg_getaddress.py +++ b/trezorlib/tests/device_tests/test_msg_getaddress.py @@ -16,9 +16,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +import pytest + +from .common import TrezorTest +from ..support import ckd_public as bip32 from trezorlib import messages as proto -import trezorlib.ckd_public as bip32 + +from trezorlib.tools import parse_path class TestMsgGetaddress(TrezorTest): @@ -45,14 +49,14 @@ class TestMsgGetaddress(TrezorTest): def test_bch(self): self.setup_mnemonic_allallall() - assert self.client.get_address('Bcash', self.client.expand_path("44'/145'/0'/0/0")) == 'bitcoincash:qr08q88p9etk89wgv05nwlrkm4l0urz4cyl36hh9sv' - assert self.client.get_address('Bcash', self.client.expand_path("44'/145'/0'/0/1")) == 'bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4' - assert self.client.get_address('Bcash', self.client.expand_path("44'/145'/0'/1/0")) == 'bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw' + assert self.client.get_address('Bcash', parse_path("44'/145'/0'/0/0")) == 'bitcoincash:qr08q88p9etk89wgv05nwlrkm4l0urz4cyl36hh9sv' + assert self.client.get_address('Bcash', parse_path("44'/145'/0'/0/1")) == 'bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4' + assert self.client.get_address('Bcash', parse_path("44'/145'/0'/1/0")) == 'bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw' def test_bch_multisig(self): self.setup_mnemonic_allallall() xpubs = [] - for n in map(lambda index: self.client.get_public_node(self.client.expand_path("44'/145'/" + str(index) + "'")), range(1, 4)): + for n in map(lambda index: self.client.get_public_node(parse_path("44'/145'/" + str(index) + "'")), range(1, 4)): xpubs.append(n.xpub) def getmultisig(chain, nr, signatures=[b'', b'', b''], xpubs=xpubs): @@ -62,8 +66,8 @@ class TestMsgGetaddress(TrezorTest): m=2, ) for nr in range(1, 4): - assert self.client.get_address('Bcash', self.client.expand_path("44'/145'/" + str(nr) + "'/0/0"), show_display=(nr == 1), multisig=getmultisig(0, 0)) == 'bitcoincash:pqguz4nqq64jhr5v3kvpq4dsjrkda75hwy86gq0qzw' - assert self.client.get_address('Bcash', self.client.expand_path("44'/145'/" + str(nr) + "'/1/0"), show_display=(nr == 1), multisig=getmultisig(1, 0)) == 'bitcoincash:pp6kcpkhua7789g2vyj0qfkcux3yvje7euhyhltn0a' + assert self.client.get_address('Bcash', parse_path("44'/145'/" + str(nr) + "'/0/0"), show_display=(nr == 1), multisig=getmultisig(0, 0)) == 'bitcoincash:pqguz4nqq64jhr5v3kvpq4dsjrkda75hwy86gq0qzw' + assert self.client.get_address('Bcash', parse_path("44'/145'/" + str(nr) + "'/1/0"), show_display=(nr == 1), multisig=getmultisig(1, 0)) == 'bitcoincash:pp6kcpkhua7789g2vyj0qfkcux3yvje7euhyhltn0a' def test_public_ckd(self): self.setup_mnemonic_nopin_nopassphrase() diff --git a/trezorlib/tests/device_tests/test_msg_getaddress_segwit.py b/trezorlib/tests/device_tests/test_msg_getaddress_segwit.py index 8d34304a0f..f0fd4c17b0 100644 --- a/trezorlib/tests/device_tests/test_msg_getaddress_segwit.py +++ b/trezorlib/tests/device_tests/test_msg_getaddress_segwit.py @@ -15,23 +15,24 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * -import trezorlib.ckd_public as bip32 +from .common import TrezorTest +from ..support import ckd_public as bip32 from trezorlib import messages as proto +from trezorlib.tools import parse_path class TestMsgGetaddressSegwit(TrezorTest): def test_show_segwit(self): self.setup_mnemonic_allallall() - assert self.client.get_address("Testnet", self.client.expand_path("49'/1'/0'/1/0"), True, None, script_type=proto.InputScriptType.SPENDP2SHWITNESS) == '2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX' - assert self.client.get_address("Testnet", self.client.expand_path("49'/1'/0'/0/0"), False, None, script_type=proto.InputScriptType.SPENDP2SHWITNESS) == '2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp' - assert self.client.get_address("Testnet", self.client.expand_path("44'/1'/0'/0/0"), False, None, script_type=proto.InputScriptType.SPENDP2SHWITNESS) == '2N6UeBoqYEEnybg4cReFYDammpsyDw8R2Mc' - assert self.client.get_address("Testnet", self.client.expand_path("44'/1'/0'/0/0"), False, None, script_type=proto.InputScriptType.SPENDADDRESS) == 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q' + assert self.client.get_address("Testnet", parse_path("49'/1'/0'/1/0"), True, None, script_type=proto.InputScriptType.SPENDP2SHWITNESS) == '2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX' + assert self.client.get_address("Testnet", parse_path("49'/1'/0'/0/0"), False, None, script_type=proto.InputScriptType.SPENDP2SHWITNESS) == '2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp' + assert self.client.get_address("Testnet", parse_path("44'/1'/0'/0/0"), False, None, script_type=proto.InputScriptType.SPENDP2SHWITNESS) == '2N6UeBoqYEEnybg4cReFYDammpsyDw8R2Mc' + assert self.client.get_address("Testnet", parse_path("44'/1'/0'/0/0"), False, None, script_type=proto.InputScriptType.SPENDADDRESS) == 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q' def test_show_multisig_3(self): self.setup_mnemonic_allallall() - nodes = map(lambda index: self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)), range(1, 4)) + nodes = map(lambda index: self.client.get_public_node(parse_path("999'/1'/%d'" % index)), range(1, 4)) multisig1 = proto.MultisigRedeemScriptType( pubkeys=list(map(lambda n: proto.HDNodePathType(node=bip32.deserialize(n.xpub), address_n=[2, 0]), nodes)), signatures=[b'', b'', b''], @@ -43,4 +44,4 @@ class TestMsgGetaddressSegwit(TrezorTest): # m=2, # ) for i in [1, 2, 3]: - assert self.client.get_address("Testnet", self.client.expand_path("999'/1'/%d'/2/0" % i), False, multisig1, script_type=proto.InputScriptType.SPENDP2SHWITNESS) == '2N2MxyAfifVhb3AMagisxaj3uij8bfXqf4Y' + assert self.client.get_address("Testnet", parse_path("999'/1'/%d'/2/0" % i), False, multisig1, script_type=proto.InputScriptType.SPENDP2SHWITNESS) == '2N2MxyAfifVhb3AMagisxaj3uij8bfXqf4Y' diff --git a/trezorlib/tests/device_tests/test_msg_getaddress_segwit_native.py b/trezorlib/tests/device_tests/test_msg_getaddress_segwit_native.py index d0c5cf01fd..3d54b51607 100644 --- a/trezorlib/tests/device_tests/test_msg_getaddress_segwit_native.py +++ b/trezorlib/tests/device_tests/test_msg_getaddress_segwit_native.py @@ -15,23 +15,24 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * -import trezorlib.ckd_public as bip32 +from .common import TrezorTest +from ..support import ckd_public as bip32 from trezorlib import messages as proto +from trezorlib.tools import parse_path class TestMsgGetaddressSegwitNative(TrezorTest): def test_show_segwit(self): self.setup_mnemonic_allallall() - assert self.client.get_address("Testnet", self.client.expand_path("49'/1'/0'/0/0"), True, None, script_type=proto.InputScriptType.SPENDWITNESS) == 'tb1qqzv60m9ajw8drqulta4ld4gfx0rdh82un5s65s' - assert self.client.get_address("Testnet", self.client.expand_path("49'/1'/0'/1/0"), False, None, script_type=proto.InputScriptType.SPENDWITNESS) == 'tb1q694ccp5qcc0udmfwgp692u2s2hjpq5h407urtu' - assert self.client.get_address("Testnet", self.client.expand_path("44'/1'/0'/0/0"), False, None, script_type=proto.InputScriptType.SPENDWITNESS) == 'tb1q54un3q39sf7e7tlfq99d6ezys7qgc62a6rxllc' - assert self.client.get_address("Testnet", self.client.expand_path("44'/1'/0'/0/0"), False, None, script_type=proto.InputScriptType.SPENDADDRESS) == 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q' + assert self.client.get_address("Testnet", parse_path("49'/1'/0'/0/0"), True, None, script_type=proto.InputScriptType.SPENDWITNESS) == 'tb1qqzv60m9ajw8drqulta4ld4gfx0rdh82un5s65s' + assert self.client.get_address("Testnet", parse_path("49'/1'/0'/1/0"), False, None, script_type=proto.InputScriptType.SPENDWITNESS) == 'tb1q694ccp5qcc0udmfwgp692u2s2hjpq5h407urtu' + assert self.client.get_address("Testnet", parse_path("44'/1'/0'/0/0"), False, None, script_type=proto.InputScriptType.SPENDWITNESS) == 'tb1q54un3q39sf7e7tlfq99d6ezys7qgc62a6rxllc' + assert self.client.get_address("Testnet", parse_path("44'/1'/0'/0/0"), False, None, script_type=proto.InputScriptType.SPENDADDRESS) == 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q' def test_show_multisig_3(self): self.setup_mnemonic_allallall() - nodes = [self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)) for index in range(1, 4)] + nodes = [self.client.get_public_node(parse_path("999'/1'/%d'" % index)) for index in range(1, 4)] multisig1 = proto.MultisigRedeemScriptType( pubkeys=list(map(lambda n: proto.HDNodePathType(node=bip32.deserialize(n.xpub), address_n=[2, 0]), nodes)), signatures=[b'', b'', b''], @@ -43,5 +44,5 @@ class TestMsgGetaddressSegwitNative(TrezorTest): m=2, ) for i in [1, 2, 3]: - assert self.client.get_address("Testnet", self.client.expand_path("999'/1'/%d'/2/1" % i), False, multisig2, script_type=proto.InputScriptType.SPENDWITNESS) == 'tb1qch62pf820spe9mlq49ns5uexfnl6jzcezp7d328fw58lj0rhlhasge9hzy' - assert self.client.get_address("Testnet", self.client.expand_path("999'/1'/%d'/2/0" % i), False, multisig1, script_type=proto.InputScriptType.SPENDWITNESS) == 'tb1qr6xa5v60zyt3ry9nmfew2fk5g9y3gerkjeu6xxdz7qga5kknz2ssld9z2z' + assert self.client.get_address("Testnet", parse_path("999'/1'/%d'/2/1" % i), False, multisig2, script_type=proto.InputScriptType.SPENDWITNESS) == 'tb1qch62pf820spe9mlq49ns5uexfnl6jzcezp7d328fw58lj0rhlhasge9hzy' + assert self.client.get_address("Testnet", parse_path("999'/1'/%d'/2/0" % i), False, multisig1, script_type=proto.InputScriptType.SPENDWITNESS) == 'tb1qr6xa5v60zyt3ry9nmfew2fk5g9y3gerkjeu6xxdz7qga5kknz2ssld9z2z' diff --git a/trezorlib/tests/device_tests/test_msg_getaddress_show.py b/trezorlib/tests/device_tests/test_msg_getaddress_show.py index 5ea4f45a36..ba9411ceb8 100644 --- a/trezorlib/tests/device_tests/test_msg_getaddress_show.py +++ b/trezorlib/tests/device_tests/test_msg_getaddress_show.py @@ -16,8 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * -import trezorlib.ckd_public as bip32 +from .common import TrezorTest +from ..support import ckd_public as bip32 from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_getecdhsessionkey.py b/trezorlib/tests/device_tests/test_msg_getecdhsessionkey.py index b411abc11f..c7049c5ffe 100644 --- a/trezorlib/tests/device_tests/test_msg_getecdhsessionkey.py +++ b/trezorlib/tests/device_tests/test_msg_getecdhsessionkey.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import unhexlify -from .common import * +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_getentropy.py b/trezorlib/tests/device_tests/test_msg_getentropy.py index 14a0df3bb6..bee7f6a182 100644 --- a/trezorlib/tests/device_tests/test_msg_getentropy.py +++ b/trezorlib/tests/device_tests/test_msg_getentropy.py @@ -16,10 +16,9 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from __future__ import print_function import math -from .common import * +from .common import TrezorTest import trezorlib.messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_getpublickey.py b/trezorlib/tests/device_tests/test_msg_getpublickey.py index 77e2547920..5047cd74ca 100644 --- a/trezorlib/tests/device_tests/test_msg_getpublickey.py +++ b/trezorlib/tests/device_tests/test_msg_getpublickey.py @@ -16,8 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * -import trezorlib.ckd_public as bip32 +from .common import TrezorTest +from ..support import ckd_public as bip32 class TestMsgGetpublickey(TrezorTest): diff --git a/trezorlib/tests/device_tests/test_msg_getpublickey_curve.py b/trezorlib/tests/device_tests/test_msg_getpublickey_curve.py index 5acf7e9568..d2418336cd 100644 --- a/trezorlib/tests/device_tests/test_msg_getpublickey_curve.py +++ b/trezorlib/tests/device_tests/test_msg_getpublickey_curve.py @@ -16,8 +16,10 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * -import trezorlib.ckd_public as bip32 +from binascii import hexlify +import pytest + +from .common import TrezorTest from trezorlib.client import CallException diff --git a/trezorlib/tests/device_tests/test_msg_lisk_signtx.py b/trezorlib/tests/device_tests/test_msg_lisk_signtx.py index 74d47cfe4e..015c450b8a 100644 --- a/trezorlib/tests/device_tests/test_msg_lisk_signtx.py +++ b/trezorlib/tests/device_tests/test_msg_lisk_signtx.py @@ -21,6 +21,7 @@ import pytest from .common import TrezorTest from trezorlib import messages as proto +from trezorlib.tools import parse_path PUBLIC_KEY = unhexlify('eb56d7bbb5e8ea9269405f7a8527fe126023d1db2c973cfac6f760b60ae27294') @@ -41,7 +42,7 @@ class TestMsgLiskSignTx(TrezorTest): ) ]) - self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), { + self.client.lisk_sign_tx(parse_path("m/44'/134'/0'/0'"), { "amount": "10000000", "recipientId": "9971262264659915921L", "timestamp": 57525937, @@ -62,7 +63,7 @@ class TestMsgLiskSignTx(TrezorTest): ) ]) - self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), { + self.client.lisk_sign_tx(parse_path("m/44'/134'/0'/0'"), { "amount": "10000000", "recipientId": "9971262264659915921L", "timestamp": 57525937, @@ -85,7 +86,7 @@ class TestMsgLiskSignTx(TrezorTest): ) ]) - self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), { + self.client.lisk_sign_tx(parse_path("m/44'/134'/0'/0'"), { "amount": "0", "timestamp": 57525937, "type": 1, @@ -109,7 +110,7 @@ class TestMsgLiskSignTx(TrezorTest): ) ]) - self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), { + self.client.lisk_sign_tx(parse_path("m/44'/134'/0'/0'"), { "amount": "0", "timestamp": 57525937, "type": 2, @@ -133,7 +134,7 @@ class TestMsgLiskSignTx(TrezorTest): ) ]) - self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), { + self.client.lisk_sign_tx(parse_path("m/44'/134'/0'/0'"), { "amount": "0", "timestamp": 57525937, "type": 3, @@ -158,7 +159,7 @@ class TestMsgLiskSignTx(TrezorTest): ) ]) - self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), { + self.client.lisk_sign_tx(parse_path("m/44'/134'/0'/0'"), { "amount": "0", "timestamp": 57525937, "type": 4, diff --git a/trezorlib/tests/device_tests/test_msg_loaddevice.py b/trezorlib/tests/device_tests/test_msg_loaddevice.py index e52840883f..317132aee8 100644 --- a/trezorlib/tests/device_tests/test_msg_loaddevice.py +++ b/trezorlib/tests/device_tests/test_msg_loaddevice.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import pytest -from .common import * +from .common import TrezorTest @pytest.mark.skip_t2 diff --git a/trezorlib/tests/device_tests/test_msg_loaddevice_xprv.py b/trezorlib/tests/device_tests/test_msg_loaddevice_xprv.py index e28a633a6d..b7017f1ca8 100644 --- a/trezorlib/tests/device_tests/test_msg_loaddevice_xprv.py +++ b/trezorlib/tests/device_tests/test_msg_loaddevice_xprv.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import pytest -from .common import * +from .common import TrezorTest @pytest.mark.skip_t2 diff --git a/trezorlib/tests/device_tests/test_msg_nem_getaddress.py b/trezorlib/tests/device_tests/test_msg_nem_getaddress.py index 4a82127dd6..56c9e4c3b6 100644 --- a/trezorlib/tests/device_tests/test_msg_nem_getaddress.py +++ b/trezorlib/tests/device_tests/test_msg_nem_getaddress.py @@ -15,7 +15,10 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +import pytest + +from .common import TrezorTest +from trezorlib.tools import parse_path @pytest.mark.nem @@ -24,5 +27,5 @@ class TestMsgNEMGetaddress(TrezorTest): def test_nem_getaddress(self): self.setup_mnemonic_nopin_nopassphrase() - assert self.client.nem_get_address(self.client.expand_path("m/44'/1'/0'/0'/0'"), 0x68) == "NB3JCHVARQNGDS3UVGAJPTFE22UQFGMCQGHUBWQN" - assert self.client.nem_get_address(self.client.expand_path("m/44'/1'/0'/0'/0'"), 0x98) == "TB3JCHVARQNGDS3UVGAJPTFE22UQFGMCQHSBNBMF" + assert self.client.nem_get_address(parse_path("m/44'/1'/0'/0'/0'"), 0x68) == "NB3JCHVARQNGDS3UVGAJPTFE22UQFGMCQGHUBWQN" + assert self.client.nem_get_address(parse_path("m/44'/1'/0'/0'/0'"), 0x98) == "TB3JCHVARQNGDS3UVGAJPTFE22UQFGMCQHSBNBMF" diff --git a/trezorlib/tests/device_tests/test_msg_nem_signtx_mosaics.py b/trezorlib/tests/device_tests/test_msg_nem_signtx_mosaics.py index 4bb369dae0..0b92351c8a 100644 --- a/trezorlib/tests/device_tests/test_msg_nem_signtx_mosaics.py +++ b/trezorlib/tests/device_tests/test_msg_nem_signtx_mosaics.py @@ -15,8 +15,12 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +import pytest +from binascii import hexlify + +from .common import TrezorTest from trezorlib import nem +from trezorlib.tools import parse_path # assertion data from T1 @@ -27,7 +31,7 @@ class TestMsgNEMSignTxMosaics(TrezorTest): def test_nem_signtx_mosaic_supply_change(self): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 74649215, "fee": 2000000, "type": nem.TYPE_MOSAIC_SUPPLY_CHANGE, @@ -51,7 +55,7 @@ class TestMsgNEMSignTxMosaics(TrezorTest): def test_nem_signtx_mosaic_creation(self): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 74649215, "fee": 2000000, "type": nem.TYPE_MOSAIC_CREATION, @@ -78,7 +82,7 @@ class TestMsgNEMSignTxMosaics(TrezorTest): def test_nem_signtx_mosaic_creation_properties(self): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 74649215, "fee": 2000000, "type": nem.TYPE_MOSAIC_CREATION, @@ -122,7 +126,7 @@ class TestMsgNEMSignTxMosaics(TrezorTest): def test_nem_signtx_mosaic_creation_levy(self): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 74649215, "fee": 2000000, "type": nem.TYPE_MOSAIC_CREATION, diff --git a/trezorlib/tests/device_tests/test_msg_nem_signtx_mosaics_t2.py b/trezorlib/tests/device_tests/test_msg_nem_signtx_mosaics_t2.py index 6068b505d8..90652154c3 100644 --- a/trezorlib/tests/device_tests/test_msg_nem_signtx_mosaics_t2.py +++ b/trezorlib/tests/device_tests/test_msg_nem_signtx_mosaics_t2.py @@ -15,11 +15,14 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +from binascii import hexlify +import pytest +import time +from .common import TrezorTest from trezorlib import messages as proto from trezorlib import nem -import time +from trezorlib.tools import parse_path # assertion data from T1 @@ -32,7 +35,7 @@ class TestMsgNEMSignTxMosaics(TrezorTest): self.setup_mnemonic_nopin_nopassphrase() with self.client: - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 74649215, "fee": 2000000, "type": nem.TYPE_MOSAIC_SUPPLY_CHANGE, @@ -182,7 +185,7 @@ class TestMsgNEMSignTxMosaics(TrezorTest): assert hexlify(tx.signature) == b'b87aac1ddf146d35e6a7f3451f57e2fe504ac559031e010a51261257c37bd50fcfa7b2939dd7a3203b54c4807d458475182f5d3dc135ec0d1d4a9cd42159fd0a' def _nem_sign(self, num_of_swipes, test_suite): - n = self.client.expand_path("m/44'/1'/0'/0'/0'") + n = parse_path("m/44'/1'/0'/0'/0'") n = self.client._convert_prime(n) msg = nem.create_sign_tx(test_suite) assert msg.transaction is not None diff --git a/trezorlib/tests/device_tests/test_msg_nem_signtx_multisig.py b/trezorlib/tests/device_tests/test_msg_nem_signtx_multisig.py index bb6e75a139..3ffab48ce7 100644 --- a/trezorlib/tests/device_tests/test_msg_nem_signtx_multisig.py +++ b/trezorlib/tests/device_tests/test_msg_nem_signtx_multisig.py @@ -15,7 +15,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +from binascii import hexlify +import pytest + +from .common import TrezorTest +from trezorlib.tools import parse_path from trezorlib import nem @@ -28,7 +32,7 @@ class TestMsgNEMSignTxMultisig(TrezorTest): def test_nem_signtx_aggregate_modification(self): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 74649215, "fee": 2000000, "type": nem.TYPE_AGGREGATE_MODIFICATION, @@ -52,7 +56,7 @@ class TestMsgNEMSignTxMultisig(TrezorTest): def test_nem_signtx_multisig(self): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 1, "fee": 10000, "type": nem.TYPE_MULTISIG, @@ -77,7 +81,7 @@ class TestMsgNEMSignTxMultisig(TrezorTest): assert hexlify(tx.data) == b'04100000010000980100000020000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b40620841027000000000000ff5f74049900000001010000010000980200000020000000c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844983a000000000000320901002800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324a80841e000000000025000000010000001d000000746573745f6e656d5f7472616e73616374696f6e5f7472616e73666572' assert hexlify(tx.signature) == b'0cab2fddf2f02b5d7201675b9a71869292fe25ed33a366c7d2cbea7676fed491faaa03310079b7e17884b6ba2e3ea21c4f728d1cca8f190b8288207f6514820a' - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 74649215, "fee": 150, "type": nem.TYPE_MULTISIG, @@ -105,7 +109,7 @@ class TestMsgNEMSignTxMultisig(TrezorTest): def test_nem_signtx_multisig_signer(self): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 333, "fee": 200, "type": nem.TYPE_MULTISIG_SIGNATURE, @@ -130,7 +134,7 @@ class TestMsgNEMSignTxMultisig(TrezorTest): assert hexlify(tx.data) == b'02100000010000984d01000020000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b4062084c800000000000000bc010000240000002000000087923cd4805f3babe6b5af9cbb2b08be4458e39531618aed73c911f160c8e38528000000544444324354364c514c49595135364b49584933454e544d36454b3344343450354b5a50464d4b32' assert hexlify(tx.signature) == b'286358a16ae545bff798feab93a713440c7c2f236d52ac0e995669d17a1915b0903667c97fa04418eccb42333cba95b19bccc8ac1faa8224dcfaeb41890ae807' - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 900000, "fee": 200000, "type": nem.TYPE_MULTISIG_SIGNATURE, diff --git a/trezorlib/tests/device_tests/test_msg_nem_signtx_others.py b/trezorlib/tests/device_tests/test_msg_nem_signtx_others.py index 02ae2757d0..c438d82b27 100644 --- a/trezorlib/tests/device_tests/test_msg_nem_signtx_others.py +++ b/trezorlib/tests/device_tests/test_msg_nem_signtx_others.py @@ -15,9 +15,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +from binascii import hexlify +import pytest + +from .common import TrezorTest from trezorlib import nem +from trezorlib.tools import parse_path # assertion data from T1 @@ -29,7 +33,7 @@ class TestMsgNEMSignTxOther(TrezorTest): self.setup_mnemonic_nopin_nopassphrase() with self.client: - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 12349215, "fee": 9900, "type": nem.TYPE_IMPORTANCE_TRANSFER, @@ -50,7 +54,7 @@ class TestMsgNEMSignTxOther(TrezorTest): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 74649215, "fee": 2000000, "type": nem.TYPE_PROVISION_NAMESPACE, diff --git a/trezorlib/tests/device_tests/test_msg_nem_signtx_transfers.py b/trezorlib/tests/device_tests/test_msg_nem_signtx_transfers.py index 456892e9a4..94ea1182d4 100644 --- a/trezorlib/tests/device_tests/test_msg_nem_signtx_transfers.py +++ b/trezorlib/tests/device_tests/test_msg_nem_signtx_transfers.py @@ -15,10 +15,14 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +from binascii import hexlify, unhexlify +import pytest + +from .common import TrezorTest from trezorlib import messages as proto from trezorlib import nem +from trezorlib.tools import parse_path # assertion data from T1 @@ -44,7 +48,7 @@ class TestMsgNEMSignTx(TrezorTest): proto.NEMSignedTx(), ]) - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 74649215, "amount": 2000000, "fee": 2000000, @@ -75,7 +79,7 @@ class TestMsgNEMSignTx(TrezorTest): proto.NEMSignedTx(), ]) - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 74649215, "amount": 2000000, "fee": 2000000, @@ -101,7 +105,7 @@ class TestMsgNEMSignTx(TrezorTest): def test_nem_signtx_xem_as_mosaic(self): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 76809215, "amount": 5000000, "fee": 1000000, @@ -129,7 +133,7 @@ class TestMsgNEMSignTx(TrezorTest): def test_nem_signtx_unknown_mosaic(self): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 76809215, "amount": 2000000, "fee": 1000000, @@ -158,7 +162,7 @@ class TestMsgNEMSignTx(TrezorTest): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 76809215, "amount": 3000000, "fee": 1000000, @@ -187,7 +191,7 @@ class TestMsgNEMSignTx(TrezorTest): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 76809215, "amount": 2000000, "fee": 1000000, @@ -215,7 +219,7 @@ class TestMsgNEMSignTx(TrezorTest): def test_nem_signtx_multiple_mosaics(self): self.setup_mnemonic_nopin_nopassphrase() - tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), { + tx = self.client.nem_sign_tx(parse_path("m/44'/1'/0'/0'/0'"), { "timeStamp": 76809215, "amount": 2000000, "fee": 1000000, diff --git a/trezorlib/tests/device_tests/test_msg_ping.py b/trezorlib/tests/device_tests/test_msg_ping.py index e797e1dab5..c5c129a770 100644 --- a/trezorlib/tests/device_tests/test_msg_ping.py +++ b/trezorlib/tests/device_tests/test_msg_ping.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import pytest -from .common import * +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_recoverydevice_dryrun.py b/trezorlib/tests/device_tests/test_msg_recoverydevice_dryrun.py index fed37ac871..0f575d3a10 100644 --- a/trezorlib/tests/device_tests/test_msg_recoverydevice_dryrun.py +++ b/trezorlib/tests/device_tests/test_msg_recoverydevice_dryrun.py @@ -16,9 +16,9 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from __future__ import print_function +import pytest -from .common import * +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_recoverydevice_t2.py b/trezorlib/tests/device_tests/test_msg_recoverydevice_t2.py index 88240219a3..ee2e2d994b 100644 --- a/trezorlib/tests/device_tests/test_msg_recoverydevice_t2.py +++ b/trezorlib/tests/device_tests/test_msg_recoverydevice_t2.py @@ -16,11 +16,12 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from __future__ import print_function import time -from .common import * +import pytest + +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_resetdevice.py b/trezorlib/tests/device_tests/test_msg_resetdevice.py index b8a63a745c..2286b523c1 100644 --- a/trezorlib/tests/device_tests/test_msg_resetdevice.py +++ b/trezorlib/tests/device_tests/test_msg_resetdevice.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import pytest -from .common import * +from .common import TrezorTest, generate_entropy from trezorlib import messages as proto from mnemonic import Mnemonic diff --git a/trezorlib/tests/device_tests/test_msg_resetdevice_skipbackup.py b/trezorlib/tests/device_tests/test_msg_resetdevice_skipbackup.py index 8893710967..127bcb48ed 100644 --- a/trezorlib/tests/device_tests/test_msg_resetdevice_skipbackup.py +++ b/trezorlib/tests/device_tests/test_msg_resetdevice_skipbackup.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import pytest -from .common import * +from .common import TrezorTest, generate_entropy from trezorlib import messages as proto from mnemonic import Mnemonic diff --git a/trezorlib/tests/device_tests/test_msg_resetdevice_t2.py b/trezorlib/tests/device_tests/test_msg_resetdevice_t2.py index 5fee646e15..823c69d5fd 100644 --- a/trezorlib/tests/device_tests/test_msg_resetdevice_t2.py +++ b/trezorlib/tests/device_tests/test_msg_resetdevice_t2.py @@ -17,8 +17,9 @@ # along with this library. If not, see . import time +import pytest -from .common import * +from .common import TrezorTest, generate_entropy from trezorlib import messages as proto from mnemonic import Mnemonic diff --git a/trezorlib/tests/device_tests/test_msg_signidentity.py b/trezorlib/tests/device_tests/test_msg_signidentity.py index 4d80d6477c..2985063f10 100644 --- a/trezorlib/tests/device_tests/test_msg_signidentity.py +++ b/trezorlib/tests/device_tests/test_msg_signidentity.py @@ -16,10 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from __future__ import print_function import struct -from .common import * +from binascii import hexlify, unhexlify + +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_signmessage.py b/trezorlib/tests/device_tests/test_msg_signmessage.py index aac02275af..592f0c15c3 100644 --- a/trezorlib/tests/device_tests/test_msg_signmessage.py +++ b/trezorlib/tests/device_tests/test_msg_signmessage.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import hexlify -from .common import * +from .common import TrezorTest class TestMsgSignmessage(TrezorTest): diff --git a/trezorlib/tests/device_tests/test_msg_signmessage_segwit.py b/trezorlib/tests/device_tests/test_msg_signmessage_segwit.py index d46a9edf03..086d216750 100644 --- a/trezorlib/tests/device_tests/test_msg_signmessage_segwit.py +++ b/trezorlib/tests/device_tests/test_msg_signmessage_segwit.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import hexlify -from .common import * +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_signmessage_segwit_native.py b/trezorlib/tests/device_tests/test_msg_signmessage_segwit_native.py index b895c8f2e2..08e8629b7c 100644 --- a/trezorlib/tests/device_tests/test_msg_signmessage_segwit_native.py +++ b/trezorlib/tests/device_tests/test_msg_signmessage_segwit_native.py @@ -15,8 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import hexlify -from .common import * +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_msg_signtx.py b/trezorlib/tests/device_tests/test_msg_signtx.py index a7d83f788a..e114ecffce 100644 --- a/trezorlib/tests/device_tests/test_msg_signtx.py +++ b/trezorlib/tests/device_tests/test_msg_signtx.py @@ -25,6 +25,7 @@ from .conftest import TREZOR_VERSION from trezorlib import coins from trezorlib import messages as proto from trezorlib.client import CallException +from trezorlib.tools import parse_path TxApiTestnet = coins.tx_api['Testnet'] @@ -92,7 +93,7 @@ class TestMsgSigntx(TrezorTest): # tx: e5040e1bc1ae7667ffb9e5248e90b2fb93cd9150234151ce90e14ab2f5933bcd # input 0: 0.31 BTC inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/1'/0'/0/0"), + address_n=parse_path("44'/1'/0'/0/0"), # amount=31000000, prev_hash=TXHASH_e5040e, prev_index=0, @@ -105,7 +106,7 @@ class TestMsgSigntx(TrezorTest): ) out2 = proto.TxOutputType( - address_n=self.client.expand_path("44'/1'/0'/1/0"), + address_n=parse_path("44'/1'/0'/1/0"), amount=900000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) @@ -189,14 +190,14 @@ class TestMsgSigntx(TrezorTest): # tx: c275c333fd1b36bef4af316226c66a8b3693fbfcc081a5e16a2ae5fcb09e92bf inp1 = proto.TxInputType( - address_n=self.client.expand_path("m/44'/0'/0'/0/5"), # 1GA9u9TfCG7SWmKCveBumdA1TZpfom6ZdJ + address_n=parse_path("m/44'/0'/0'/0/5"), # 1GA9u9TfCG7SWmKCveBumdA1TZpfom6ZdJ # amount=50000, prev_hash=TXHASH_50f6f1, prev_index=1, ) out1 = proto.TxOutputType( - address_n=self.client.expand_path("m/44'/0'/0'/1/3"), # 1EcL6AyfQTyWKGvXwNSfsWoYnD3whzVFdu + address_n=parse_path("m/44'/0'/0'/1/3"), # 1EcL6AyfQTyWKGvXwNSfsWoYnD3whzVFdu amount=30000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) @@ -637,7 +638,7 @@ class TestMsgSigntx(TrezorTest): self.client.set_tx_api(TxApiTestnet) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/1'/4'/0/0"), + address_n=parse_path("44'/1'/4'/0/0"), # moUJnmge8SRXuediK7bW6t4YfrPqbE6hD7 prev_hash=TXHASH_d2dcda, prev_index=1, @@ -651,7 +652,7 @@ class TestMsgSigntx(TrezorTest): ) out2 = proto.TxOutputType( - address_n=self.client.expand_path("44'/1'/12345'/1/0"), + address_n=parse_path("44'/1'/12345'/1/0"), amount=123400000 - 5000 - 100000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) @@ -755,7 +756,7 @@ class TestMsgSigntx(TrezorTest): # tx: e5040e1bc1ae7667ffb9e5248e90b2fb93cd9150234151ce90e14ab2f5933bcd # input 0: 0.31 BTC inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/1'/0'/0/0"), + address_n=parse_path("44'/1'/0'/0/0"), # amount=31000000, prev_hash=TXHASH_e5040e, prev_index=0, @@ -768,13 +769,13 @@ class TestMsgSigntx(TrezorTest): ) out_change1 = proto.TxOutputType( - address_n=self.client.expand_path("44'/1'/0'/1/0"), + address_n=parse_path("44'/1'/0'/1/0"), amount=900000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out_change2 = proto.TxOutputType( - address_n=self.client.expand_path("44'/1'/0'/1/1"), + address_n=parse_path("44'/1'/0'/1/1"), amount=10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) @@ -814,7 +815,7 @@ class TestMsgSigntx(TrezorTest): # tx: e5040e1bc1ae7667ffb9e5248e90b2fb93cd9150234151ce90e14ab2f5933bcd # input 0: 0.31 BTC inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/1'/0'/0/0"), + address_n=parse_path("44'/1'/0'/0/0"), # amount=31000000, prev_hash=TXHASH_e5040e, prev_index=0, @@ -828,7 +829,7 @@ class TestMsgSigntx(TrezorTest): # change on main chain is allowed => treated as a change out_change = proto.TxOutputType( - address_n=self.client.expand_path("44'/1'/0'/0/0"), + address_n=parse_path("44'/1'/0'/0/0"), amount=900000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) diff --git a/trezorlib/tests/device_tests/test_msg_signtx_bcash.py b/trezorlib/tests/device_tests/test_msg_signtx_bcash.py index e2bb949781..e8036d8388 100644 --- a/trezorlib/tests/device_tests/test_msg_signtx_bcash.py +++ b/trezorlib/tests/device_tests/test_msg_signtx_bcash.py @@ -15,11 +15,16 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +import pytest +from binascii import hexlify, unhexlify + +from .common import TrezorTest +from ..support.ckd_public import deserialize from trezorlib import coins from trezorlib import messages as proto -from trezorlib.ckd_public import deserialize from trezorlib.client import CallException +from trezorlib.tools import parse_path + TxApiBcash = coins.tx_api['Bcash'] @@ -30,7 +35,7 @@ class TestMsgSigntxBch(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBcash) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/0'/0/0"), + address_n=parse_path("44'/145'/0'/0/0"), # bitcoincash:qr08q88p9etk89wgv05nwlrkm4l0urz4cyl36hh9sv amount=1995344, prev_hash=unhexlify('bc37c28dfb467d2ecb50261387bf752a3977d7e5337915071bb4151e6b711a78'), @@ -38,7 +43,7 @@ class TestMsgSigntxBch(TrezorTest): script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( - address_n=self.client.expand_path("44'/145'/0'/1/0"), + address_n=parse_path("44'/145'/0'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) @@ -67,7 +72,7 @@ class TestMsgSigntxBch(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBcash) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/0'/1/0"), + address_n=parse_path("44'/145'/0'/1/0"), # bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw amount=1896050, prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'), @@ -75,7 +80,7 @@ class TestMsgSigntxBch(TrezorTest): script_type=proto.InputScriptType.SPENDADDRESS, ) inp2 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/0'/0/1"), + address_n=parse_path("44'/145'/0'/0/1"), # bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4 amount=73452, prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'), @@ -107,7 +112,7 @@ class TestMsgSigntxBch(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBcash) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/0'/1/0"), + address_n=parse_path("44'/145'/0'/1/0"), # bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw amount=1896050, prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'), @@ -115,7 +120,7 @@ class TestMsgSigntxBch(TrezorTest): script_type=proto.InputScriptType.SPENDADDRESS, ) inp2 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/0'/0/1"), + address_n=parse_path("44'/145'/0'/0/1"), # bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4 amount=73452, prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'), @@ -147,7 +152,7 @@ class TestMsgSigntxBch(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBcash) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/0'/1/0"), + address_n=parse_path("44'/145'/0'/1/0"), # bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw amount=300, prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'), @@ -155,7 +160,7 @@ class TestMsgSigntxBch(TrezorTest): script_type=proto.InputScriptType.SPENDADDRESS, ) inp2 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/0'/0/1"), + address_n=parse_path("44'/145'/0'/0/1"), # bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4 amount=70, prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'), @@ -231,7 +236,7 @@ class TestMsgSigntxBch(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBcash) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/1000'/0/0"), + address_n=parse_path("44'/145'/1000'/0/0"), # bitcoincash:qr08q88p9etk89wgv05nwlrkm4l0urz4cyl36hh9sv amount=1995344, prev_hash=unhexlify('bc37c28dfb467d2ecb50261387bf752a3977d7e5337915071bb4151e6b711a78'), @@ -239,7 +244,7 @@ class TestMsgSigntxBch(TrezorTest): script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( - address_n=self.client.expand_path("44'/145'/1000'/1/0"), + address_n=parse_path("44'/145'/1000'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) @@ -253,7 +258,6 @@ class TestMsgSigntxBch(TrezorTest): attack_ctr = 0 def attack_processor(req, msg): - import sys global attack_ctr if req.details.tx_hash is not None: @@ -286,7 +290,7 @@ class TestMsgSigntxBch(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBcash) xpubs = [] - for n in map(lambda index: self.client.get_public_node(self.client.expand_path("44'/145'/" + str(index) + "'")), range(1, 4)): + for n in map(lambda index: self.client.get_public_node(parse_path("44'/145'/" + str(index) + "'")), range(1, 4)): xpubs.append(n.xpub) def getmultisig(chain, nr, signatures=[b'', b'', b''], xpubs=xpubs): @@ -301,7 +305,7 @@ class TestMsgSigntxBch(TrezorTest): public_key=unhexlify('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71')) sig = unhexlify(b'304402207274b5a4d15e75f3df7319a375557b0efba9b27bc63f9f183a17da95a6125c94022000efac57629f1522e2d3958430e2ef073b0706cfac06cce492651b79858f09ae') inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/1'/1/0"), + address_n=parse_path("44'/145'/1'/1/0"), multisig=getmultisig(1, 0, [b'', sig, b'']), # bitcoincash:pp6kcpkhua7789g2vyj0qfkcux3yvje7euhyhltn0a amount=24000, @@ -310,7 +314,7 @@ class TestMsgSigntxBch(TrezorTest): script_type=proto.InputScriptType.SPENDMULTISIG, ) out1 = proto.TxOutputType( - address_n=self.client.expand_path("44'/145'/1'/1/1"), + address_n=parse_path("44'/145'/1'/1/1"), multisig=proto.MultisigRedeemScriptType( pubkeys=[proto.HDNodePathType(node=deserialize(xpubs[0]), address_n=[1, 1]), proto.HDNodePathType(node=correcthorse, address_n=[]), @@ -339,7 +343,7 @@ class TestMsgSigntxBch(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBcash) xpubs = [] - for n in map(lambda index: self.client.get_public_node(self.client.expand_path("44'/145'/" + str(index) + "'")), range(1, 4)): + for n in map(lambda index: self.client.get_public_node(parse_path("44'/145'/" + str(index) + "'")), range(1, 4)): xpubs.append(n.xpub) def getmultisig(chain, nr, signatures=[b'', b'', b''], xpubs=xpubs): @@ -349,7 +353,7 @@ class TestMsgSigntxBch(TrezorTest): m=2, ) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/3'/0/0"), + address_n=parse_path("44'/145'/3'/0/0"), multisig=getmultisig(0, 0), # bitcoincash:pqguz4nqq64jhr5v3kvpq4dsjrkda75hwy86gq0qzw amount=48490, @@ -363,7 +367,7 @@ class TestMsgSigntxBch(TrezorTest): script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( - address_n=self.client.expand_path("44'/145'/3'/1/0"), + address_n=parse_path("44'/145'/3'/1/0"), multisig=getmultisig(1, 0), script_type=proto.OutputScriptType.PAYTOMULTISIG, amount=24000 @@ -385,7 +389,7 @@ class TestMsgSigntxBch(TrezorTest): assert hexlify(signatures1[0]) == b'3045022100bcb1a7134a13025a06052546ee1c6ac3640a0abd2d130190ed13ed7fcb43e9cd02207c381478e2ee123c850425bfbf6d3c691230eb37e333832cb32a1ed3f2cd9e85' inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/145'/1'/0/0"), + address_n=parse_path("44'/145'/1'/0/0"), multisig=getmultisig(0, 0, [b'', b'', signatures1[0]]), # bitcoincash:pqguz4nqq64jhr5v3kvpq4dsjrkda75hwy86gq0qzw amount=48490, diff --git a/trezorlib/tests/device_tests/test_msg_signtx_bitcoin_gold.py b/trezorlib/tests/device_tests/test_msg_signtx_bitcoin_gold.py index 99b5082c00..c08514166a 100644 --- a/trezorlib/tests/device_tests/test_msg_signtx_bitcoin_gold.py +++ b/trezorlib/tests/device_tests/test_msg_signtx_bitcoin_gold.py @@ -16,11 +16,15 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +import pytest +from binascii import hexlify, unhexlify + +from .common import TrezorTest +from ..support.ckd_public import deserialize from trezorlib import coins from trezorlib import messages as proto -from trezorlib.ckd_public import deserialize from trezorlib.client import CallException +from trezorlib.tools import parse_path TxApiBitcoinGold = coins.tx_api["Bitcoin Gold"] @@ -32,14 +36,14 @@ class TestMsgSigntxBitcoinGold(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBitcoinGold) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/156'/0'/0/0"), + address_n=parse_path("44'/156'/0'/0/0"), amount=1995344, prev_hash=unhexlify('25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985'), prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( - address_n=self.client.expand_path("44'/156'/0'/1/0"), + address_n=parse_path("44'/156'/0'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) @@ -68,14 +72,14 @@ class TestMsgSigntxBitcoinGold(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBitcoinGold) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/156'/0'/1/0"), + address_n=parse_path("44'/156'/0'/1/0"), amount=1896050, prev_hash=unhexlify('25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985'), prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) inp2 = proto.TxInputType( - address_n=self.client.expand_path("44'/156'/0'/0/1"), + address_n=parse_path("44'/156'/0'/0/1"), # 1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3 amount=73452, prev_hash=unhexlify('db77c2461b840e6edbe7f9280043184a98e020d9795c1b65cb7cef2551a8fb18'), @@ -107,7 +111,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBitcoinGold) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/156'/1000'/0/0"), + address_n=parse_path("44'/156'/1000'/0/0"), # 1MH9KKcvdCTY44xVDC2k3fjBbX5Cz29N1q amount=1995344, prev_hash=unhexlify('25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985'), @@ -115,7 +119,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( - address_n=self.client.expand_path("44'/156'/1000'/1/0"), + address_n=parse_path("44'/156'/1000'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) @@ -129,7 +133,6 @@ class TestMsgSigntxBitcoinGold(TrezorTest): attack_ctr = 0 def attack_processor(req, msg): - import sys global attack_ctr if req.details.tx_hash is not None: @@ -162,7 +165,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBitcoinGold) xpubs = [] - for n in map(lambda index: self.client.get_public_node(self.client.expand_path("44'/156'/" + str(index) + "'")), range(1, 4)): + for n in map(lambda index: self.client.get_public_node(parse_path("44'/156'/" + str(index) + "'")), range(1, 4)): xpubs.append(n.xpub) def getmultisig(chain, nr, signatures=[b'', b'', b''], xpubs=xpubs): @@ -172,7 +175,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): m=2, ) inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/156'/3'/0/0"), + address_n=parse_path("44'/156'/3'/0/0"), multisig=getmultisig(0, 0), # 33Ju286QvonBz5N1V754ZekQv4GLJqcc5R amount=48490, @@ -186,7 +189,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( - address_n=self.client.expand_path("44'/156'/3'/1/0"), + address_n=parse_path("44'/156'/3'/1/0"), multisig=getmultisig(1, 0), script_type=proto.OutputScriptType.PAYTOMULTISIG, amount=24000 @@ -208,7 +211,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): assert hexlify(signatures1[0]) == b'3045022100b1594f3b186d0dedbf61e53a1c407b1e0747098b7375941df85af045040f578e022013ba1893eb9e2fd854dd07073a83b261cf4beba76f66b07742e462b4088a7e4a' inp1 = proto.TxInputType( - address_n=self.client.expand_path("44'/156'/1'/0/0"), + address_n=parse_path("44'/156'/1'/0/0"), multisig=getmultisig(0, 0, [b'', b'', signatures1[0]]), # 33Ju286QvonBz5N1V754ZekQv4GLJqcc5R amount=48490, @@ -239,7 +242,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBitcoinGold) inp1 = proto.TxInputType( - address_n=self.client.expand_path("49'/156'/0'/1/0"), + address_n=parse_path("49'/156'/0'/1/0"), amount=123456789, prev_hash=unhexlify('25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985'), prev_index=0, @@ -277,7 +280,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBitcoinGold) inp1 = proto.TxInputType( - address_n=self.client.expand_path("49'/156'/0'/1/0"), + address_n=parse_path("49'/156'/0'/1/0"), amount=123456789, prev_hash=unhexlify('25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985'), prev_index=0, @@ -289,7 +292,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( - address_n=self.client.expand_path("49'/156'/0'/1/0"), + address_n=parse_path("49'/156'/0'/1/0"), script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, amount=123456789 - 11000 - 12300000, ) @@ -315,7 +318,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): def test_send_multisig_1(self): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBitcoinGold) - nodes = map(lambda index: self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)), range(1, 4)) + nodes = map(lambda index: self.client.get_public_node(parse_path("999'/1'/%d'" % index)), range(1, 4)) multisig = proto.MultisigRedeemScriptType( pubkeys=list(map(lambda n: proto.HDNodePathType(node=deserialize(n.xpub), address_n=[2, 0]), nodes)), signatures=[b'', b'', b''], @@ -323,7 +326,7 @@ class TestMsgSigntxBitcoinGold(TrezorTest): ) inp1 = proto.TxInputType( - address_n=self.client.expand_path("999'/1'/1'/2/0"), + address_n=parse_path("999'/1'/1'/2/0"), prev_hash=unhexlify('25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985'), prev_index=1, script_type=proto.InputScriptType.SPENDP2SHWITNESS, diff --git a/trezorlib/tests/device_tests/test_msg_signtx_decred.py b/trezorlib/tests/device_tests/test_msg_signtx_decred.py index e0d2ae8ce9..90b66e02be 100644 --- a/trezorlib/tests/device_tests/test_msg_signtx_decred.py +++ b/trezorlib/tests/device_tests/test_msg_signtx_decred.py @@ -15,10 +15,14 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +from binascii import unhexlify +import pytest + +from .common import TrezorTest from trezorlib import coins from trezorlib import messages as proto +from trezorlib.tools import parse_path TxApiDecredTestnet = coins.tx_api['Decred Testnet'] @@ -41,7 +45,7 @@ class TestMsgSigntxDecred(TrezorTest): inp1 = proto.TxInputType( # TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz - address_n=self.client.expand_path("m/44'/1'/0'/0/0"), + address_n=parse_path("m/44'/1'/0'/0/0"), prev_hash=TXHASH_e16248, prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, @@ -80,7 +84,7 @@ class TestMsgSigntxDecred(TrezorTest): inp1 = proto.TxInputType( # TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz - address_n=self.client.expand_path("m/44'/1'/0'/0/0"), + address_n=parse_path("m/44'/1'/0'/0/0"), prev_hash=TXHASH_5e6e35, prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, @@ -89,7 +93,7 @@ class TestMsgSigntxDecred(TrezorTest): inp2 = proto.TxInputType( # TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz - address_n=self.client.expand_path("m/44'/1'/0'/0/0"), + address_n=parse_path("m/44'/1'/0'/0/0"), prev_hash=TXHASH_ccf95b, prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, @@ -98,7 +102,7 @@ class TestMsgSigntxDecred(TrezorTest): inp3 = proto.TxInputType( # Tskt39YEvzoJ5KBDH4f1auNzG3jViVjZ2RV - address_n=self.client.expand_path("m/44'/1'/0'/0/1"), + address_n=parse_path("m/44'/1'/0'/0/1"), prev_hash=TXHASH_f395ef, prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, @@ -114,7 +118,7 @@ class TestMsgSigntxDecred(TrezorTest): out2 = proto.TxOutputType( # TsaSFRwfN9muW5F6ZX36iSksc9hruiC5F97 - address_n=self.client.expand_path("m/44'/1'/0'/1/0"), + address_n=parse_path("m/44'/1'/0'/1/0"), amount=100000000, script_type=proto.OutputScriptType.PAYTOADDRESS, decred_script_version=0, @@ -154,7 +158,7 @@ class TestMsgSigntxDecred(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiDecredTestnet) - paths = [self.client.expand_path("m/48'/1'/%d'" % index) for index in range(3)] + paths = [parse_path("m/48'/1'/%d'" % index) for index in range(3)] nodes = [self.client.get_public_node(address_n, coin_name="Decred Testnet").node for address_n in paths] signatures = [ @@ -163,7 +167,7 @@ class TestMsgSigntxDecred(TrezorTest): ] def create_multisig(index, address, signatures=None): - address_n = self.client.expand_path(address) + address_n = parse_path(address) multisig = proto.MultisigRedeemScriptType( pubkeys=[proto.HDNodePathType(node=node, address_n=address_n) for node in nodes], signatures=signatures, diff --git a/trezorlib/tests/device_tests/test_msg_signtx_segwit.py b/trezorlib/tests/device_tests/test_msg_signtx_segwit.py index fb274179a4..f45cd01520 100644 --- a/trezorlib/tests/device_tests/test_msg_signtx_segwit.py +++ b/trezorlib/tests/device_tests/test_msg_signtx_segwit.py @@ -18,12 +18,14 @@ from binascii import hexlify, unhexlify import pytest +from ..support.ckd_public import deserialize from .conftest import TREZOR_VERSION from .common import TrezorTest + from trezorlib import coins from trezorlib import messages as proto -from trezorlib.ckd_public import deserialize from trezorlib.client import CallException +from trezorlib.tools import parse_path TxApiTestnet = coins.tx_api["Testnet"] @@ -34,7 +36,7 @@ class TestMsgSigntxSegwit(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) inp1 = proto.TxInputType( - address_n=self.client.expand_path("49'/1'/0'/1/0"), + address_n=parse_path("49'/1'/0'/1/0"), # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX amount=123456789, prev_hash=unhexlify('20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'), @@ -73,7 +75,7 @@ class TestMsgSigntxSegwit(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) inp1 = proto.TxInputType( - address_n=self.client.expand_path("49'/1'/0'/1/0"), + address_n=parse_path("49'/1'/0'/1/0"), # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX amount=123456789, prev_hash=unhexlify('20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'), @@ -86,7 +88,7 @@ class TestMsgSigntxSegwit(TrezorTest): script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( - address_n=self.client.expand_path("49'/1'/0'/1/0"), + address_n=parse_path("49'/1'/0'/1/0"), script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, amount=123456789 - 11000 - 12300000, ) @@ -110,7 +112,7 @@ class TestMsgSigntxSegwit(TrezorTest): def test_send_multisig_1(self): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) - nodes = map(lambda index: self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)), range(1, 4)) + nodes = map(lambda index: self.client.get_public_node(parse_path("999'/1'/%d'" % index)), range(1, 4)) multisig = proto.MultisigRedeemScriptType( pubkeys=list(map(lambda n: proto.HDNodePathType(node=deserialize(n.xpub), address_n=[2, 0]), nodes)), signatures=[b'', b'', b''], @@ -118,7 +120,7 @@ class TestMsgSigntxSegwit(TrezorTest): ) inp1 = proto.TxInputType( - address_n=self.client.expand_path("999'/1'/1'/2/0"), + address_n=parse_path("999'/1'/1'/2/0"), prev_hash=unhexlify('9c31922be756c06d02167656465c8dc83bb553bf386a3f478ae65b5c021002be'), prev_index=1, script_type=proto.InputScriptType.SPENDP2SHWITNESS, @@ -167,7 +169,7 @@ class TestMsgSigntxSegwit(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) inp1 = proto.TxInputType( - address_n=self.client.expand_path("49'/1'/0'/1/0"), + address_n=parse_path("49'/1'/0'/1/0"), # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX amount=123456789, prev_hash=unhexlify('20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'), @@ -180,7 +182,7 @@ class TestMsgSigntxSegwit(TrezorTest): script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( - address_n=self.client.expand_path("49'/1'/12345'/1/0"), + address_n=parse_path("49'/1'/12345'/1/0"), script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, amount=123456789 - 11000 - 12300000, ) @@ -189,7 +191,6 @@ class TestMsgSigntxSegwit(TrezorTest): run_attack = True def attack_processor(req, msg): - import sys global run_attack if req.details.tx_hash is not None: diff --git a/trezorlib/tests/device_tests/test_msg_signtx_segwit_native.py b/trezorlib/tests/device_tests/test_msg_signtx_segwit_native.py index f82f93ff82..a5081c6b5d 100644 --- a/trezorlib/tests/device_tests/test_msg_signtx_segwit_native.py +++ b/trezorlib/tests/device_tests/test_msg_signtx_segwit_native.py @@ -15,11 +15,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +from binascii import hexlify, unhexlify +from .common import TrezorTest +from ..support.ckd_public import deserialize from trezorlib import coins from trezorlib import messages as proto -from trezorlib.ckd_public import deserialize +from trezorlib.tools import parse_path TxApiTestnet = coins.tx_api['Testnet'] @@ -30,7 +32,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) inp1 = proto.TxInputType( - address_n=self.client.expand_path("49'/1'/0'/1/0"), + address_n=parse_path("49'/1'/0'/1/0"), # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX amount=123456789, prev_hash=unhexlify('20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'), @@ -69,7 +71,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) inp1 = proto.TxInputType( - address_n=self.client.expand_path("49'/1'/0'/1/0"), + address_n=parse_path("49'/1'/0'/1/0"), # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX amount=123456789, prev_hash=unhexlify('20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'), @@ -82,7 +84,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( - address_n=self.client.expand_path("49'/1'/0'/1/0"), + address_n=parse_path("49'/1'/0'/1/0"), script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, amount=123456789 - 11000 - 12300000, ) @@ -107,7 +109,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) inp1 = proto.TxInputType( - address_n=self.client.expand_path("49'/1'/0'/0/0"), + address_n=parse_path("49'/1'/0'/0/0"), # tb1qqzv60m9ajw8drqulta4ld4gfx0rdh82un5s65s amount=12300000, prev_hash=unhexlify('09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a'), @@ -146,7 +148,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) inp1 = proto.TxInputType( - address_n=self.client.expand_path("49'/1'/0'/0/0"), + address_n=parse_path("49'/1'/0'/0/0"), # tb1qqzv60m9ajw8drqulta4ld4gfx0rdh82un5s65s amount=12300000, prev_hash=unhexlify('09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a'), @@ -159,7 +161,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( - address_n=self.client.expand_path("49'/1'/0'/1/0"), + address_n=parse_path("49'/1'/0'/1/0"), script_type=proto.OutputScriptType.PAYTOWITNESS, amount=12300000 - 11000 - 5000000, ) @@ -184,7 +186,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) inp1 = proto.TxInputType( - address_n=self.client.expand_path("49'/1'/0'/1/0"), + address_n=parse_path("49'/1'/0'/1/0"), # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX amount=111145789, prev_hash=unhexlify('09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a'), @@ -192,7 +194,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): script_type=proto.InputScriptType.SPENDP2SHWITNESS, ) inp2 = proto.TxInputType( - address_n=self.client.expand_path("49'/1'/0'/1/0"), + address_n=parse_path("49'/1'/0'/1/0"), # tb1q694ccp5qcc0udmfwgp692u2s2hjpq5h407urtu amount=7289000, prev_hash=unhexlify('65b811d3eca0fe6915d9f2d77c86c5a7f19bf66b1b1253c2c51cb4ae5f0c017b'), @@ -205,7 +207,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( - # address_n=self.client.expand_path("44'/1'/0'/0/0"), + # address_n=parse_path("44'/1'/0'/0/0"), # script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, address='2N6UeBoqYEEnybg4cReFYDammpsyDw8R2Mc', script_type=proto.OutputScriptType.PAYTOADDRESS, @@ -245,7 +247,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): def test_send_multisig_1(self): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) - nodes = [self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)) for index in range(1, 4)] + nodes = [self.client.get_public_node(parse_path("999'/1'/%d'" % index)) for index in range(1, 4)] multisig = proto.MultisigRedeemScriptType( pubkeys=list(map(lambda n: proto.HDNodePathType(node=deserialize(n.xpub), address_n=[2, 0]), nodes)), signatures=[b'', b'', b''], @@ -253,7 +255,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): ) inp1 = proto.TxInputType( - address_n=self.client.expand_path("999'/1'/1'/2/0"), + address_n=parse_path("999'/1'/1'/2/0"), prev_hash=unhexlify('9c31922be756c06d02167656465c8dc83bb553bf386a3f478ae65b5c021002be'), prev_index=1, script_type=proto.InputScriptType.SPENDP2SHWITNESS, @@ -301,7 +303,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): def test_send_multisig_2(self): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) - nodes = [self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)) for index in range(1, 4)] + nodes = [self.client.get_public_node(parse_path("999'/1'/%d'" % index)) for index in range(1, 4)] multisig = proto.MultisigRedeemScriptType( pubkeys=list(map(lambda n: proto.HDNodePathType(node=deserialize(n.xpub), address_n=[2, 1]), nodes)), signatures=[b'', b'', b''], @@ -309,7 +311,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): ) inp1 = proto.TxInputType( - address_n=self.client.expand_path("999'/1'/2'/2/1"), + address_n=parse_path("999'/1'/2'/2/1"), prev_hash=unhexlify('f41cbedd8becee05a830f418d13aa665125464547db5c7a6cd28f21639fe1228'), prev_index=0, script_type=proto.InputScriptType.SPENDWITNESS, @@ -357,7 +359,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): def test_send_multisig_3_change(self): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) - nodes = [self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)) for index in range(1, 4)] + nodes = [self.client.get_public_node(parse_path("999'/1'/%d'" % index)) for index in range(1, 4)] multisig = proto.MultisigRedeemScriptType( pubkeys=list(map(lambda n: proto.HDNodePathType(node=deserialize(n.xpub), address_n=[2, 0]), nodes)), signatures=[b'', b'', b''], @@ -370,7 +372,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): ) inp1 = proto.TxInputType( - address_n=self.client.expand_path("999'/1'/1'/2/0"), + address_n=parse_path("999'/1'/1'/2/0"), prev_hash=unhexlify('c9348040bbc2024e12dcb4a0b4806b0398646b91acf314da028c3f03dd0179fc'), prev_index=0, script_type=proto.InputScriptType.SPENDWITNESS, @@ -379,7 +381,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): ) out1 = proto.TxOutputType( - address_n=self.client.expand_path("999'/1'/1'/1/1"), + address_n=parse_path("999'/1'/1'/1/1"), amount=1603000, multisig=multisig2, script_type=proto.OutputScriptType.PAYTOP2SHWITNESS @@ -418,7 +420,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): def test_send_multisig_4_change(self): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiTestnet) - nodes = [self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)) for index in range(1, 4)] + nodes = [self.client.get_public_node(parse_path("999'/1'/%d'" % index)) for index in range(1, 4)] multisig = proto.MultisigRedeemScriptType( pubkeys=list(map(lambda n: proto.HDNodePathType(node=deserialize(n.xpub), address_n=[1, 1]), nodes)), signatures=[b'', b'', b''], @@ -431,7 +433,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): ) inp1 = proto.TxInputType( - address_n=self.client.expand_path("999'/1'/1'/1/1"), + address_n=parse_path("999'/1'/1'/1/1"), prev_hash=unhexlify('31bc1c88ce6ae337a6b3057a16d5bad0b561ad1dfc047d0a7fbb8814668f91e5'), prev_index=0, script_type=proto.InputScriptType.SPENDP2SHWITNESS, @@ -440,7 +442,7 @@ class TestMsgSigntxSegwitNative(TrezorTest): ) out1 = proto.TxOutputType( - address_n=self.client.expand_path("999'/1'/1'/1/2"), + address_n=parse_path("999'/1'/1'/1/2"), amount=1602000, multisig=multisig2, script_type=proto.OutputScriptType.PAYTOWITNESS diff --git a/trezorlib/tests/device_tests/test_msg_signtx_zcash.py b/trezorlib/tests/device_tests/test_msg_signtx_zcash.py index de78da648e..7a437f4c4d 100644 --- a/trezorlib/tests/device_tests/test_msg_signtx_zcash.py +++ b/trezorlib/tests/device_tests/test_msg_signtx_zcash.py @@ -15,12 +15,14 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import unhexlify, hexlify +import pytest - -from .common import * +from .common import TrezorTest from trezorlib import coins from trezorlib import messages as proto +from trezorlib.tools import parse_path TxApiZcash = coins.tx_api["Zcash"] @@ -42,7 +44,7 @@ class TestMsgSigntxZcash(TrezorTest): # input 0: 1.234567 TAZ inp1 = proto.TxInputType( - address_n=[2147483692, 2147483649, 2147483648, 0, 0], # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu + address_n=parse_path("m/Zcash Testnet/0h/0/0"), # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu # amount=123456700, prev_hash=TXHASH_93373e, prev_index=0, diff --git a/trezorlib/tests/device_tests/test_msg_stellar_get_public_key.py b/trezorlib/tests/device_tests/test_msg_stellar_get_public_key.py index cd7cec2791..0a45fa6314 100644 --- a/trezorlib/tests/device_tests/test_msg_stellar_get_public_key.py +++ b/trezorlib/tests/device_tests/test_msg_stellar_get_public_key.py @@ -12,11 +12,12 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import pytest from .common import TrezorTest from .conftest import TREZOR_VERSION from trezorlib import stellar -import pytest +from trezorlib.tools import parse_path @pytest.mark.stellar @@ -27,5 +28,5 @@ class TestMsgStellarGetPublicKey(TrezorTest): self.setup_mnemonic_nopin_nopassphrase() # GAK5MSF74TJW6GLM7NLTL76YZJKM2S4CGP3UH4REJHPHZ4YBZW2GSBPW - response = self.client.stellar_get_public_key(self.client.expand_path("m/44'/148'/0'")) + response = self.client.stellar_get_public_key(parse_path(stellar.DEFAULT_BIP32_PATH)) assert stellar.address_from_public_key(response.public_key) == b'GAK5MSF74TJW6GLM7NLTL76YZJKM2S4CGP3UH4REJHPHZ4YBZW2GSBPW' diff --git a/trezorlib/tests/device_tests/test_msg_stellar_sign_transaction.py b/trezorlib/tests/device_tests/test_msg_stellar_sign_transaction.py index 70c5bbe13f..57e7974304 100644 --- a/trezorlib/tests/device_tests/test_msg_stellar_sign_transaction.py +++ b/trezorlib/tests/device_tests/test_msg_stellar_sign_transaction.py @@ -22,6 +22,8 @@ from .common import TrezorTest from .conftest import TREZOR_VERSION from binascii import hexlify, unhexlify from trezorlib import messages as proto +from trezorlib import stellar +from trezorlib.tools import parse_path import pytest @@ -29,14 +31,12 @@ import pytest @pytest.mark.xfail(TREZOR_VERSION == 2, reason="T2 support is not yet finished") class TestMsgStellarSignTransaction(TrezorTest): + ADDRESS_N = parse_path(stellar.DEFAULT_BIP32_PATH) + def get_network_passphrase(self): """Use the same passphrase as the network that generated the test XDR/signatures""" return "Integration Test Network ; zulucrypto" - def get_address_n(self): - """BIP32 path of the default account""" - return self.client.expand_path("m/44'/148'/0'") - def test_sign_tx_bump_sequence_op(self): self.setup_mnemonic_nopin_nopassphrase() @@ -44,7 +44,7 @@ class TestMsgStellarSignTransaction(TrezorTest): op.bump_to = 0x7fffffffffffffff tx = self._create_msg() - response = self.client.stellar_sign_transaction(tx, [op], self.get_address_n(), self.get_network_passphrase()) + response = self.client.stellar_sign_transaction(tx, [op], self.ADDRESS_N, self.get_network_passphrase()) assert b64encode(response.signature) == b'UAOL4ZPYIOzEgM66kBrhyNjLR66dNXtuNrmvd3m0/pc8qCSoLmYY4TybS0lHiMtb+LFZESTaxrpErMHz1sZ6DQ==' def test_sign_tx_account_merge_op(self): @@ -56,7 +56,7 @@ class TestMsgStellarSignTransaction(TrezorTest): tx = self._create_msg() - response = self.client.stellar_sign_transaction(tx, [op], self.get_address_n(), self.get_network_passphrase()) + response = self.client.stellar_sign_transaction(tx, [op], self.ADDRESS_N, self.get_network_passphrase()) assert hexlify(response.public_key) == b'15d648bfe4d36f196cfb5735ffd8ca54cd4b8233f743f22449de7cf301cdb469' assert b64encode(response.signature) == b'gjoPRj4sW5o7NAXzYOqPK0uxfPbeKb4Qw48LJiCH/XUZ6YVCiZogePC0Z5ISUlozMh6YO6HoYtuLPbm7jq+eCA==' diff --git a/trezorlib/tests/device_tests/test_msg_verifymessage.py b/trezorlib/tests/device_tests/test_msg_verifymessage.py index ba51f4a58b..7c64670b0d 100644 --- a/trezorlib/tests/device_tests/test_msg_verifymessage.py +++ b/trezorlib/tests/device_tests/test_msg_verifymessage.py @@ -15,9 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import unhexlify -from .common import * -import base64 +from .common import TrezorTest class TestMsgVerifymessage(TrezorTest): diff --git a/trezorlib/tests/device_tests/test_msg_verifymessage_segwit.py b/trezorlib/tests/device_tests/test_msg_verifymessage_segwit.py index ba8cf46c2b..15c21b03b0 100644 --- a/trezorlib/tests/device_tests/test_msg_verifymessage_segwit.py +++ b/trezorlib/tests/device_tests/test_msg_verifymessage_segwit.py @@ -15,9 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import unhexlify -from .common import * -import base64 +from .common import TrezorTest class TestMsgVerifymessageSegwit(TrezorTest): diff --git a/trezorlib/tests/device_tests/test_msg_verifymessage_segwit_native.py b/trezorlib/tests/device_tests/test_msg_verifymessage_segwit_native.py index fa2beb084a..dbaa4bd107 100644 --- a/trezorlib/tests/device_tests/test_msg_verifymessage_segwit_native.py +++ b/trezorlib/tests/device_tests/test_msg_verifymessage_segwit_native.py @@ -15,9 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import unhexlify -from .common import * -import base64 +from .common import TrezorTest class TestMsgVerifymessageSegwitNative(TrezorTest): diff --git a/trezorlib/tests/device_tests/test_msg_wipedevice.py b/trezorlib/tests/device_tests/test_msg_wipedevice.py index a089de6825..2a5f259eb7 100644 --- a/trezorlib/tests/device_tests/test_msg_wipedevice.py +++ b/trezorlib/tests/device_tests/test_msg_wipedevice.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_multisig.py b/trezorlib/tests/device_tests/test_multisig.py index 115f0fd605..34b29e7c3f 100644 --- a/trezorlib/tests/device_tests/test_multisig.py +++ b/trezorlib/tests/device_tests/test_multisig.py @@ -20,11 +20,10 @@ from binascii import hexlify, unhexlify import pytest from .common import TrezorTest +from ..support import ckd_public as bip32 from trezorlib import messages as proto -import trezorlib.ckd_public as bip32 from trezorlib.client import CallException - TXHASH_c6091a = unhexlify('c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52') diff --git a/trezorlib/tests/device_tests/test_multisig_change.py b/trezorlib/tests/device_tests/test_multisig_change.py index 2d2d1c4dd2..e09dcbd03d 100644 --- a/trezorlib/tests/device_tests/test_multisig_change.py +++ b/trezorlib/tests/device_tests/test_multisig_change.py @@ -16,10 +16,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from .common import * +from binascii import hexlify, unhexlify + +from .common import TrezorTest +from ..support import ckd_public as bip32 from trezorlib import messages as proto -import trezorlib.ckd_public as bip32 from trezorlib.coins import tx_api +from trezorlib.tools import parse_path class TestMultisigChange(TrezorTest): @@ -193,7 +196,7 @@ class TestMultisigChange(TrezorTest): ) out2 = proto.TxOutputType( - address_n=self.client.expand_path("45'/0/1/1"), + address_n=parse_path("45'/0/1/1"), amount=44000000, script_type=proto.OutputScriptType.PAYTOADDRESS ) @@ -209,7 +212,7 @@ class TestMultisigChange(TrezorTest): self.setup_mnemonic_nopin_nopassphrase() out1 = proto.TxOutputType( - address_n=self.client.expand_path("45'/0/1/0"), + address_n=parse_path("45'/0/1/0"), amount=40000000, script_type=proto.OutputScriptType.PAYTOADDRESS ) diff --git a/trezorlib/tests/device_tests/test_op_return.py b/trezorlib/tests/device_tests/test_op_return.py index 91e370f807..b0f7a94369 100644 --- a/trezorlib/tests/device_tests/test_op_return.py +++ b/trezorlib/tests/device_tests/test_op_return.py @@ -20,7 +20,6 @@ import pytest from .common import TrezorTest from .conftest import TREZOR_VERSION - from trezorlib import messages as proto from trezorlib.client import CallException diff --git a/trezorlib/tests/device_tests/test_protect_call.py b/trezorlib/tests/device_tests/test_protect_call.py index 3b7980e9b8..10fe06ee12 100644 --- a/trezorlib/tests/device_tests/test_protect_call.py +++ b/trezorlib/tests/device_tests/test_protect_call.py @@ -16,10 +16,10 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from __future__ import print_function - import time -from .common import * +import pytest + +from .common import TrezorTest from trezorlib import messages as proto from trezorlib.client import PinException, CallException diff --git a/trezorlib/tests/device_tests/test_protection_levels.py b/trezorlib/tests/device_tests/test_protection_levels.py index f0922d5ff6..caaaea1f84 100644 --- a/trezorlib/tests/device_tests/test_protection_levels.py +++ b/trezorlib/tests/device_tests/test_protection_levels.py @@ -15,8 +15,10 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import unhexlify +import pytest -from .common import * +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/device_tests/test_zerosig.py b/trezorlib/tests/device_tests/test_zerosig.py index 507ef7d719..5b65a1f181 100644 --- a/trezorlib/tests/device_tests/test_zerosig.py +++ b/trezorlib/tests/device_tests/test_zerosig.py @@ -15,12 +15,9 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +from binascii import unhexlify -from __future__ import print_function - -import sys -from .common import * - +from .common import TrezorTest from trezorlib import messages as proto diff --git a/trezorlib/tests/support/__init__.py b/trezorlib/tests/support/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/trezorlib/ckd_public.py b/trezorlib/tests/support/ckd_public.py similarity index 93% rename from trezorlib/ckd_public.py rename to trezorlib/tests/support/ckd_public.py index 9b187880c3..cb4f2fa5ba 100644 --- a/trezorlib/ckd_public.py +++ b/trezorlib/tests/support/ckd_public.py @@ -27,10 +27,8 @@ from ecdsa.util import string_to_number, number_to_string from ecdsa.curves import SECP256k1 from ecdsa.ellipticcurve import Point, INFINITY -from . import tools -from . import messages as proto - -PRIME_DERIVATION_FLAG = 0x80000000 +from trezorlib import tools +from trezorlib import messages def point_to_pubkey(point): @@ -61,7 +59,7 @@ def sec_to_public_pair(pubkey): def is_prime(n): - return (bool)(n & PRIME_DERIVATION_FLAG) + return bool(n & tools.HARDENED_FLAG) def fingerprint(pubkey): @@ -76,7 +74,7 @@ def public_ckd(public_node, n): if not isinstance(n, list): raise ValueError('Parameter must be a list') - node = proto.HDNodeType() + node = messages.HDNodeType() node.CopyFrom(public_node) for i in n: @@ -98,7 +96,7 @@ def get_subnode(node, i): I64 = hmac.HMAC(key=node.chain_code, msg=data, digestmod=hashlib.sha512).digest() I_left_as_exponent = string_to_number(I64[:32]) - node_out = proto.HDNodeType() + node_out = messages.HDNodeType() node_out.depth = node.depth + 1 node_out.child_num = i node_out.chain_code = I64[32:] @@ -128,17 +126,17 @@ def serialize(node, version=0x0488B21E): s += b'\x00' + node.private_key else: s += node.public_key - s += tools.Hash(s)[:4] + s += tools.btc_hash(s)[:4] return tools.b58encode(s) def deserialize(xpub): data = tools.b58decode(xpub, None) - if tools.Hash(data[:-4])[:4] != data[-4:]: + if tools.btc_hash(data[:-4])[:4] != data[-4:]: raise ValueError("Checksum failed") - node = proto.HDNodeType() + node = messages.HDNodeType() node.depth = struct.unpack('>B', data[4:5])[0] node.fingerprint = struct.unpack('>I', data[5:9])[0] node.child_num = struct.unpack('>I', data[9:13])[0] diff --git a/trezorlib/tests/unit_tests/test_ckd_public.py b/trezorlib/tests/unit_tests/test_ckd_public.py index d7f36fb3d0..b6488a7738 100644 --- a/trezorlib/tests/unit_tests/test_ckd_public.py +++ b/trezorlib/tests/unit_tests/test_ckd_public.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -from trezorlib import ckd_public +from ..support import ckd_public def test_ckd_public(): diff --git a/trezorlib/tests/unit_tests/test_cosi.py b/trezorlib/tests/unit_tests/test_cosi.py new file mode 100644 index 0000000000..63d03d4c9c --- /dev/null +++ b/trezorlib/tests/unit_tests/test_cosi.py @@ -0,0 +1,124 @@ +import binascii +import hashlib +import pytest + +from trezorlib import cosi + +# These tests calculate Ed25519 signatures in pure Python. +# In addition to being Python, this is also DJB's proof-of-concept, unoptimized code. +# As a result, it is actually very noticeably slow. On a gen8 Core i5, this takes around 40 seconds. +# To skip the test, run `pytest -m "not slow_cosi"`. + +# Therefore, the tests are skipped by default. +# Run `pytest -m slow_cosi` to explicitly enable. + +pytestmark = pytest.mark.slow_cosi +if "slow_cosi" not in pytest.config.getoption("-m"): + pytestmark = pytest.mark.skip("Skipping slow CoSi tests. 'pytest -m slow_cosi' to run.") + + +RFC8032_VECTORS = ( + ( # test 1 + # privkey + binascii.unhexlify("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"), + # pubkey + binascii.unhexlify("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"), + # message + binascii.unhexlify(""), + # signature + binascii.unhexlify("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155" + "5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"), + ), + ( # test 2 + # privkey + binascii.unhexlify("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb"), + # pubkey + binascii.unhexlify("3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c"), + # message + binascii.unhexlify("72"), + # signature + binascii.unhexlify("92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da" + "085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00"), + ), + ( # test 3 + # privkey + binascii.unhexlify("c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7"), + # pubkey + binascii.unhexlify("fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025"), + # message + binascii.unhexlify("af82"), + # signature + binascii.unhexlify("6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac" + "18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a"), + ), + ( # test SHA(abc) + # privkey + binascii.unhexlify("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"), + # pubkey + binascii.unhexlify("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"), + # message + hashlib.sha512(b"abc").digest(), + # signature + binascii.unhexlify("dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b589" + "09351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704"), + ), +) + +COMBINED_KEY = binascii.unhexlify("283967b1c19ff93d2924cdcba95e586547cafef509ea402963ceefe96ccb44f2") +GLOBAL_COMMIT = binascii.unhexlify("75bd5806c6366e0374a1c6e020c53feb0791d6cc07560d27d8c158f886ecf389") + + +@pytest.mark.parametrize("privkey, pubkey, message, signature", + RFC8032_VECTORS) +def test_single_eddsa_vector(privkey, pubkey, message, signature): + my_pubkey = cosi.pubkey_from_privkey(privkey) + assert my_pubkey == pubkey + try: + cosi.verify(signature, message, pubkey) + except ValueError: + pytest.fail("Signature does not verify.") + + fake_signature = b'\xf1' + signature[1:] + with pytest.raises(ValueError): + cosi.verify(fake_signature, message, pubkey) + + +def test_combine_keys(): + pubkeys = [pubkey for _, pubkey, _, _ in RFC8032_VECTORS] + assert cosi.combine_keys(pubkeys) == COMBINED_KEY + + Rs = [cosi.get_nonce(privkey, message)[1] for privkey, _, message, _ in RFC8032_VECTORS] + assert cosi.combine_keys(Rs) == GLOBAL_COMMIT + + +@pytest.mark.parametrize("keyset", [ + (0,), + (0, 1), + (0, 1, 2), + (0, 1, 2, 3), + (1, 3), +]) +def test_cosi_combination(keyset): + message = hashlib.sha512(b"You all have to sign this.").digest() + selection = [RFC8032_VECTORS[i] for i in keyset] + + # zip(*iterable) turns a list of tuples to a tuple of lists + privkeys, pubkeys, _, _ = zip(*selection) + nonce_pairs = [cosi.get_nonce(pk, message) for pk in privkeys] + nonces, commits = zip(*nonce_pairs) + + # calculate global pubkey and commitment + global_pk = cosi.combine_keys(pubkeys) + global_commit = cosi.combine_keys(commits) + + # generate individual signatures + signatures = [cosi.sign_with_privkey(message, privkey, global_pk, nonce, global_commit) + for privkey, nonce in zip(privkeys, nonces)] + + # combine signatures + global_sig = cosi.combine_sig(global_commit, signatures) + + try: + cosi.verify(global_sig, message, global_pk) + except ValueError: + pytest.fail("Failed to validate global signature") diff --git a/trezorlib/tools.py b/trezorlib/tools.py index 56e409dceb..bb24e9dd63 100644 --- a/trezorlib/tools.py +++ b/trezorlib/tools.py @@ -18,12 +18,27 @@ # along with this library. If not, see . import hashlib -import binascii import struct -import sys +from typing import NewType, List + +from .coins import slip44 + +HARDENED_FLAG = 1 << 31 + +Address = NewType('Address', List[int]) -def Hash(data): +def H_(x: int) -> int: + """ + Shortcut function that "hardens" a number in a BIP44 path. + """ + return x | HARDENED_FLAG + + +def btc_hash(data): + """ + Double-SHA256 hash as used in BTC + """ return hashlib.sha256(hashlib.sha256(data).digest()).digest() @@ -35,7 +50,7 @@ def hash_160(public_key): def hash_160_to_bc_address(h160, address_type): vh160 = struct.pack(' Address: + """ + Convert BIP32 path string to list of uint32 integers with hardened flags. + Several conventions are supported to set the hardened flag: -1, 1', 1h + + e.g.: "0/1h/1" -> [0, 0x80000001, 1] + + :param nstr: path string + :return: list of integers + """ + if not nstr: + return [] + + n = nstr.split('/') + + # m/a/b/c => a/b/c + if n[0] == 'm': + n = n[1:] + + # coin_name/a/b/c => 44'/SLIP44_constant'/a/b/c + if n[0] in slip44: + coin_id = slip44[n[0]] + n[0:1] = ['44h', '{}h'.format(coin_id)] + + def str_to_harden(x: str) -> int: + if x.startswith('-'): + return H_(abs(int(x))) + elif x.endswith(('h', "'")): + return H_(int(x[:-1])) + else: + return int(x) + + try: + return list(str_to_harden(x) for x in n) + except Exception: + raise ValueError('Invalid BIP32 path', nstr) diff --git a/trezorlib/transport/__init__.py b/trezorlib/transport/__init__.py index e6a4bca13e..0aa22a92e9 100644 --- a/trezorlib/transport/__init__.py +++ b/trezorlib/transport/__init__.py @@ -17,6 +17,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import importlib +import logging + +from typing import Iterable, Type, List, Set + +LOG = logging.getLogger(__name__) + class TransportException(Exception): pass @@ -63,54 +70,52 @@ class Transport(object): raise TransportException('{} device not found: {}'.format(cls.PATH_PREFIX, path)) -def all_transports(): - transports = [] - try: - from .bridge import BridgeTransport - transports.append(BridgeTransport) - except: - pass - - try: - from .hid import HidTransport - transports.append(HidTransport) - except: - pass - - try: - from .udp import UdpTransport - transports.append(UdpTransport) - except: - pass - - try: - from .webusb import WebUsbTransport - transports.append(WebUsbTransport) - except: - pass +def all_transports() -> Iterable[Type[Transport]]: + transports = set() # type: Set[Type[Transport]] + for modname in ("bridge", "hid", "udp", "webusb"): + try: + # Import the module and find the Transport class. + # To avoid iterating over every item, the module should assign its Transport class + # to a constant named TRANSPORT. + module = importlib.import_module("." + modname, __name__) + try: + transports.add(getattr(module, "TRANSPORT")) + except AttributeError: + LOG.warning("Skipping broken module {}".format(modname)) + except ImportError as e: + LOG.info("Failed to import module {}: {}".format(modname, e)) return transports -def enumerate_devices(): - return [device - for transport in all_transports() - for device in transport.enumerate()] +def enumerate_devices() -> Iterable[Transport]: + devices = [] # type: List[Transport] + for transport in all_transports(): + try: + found = transport.enumerate() + LOG.info("Enumerating {}: found {} devices".format(transport.__name__, len(found))) + devices.extend(found) + except NotImplementedError: + LOG.error("{} does not implement device enumeration".format(transport.__name__)) + except Exception as e: + LOG.error("Failed to enumerate {}. {}: {}".format(transport.__name__, e.__class__.__name__, e)) + return devices -def get_transport(path=None, prefix_search=False): +def get_transport(path: str = None, prefix_search: bool = False) -> Transport: if path is None: try: - return enumerate_devices()[0] + return next(iter(enumerate_devices())) except IndexError: raise Exception("No TREZOR device found") from None # Find whether B is prefix of A (transport name is part of the path) # or A is prefix of B (path is a prefix, or a name, of transport). # This naively expects that no two transports have a common prefix. - def match_prefix(a, b): + def match_prefix(a: str, b: str) -> bool: return a.startswith(b) or b.startswith(a) + LOG.info("looking for device by {}: {}".format("prefix" if prefix_search else "full path", path)) transports = [t for t in all_transports() if match_prefix(path, t.PATH_PREFIX)] if transports: return transports[0].find_by_path(path, prefix_search=prefix_search) diff --git a/trezorlib/transport/bridge.py b/trezorlib/transport/bridge.py index cb38ec64ff..4b20780abe 100644 --- a/trezorlib/transport/bridge.py +++ b/trezorlib/transport/bridge.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . +import logging import requests import binascii from io import BytesIO @@ -27,6 +28,8 @@ from .. import messages from .. import protobuf from . import Transport, TransportException +LOG = logging.getLogger(__name__) + TREZORD_HOST = 'http://127.0.0.1:21325' @@ -78,6 +81,8 @@ class BridgeTransport(Transport): self.session = None def write(self, msg): + LOG.debug("sending message: {}".format(msg.__class__.__name__), + extra={'protobuf': msg}) data = BytesIO() protobuf.dump_message(data, msg) ser = data.getvalue() @@ -97,5 +102,10 @@ class BridgeTransport(Transport): (msg_type, datalen) = struct.unpack('>HL', data[:headerlen]) data = BytesIO(data[headerlen:headerlen + datalen]) msg = protobuf.load_message(data, mapping.get_class(msg_type)) + LOG.debug("received message: {}".format(msg.__class__.__name__), + extra={'protobuf': msg}) self.response = None return msg + + +TRANSPORT = BridgeTransport diff --git a/trezorlib/transport/hid.py b/trezorlib/transport/hid.py index 9a47354ab8..991998a826 100644 --- a/trezorlib/transport/hid.py +++ b/trezorlib/transport/hid.py @@ -180,3 +180,6 @@ def is_wirelink(dev): def is_debuglink(dev): return (dev['usage_page'] == 0xFF01 or dev['interface_number'] == 1) + + +TRANSPORT = HidTransport diff --git a/trezorlib/transport/udp.py b/trezorlib/transport/udp.py index ffcfb250f6..631cd0a18e 100644 --- a/trezorlib/transport/udp.py +++ b/trezorlib/transport/udp.py @@ -124,3 +124,6 @@ class UdpTransport(Transport): if len(chunk) != 64: raise TransportException('Unexpected chunk size: %d' % len(chunk)) return bytearray(chunk) + + +TRANSPORT = UdpTransport diff --git a/trezorlib/transport/webusb.py b/trezorlib/transport/webusb.py index b9782f748d..81ea75a713 100644 --- a/trezorlib/transport/webusb.py +++ b/trezorlib/transport/webusb.py @@ -188,3 +188,6 @@ def is_vendor_class(dev): def dev_to_str(dev): return ':'.join(str(x) for x in ['%03i' % (dev.getBusNumber(), )] + dev.getPortNumberList()) + + +TRANSPORT = WebUsbTransport diff --git a/trigger-travis.sh b/trigger-travis.sh index 12a2ff6b24..51d47063b3 100755 --- a/trigger-travis.sh +++ b/trigger-travis.sh @@ -9,6 +9,11 @@ if [ "$TRAVIS_REPO_SLUG" != "$SOURCE" ]; then exit 0; fi +if [ "$TRAVIS_BRANCH" != "master" ]; then + echo "not triggering from non-master branch" + exit 0; +fi + if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then echo "not triggering from pull requests" exit 0;