mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-27 16:48:09 +00:00
Merge branch 'matejcik/refactor'
This commit is contained in:
commit
279da34864
6
.flake8
6
.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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
94
trezorctl
94
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)
|
||||
|
||||
|
@ -1,19 +1,21 @@
|
||||
# orignal version downloaded from https://ed25519.cr.yp.to/python/ed25519.py
|
||||
# modified for Python 3 by Jochen Hoenicke <hoenicke@gmail.com>
|
||||
|
||||
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:
|
@ -17,8 +17,8 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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)
|
||||
|
72
trezorlib/cosi.py
Normal file
72
trezorlib/cosi.py
Normal file
@ -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))
|
@ -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):
|
||||
|
@ -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')
|
34
trezorlib/log.py
Normal file
34
trezorlib/log.py
Normal file
@ -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)
|
@ -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)
|
||||
)
|
||||
|
@ -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:]
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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__))
|
||||
|
@ -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", [])
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
from trezorlib import messages
|
||||
|
||||
|
@ -15,11 +15,10 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from .common import *
|
||||
import time
|
||||
import pytest
|
||||
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
class TestBip32Speed(TrezorTest):
|
||||
|
@ -16,10 +16,13 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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)
|
||||
|
@ -15,9 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
|
||||
from .common import TrezorTest
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
import time
|
||||
from trezorlib import messages as proto
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
@ -15,8 +15,10 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import hexlify, unhexlify
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
class TestMsgCipherkeyvalue(TrezorTest):
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
@ -15,9 +15,10 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import hexlify
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
@pytest.mark.ethereum
|
||||
|
@ -14,8 +14,10 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import hexlify
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
@pytest.mark.ethereum
|
||||
|
@ -15,9 +15,10 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import unhexlify, hexlify
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
||||
|
@ -14,8 +14,11 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import unhexlify
|
||||
|
||||
from .common import *
|
||||
import pytest
|
||||
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
@pytest.mark.ethereum
|
||||
|
@ -16,9 +16,13 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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()
|
||||
|
@ -15,23 +15,24 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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'
|
||||
|
@ -15,23 +15,24 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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'
|
||||
|
@ -16,8 +16,8 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import unhexlify
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
||||
|
@ -16,10 +16,9 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import math
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
import trezorlib.messages as proto
|
||||
|
||||
|
@ -16,8 +16,8 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .common import *
|
||||
import trezorlib.ckd_public as bip32
|
||||
from .common import TrezorTest
|
||||
from ..support import ckd_public as bip32
|
||||
|
||||
|
||||
class TestMsgGetpublickey(TrezorTest):
|
||||
|
@ -16,8 +16,10 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .common import *
|
||||
import trezorlib.ckd_public as bip32
|
||||
from binascii import hexlify
|
||||
import pytest
|
||||
|
||||
from .common import TrezorTest
|
||||
from trezorlib.client import CallException
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
@pytest.mark.skip_t2
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
@pytest.mark.skip_t2
|
||||
|
@ -15,7 +15,10 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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"
|
||||
|
@ -15,8 +15,12 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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,
|
||||
|
@ -15,11 +15,14 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
|
@ -15,7 +15,11 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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,
|
||||
|
@ -15,9 +15,13 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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,
|
||||
|
@ -15,10 +15,14 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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,
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
@ -16,9 +16,9 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
||||
|
@ -16,11 +16,12 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import time
|
||||
|
||||
from .common import *
|
||||
import pytest
|
||||
|
||||
from .common import TrezorTest
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest, generate_entropy
|
||||
|
||||
from trezorlib import messages as proto
|
||||
from mnemonic import Mnemonic
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest, generate_entropy
|
||||
from trezorlib import messages as proto
|
||||
from mnemonic import Mnemonic
|
||||
|
||||
|
@ -17,8 +17,9 @@
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import time
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest, generate_entropy
|
||||
|
||||
from trezorlib import messages as proto
|
||||
from mnemonic import Mnemonic
|
||||
|
@ -16,10 +16,11 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import hexlify
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
class TestMsgSignmessage(TrezorTest):
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import hexlify
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
||||
|
@ -15,8 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import hexlify
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -15,11 +15,16 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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,
|
||||
|
@ -16,11 +16,15 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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,
|
||||
|
@ -15,10 +15,14 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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,
|
||||
|
@ -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:
|
||||
|
@ -15,11 +15,13 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
|
@ -15,12 +15,14 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
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,
|
||||
|
@ -12,11 +12,12 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
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'
|
||||
|
@ -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=='
|
||||
|
@ -15,9 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import unhexlify
|
||||
|
||||
from .common import *
|
||||
import base64
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
class TestMsgVerifymessage(TrezorTest):
|
||||
|
@ -15,9 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import unhexlify
|
||||
|
||||
from .common import *
|
||||
import base64
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
class TestMsgVerifymessageSegwit(TrezorTest):
|
||||
|
@ -15,9 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import unhexlify
|
||||
|
||||
from .common import *
|
||||
import base64
|
||||
from .common import TrezorTest
|
||||
|
||||
|
||||
class TestMsgVerifymessageSegwitNative(TrezorTest):
|
||||
|
@ -16,7 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
@ -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')
|
||||
|
||||
|
||||
|
@ -16,10 +16,13 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
)
|
||||
|
@ -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
|
||||
|
||||
|
@ -16,10 +16,10 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
|
||||
|
@ -15,8 +15,10 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import unhexlify
|
||||
import pytest
|
||||
|
||||
from .common import *
|
||||
from .common import TrezorTest
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
||||
|
@ -15,12 +15,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
from binascii import unhexlify
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
from .common import *
|
||||
|
||||
from .common import TrezorTest
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
||||
|
0
trezorlib/tests/support/__init__.py
Normal file
0
trezorlib/tests/support/__init__.py
Normal file
@ -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]
|
@ -16,7 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from trezorlib import ckd_public
|
||||
from ..support import ckd_public
|
||||
|
||||
|
||||
def test_ckd_public():
|
||||
|
124
trezorlib/tests/unit_tests/test_cosi.py
Normal file
124
trezorlib/tests/unit_tests/test_cosi.py
Normal file
@ -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")
|
@ -18,12 +18,27 @@
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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('<B', address_type) + h160
|
||||
h = Hash(vh160)
|
||||
h = btc_hash(vh160)
|
||||
addr = vh160 + h[0:4]
|
||||
return b58encode(addr)
|
||||
|
||||
@ -109,3 +124,41 @@ def b58decode(v, length):
|
||||
return None
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def parse_path(nstr: str) -> 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)
|
||||
|
@ -17,6 +17,13 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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)
|
||||
|
@ -17,6 +17,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
|
@ -180,3 +180,6 @@ def is_wirelink(dev):
|
||||
|
||||
def is_debuglink(dev):
|
||||
return (dev['usage_page'] == 0xFF01 or dev['interface_number'] == 1)
|
||||
|
||||
|
||||
TRANSPORT = HidTransport
|
||||
|
@ -124,3 +124,6 @@ class UdpTransport(Transport):
|
||||
if len(chunk) != 64:
|
||||
raise TransportException('Unexpected chunk size: %d' % len(chunk))
|
||||
return bytearray(chunk)
|
||||
|
||||
|
||||
TRANSPORT = UdpTransport
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user