1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-23 07:58:09 +00:00

Merge remote-tracking branch 'upstream/master' into stellar

This commit is contained in:
ZuluCrypto 2018-04-28 12:47:59 -06:00
commit 200b5a71df
No known key found for this signature in database
GPG Key ID: 0D1266F87C28A2E1
65 changed files with 2193 additions and 353 deletions

View File

@ -1,17 +1,13 @@
[flake8]
filename =
*.py,
trezorctl
./trezorctl
exclude =
.tox/,
build/,
dist/,
trezorlib/*_pb2.py
vendor/,
ignore =
# F821 undefined name 'unicode'
F821,
# F841 local variable is assigned to but never used
F841,
# F401: module imported but unused
F401,
# F403: used import *

3
.gitignore vendored
View File

@ -14,3 +14,6 @@ docs/_build
docs/.docs-build-environment
.tox/
.cache/
.pytest_cache/
trezorlib/coins.json

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "vendor/trezor-common"]
path = vendor/trezor-common
url = https://github.com/trezor/trezor-common.git

View File

@ -14,6 +14,10 @@ addons:
- libudev-dev
- libusb-1.0-0-dev
env:
global:
PROTOBUF_VERSION=3.4.0
python:
- "3.3"
- "3.4"
@ -23,14 +27,20 @@ python:
install:
# Optimisation: build requirements as wheels, which get cached by Travis
- pip install "pip>=7.0" wheel
- pip install "setuptools>=19.0"
- pip install "setuptools>=38"
- pip install tox-travis
- pip install flake8
# protobuf-related dependencies
- curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip"
- unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d protoc
- export PATH="$(pwd)/protoc/bin:$PATH"
- pip install "protobuf == ${PROTOBUF_VERSION}"
script:
# check that generated protobuf messages are identical to in-tree ones
- ./tools/build_protobuf messages.tmp && diff -ur messages.tmp trezorlib/messages && rm -r messages.tmp
- python setup.py install
- flake8
- flake8 trezorctl
- tox
notifications:

View File

@ -1,3 +1,6 @@
recursive-include bash_completion.d *.sh
include tools/*
include trezorlib/tests/txcache/*.json
include vendor/trezor-common/coins.json
include vendor/trezor-common/protob/*.proto
include COPYING

View File

@ -77,3 +77,23 @@ Example: your PIN is **1234** and TREZOR is displaying the following:
=== === ===
You have to enter: **3795**
Contributing
------------
Python-trezor pulls coins info and protobuf messages from `trezor-common <https://github.com/trezor/trezor-common>`_ repository. If you are
developing new features for Trezor, you will want to start there. Once your changes are accepted to ``trezor-common``, you can make a PR
against this repository. Don't forget to update the submodule with:
.. code::
git submodule update --init --remote
Then, rebuild the protobuf messages and get ``coins.json`` by running:
.. code::
python3 setup.py prebuild
To get support for BTC-like coins, these steps are enough and no further changes to the library are necessary.

View File

@ -1,5 +1,10 @@
#!/usr/bin/env python3
from setuptools import setup
import os.path
import shutil
import subprocess
from setuptools import setup, Command
from setuptools.command.build_py import build_py
install_requires = [
'setuptools>=19.0',
@ -24,6 +29,44 @@ else:
from trezorlib import __version__ as VERSION
class PrebuildCommand(Command):
description = 'update vendored files (coins.json, protobuf messages)'
user_options = []
TREZOR_COMMON = os.path.join('vendor', 'trezor-common')
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
# check for existence of the submodule directory
coins_json = os.path.join(self.TREZOR_COMMON, 'coins.json')
if not os.path.exists(coins_json):
raise Exception('trezor-common submodule seems to be missing.\n' +
'Use "git submodule update --init" to retrieve it.')
# copy coins.json to the tree
shutil.copy(coins_json, 'trezorlib')
# regenerate messages
try:
subprocess.check_call(os.path.join(os.getcwd(), 'tools', 'build_protobuf'))
except Exception as e:
print(e)
print("Generating protobuf failed. Maybe you don't have 'protoc', or maybe you are on Windows?")
print("Using pre-generated files.")
class CustomBuild(build_py):
def run(self):
self.run_command('prebuild')
super().run()
setup(
name='trezor',
version=VERSION,
@ -39,6 +82,9 @@ setup(
'trezorlib.tests.device_tests',
'trezorlib.tests.unit_tests',
],
package_data={
'trezorlib': ['coins.json'],
},
scripts=['trezorctl'],
install_requires=install_requires,
python_requires='>=3.3',
@ -51,4 +97,8 @@ setup(
'Operating System :: MacOS :: MacOS X',
'Programming Language :: Python :: 3 :: Only',
],
cmdclass={
'prebuild': PrebuildCommand,
'build_py': CustomBuild,
},
)

View File

@ -1,32 +1,52 @@
#!/bin/bash
set -e
if [ -n "$1" ]; then
OUTDIR=`readlink -f "$1"`
fi
cd "$(dirname "$0")"
GENPATH="../trezorlib/messages"
INDEX="$GENPATH/__init__.py"
PROTO_PATH="../../trezor-common/protob"
# set up paths
INDEX="__init__.py"
GENPATH="${OUTDIR:-../trezorlib/messages}"
PROTO_PATH="../vendor/trezor-common/protob"
PROTO_FILES="types messages"
PB2_OUT="pb2"
rm -f "$GENPATH/[A-Z]*.py"
mkdir -p "$GENPATH"
# set up temporary directory & cleanup
TMPDIR=$(mktemp -d)
function cleanup {
rm -r $TMPDIR
}
trap cleanup EXIT
cat > "$INDEX" << EOF
# set up pb2 outdir
PB2_OUT="$TMPDIR/pb2"
mkdir -p "$PB2_OUT"
# compile .proto files to python2 modules using google protobuf library
for file in $PROTO_FILES; do
protoc --python_out="$PB2_OUT" -I/usr/include -I"$PROTO_PATH" "$PROTO_PATH/$file.proto"
done
# create index (__init__.py)
cat > "$TMPDIR/$INDEX" << EOF
# Automatically generated by pb2py
EOF
mkdir -p "$PB2_OUT"
# convert google protobuf library to trezor's internal format
for file in $PROTO_FILES; do
# Compile .proto files to python2 modules using google protobuf library
protoc --python_out="$PB2_OUT" -I/usr/include -I"$PROTO_PATH" "$PROTO_PATH/$file.proto"
./pb2py -P "trezorlib.protobuf" -p "$PB2_OUT" -l "$TMPDIR/$INDEX" "$file" "$TMPDIR"
done
for file in $PROTO_FILES; do
# Convert google protobuf library to trezor's internal format
./pb2py -P "trezorlib.protobuf" -p "$PB2_OUT" -l "$INDEX" "$file" "$GENPATH"
done
# ensure $GENPATH exists and is empty of messages
mkdir -p "$GENPATH"
# only remove messages - there could possibly be other files not starting with capital letter
rm -f "$GENPATH"/[A-Z]*.py
rm -rf "$PB2_OUT"
# move generated files to the destination
# (this assumes $INDEX is *.py, otherwise we'd have to add $INDEX separately)
mv "$TMPDIR"/*.py "$GENPATH"
# the exit trap handles removing the tmp directory

85
tools/deserialize_tx.py Executable file
View File

@ -0,0 +1,85 @@
#!/usr/bin/env python3
import binascii
import os
import sys
try:
import construct as c
except ImportError:
sys.stderr.write("This tool requires Construct. Install it with 'pip install Construct'.\n")
sys.exit(1)
from construct import this, len_
if os.isatty(sys.stdin.fileno()):
tx_hex = input("Enter transaction in hex format: ")
else:
tx_hex = sys.stdin.read().strip()
tx_bin = binascii.unhexlify(tx_hex)
CompactUintStruct = c.Struct(
"base" / c.Int8ul,
"ext" / c.Switch(this.base, {0xfd: c.Int16ul, 0xfe: c.Int32ul, 0xff: c.Int64ul}),
)
class CompactUintAdapter(c.Adapter):
def _encode(self, obj, context, path):
if obj < 0xfd:
return {"base": obj}
if obj < 2 ** 16:
return {"base": 0xfd, "ext": obj}
if obj < 2 ** 32:
return {"base": 0xfe, "ext": obj}
if obj < 2 ** 64:
return {"base": 0xff, "ext": obj}
raise ValueError("Value too big for compact uint")
def _decode(self, obj, context, path):
return obj["ext"] or obj["base"]
class ConstFlag(c.Adapter):
def __init__(self, const):
self.const = const
super().__init__(c.Optional(c.Const(const)))
def _encode(self, obj, context, path):
return self.const if obj else None
def _decode(self, obj, context, path):
return obj is not None
CompactUint = CompactUintAdapter(CompactUintStruct)
TxInput = c.Struct(
"tx" / c.Bytes(32),
"index" / c.Int32ul,
# TODO coinbase tx
"script" / c.Prefixed(CompactUint, c.GreedyBytes),
"sequence" / c.Int32ul,
)
TxOutput = c.Struct(
"value" / c.Int64ul,
"pk_script" / c.Prefixed(CompactUint, c.GreedyBytes),
)
StackItem = c.Prefixed(CompactUint, c.GreedyBytes)
TxInputWitness = c.PrefixedArray(CompactUint, StackItem)
Transaction = c.Struct(
"version" / c.Int32ul,
"segwit" / ConstFlag(b"\x00\x01"),
"inputs" / c.PrefixedArray(CompactUint, TxInput),
"outputs" / c.PrefixedArray(CompactUint, TxOutput),
"witness" / c.If(this.segwit, TxInputWitness[len_(this.inputs)]),
"lock_time" / c.Int32ul,
c.Terminated,
)
print(Transaction.parse(tx_bin))

View File

@ -102,9 +102,9 @@ def main():
data = {'label': label,
'bip32_path': bip32_path,
'password_encrypted_hex': binascii.hexlify(passw_encrypted)}
'password_encrypted_hex': binascii.hexlify(passw_encrypted).decode('ascii')}
json.dump(data, open(passw_file, 'wb'))
json.dump(data, open(passw_file, 'w'))
# Let's load password
data = json.load(open(passw_file, 'r'))

View File

@ -111,7 +111,7 @@ class MyTxApiBitcoin(object):
txser = self.serialize_tx(t)
txhash = tools.Hash(txser)[::-1]
outi = self.inputs.append(
self.inputs.append(
proto_types.TxInputType(
address_n=self.client.expand_path("44'/0'/0'/0/%d" % idx),
script_type=(
@ -178,42 +178,42 @@ def main():
# Get the first address of first BIP44 account
# (should be the same address as shown in wallet.trezor.io)
outputs = [
proto_types.TxOutputType(
amount=0,
script_type=proto_types.PAYTOADDRESS,
address='p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm'
# op_return_data=binascii.unhexlify('2890770995194662774cd192ee383b805e9a066e6a456be037727649228fb7f6')
# address_n=client.expand_path("44'/0'/0'/0/35"),
# address='3PUxV6Cc4udQZQsJhArVUzvvVoKC8ohkAj',
),
# proto_types.TxOutputType(
# amount=0,
# script_type=proto_types.PAYTOOPRETURN,
# op_return_data=binascii.unhexlify('2890770995194662774cd192ee383b805e9a066e6a456be037727649228fb7f6')
# ),
# proto_types.TxOutputType(
# amount= 8120,
# script_type=proto_types.PAYTOADDRESS,
# address_n=client.expand_path("44'/1'/0'/1/0"),
# address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ',
# address='14KRxYgFc7Se8j7MDdrK5PTNv8meq4GivK',
# ),
# proto_types.TxOutputType(
# amount= 18684 - 2000,
# script_type=proto_types.PAYTOADDRESS,
# address_n=client.expand_path("44'/0'/0'/0/7"),
# # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ',
# # address='1s9TSqr3PHZdXGrYws59Uaf5SPqavH43z',
# ),
# proto_types.TxOutputType(
# amount= 1000,
# script_type=proto_types.PAYTOADDRESS,
# # address_n=client.expand_path("44'/0'/0'/0/18"),
# # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ',
# # address='1NcMqUvyWv1K3Zxwmx5sqfj7ZEmPCSdJFM',
# ),
]
# outputs = [
# proto_types.TxOutputType(
# amount=0,
# script_type=proto_types.PAYTOADDRESS,
# address='p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm'
# # op_return_data=binascii.unhexlify('2890770995194662774cd192ee383b805e9a066e6a456be037727649228fb7f6')
# # address_n=client.expand_path("44'/0'/0'/0/35"),
# # address='3PUxV6Cc4udQZQsJhArVUzvvVoKC8ohkAj',
# ),
# proto_types.TxOutputType(
# amount=0,
# script_type=proto_types.PAYTOOPRETURN,
# op_return_data=binascii.unhexlify('2890770995194662774cd192ee383b805e9a066e6a456be037727649228fb7f6')
# ),
# proto_types.TxOutputType(
# amount= 8120,
# script_type=proto_types.PAYTOADDRESS,
# address_n=client.expand_path("44'/1'/0'/1/0"),
# address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ',
# address='14KRxYgFc7Se8j7MDdrK5PTNv8meq4GivK',
# ),
# proto_types.TxOutputType(
# amount= 18684 - 2000,
# script_type=proto_types.PAYTOADDRESS,
# address_n=client.expand_path("44'/0'/0'/0/7"),
# # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ',
# # address='1s9TSqr3PHZdXGrYws59Uaf5SPqavH43z',
# ),
# proto_types.TxOutputType(
# amount= 1000,
# script_type=proto_types.PAYTOADDRESS,
# # address_n=client.expand_path("44'/0'/0'/0/18"),
# # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ',
# # address='1NcMqUvyWv1K3Zxwmx5sqfj7ZEmPCSdJFM',
# ),
# ]
# (signatures, serialized_tx) = client.sign_tx('Testnet', inputs, outputs)
(signatures, serialized_tx) = client.sign_tx('Bitcoin', txstore.get_inputs(), txstore.get_outputs())

116
trezorctl
View File

@ -30,9 +30,9 @@ import sys
from trezorlib.client import TrezorClient, TrezorClientVerbose, CallException, format_protobuf
from trezorlib.transport import get_transport, enumerate_devices, TransportException
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib import protobuf
from trezorlib.coins import coins_txapi
from trezorlib.ckd_public import PRIME_DERIVATION_FLAG
from trezorlib import stellar
@ -88,7 +88,7 @@ def cli(ctx, path, verbose, is_json):
if path is not None:
click.echo("Using path: {}".format(path))
sys.exit(1)
return cls(device)
return cls(transport=device)
ctx.obj = get_device
@ -211,6 +211,23 @@ def set_passphrase_source(connect, source):
return connect().apply_settings(passphrase_source=source)
@cli.command(help='Set auto-lock delay (in seconds).')
@click.argument('delay', type=str)
@click.pass_obj
def set_auto_lock_delay(connect, delay):
value, unit = delay[:-1], delay[-1:]
units = {
's': 1,
'm': 60,
'h': 3600,
}
if unit in units:
seconds = float(value) * units[unit]
else:
seconds = float(delay) # assume seconds if no unit is specified
return connect().apply_settings(auto_lock_delay_ms=int(seconds * 1000))
@cli.command(help='Set device flags.')
@click.argument('flags')
@click.pass_obj
@ -234,7 +251,7 @@ def set_homescreen(connect, filename):
elif filename.endswith('.toif'):
img = open(filename, 'rb').read()
if img[:8] != b'TOIf\x90\x00\x90\x00':
raise CallException(types.Failure_DataError, 'File is not a TOIF file with size of 144x144')
raise CallException(proto.FailureType.DataError, 'File is not a TOIF file with size of 144x144')
else:
from PIL import Image
im = Image.open(filename)
@ -471,11 +488,11 @@ def get_public_node(connect, coin, address, curve, show_display):
@click.pass_obj
def sign_tx(connect, coin):
client = connect()
if coin in coins_txapi:
txapi = coins_txapi[coin]
if coin in coins.tx_api:
txapi = coins.tx_api[coin]
else:
click.echo('Coin "%s" is not recognized.' % coin, err=True)
click.echo('Supported coin types: %s' % ', '.join(coins_txapi.keys()), err=True)
click.echo('Supported coin types: %s' % ', '.join(coins.tx_api.keys()), err=True)
sys.exit(1)
client.set_tx_api(txapi)
@ -705,9 +722,10 @@ def ethereum_get_address(connect, address, show_display):
@click.option('-i', '--nonce', type=int, help='Transaction counter - Required for offline signing')
@click.option('-d', '--data', default='', help='Data as hex string, e.g. 0x12345678')
@click.option('-p', '--publish', is_flag=True, help='Publish transaction via RPC')
@click.option('-x', '--tx-type', type=int, help='TX type (used only for Wanchain)')
@click.argument('to')
@click.pass_obj
def ethereum_sign_tx(connect, host, chain_id, address, value, gas_limit, gas_price, nonce, data, publish, to):
def ethereum_sign_tx(connect, host, chain_id, address, value, gas_limit, gas_price, nonce, data, publish, to, tx_type):
from ethjsonrpc import EthJsonRpc
import rlp
@ -759,7 +777,7 @@ def ethereum_sign_tx(connect, host, chain_id, address, value, gas_limit, gas_pri
address_n = client.expand_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:
if gas_price is None or gas_limit is None or nonce is None or publish:
host, port = host.split(':')
eth = EthJsonRpc(host, int(port))
@ -782,6 +800,7 @@ def ethereum_sign_tx(connect, host, chain_id, address, value, gas_limit, gas_pri
sig = client.ethereum_sign_tx(
n=address_n,
tx_type=tx_type,
nonce=nonce,
gas_price=gas_price,
gas_limit=gas_limit,
@ -790,8 +809,12 @@ def ethereum_sign_tx(connect, host, chain_id, address, value, gas_limit, gas_pri
data=data,
chain_id=chain_id)
transaction = rlp.encode(
(nonce, gas_price, gas_limit, to_address, value, data) + sig)
if tx_type is None:
transaction = rlp.encode(
(nonce, gas_price, gas_limit, to_address, value, data) + sig)
else:
transaction = rlp.encode(
(tx_type, nonce, gas_price, gas_limit, to_address, value, data) + sig)
tx_hex = '0x%s' % binascii.hexlify(transaction).decode()
if publish:
@ -839,6 +862,79 @@ def nem_sign_tx(connect, address, file, broadcast):
return payload
#
# Lisk functions
#
@cli.command(help='Get Lisk address for specified path.')
@click.option('-n', '--address', required=True, help="BIP-32 path, e.g. m/44'/134'/0'/0'")
@click.option('-d', '--show-display', is_flag=True)
@click.pass_obj
def lisk_get_address(connect, address, show_display):
client = connect()
address_n = client.expand_path(address)
return client.lisk_get_address(address_n, show_display)
@cli.command(help='Get Lisk public key for specified path.')
@click.option('-n', '--address', required=True, help="BIP-32 path, e.g. m/44'/134'/0'/0'")
@click.option('-d', '--show-display', is_flag=True)
@click.pass_obj
def lisk_get_public_key(connect, address, show_display):
client = connect()
address_n = client.expand_path(address)
res = client.lisk_get_public_key(address_n, show_display)
output = {
"public_key": binascii.hexlify(res.public_key).decode()
}
return output
@cli.command(help='Sign message with Lisk address.')
@click.option('-n', '--address', required=True, help="BIP-32 path, e.g. m/44'/134'/0'/0'")
@click.argument('message')
@click.pass_obj
def lisk_sign_message(connect, address, message):
client = connect()
address_n = client.expand_path(address)
res = client.lisk_sign_message(address_n, message)
output = {
'message': message,
'address': res.address,
'signature': binascii.hexlify(res.signature).decode()
}
return output
@cli.command(help='Verify message signed with Lisk address.')
@click.argument('pubkey')
@click.argument('signature')
@click.argument('message')
@click.pass_obj
def lisk_verify_message(connect, pubkey, signature, message):
signature = bytes.fromhex(signature)
pubkey = bytes.fromhex(pubkey)
return connect().lisk_verify_message(pubkey, signature, message)
@cli.command(help='Sign Lisk transaction.')
@click.option('-n', '--address', required=True, help="BIP-32 path to signing key, e.g. m/44'/134'/0'/0'")
@click.option('-f', '--file', type=click.File('r'), default='-', help='Transaction in JSON format')
# @click.option('-b', '--broadcast', help='Broadcast Lisk transaction')
@click.pass_obj
def lisk_sign_tx(connect, address, file):
client = connect()
address_n = client.expand_path(address)
transaction = client.lisk_sign_tx(address_n, json.load(file))
payload = {
"signature": binascii.hexlify(transaction.signature).decode()
}
return payload
#
# CoSi functions
#

View File

@ -34,8 +34,8 @@ from . import messages as proto
from . import tools
from . import mapping
from . import nem
from .coins import slip44
from . import stellar
from .coins import coins_slip44
from .debuglink import DebugLink
from .protobuf import MessageType
@ -43,11 +43,6 @@ from .protobuf import MessageType
if sys.version_info.major < 3:
raise Exception("Trezorlib does not support Python 2 anymore.")
# try:
# from PIL import Image
# SCREENSHOT = True
# except:
# SCREENSHOT = False
SCREENSHOT = False
@ -425,6 +420,7 @@ class DebugLinkMixin(object):
def call_raw(self, msg):
if SCREENSHOT and self.debug:
from PIL import Image
layout = self.debug.read_layout()
im = Image.new("RGB", (128, 64))
pix = im.load()
@ -497,8 +493,9 @@ class ProtocolMixin(object):
PRIME_DERIVATION_FLAG = 0x80000000
VENDORS = ('bitcointrezor.com', 'trezor.io')
def __init__(self, *args, **kwargs):
def __init__(self, state=None, *args, **kwargs):
super(ProtocolMixin, self).__init__(*args, **kwargs)
self.state = state
self.init_device()
self.tx_api = None
@ -506,7 +503,10 @@ class ProtocolMixin(object):
self.tx_api = tx_api
def init_device(self):
self.features = expect(proto.Features)(self.call)(proto.Initialize())
init_msg = proto.Initialize()
if self.state is not None:
init_msg.state = self.state
self.features = expect(proto.Features)(self.call)(init_msg)
if str(self.features.vendor) not in self.VENDORS:
raise RuntimeError("Unsupported device")
@ -531,8 +531,8 @@ class ProtocolMixin(object):
n = n[1:]
# coin_name/a/b/c => 44'/SLIP44_constant'/a/b/c
if n[0] in coins_slip44:
n = ["44'", "%d'" % coins_slip44[n[0]]] + n[1:]
if n[0] in slip44:
n = ["44'", "%d'" % slip44[n[0]]] + n[1:]
path = []
for x in n:
@ -573,7 +573,7 @@ class ProtocolMixin(object):
return self.call(proto.EthereumGetAddress(address_n=n, show_display=show_display))
@session
def ethereum_sign_tx(self, n, nonce, gas_price, gas_limit, to, value, data=None, chain_id=None):
def ethereum_sign_tx(self, n, nonce, gas_price, gas_limit, to, value, data=None, chain_id=None, tx_type=None):
def int_to_big_endian(value):
import rlp.utils
if value == 0:
@ -600,6 +600,9 @@ class ProtocolMixin(object):
if chain_id:
msg.chain_id = chain_id
if tx_type is not None:
msg.tx_type = tx_type
response = self.call(msg)
while response.data_length is not None:
@ -625,6 +628,78 @@ class ProtocolMixin(object):
return True
return False
#
# Lisk functions
#
@field('address')
@expect(proto.LiskAddress)
def lisk_get_address(self, n, show_display=False):
n = self._convert_prime(n)
return self.call(proto.LiskGetAddress(address_n=n, show_display=show_display))
@expect(proto.LiskPublicKey)
def lisk_get_public_key(self, n, show_display=False):
n = self._convert_prime(n)
return self.call(proto.LiskGetPublicKey(address_n=n, show_display=show_display))
@expect(proto.LiskMessageSignature)
def lisk_sign_message(self, n, message):
n = self._convert_prime(n)
message = normalize_nfc(message)
return self.call(proto.LiskSignMessage(address_n=n, message=message))
def lisk_verify_message(self, pubkey, signature, message):
message = normalize_nfc(message)
try:
resp = self.call(proto.LiskVerifyMessage(signature=signature, public_key=pubkey, message=message))
except CallException as e:
resp = e
return isinstance(resp, proto.Success)
@expect(proto.LiskSignedTx)
def lisk_sign_tx(self, n, transaction):
n = self._convert_prime(n)
def asset_to_proto(asset):
msg = proto.LiskTransactionAsset()
if "votes" in asset:
msg.votes = asset["votes"]
if "data" in asset:
msg.data = asset["data"]
if "signature" in asset:
msg.signature = proto.LiskSignatureType()
msg.signature.public_key = binascii.unhexlify(asset["signature"]["publicKey"])
if "delegate" in asset:
msg.delegate = proto.LiskDelegateType()
msg.delegate.username = asset["delegate"]["username"]
if "multisignature" in asset:
msg.multisignature = proto.LiskMultisignatureType()
msg.multisignature.min = asset["multisignature"]["min"]
msg.multisignature.life_time = asset["multisignature"]["lifetime"]
msg.multisignature.keys_group = asset["multisignature"]["keysgroup"]
return msg
msg = proto.LiskTransactionCommon()
msg.type = transaction["type"]
msg.fee = int(transaction["fee"]) # Lisk use strings for big numbers (javascript issue)
msg.amount = int(transaction["amount"]) # And we convert it back to number
msg.timestamp = transaction["timestamp"]
if "recipientId" in transaction:
msg.recipient_id = transaction["recipientId"]
if "senderPublicKey" in transaction:
msg.sender_public_key = binascii.unhexlify(transaction["senderPublicKey"])
if "requesterPublicKey" in transaction:
msg.requester_public_key = binascii.unhexlify(transaction["requesterPublicKey"])
if "signature" in transaction:
msg.signature = binascii.unhexlify(transaction["signature"])
msg.asset = asset_to_proto(transaction["asset"])
return self.call(proto.LiskSignTx(address_n=n, transaction=msg))
@field('entropy')
@expect(proto.Entropy)
def get_entropy(self, size):
@ -644,7 +719,7 @@ class ProtocolMixin(object):
@field('message')
@expect(proto.Success)
def apply_settings(self, label=None, language=None, use_passphrase=None, homescreen=None, passphrase_source=None):
def apply_settings(self, label=None, language=None, use_passphrase=None, homescreen=None, passphrase_source=None, auto_lock_delay_ms=None):
settings = proto.ApplySettings()
if label is not None:
settings.label = label
@ -656,6 +731,8 @@ class ProtocolMixin(object):
settings.homescreen = homescreen
if passphrase_source is not None:
settings.passphrase_source = passphrase_source
if auto_lock_delay_ms is not None:
settings.auto_lock_delay_ms = auto_lock_delay_ms
out = self.call(settings)
self.init_device() # Reload Features
@ -801,7 +878,7 @@ class ProtocolMixin(object):
@session
def sign_tx(self, coin_name, inputs, outputs, version=None, lock_time=None, debug_processor=None):
start = time.time()
# start = time.time()
txes = self._prepare_sign_tx(inputs, outputs)
# Prepare and send initial message
@ -1151,12 +1228,15 @@ class ProtocolMixin(object):
class TrezorClient(ProtocolMixin, TextUIMixin, BaseClient):
pass
def __init__(self, transport, *args, **kwargs):
super().__init__(transport=transport, *args, **kwargs)
class TrezorClientVerbose(ProtocolMixin, TextUIMixin, VerboseWireMixin, BaseClient):
pass
def __init__(self, transport, *args, **kwargs):
super().__init__(transport=transport, *args, **kwargs)
class TrezorClientDebugLink(ProtocolMixin, DebugLinkMixin, VerboseWireMixin, BaseClient):
pass
def __init__(self, transport, *args, **kwargs):
super().__init__(transport=transport, *args, **kwargs)

View File

@ -1,31 +1,45 @@
from .tx_api import TxApiBitcoin, TxApiTestnet, TxApiLitecoin, TxApiZcash, TxApiDash, TxApiBcash, TxApiDecredTestnet, TxApiDogecoin, TxApiMonacoin, TxApiBitcoinGold
import os.path
import json
coins_slip44 = {
'Bitcoin': 0,
'Testnet': 1,
'Decred Testnet': 1,
'Litecoin': 2,
'Dogecoin': 3,
'Dash': 5,
'Namecoin': 7,
'Monacoin': 22,
'Decred': 42,
'Ether': 60,
'EtherClassic': 61,
'Zcash': 133,
'Bcash': 145,
'Bitcoin Gold': 156,
}
from .tx_api import TxApiInsight, TxApiBlockCypher
coins_txapi = {
'Bitcoin': TxApiBitcoin,
'Testnet': TxApiTestnet,
'Litecoin': TxApiLitecoin,
'Dash': TxApiDash,
'Zcash': TxApiZcash,
'Bcash': TxApiBcash,
'Decred Testnet': TxApiDecredTestnet,
'Dogecoin': TxApiDogecoin,
'Monacoin': TxApiMonacoin,
'Bitcoin Gold': TxApiBitcoinGold,
}
COINS_JSON = os.path.join(os.path.dirname(__file__), 'coins.json')
def _load_coins_json():
# Load coins.json to local variables
# NOTE: coins.json comes from 'vendor/trezor-common/coins.json',
# which is a git submodule. If you're trying to run trezorlib directly
# from the checkout (or tarball), initialize the submodule with:
# $ git submodule update --init
# and install coins.json with:
# $ python setup.py prebuild
with open(COINS_JSON) as coins_json:
coins_list = json.load(coins_json)
return {coin['coin_name']: coin for coin in coins_list}
def _insight_for_coin(coin):
if not coin['bitcore']:
return None
zcash = coin['coin_name'].lower().startswith('zcash')
network = 'insight_{}'.format(coin['coin_name'].lower().replace(' ', '_'))
url = coin['bitcore'][0] + 'api/'
return TxApiInsight(network=network, url=url, zcash=zcash)
# exported variables
__all__ = ['by_name', 'slip44', 'tx_api']
try:
by_name = _load_coins_json()
except Exception as e:
raise ImportError("Failed to load coins.json. Check your installation.") from e
slip44 = {name: coin['bip44'] for name, coin in by_name.items()}
tx_api = {name: _insight_for_coin(coin)
for name, coin in by_name.items()
if coin["bitcore"]}
# fixup for Dogecoin
tx_api['Dogecoin'] = TxApiBlockCypher(network='blockcypher_dogecoin', url='https://api.blockcypher.com/v1/doge/main/')

View File

@ -0,0 +1,9 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskAddress(p.MessageType):
FIELDS = {
1: ('address', p.UnicodeType, 0),
}
MESSAGE_WIRE_TYPE = 115

View File

@ -0,0 +1,8 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskDelegateType(p.MessageType):
FIELDS = {
1: ('username', p.UnicodeType, 0),
}

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskGetAddress(p.MessageType):
FIELDS = {
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
2: ('show_display', p.BoolType, 0),
}
MESSAGE_WIRE_TYPE = 114

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskGetPublicKey(p.MessageType):
FIELDS = {
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
2: ('show_display', p.BoolType, 0),
}
MESSAGE_WIRE_TYPE = 121

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskMessageSignature(p.MessageType):
FIELDS = {
1: ('address', p.UnicodeType, 0),
2: ('signature', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 119

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskMultisignatureType(p.MessageType):
FIELDS = {
1: ('min', p.UVarintType, 0),
2: ('life_time', p.UVarintType, 0),
3: ('keys_group', p.UnicodeType, p.FLAG_REPEATED),
}

View File

@ -0,0 +1,9 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskPublicKey(p.MessageType):
FIELDS = {
1: ('public_key', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 122

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskSignMessage(p.MessageType):
FIELDS = {
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
2: ('message', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 118

View File

@ -0,0 +1,11 @@
# Automatically generated by pb2py
from .. import protobuf as p
from .LiskTransactionCommon import LiskTransactionCommon
class LiskSignTx(p.MessageType):
FIELDS = {
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
2: ('transaction', LiskTransactionCommon, 0),
}
MESSAGE_WIRE_TYPE = 116

View File

@ -0,0 +1,8 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskSignatureType(p.MessageType):
FIELDS = {
1: ('public_key', p.BytesType, 0),
}

View File

@ -0,0 +1,9 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskSignedTx(p.MessageType):
FIELDS = {
1: ('signature', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 117

View File

@ -0,0 +1,15 @@
# Automatically generated by pb2py
from .. import protobuf as p
from .LiskDelegateType import LiskDelegateType
from .LiskMultisignatureType import LiskMultisignatureType
from .LiskSignatureType import LiskSignatureType
class LiskTransactionAsset(p.MessageType):
FIELDS = {
1: ('signature', LiskSignatureType, 0),
2: ('delegate', LiskDelegateType, 0),
3: ('votes', p.UnicodeType, p.FLAG_REPEATED),
4: ('multisignature', LiskMultisignatureType, 0),
5: ('data', p.UnicodeType, 0),
}

View File

@ -0,0 +1,17 @@
# Automatically generated by pb2py
from .. import protobuf as p
from .LiskTransactionAsset import LiskTransactionAsset
class LiskTransactionCommon(p.MessageType):
FIELDS = {
1: ('type', p.UVarintType, 0),
2: ('amount', p.UVarintType, 0), # default=0
3: ('fee', p.UVarintType, 0),
4: ('recipient_id', p.UnicodeType, 0),
5: ('sender_public_key', p.BytesType, 0),
6: ('requester_public_key', p.BytesType, 0),
7: ('signature', p.BytesType, 0),
8: ('timestamp', p.UVarintType, 0),
9: ('asset', LiskTransactionAsset, 0),
}

View File

@ -0,0 +1,9 @@
# Automatically generated by pb2py
Transfer = 0
RegisterSecondPassphrase = 1
RegisterDelegate = 2
CastVotes = 3
RegisterMultisignatureAccount = 4
CreateDapp = 5
TransferIntoDapp = 6
TransferOutOfDapp = 7

View File

@ -0,0 +1,11 @@
# Automatically generated by pb2py
from .. import protobuf as p
class LiskVerifyMessage(p.MessageType):
FIELDS = {
1: ('signature', p.BytesType, 0),
2: ('public_key', p.BytesType, 0),
3: ('message', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 120

View File

@ -84,6 +84,15 @@ DebugLinkMemoryRead = 110
DebugLinkMemory = 111
DebugLinkMemoryWrite = 112
DebugLinkFlashErase = 113
LiskGetAddress = 114
LiskAddress = 115
LiskSignTx = 116
LiskSignedTx = 117
LiskSignMessage = 118
LiskMessageSignature = 119
LiskVerifyMessage = 120
LiskGetPublicKey = 121
LiskPublicKey = 122
StellarGetPublicKey = 200
StellarPublicKey = 201
StellarSignTx = 202

View File

@ -4,6 +4,11 @@ from .CoinType import CoinType
from .HDNodePathType import HDNodePathType
from .HDNodeType import HDNodeType
from .IdentityType import IdentityType
from .LiskDelegateType import LiskDelegateType
from .LiskMultisignatureType import LiskMultisignatureType
from .LiskSignatureType import LiskSignatureType
from .LiskTransactionAsset import LiskTransactionAsset
from .LiskTransactionCommon import LiskTransactionCommon
from .MultisigRedeemScriptType import MultisigRedeemScriptType
from .NEMAggregateModification import NEMAggregateModification
from .NEMCosignatoryModification import NEMCosignatoryModification
@ -35,6 +40,7 @@ from . import NEMMosaicLevy
from . import NEMSupplyChangeType
from . import NEMModificationType
from . import NEMImportanceTransferMode
from . import LiskTransactionType
from .Address import Address
from .ApplyFlags import ApplyFlags
from .ApplySettings import ApplySettings
@ -87,6 +93,15 @@ from .GetEntropy import GetEntropy
from .GetFeatures import GetFeatures
from .GetPublicKey import GetPublicKey
from .Initialize import Initialize
from .LiskAddress import LiskAddress
from .LiskGetAddress import LiskGetAddress
from .LiskGetPublicKey import LiskGetPublicKey
from .LiskMessageSignature import LiskMessageSignature
from .LiskPublicKey import LiskPublicKey
from .LiskSignMessage import LiskSignMessage
from .LiskSignTx import LiskSignTx
from .LiskSignedTx import LiskSignedTx
from .LiskVerifyMessage import LiskVerifyMessage
from .LoadDevice import LoadDevice
from .MessageSignature import MessageSignature
from .NEMAddress import NEMAddress

View File

@ -2,13 +2,13 @@ import binascii
import json
from . import messages as proto
TYPE_MOSAIC_TRANSFER = 0x0101
TYPE_TRANSACTION_TRANSFER = 0x0101
TYPE_IMPORTANCE_TRANSFER = 0x0801
TYPE_MULTISIG_CHANGE = 0x1001
TYPE_MULTISIG_SIGN = 0x1002
TYPE_MULTISIG_TX = 0x1004
TYPE_AGGREGATE_MODIFICATION = 0x1001
TYPE_MULTISIG_SIGNATURE = 0x1002
TYPE_MULTISIG = 0x1004
TYPE_PROVISION_NAMESPACE = 0x2001
TYPE_MOSAIC_DEFINITION_CREATION = 0x4001
TYPE_MOSAIC_CREATION = 0x4001
TYPE_MOSAIC_SUPPLY_CHANGE = 0x4002
@ -19,7 +19,7 @@ def create_transaction_common(transaction):
msg.fee = transaction["fee"]
msg.deadline = transaction["deadline"]
if "signed" in transaction:
if "signer" in transaction:
msg.signer = binascii.unhexlify(transaction["signer"])
return msg
@ -68,6 +68,7 @@ def create_provision_namespace(transaction):
msg.sink = transaction["rentalFeeSink"]
msg.fee = transaction["rentalFee"]
return msg
def create_mosaic_creation(transaction):
@ -113,27 +114,36 @@ def create_supply_change(transaction):
return msg
def create_importance_transfer(transaction):
msg = proto.NEMImportanceTransfer()
msg.mode = transaction["importanceTransfer"]["mode"]
msg.public_key = binascii.unhexlify(transaction["importanceTransfer"]["publicKey"])
return msg
def create_sign_tx(transaction):
msg = proto.NEMSignTx()
msg.transaction = create_transaction_common(transaction)
msg.cosigning = (transaction["type"] == TYPE_MULTISIG_SIGN)
msg.cosigning = (transaction["type"] == TYPE_MULTISIG_SIGNATURE)
if transaction["type"] in (TYPE_MULTISIG_SIGN, TYPE_MULTISIG_TX):
if transaction["type"] in (TYPE_MULTISIG_SIGNATURE, TYPE_MULTISIG):
transaction = transaction["otherTrans"]
msg.multisig = create_transaction_common(transaction)
elif "otherTrans" in transaction:
raise ValueError("Transaction does not support inner transaction")
if transaction["type"] == TYPE_MOSAIC_TRANSFER:
if transaction["type"] == TYPE_TRANSACTION_TRANSFER:
msg.transfer = create_transfer(transaction)
elif transaction["type"] == TYPE_MULTISIG_CHANGE:
elif transaction["type"] == TYPE_AGGREGATE_MODIFICATION:
msg.aggregate_modification = create_aggregate_modification(transaction)
elif transaction["type"] == TYPE_PROVISION_NAMESPACE:
msg.provision_namespace = create_provision_namespace(transaction)
elif transaction["type"] == TYPE_MOSAIC_DEFINITION_CREATION:
elif transaction["type"] == TYPE_MOSAIC_CREATION:
msg.mosaic_creation = create_mosaic_creation(transaction)
elif transaction["type"] == TYPE_MOSAIC_SUPPLY_CHANGE:
msg.mosaic_supply_change = create_supply_change(transaction)
msg.supply_change = create_supply_change(transaction)
elif transaction["type"] == TYPE_IMPORTANCE_TRANSFER:
msg.importance_transfer = create_importance_transfer(transaction)
else:
raise ValueError("Unknown transaction type")

View File

@ -22,9 +22,10 @@ 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.transport import get_transport
from trezorlib import tx_api
tests_dir = os.path.dirname(os.path.abspath(__file__))
tx_api.cache_dir = os.path.join(tests_dir, '../txcache')
@ -42,7 +43,7 @@ class TrezorTest:
debuglink = wirelink.find_debug()
self.client = TrezorClientDebugLink(wirelink)
self.client.set_debuglink(debuglink)
self.client.set_tx_api(tx_api.TxApiBitcoin)
self.client.set_tx_api(coins.tx_api['Bitcoin'])
# self.client.set_buttonwait(3)
# 1 2 3 4 5 6 7 8 9 10 11 12

View File

@ -0,0 +1,34 @@
import pytest
from . import common
from trezorlib.client import TrezorClient
def device_version():
device = common.get_device()
if not device:
raise RuntimeError()
client = TrezorClient(device)
if client.features.model == "T":
return 2
else:
return 1
try:
TREZOR_VERSION = device_version()
except:
raise
TREZOR_VERSION = None
def pytest_runtest_setup(item):
'''
Called for each test item (class, individual tests).
Ensures that 'skip_t2' tests are skipped on T2
and 'skip_t1' tests are skipped on T1.
'''
if item.get_marker("skip_t2") and TREZOR_VERSION == 2:
pytest.skip("Test excluded on Trezor T")
if item.get_marker("skip_t1") and TREZOR_VERSION == 1:
pytest.skip("Test excluded on Trezor 1")

View File

@ -18,6 +18,7 @@
from .common import *
import time
from trezorlib import messages as proto
@ -96,3 +97,60 @@ class TestMsgApplysettings(TrezorTest):
proto.Success(),
proto.Features()])
self.client.apply_settings(homescreen=img)
@pytest.mark.skip_t2
def test_apply_auto_lock_delay(self):
self.setup_mnemonic_pin_passphrase()
with self.client:
self.client.set_expected_responses([proto.PinMatrixRequest(),
proto.ButtonRequest(),
proto.Success(),
proto.Features()])
self.client.apply_settings(auto_lock_delay_ms=int(10e3)) # 10 secs
time.sleep(0.1) # sleep less than auto-lock delay
with self.client:
# No PIN protection is required.
self.client.set_expected_responses([proto.Success()])
self.client.ping(msg='', pin_protection=True)
time.sleep(10.1) # sleep more than auto-lock delay
with self.client:
self.client.set_expected_responses([proto.PinMatrixRequest(),
proto.Success()])
self.client.ping(msg='', pin_protection=True)
@pytest.mark.skip_t2
def test_apply_minimal_auto_lock_delay(self):
"""
Verify that the delay is not below the minimal auto-lock delay (10 secs)
otherwise the device may auto-lock before any user interaction.
"""
self.setup_mnemonic_pin_passphrase()
with self.client:
self.client.set_expected_responses([proto.PinMatrixRequest(),
proto.ButtonRequest(),
proto.Success(),
proto.Features()])
# Note: the actual delay will be 10 secs (see above).
self.client.apply_settings(auto_lock_delay_ms=int(1e3))
time.sleep(0.1) # sleep less than auto-lock delay
with self.client:
# No PIN protection is required.
self.client.set_expected_responses([proto.Success()])
self.client.ping(msg='', pin_protection=True)
time.sleep(2) # sleep less than the minimal auto-lock delay
with self.client:
# No PIN protection is required.
self.client.set_expected_responses([proto.Success()])
self.client.ping(msg='', pin_protection=True)
time.sleep(10.1) # sleep more than the minimal auto-lock delay
with self.client:
self.client.set_expected_responses([proto.PinMatrixRequest(),
proto.Success()])
self.client.ping(msg='', pin_protection=True)

View File

@ -43,12 +43,14 @@ class TestMsgGetaddress(TrezorTest):
self.setup_mnemonic_nopin_nopassphrase()
assert self.client.get_address('Testnet', [111, 42]) == 'moN6aN6NP1KWgnPSqzrrRPvx2x1UtZJssa'
@pytest.mark.skip_t2
def test_bch(self):
self.setup_mnemonic_allallall()
assert self.client.get_address('Bcash', self.client.expand_path("44'/145'/0'/0/0")) == '1MH9KKcvdCTY44xVDC2k3fjBbX5Cz29N1q'
assert self.client.get_address('Bcash', self.client.expand_path("44'/145'/0'/0/1")) == '1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3'
assert self.client.get_address('Bcash', self.client.expand_path("44'/145'/0'/1/0")) == '1HADRPJpgqBzThepERpVXNi6qRgiLQRNoE'
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'
@pytest.mark.skip_t2
def test_bch_multisig(self):
self.setup_mnemonic_allallall()
xpubs = []
@ -62,8 +64,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)) == '33Ju286QvonBz5N1V754ZekQv4GLJqcc5R'
assert self.client.get_address('Bcash', self.client.expand_path("44'/145'/" + str(nr) + "'/1/0"), show_display=(nr == 1), multisig=getmultisig(1, 0)) == '3CPtPpL5mGAPdxUeUDfm2RNdWoSN9dKpXE'
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'
def test_public_ckd(self):
self.setup_mnemonic_nopin_nopassphrase()

View File

@ -0,0 +1,33 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2012-2016 Marek Palatinus <slush@satoshilabs.com>
# Copyright (C) 2012-2016 Pavol Rusnak <stick@satoshilabs.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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
@pytest.mark.xfail # drop when trezor-core PR #90 is merged
@pytest.mark.skip_t1
class TestMsgLiskGetaddress(TrezorTest):
def test_lisk_getaddress(self):
self.setup_mnemonic_nopin_nopassphrase()
assert self.client.lisk_get_address([2147483692, 2147483782]) == '1431530009238518937L'
assert self.client.lisk_get_address([2147483692, 2147483782, 2147483648]) == '17563781916205589679L'
assert self.client.lisk_get_address([2147483692, 2147483782, 2147483648, 2147483649]) == '1874186517773691964L'
assert self.client.lisk_get_address([2147483692, 2147483782, 2147484647, 2147484647]) == '16295203558710684671L'

View File

@ -0,0 +1,31 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2016-2017 Pavol Rusnak <stick@satoshilabs.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 TrezorTest
@pytest.mark.xfail # drop when trezor-core PR #90 is merged
@pytest.mark.skip_t1
class TestMsgLiskGetPublicKey(TrezorTest):
def test_lisk_get_public_key(self):
self.setup_mnemonic_nopin_nopassphrase()
sig = self.client.lisk_get_public_key([2147483692, 2147483782, 2147483648, 2147483648])
assert hexlify(sig.public_key) == b'eb56d7bbb5e8ea9269405f7a8527fe126023d1db2c973cfac6f760b60ae27294'

View File

@ -0,0 +1,39 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2016-2017 Pavol Rusnak <stick@satoshilabs.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 TrezorTest
@pytest.mark.xfail # drop when trezor-core PR #90 is merged
@pytest.mark.skip_t1
class TestMsgLiskSignmessage(TrezorTest):
def test_sign(self):
self.setup_mnemonic_nopin_nopassphrase()
sig = self.client.lisk_sign_message([2147483692, 2147483782, 2147483648, 2147483648], 'This is an example of a signed message.')
assert sig.address == '7623396847864198749L'
assert hexlify(sig.signature) == b'af1d384cce25354b5af129662caed6f3514c6f1f6a206662d301fd56aa5549aa23c3f82009f213a7a4d9297015c2e5b06584273df7c42d78b4e531fe4d4fc80e'
def test_sign_long(self):
self.setup_mnemonic_nopin_nopassphrase()
sig = self.client.lisk_sign_message([2147483692, 2147483782, 2147483648], 'VeryLongMessage!' * 64)
assert sig.address == '17563781916205589679L'
print(hexlify(sig.signature))
assert hexlify(sig.signature) == b'a675152c2af34e85dbd75740681efb7d67bf910561d6c9d1e075be2f99d9bc544d62c52f6619756b0e329a2f2d82756ced53b4261a028fcee0d37d7e641ef404'

View File

@ -0,0 +1,176 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2012-2016 Marek Palatinus <slush@satoshilabs.com>
# Copyright (C) 2012-2016 Pavol Rusnak <stick@satoshilabs.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 TrezorTest
from trezorlib import messages as proto
PUBLIC_KEY = unhexlify('eb56d7bbb5e8ea9269405f7a8527fe126023d1db2c973cfac6f760b60ae27294')
@pytest.mark.xfail # drop when trezor-core PR #90 is merged
@pytest.mark.skip_t1
class TestMsgLiskSignTx(TrezorTest):
def test_lisk_sign_tx_send(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
proto.LiskSignedTx(
signature=unhexlify('b62717d581e5713bca60b758b661e6cfa091addc6caedd57534e06cda805943ee80797b9fb9a1e1b2bd584e292d2a7f832a4d1b3f15f00e1ee1b72de7e195a08')
)
])
self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), {
"amount": "10000000",
"recipientId": "9971262264659915921L",
"timestamp": 57525937,
"type": 0,
"fee": "10000000",
"asset": {}
})
def test_lisk_sign_tx_send_with_data(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
proto.LiskSignedTx(
signature=unhexlify('5dd0dbb87ee46f3e985b1ef2df85cb0bec481e8601d150388f73e198cdd57a698eab076c7cd5b281fbb6a83dd3dc64d91a6eccd1614dffd46f101194ffa3a004')
)
])
self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), {
"amount": "10000000",
"recipientId": "9971262264659915921L",
"timestamp": 57525937,
"type": 0,
"fee": "20000000",
"asset": {
"data": "Test data"
}
})
def test_lisk_sign_tx_second_signature(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
proto.ButtonRequest(code=proto.ButtonRequestType.PublicKey),
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
proto.LiskSignedTx(
signature=unhexlify('f02bdc40a7599c21d29db4080ff1ff8934f76eedf5b0c4fa695c8a64af2f0b40a5c4f92db203863eebbbfad8f0611a23f451ed8bb711490234cdfb034728fd01')
)
])
self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), {
"amount": "0",
"timestamp": 57525937,
"type": 1,
"fee": "500000000",
"asset": {
"signature": {
"publicKey": "5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09"
}
}
})
def test_lisk_sign_tx_delegate_registration(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
proto.LiskSignedTx(
signature=unhexlify('5ac02b2882b9d7d0f944e48baadc27de1296cc08c3533f7c8e380fbbb9fb4a6ac81b5dc57060d7d8c68912eea24eb6e39024801bccc0d55020e2052b0c2bb701')
)
])
self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), {
"amount": "0",
"timestamp": 57525937,
"type": 2,
"fee": "2500000000",
"asset": {
"delegate": {
"username": "trezor_t"
}
}
})
def test_lisk_sign_tx_cast_votes(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
proto.LiskSignedTx(
signature=unhexlify('1d0599a8387edaa4a6d309b8a78accd1ceaff20ff9d87136b01cba0efbcb9781c13dc2b0bab5a1ea4f196d8dcc9dbdbd2d56dbffcc088fc77686b2e2c2fe560f')
)
])
self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), {
"amount": "0",
"timestamp": 57525937,
"type": 3,
"fee": "100000000",
"asset": {
"votes": [
"+b002f58531c074c7190714523eec08c48db8c7cfc0c943097db1a2e82ed87f84",
"-ec111c8ad482445cfe83d811a7edd1f1d2765079c99d7d958cca1354740b7614"
]
}
})
def test_lisk_sign_tx_multisignature(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
proto.LiskSignedTx(
signature=unhexlify('88923866c2d500a6927715699ab41a0f58ea4b52e552d90e923bc24ac9da240f2328c93f9ce043a1da4937d4b61c7f57c02fc931f9824d06b24731e7be23c506')
)
])
self.client.lisk_sign_tx(self.client.expand_path("m/44'/134'/0'/0'"), {
"amount": "0",
"timestamp": 57525937,
"type": 4,
"fee": "1500000000",
"asset": {
"multisignature": {
"min": 2,
"lifetime": 5,
"keysgroup": [
"+5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09",
"+922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa"
]
}
}
})

View File

@ -0,0 +1,55 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2016-2017 Pavol Rusnak <stick@satoshilabs.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 TrezorTest
from trezorlib import messages as proto
@pytest.mark.xfail # drop when trezor-core PR #90 is merged
@pytest.mark.skip_t1
class TestMsgLiskVerifymessage(TrezorTest):
def test_verify(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
proto.ButtonRequest(code=proto.ButtonRequestType.Other),
proto.ButtonRequest(code=proto.ButtonRequestType.Other),
proto.Success(message='Message verified')
])
self.client.lisk_verify_message(
unhexlify('eb56d7bbb5e8ea9269405f7a8527fe126023d1db2c973cfac6f760b60ae27294'),
unhexlify('af1d384cce25354b5af129662caed6f3514c6f1f6a206662d301fd56aa5549aa23c3f82009f213a7a4d9297015c2e5b06584273df7c42d78b4e531fe4d4fc80e'),
'This is an example of a signed message.'
)
def test_verify_long(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
proto.ButtonRequest(code=proto.ButtonRequestType.Other),
proto.ButtonRequest(code=proto.ButtonRequestType.Other),
proto.Success(message='Message verified')
])
self.client.lisk_verify_message(
unhexlify('eb56d7bbb5e8ea9269405f7a8527fe126023d1db2c973cfac6f760b60ae27294'),
unhexlify('7b4b481f6a07a874bdd1b590cd2b933c8b571c721484d9dc303f81b22d1f3c5f55ffe0704dbfd543ff9ea3e795facda871ddb422522257d33a8fe16ab4169601'),
'VeryLongMessage!' * 64
)

View File

@ -18,7 +18,7 @@
from .common import *
@pytest.mark.skip_t2
@pytest.mark.xfail # to be removed when nem is merged
class TestMsgNEMGetaddress(TrezorTest):
def test_nem_getaddress(self):

View File

@ -1,139 +0,0 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2017 Saleem Rashid <trezor@saleemrashid.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 trezorlib import messages as proto
# assertion data from T1
@pytest.mark.skip_t2
class TestMsgNEMSigntx(TrezorTest):
def test_nem_signtx_simple(self):
# tx hash: 209368053ac61969b6838ceb7e31badeb622ed6aa42d6c58365c42ad1a11e19d
signature = unhexlify(
"9cda2045324d05c791a4fc312ecceb62954e7740482f8df8928560d63cf273dea595023640179f112de755c79717757ef76962175378d6d87360ddb3f3e5f70f"
)
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
# Confirm transfer and network fee
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
# Unencrypted message
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
# Confirm recipient
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.NEMSignedTx(signature=signature),
])
tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), {
"timeStamp": 74649215,
"amount": 2000000,
"fee": 2000000,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"type": 257,
"deadline": 74735615,
"message": {
"payload": hexlify(b"test_nem_transaction_transfer"),
"type": 1,
},
"version": (0x98 << 24),
})
assert hexlify(tx.data) == b'01010000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f74042800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324a80841e000000000025000000010000001d000000746573745f6e656d5f7472616e73616374696f6e5f7472616e73666572'
assert tx.signature == signature
def test_nem_signtx_encrypted_payload(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
# Confirm transfer and network fee
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
# Ask for encryption
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
# Confirm recipient
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.NEMSignedTx(),
])
tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), {
"timeStamp": 74649215,
"amount": 2000000,
"fee": 2000000,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"type": 257,
"deadline": 74735615,
"message": {
# plain text is 32B long => cipher text is 48B
# as per PKCS#7 another block containing padding is added
"payload": hexlify(b"this message should be encrypted"),
"publicKey": "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541",
"type": 2,
},
"version": (0x98 << 24),
})
assert hexlify(tx.data[:124]) == b'01010000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f74042800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324a80841e0000000000680000000200000060000000'
# after 124th byte comes iv (16B) salt (32B) and encrypted payload (48B)
assert len(tx.data[124:]) == 16 + 32 + 48
# because IV and salt are random (therefore the encrypted payload as well) those data can't be asserted
assert len(tx.signature) == 64
def test_nem_signtx_xem_as_mosaic(self):
# tx hash: 9f8741194576a090bc71a3f43a03855950f94278fa121e99203e45967e19a7d0
signature = unhexlify(
"1bca7b1b9ffb16d2c2adffa665be072bd2d7a0eafe4a9911dc473500c272905edf3d626274deb52aa490137a276d1fca67ee487079ebf9c09f9faa414f8e7c02"
)
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
# Confirm transfer and network fee
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
# Confirm recipient
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.NEMSignedTx(signature=signature),
])
tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), {
"timeStamp": 76809215,
"amount": 1000000,
"fee": 1000000,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"type": 257,
"deadline": 76895615,
"version": (0x98 << 24),
"message": {
},
"mosaics": [
{
"mosaicId": {
"namespaceId": "nem",
"name": "xem",
},
"quantity": 1000000,
},
],
})
assert hexlify(tx.data) == b'0101000002000098ff03940420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208440420f00000000007f5595042800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324a40420f000000000000000000010000001a0000000e000000030000006e656d0300000078656d40420f0000000000'
assert tx.signature == signature

View File

@ -0,0 +1,171 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2017 Saleem Rashid <trezor@saleemrashid.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 trezorlib import nem
# assertion data from T1
@pytest.mark.skip_t2
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'"), {
"timeStamp": 74649215,
"fee": 2000000,
"type": nem.TYPE_MOSAIC_SUPPLY_CHANGE,
"deadline": 74735615,
"message": {
},
"mosaicId": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
"supplyType": 1,
"delta": 1,
"version": (0x98 << 24),
"creationFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"creationFee": 1500,
})
assert hexlify(tx.data) == b'02400000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f74041a0000000600000068656c6c6f6d0c00000048656c6c6f206d6f73616963010000000100000000000000'
assert hexlify(tx.signature) == b'928b03c4a69fff35ecf0912066ea705895b3028fad141197d7ea2b56f1eef2a2516455e6f35d318f6fa39e2bb40492ac4ae603260790f7ebc7ea69feb4ca4c0a'
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'"), {
"timeStamp": 74649215,
"fee": 2000000,
"type": nem.TYPE_MOSAIC_CREATION,
"deadline": 74735615,
"message": {
},
"mosaicDefinition": {
"id": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
"levy": {},
"properties": {},
"description": "lorem"
},
"version": (0x98 << 24),
"creationFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"creationFee": 1500,
})
assert hexlify(tx.data) == b'01400000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f7404c100000020000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b40620841a0000000600000068656c6c6f6d0c00000048656c6c6f206d6f73616963050000006c6f72656d04000000150000000c00000064697669736962696c6974790100000030160000000d000000696e697469616c537570706c7901000000301a0000000d000000737570706c794d757461626c650500000066616c7365190000000c0000007472616e7366657261626c650500000066616c7365000000002800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324adc05000000000000'
assert hexlify(tx.signature) == b'537adf4fd9bd5b46e204b2db0a435257a951ed26008305e0aa9e1201dafa4c306d7601a8dbacabf36b5137724386124958d53202015ab31fb3d0849dfed2df0e'
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'"), {
"timeStamp": 74649215,
"fee": 2000000,
"type": nem.TYPE_MOSAIC_CREATION,
"deadline": 74735615,
"message": {
},
"mosaicDefinition": {
"id": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
"levy": {},
"properties": [
{
"name": "divisibility",
"value": "4"
},
{
"name": "initialSupply",
"value": "200"
},
{
"name": "supplyMutable",
"value": "false"
},
{
"name": "transferable",
"value": "true"
}
],
"description": "lorem"
},
"version": (0x98 << 24),
"creationFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"creationFee": 1500,
})
assert hexlify(tx.data) == b'01400000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f7404c200000020000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b40620841a0000000600000068656c6c6f6d0c00000048656c6c6f206d6f73616963050000006c6f72656d04000000150000000c00000064697669736962696c6974790100000034180000000d000000696e697469616c537570706c79030000003230301a0000000d000000737570706c794d757461626c650500000066616c7365180000000c0000007472616e7366657261626c650400000074727565000000002800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324adc05000000000000'
assert hexlify(tx.signature) == b'f17c859710060f2ea9a0ab740ef427431cf36bdc7d263570ca282bd66032e9f5737a921be9839429732e663be2bb74ccc16f34f5157ff2ef00a65796b54e800e'
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'"), {
"timeStamp": 74649215,
"fee": 2000000,
"type": nem.TYPE_MOSAIC_CREATION,
"deadline": 74735615,
"message": {
},
"mosaicDefinition": {
"id": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
"properties": [
{
"name": "divisibility",
"value": "4"
},
{
"name": "initialSupply",
"value": "200"
},
{
"name": "supplyMutable",
"value": "false"
},
{
"name": "transferable",
"value": "true"
}
],
"levy": {
"type": 1,
"fee": 2,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"mosaicId": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
},
"description": "lorem"
},
"version": (0x98 << 24),
"creationFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"creationFee": 1500,
})
assert hexlify(tx.data) == b'01400000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f74041801000020000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b40620841a0000000600000068656c6c6f6d0c00000048656c6c6f206d6f73616963050000006c6f72656d04000000150000000c00000064697669736962696c6974790100000034180000000d000000696e697469616c537570706c79030000003230301a0000000d000000737570706c794d757461626c650500000066616c7365180000000c0000007472616e7366657261626c65040000007472756556000000010000002800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324a1a0000000600000068656c6c6f6d0c00000048656c6c6f206d6f7361696302000000000000002800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324adc05000000000000'
assert hexlify(tx.signature) == b'b87aac1ddf146d35e6a7f3451f57e2fe504ac559031e010a51261257c37bd50fcfa7b2939dd7a3203b54c4807d458475182f5d3dc135ec0d1d4a9cd42159fd0a'

View File

@ -0,0 +1,215 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2017 Saleem Rashid <trezor@saleemrashid.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 trezorlib import messages as proto
from trezorlib import nem
import time
# assertion data from T1
@pytest.mark.skip_t1
@pytest.mark.xfail # to be removed when nem is merged
class TestMsgNEMSignTxMosaics(TrezorTest):
def test_nem_signtx_mosaic_supply_change(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), {
"timeStamp": 74649215,
"fee": 2000000,
"type": nem.TYPE_MOSAIC_SUPPLY_CHANGE,
"deadline": 74735615,
"message": {
},
"mosaicId": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
"supplyType": 1,
"delta": 1,
"version": (0x98 << 24),
"creationFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"creationFee": 1500,
})
assert hexlify(tx.data) == b'02400000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f74041a0000000600000068656c6c6f6d0c00000048656c6c6f206d6f73616963010000000100000000000000'
assert hexlify(tx.signature) == b'928b03c4a69fff35ecf0912066ea705895b3028fad141197d7ea2b56f1eef2a2516455e6f35d318f6fa39e2bb40492ac4ae603260790f7ebc7ea69feb4ca4c0a'
def test_nem_signtx_mosaic_creation(self):
self.setup_mnemonic_nopin_nopassphrase()
test_suite = {
"timeStamp": 74649215,
"fee": 2000000,
"type": nem.TYPE_MOSAIC_CREATION,
"deadline": 74735615,
"message": {
},
"mosaicDefinition": {
"id": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
"levy": {},
"properties": {},
"description": "lorem"
},
"version": (0x98 << 24),
"creationFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"creationFee": 1500,
}
# not using client.nem_sign_tx() because of swiping
tx = self._nem_sign(2, test_suite)
assert hexlify(tx.data) == b'01400000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f7404c100000020000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b40620841a0000000600000068656c6c6f6d0c00000048656c6c6f206d6f73616963050000006c6f72656d04000000150000000c00000064697669736962696c6974790100000030160000000d000000696e697469616c537570706c7901000000301a0000000d000000737570706c794d757461626c650500000066616c7365190000000c0000007472616e7366657261626c650500000066616c7365000000002800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324adc05000000000000'
assert hexlify(tx.signature) == b'537adf4fd9bd5b46e204b2db0a435257a951ed26008305e0aa9e1201dafa4c306d7601a8dbacabf36b5137724386124958d53202015ab31fb3d0849dfed2df0e'
def test_nem_signtx_mosaic_creation_properties(self):
self.setup_mnemonic_nopin_nopassphrase()
test_suite = {
"timeStamp": 74649215,
"fee": 2000000,
"type": nem.TYPE_MOSAIC_CREATION,
"deadline": 74735615,
"message": {
},
"mosaicDefinition": {
"id": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
"levy": {},
"properties": [
{
"name": "divisibility",
"value": "4"
},
{
"name": "initialSupply",
"value": "200"
},
{
"name": "supplyMutable",
"value": "false"
},
{
"name": "transferable",
"value": "true"
}
],
"description": "lorem"
},
"version": (0x98 << 24),
"creationFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"creationFee": 1500,
}
# not using client.nem_sign_tx() because of swiping
tx = self._nem_sign(2, test_suite)
assert hexlify(tx.data) == b'01400000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f7404c200000020000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b40620841a0000000600000068656c6c6f6d0c00000048656c6c6f206d6f73616963050000006c6f72656d04000000150000000c00000064697669736962696c6974790100000034180000000d000000696e697469616c537570706c79030000003230301a0000000d000000737570706c794d757461626c650500000066616c7365180000000c0000007472616e7366657261626c650400000074727565000000002800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324adc05000000000000'
assert hexlify(tx.signature) == b'f17c859710060f2ea9a0ab740ef427431cf36bdc7d263570ca282bd66032e9f5737a921be9839429732e663be2bb74ccc16f34f5157ff2ef00a65796b54e800e'
def test_nem_signtx_mosaic_creation_levy(self):
self.setup_mnemonic_nopin_nopassphrase()
test_suite = {
"timeStamp": 74649215,
"fee": 2000000,
"type": nem.TYPE_MOSAIC_CREATION,
"deadline": 74735615,
"message": {
},
"mosaicDefinition": {
"id": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
"properties": [
{
"name": "divisibility",
"value": "4"
},
{
"name": "initialSupply",
"value": "200"
},
{
"name": "supplyMutable",
"value": "false"
},
{
"name": "transferable",
"value": "true"
}
],
"levy": {
"type": 1,
"fee": 2,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"mosaicId": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
},
"description": "lorem"
},
"version": (0x98 << 24),
"creationFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"creationFee": 1500,
}
tx = self._nem_sign(6, test_suite)
assert hexlify(tx.data) == b'01400000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f74041801000020000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b40620841a0000000600000068656c6c6f6d0c00000048656c6c6f206d6f73616963050000006c6f72656d04000000150000000c00000064697669736962696c6974790100000034180000000d000000696e697469616c537570706c79030000003230301a0000000d000000737570706c794d757461626c650500000066616c7365180000000c0000007472616e7366657261626c65040000007472756556000000010000002800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324a1a0000000600000068656c6c6f6d0c00000048656c6c6f206d6f7361696302000000000000002800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324adc05000000000000'
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 = self.client._convert_prime(n)
msg = nem.create_sign_tx(test_suite)
assert msg.transaction is not None
msg.transaction.address_n = n
# Sending NEMSignTx message
self.client.transport.write(msg)
ret = self.client.transport.read()
# Confirm action
assert isinstance(ret, proto.ButtonRequest)
self.client.debug.press_yes()
self.client.transport.write(proto.ButtonAck())
time.sleep(1)
for i in range(num_of_swipes):
self.client.debug.swipe_down()
time.sleep(1)
self.client.debug.press_yes()
ret = self.client.transport.read()
# Confirm action
assert isinstance(ret, proto.ButtonRequest)
self.client.debug.press_yes()
self.client.transport.write(proto.ButtonAck())
ret = self.client.transport.read()
# Confirm tx
assert isinstance(ret, proto.ButtonRequest)
self.client.debug.press_yes()
self.client.transport.write(proto.ButtonAck())
return self.client.transport.read()

View File

@ -0,0 +1,159 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2017 Saleem Rashid <trezor@saleemrashid.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 trezorlib import nem
# assertion data from T1
@pytest.mark.xfail # to be removed when nem is merged
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'"), {
"timeStamp": 74649215,
"fee": 2000000,
"type": nem.TYPE_AGGREGATE_MODIFICATION,
"deadline": 74735615,
"message": {
},
"modifications": [
{
"modificationType": 1, # Add
"cosignatoryAccount": "c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844"
},
],
"minCosignatories": {
"relativeChange": 3
},
"version": (0x98 << 24),
})
assert hexlify(tx.data) == b'01100000020000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f740401000000280000000100000020000000c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f878440400000003000000'
assert hexlify(tx.signature) == b'1200e552d8732ce3eae96719731194abfc5a09d98f61bb35684f4eeaeff15b1bdf326ee7b1bbbe89d3f68c8e07ad3daf72e4c7f031094ad2236b97918ad98601'
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'"), {
"timeStamp": 1,
"fee": 10000,
"type": nem.TYPE_MULTISIG,
"deadline": 74735615,
"otherTrans": { # simple transaction transfer
"timeStamp": 2,
"amount": 2000000,
"fee": 15000,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"type": nem.TYPE_TRANSACTION_TRANSFER,
"deadline": 67890,
"message": {
"payload": hexlify(b"test_nem_transaction_transfer"),
"type": 1,
},
"version": (0x98 << 24),
"signer": 'c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844',
},
"version": (0x98 << 24),
})
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'"), {
"timeStamp": 74649215,
"fee": 150,
"type": nem.TYPE_MULTISIG,
"deadline": 789,
"otherTrans": {
"timeStamp": 123456,
"fee": 2000,
"type": nem.TYPE_PROVISION_NAMESPACE,
"deadline": 100,
"message": {
},
"newPart": "ABCDE",
"rentalFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"rentalFee": 1500,
"parent": None,
"version": (0x98 << 24),
"signer": 'c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844',
},
"version": (0x98 << 24),
})
assert hexlify(tx.data) == b'04100000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b40620849600000000000000150300007d000000012000000100009840e2010020000000c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844d007000000000000640000002800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324adc05000000000000050000004142434445ffffffff'
assert hexlify(tx.signature) == b'c915ca3332380925f4050301cdc62269cf29437ac5955321b18da34e570c7fdbb1aec2940a2a553a2a5c90950a4db3c8d3ef899c1a108582e0657f66fbbb0b04'
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'"), {
"timeStamp": 333,
"fee": 200,
"type": nem.TYPE_MULTISIG_SIGNATURE,
"deadline": 444,
"otherTrans": { # simple transaction transfer
"timeStamp": 555,
"amount": 2000000,
"fee": 2000000,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"type": nem.TYPE_TRANSACTION_TRANSFER,
"deadline": 666,
"message": {
"payload": hexlify(b"test_nem_transaction_transfer"),
"type": 1,
},
"version": (0x98 << 24),
"signer": 'c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844',
},
"version": (0x98 << 24),
})
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'"), {
"timeStamp": 900000,
"fee": 200000,
"type": nem.TYPE_MULTISIG_SIGNATURE,
"deadline": 100,
"otherTrans": { # simple transaction transfer
"timeStamp": 101111,
"fee": 1000,
"type": nem.TYPE_MOSAIC_SUPPLY_CHANGE,
"deadline": 13123,
"message": {
},
"mosaicId": {
"namespaceId": "hellom",
"name": "Hello mosaic"
},
"supplyType": 1,
"delta": 1,
"version": (0x98 << 24),
"creationFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"creationFee": 1500,
"signer": 'c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844',
},
"version": (0x98 << 24),
})
assert hexlify(tx.data) == b'0210000001000098a0bb0d0020000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b4062084400d030000000000640000002400000020000000c51395626a89a71c1ed785fb5974307a049b3b9e2165d56ed0302fe6b4f02a0128000000544444324354364c514c49595135364b49584933454e544d36454b3344343450354b5a50464d4b32'
assert hexlify(tx.signature) == b'32b1fdf788c4a90c01eedf5972b7709745831d620c13e1e97b0de6481837e162ee551573f2409822754ae940731909ec4b79cf836487e898df476adb10467506'

View File

@ -0,0 +1,67 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2017 Saleem Rashid <trezor@saleemrashid.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 trezorlib import nem
# assertion data from T1
@pytest.mark.xfail # to be removed when nem is merged
class TestMsgNEMSignTxOther(TrezorTest):
def test_nem_signtx_importance_transfer(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), {
"timeStamp": 12349215,
"fee": 9900,
"type": nem.TYPE_IMPORTANCE_TRANSFER,
"deadline": 99,
"message": {
},
"importanceTransfer": {
"mode": 1, # activate
"publicKey": "c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844",
},
"version": (0x98 << 24),
})
assert hexlify(tx.data) == b'01080000010000981f6fbc0020000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b4062084ac26000000000000630000000100000020000000c5f54ba980fcbb657dbaaa42700539b207873e134d2375efeab5f1ab52f87844'
assert hexlify(tx.signature) == b'b6d9434ec5df80e65e6e45d7f0f3c579b4adfe8567c42d981b06e8ac368b1aad2b24eebecd5efd41f4497051fca8ea8a5e77636a79afc46ee1a8e0fe9e3ba90b'
def test_nem_signtx_provision_namespace(self):
self.setup_mnemonic_nopin_nopassphrase()
tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), {
"timeStamp": 74649215,
"fee": 2000000,
"type": nem.TYPE_PROVISION_NAMESPACE,
"deadline": 74735615,
"message": {
},
"newPart": "ABCDE",
"rentalFeeSink": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"rentalFee": 1500,
"parent": None,
"version": (0x98 << 24),
})
assert hexlify(tx.data) == b'01200000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f74042800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324adc05000000000000050000004142434445ffffffff'
assert hexlify(tx.signature) == b'f047ae7987cd3a60c0d5ad123aba211185cb6266a7469dfb0491a0df6b5cd9c92b2e2b9f396cc2a3146ee185ba02df4f9e7fb238fe479917b3d274d97336640d'

View File

@ -0,0 +1,240 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2017 Saleem Rashid <trezor@saleemrashid.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 trezorlib import messages as proto
from trezorlib import nem
# assertion data from T1
@pytest.mark.xfail # to be removed when nem is merged
class TestMsgNEMSignTx(TrezorTest):
def test_nem_signtx_simple(self):
# tx hash: 209368053ac61969b6838ceb7e31badeb622ed6aa42d6c58365c42ad1a11e19d
signature = unhexlify(
"9cda2045324d05c791a4fc312ecceb62954e7740482f8df8928560d63cf273dea595023640179f112de755c79717757ef76962175378d6d87360ddb3f3e5f70f"
)
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
# Confirm transfer and network fee
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
# Unencrypted message
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
# Confirm recipient
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.NEMSignedTx(),
])
tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), {
"timeStamp": 74649215,
"amount": 2000000,
"fee": 2000000,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"type": nem.TYPE_TRANSACTION_TRANSFER,
"deadline": 74735615,
"message": {
"payload": hexlify(b"test_nem_transaction_transfer"),
"type": 1,
},
"version": (0x98 << 24),
})
assert hexlify(tx.data) == b'01010000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f74042800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324a80841e000000000025000000010000001d000000746573745f6e656d5f7472616e73616374696f6e5f7472616e73666572'
assert tx.signature == signature
def test_nem_signtx_encrypted_payload(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
self.client.set_expected_responses([
# Confirm transfer and network fee
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
# Ask for encryption
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
# Confirm recipient
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.NEMSignedTx(),
])
tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), {
"timeStamp": 74649215,
"amount": 2000000,
"fee": 2000000,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"type": nem.TYPE_TRANSACTION_TRANSFER,
"deadline": 74735615,
"message": {
# plain text is 32B long => cipher text is 48B
# as per PKCS#7 another block containing padding is added
"payload": hexlify(b"this message should be encrypted"),
"publicKey": "5a5e14c633d7d269302849d739d80344ff14db51d7bcda86045723f05c4e4541",
"type": 2,
},
"version": (0x98 << 24),
})
assert hexlify(tx.data[:124]) == b'01010000010000987f0e730420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208480841e0000000000ff5f74042800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324a80841e0000000000680000000200000060000000'
# after 124th byte comes iv (16B) salt (32B) and encrypted payload (48B)
assert len(tx.data[124:]) == 16 + 32 + 48
# because IV and salt are random (therefore the encrypted payload as well) those data can't be asserted
assert len(tx.signature) == 64
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'"), {
"timeStamp": 76809215,
"amount": 5000000,
"fee": 1000000,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"type": nem.TYPE_TRANSACTION_TRANSFER,
"deadline": 76895615,
"version": (0x98 << 24),
"message": {
},
"mosaics": [
{
"mosaicId": {
"namespaceId": "nem",
"name": "xem",
},
"quantity": 9000000,
},
],
})
# trezor should display 45 XEM (multiplied by amount)
assert hexlify(tx.data) == b'0101000002000098ff03940420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208440420f00000000007f5595042800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324a404b4c000000000000000000010000001a0000000e000000030000006e656d0300000078656d4054890000000000'
assert hexlify(tx.signature) == b'7b25a84b65adb489ea55739f1ca2d83a0ae069c3c58d0ea075fc30bfe8f649519199ad2324ca229c6c3214191469f95326e99712124592cae7cd3a092c93ac0c'
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'"), {
"timeStamp": 76809215,
"amount": 2000000,
"fee": 1000000,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"type": nem.TYPE_TRANSACTION_TRANSFER,
"deadline": 76895615,
"version": (0x98 << 24),
"message": {
},
"mosaics": [
{
"mosaicId": {
"namespaceId": "xxx",
"name": "aa",
},
"quantity": 3500000,
},
],
})
# trezor should display warning about unknown mosaic and then dialog for 7000000 raw units of xxx.aa and 0 XEM
assert hexlify(tx.data) == b'0101000002000098ff03940420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208440420f00000000007f5595042800000054414c49434532474d4133344358484437584c4a513533364e4d35554e4b5148544f524e4e54324a80841e00000000000000000001000000190000000d00000003000000787878020000006161e067350000000000'
assert hexlify(tx.signature) == b'2f0280420eceb41ef9e5d94fa44ddda9cdc70b8f423ae18af577f6d85df64bb4aaf40cf24fc6eef47c63b0963611f8682348cecdc49a9b64eafcbe7afcb49102'
def test_nem_signtx_known_mosaic(self):
self.setup_mnemonic_nopin_nopassphrase()
tx = self.client.nem_sign_tx(self.client.expand_path("m/44'/1'/0'/0'/0'"), {
"timeStamp": 76809215,
"amount": 3000000,
"fee": 1000000,
"recipient": "NDMYSLXI4L3FYUQWO4MJOVL6BSTJJXKDSZRMT4LT",
"type": nem.TYPE_TRANSACTION_TRANSFER,
"deadline": 76895615,
"version": (0x68 << 24),
"message": {
},
"mosaics": [
{
"mosaicId": {
"namespaceId": "dim",
"name": "token",
},
"quantity": 111000,
},
],
})
# trezor should display 0 XEM and 0.333 DIMTOK
assert hexlify(tx.data) == b'0101000002000068ff03940420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208440420f00000000007f559504280000004e444d59534c5849344c3346595551574f344d4a4f564c364253544a4a584b44535a524d54344c54c0c62d000000000000000000010000001c000000100000000300000064696d05000000746f6b656e98b1010000000000'
assert hexlify(tx.signature) == b'e7f14ef8c39727bfd257e109cd5acac31542f2e41f2e5deb258fc1db602b690eb1cabca41a627fe2adc51f3193db85c76b41c80bb60161eb8738ebf20b507104'
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'"), {
"timeStamp": 76809215,
"amount": 2000000,
"fee": 1000000,
"recipient": "NDMYSLXI4L3FYUQWO4MJOVL6BSTJJXKDSZRMT4LT",
"type": nem.TYPE_TRANSACTION_TRANSFER,
"deadline": 76895615,
"version": (0x68 << 24),
"message": {
},
"mosaics": [
{
"mosaicId": {
"namespaceId": "nem",
"name": "xem",
},
"quantity": 3000000,
},
{
"mosaicId": {
"namespaceId": "abc",
"name": "mosaic",
},
"quantity": 200,
},
{
"mosaicId": {
"namespaceId": "nem",
"name": "xem",
},
"quantity": 30000,
},
{
"mosaicId": {
"namespaceId": "abc",
"name": "mosaic",
},
"quantity": 2000000,
},
{
"mosaicId": {
"namespaceId": "breeze",
"name": "breeze-token",
},
"quantity": 111000,
}
]
})
# trezor should display warning, 6.06 XEM, 4000400 raw units of abc.mosaic (mosaics are merged)
# and 222000 BREEZE
assert hexlify(tx.data) == b'0101000002000068ff03940420000000edfd32f6e760648c032f9acb4b30d514265f6a5b5f8a7154f2618922b406208440420f00000000007f559504280000004e444d59534c5849344c3346595551574f344d4a4f564c364253544a4a584b44535a524d54344c5480841e000000000000000000030000001d0000001100000003000000616263060000006d6f7361696348851e0000000000260000001a00000006000000627265657a650c000000627265657a652d746f6b656e98b10100000000001a0000000e000000030000006e656d0300000078656df03b2e0000000000'
assert hexlify(tx.signature) == b'b2b9319fca87a05bee17108edd9a8f78aeffef74bf6b4badc6da5d46e8ff4fe82e24bf69d8e6c4097d072adf39d0c753e7580f8afb21e3288ebfb7c4d84e470d'

View File

@ -0,0 +1,105 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2012-2016 Marek Palatinus <slush@satoshilabs.com>
# Copyright (C) 2012-2016 Pavol Rusnak <stick@satoshilabs.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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 *
from trezorlib import messages as proto
@pytest.mark.skip_t1
class TestMsgRecoverydeviceT2(TrezorTest):
def test_pin_passphrase(self):
mnemonic = self.mnemonic12.split(' ')
ret = self.client.call_raw(proto.RecoveryDevice(
passphrase_protection=True,
pin_protection=True,
label='label',
enforce_wordlist=True))
# Enter word count
assert ret == proto.ButtonRequest(code=proto.ButtonRequestType.MnemonicWordCount)
self.client.debug.input(str(len(mnemonic)))
ret = self.client.call_raw(proto.ButtonAck())
# Enter mnemonic words
assert ret == proto.ButtonRequest(code=proto.ButtonRequestType.MnemonicInput)
self.client.transport.write(proto.ButtonAck())
for word in mnemonic:
time.sleep(1)
self.client.debug.input(word)
ret = self.client.transport.read()
# Enter PIN for first time
assert ret == proto.ButtonRequest(code=proto.ButtonRequestType.Other)
self.client.debug.input('654')
ret = self.client.call_raw(proto.ButtonAck())
# Enter PIN for second time
assert ret == proto.ButtonRequest(code=proto.ButtonRequestType.Other)
self.client.debug.input('654')
ret = self.client.call_raw(proto.ButtonAck())
# Workflow succesfully ended
assert ret == proto.Success(message='Device recovered')
# Mnemonic is the same
self.client.init_device()
assert self.client.debug.read_mnemonic() == self.mnemonic12
assert self.client.features.pin_protection is True
assert self.client.features.passphrase_protection is True
def test_nopin_nopassphrase(self):
mnemonic = self.mnemonic12.split(' ')
ret = self.client.call_raw(proto.RecoveryDevice(
passphrase_protection=False,
pin_protection=False,
label='label',
enforce_wordlist=True))
# Enter word count
assert ret == proto.ButtonRequest(code=proto.ButtonRequestType.MnemonicWordCount)
self.client.debug.input(str(len(mnemonic)))
ret = self.client.call_raw(proto.ButtonAck())
# Enter mnemonic words
assert ret == proto.ButtonRequest(code=proto.ButtonRequestType.MnemonicInput)
self.client.transport.write(proto.ButtonAck())
for word in mnemonic:
time.sleep(1)
self.client.debug.input(word)
ret = self.client.transport.read()
# Workflow succesfully ended
assert ret == proto.Success(message='Device recovered')
# Mnemonic is the same
self.client.init_device()
assert self.client.debug.read_mnemonic() == self.mnemonic12
assert self.client.features.pin_protection is False
assert self.client.features.passphrase_protection is False
def test_already_initialized(self):
self.setup_mnemonic_nopin_nopassphrase()
with pytest.raises(Exception):
self.client.recovery_device(12, False, False, 'label', 'english')

View File

@ -18,9 +18,11 @@
from .common import *
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib.client import CallException
from trezorlib.tx_api import TxApiTestnet
TxApiTestnet = coins.tx_api['Testnet']
TXHASH_157041 = unhexlify('1570416eb4302cf52979afd5e6909e37d8fdd874301f7cc87e547e509cb1caa6')

View File

@ -16,12 +16,15 @@
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib.tx_api import TxApiBcash
from trezorlib.ckd_public import deserialize
from trezorlib.client import CallException
TxApiBcash = coins.tx_api['Bcash']
@pytest.mark.skip_t2
class TestMsgSigntxBch(TrezorTest):
def test_send_bch_change(self):
@ -29,7 +32,7 @@ class TestMsgSigntxBch(TrezorTest):
self.client.set_tx_api(TxApiBcash)
inp1 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/0'/0/0"),
# 1MH9KKcvdCTY44xVDC2k3fjBbX5Cz29N1q
# bitcoincash:qr08q88p9etk89wgv05nwlrkm4l0urz4cyl36hh9sv
amount=1995344,
prev_hash=unhexlify('bc37c28dfb467d2ecb50261387bf752a3977d7e5337915071bb4151e6b711a78'),
prev_index=0,
@ -41,7 +44,7 @@ class TestMsgSigntxBch(TrezorTest):
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
out2 = proto.TxOutputType(
address='1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3',
address='bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4',
amount=73452,
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
@ -66,7 +69,7 @@ class TestMsgSigntxBch(TrezorTest):
self.client.set_tx_api(TxApiBcash)
inp1 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/0'/1/0"),
# 1HADRPJpgqBzThepERpVXNi6qRgiLQRNoE
# bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw
amount=1896050,
prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'),
prev_index=0,
@ -74,7 +77,47 @@ class TestMsgSigntxBch(TrezorTest):
)
inp2 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/0'/0/1"),
# 1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3
# bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4
amount=73452,
prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'),
prev_index=1,
script_type=proto.InputScriptType.SPENDADDRESS,
)
out1 = proto.TxOutputType(
address='bitcoincash:qq6wnnkrz7ykaqvxrx4hmjvayvzjzml54uyk76arx4',
amount=1934960,
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Bcash', [inp1, inp2], [out1])
assert hexlify(serialized_tx) == b'01000000022c06cf6f215c5cbfd7caa8e71b1b32630cabf1f816a4432815b037b277852e50000000006a47304402207a2a955f1cb3dc5f03f2c82934f55654882af4e852e5159639f6349e9386ec4002205fb8419dce4e648eae8f67bc4e369adfb130a87d2ea2d668f8144213b12bb457412103174c61e9c5362507e8061e28d2c0ce3d4df4e73f3535ae0b12f37809e0f92d2dffffffff2c06cf6f215c5cbfd7caa8e71b1b32630cabf1f816a4432815b037b277852e50010000006a473044022062151cf960b71823bbe68c7ed2c2a93ad1b9706a30255fddb02fcbe056d8c26102207bad1f0872bc5f0cfaf22e45c925c35d6c1466e303163b75cb7688038f1a5541412102595caf9aeb6ffdd0e82b150739a83297358b9a77564de382671056ad9e5b8c58ffffffff0170861d00000000001976a91434e9cec317896e818619ab7dc99d2305216ff4af88ac00000000'
def test_send_bch_oldaddr(self):
self.setup_mnemonic_allallall()
self.client.set_tx_api(TxApiBcash)
inp1 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/0'/1/0"),
# bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw
amount=1896050,
prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'),
prev_index=0,
script_type=proto.InputScriptType.SPENDADDRESS,
)
inp2 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/0'/0/1"),
# bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4
amount=73452,
prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'),
prev_index=1,
@ -106,7 +149,7 @@ class TestMsgSigntxBch(TrezorTest):
self.client.set_tx_api(TxApiBcash)
inp1 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/0'/1/0"),
# 1HADRPJpgqBzThepERpVXNi6qRgiLQRNoE
# bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw
amount=300,
prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'),
prev_index=0,
@ -114,14 +157,14 @@ class TestMsgSigntxBch(TrezorTest):
)
inp2 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/0'/0/1"),
# 1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3
# bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4
amount=70,
prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'),
prev_index=1,
script_type=proto.InputScriptType.SPENDADDRESS,
)
out1 = proto.TxOutputType(
address='15pnEDZJo3ycPUamqP3tEDnEju1oW5fBCz',
address='bitcoincash:qq6wnnkrz7ykaqvxrx4hmjvayvzjzml54uyk76arx4',
amount=200,
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
@ -192,7 +235,7 @@ class TestMsgSigntxBch(TrezorTest):
self.client.set_tx_api(TxApiBcash)
inp1 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/1000'/0/0"),
# 1MH9KKcvdCTY44xVDC2k3fjBbX5Cz29N1q
# bitcoincash:qr08q88p9etk89wgv05nwlrkm4l0urz4cyl36hh9sv
amount=1995344,
prev_hash=unhexlify('bc37c28dfb467d2ecb50261387bf752a3977d7e5337915071bb4151e6b711a78'),
prev_index=0,
@ -204,7 +247,7 @@ class TestMsgSigntxBch(TrezorTest):
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
out2 = proto.TxOutputType(
address='1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3',
address='bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4',
amount=73452,
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
@ -263,7 +306,7 @@ class TestMsgSigntxBch(TrezorTest):
inp1 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/1'/1/0"),
multisig=getmultisig(1, 0, [b'', sig, b'']),
# 3CPtPpL5mGAPdxUeUDfm2RNdWoSN9dKpXE
# bitcoincash:pp6kcpkhua7789g2vyj0qfkcux3yvje7euhyhltn0a
amount=24000,
prev_hash=unhexlify('f68caf10df12d5b07a34601d88fa6856c6edcbf4d05ebef3486510ae1c293d5f'),
prev_index=1,
@ -311,14 +354,14 @@ class TestMsgSigntxBch(TrezorTest):
inp1 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/3'/0/0"),
multisig=getmultisig(0, 0),
# 33Ju286QvonBz5N1V754ZekQv4GLJqcc5R
# bitcoincash:pqguz4nqq64jhr5v3kvpq4dsjrkda75hwy86gq0qzw
amount=48490,
prev_hash=unhexlify('8b6db9b8ba24235d86b053ea2ccb484fc32b96f89c3c39f98d86f90db16076a0'),
prev_index=0,
script_type=proto.InputScriptType.SPENDMULTISIG,
)
out1 = proto.TxOutputType(
address='113Q5hHQNQ3bc1RpPX6UNw4GAXstyeA3Dk',
address='bitcoincash:qqq8gx2j76nw4dfefumxmdwvtf2tpsjznusgsmzex9',
amount=24000,
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
@ -347,7 +390,7 @@ class TestMsgSigntxBch(TrezorTest):
inp1 = proto.TxInputType(
address_n=self.client.expand_path("44'/145'/1'/0/0"),
multisig=getmultisig(0, 0, [b'', b'', signatures1[0]]),
# 33Ju286QvonBz5N1V754ZekQv4GLJqcc5R
# bitcoincash:pqguz4nqq64jhr5v3kvpq4dsjrkda75hwy86gq0qzw
amount=48490,
prev_hash=unhexlify('8b6db9b8ba24235d86b053ea2ccb484fc32b96f89c3c39f98d86f90db16076a0'),
prev_index=0,

View File

@ -17,11 +17,13 @@
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib.tx_api import TxApiBitcoinGold
from trezorlib.ckd_public import deserialize
from trezorlib.client import CallException
TxApiBitcoinGold = coins.tx_api["Bitcoin Gold"]
# All data taken from T1
class TestMsgSigntxBitcoinGold(TrezorTest):

View File

@ -17,8 +17,10 @@
from .common import *
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib.tx_api import TxApiDecredTestnet
TxApiDecredTestnet = coins.tx_api['Decred Testnet']
TXHASH_e16248 = unhexlify("e16248f0b39a0a0c0e53d6f2f84c2a944f0d50e017a82701e8e02e46e979d5ed")

View File

@ -17,11 +17,13 @@
from .common import *
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib.tx_api import TxApiTestnet
from trezorlib.ckd_public import deserialize
from trezorlib.client import CallException
TxApiTestnet = coins.tx_api["Testnet"]
class TestMsgSigntxSegwit(TrezorTest):

View File

@ -17,10 +17,12 @@
from .common import *
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib.tx_api import TxApiTestnet
from trezorlib.ckd_public import deserialize
TxApiTestnet = coins.tx_api['Testnet']
class TestMsgSigntxSegwitNative(TrezorTest):

View File

@ -18,8 +18,11 @@
from .common import *
from trezorlib import coins
from trezorlib import messages as proto
from trezorlib.tx_api import TxApiZcash
TxApiZcash = coins.tx_api["Zcash"]
TXHASH_93373e = unhexlify('93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c')

View File

@ -19,14 +19,14 @@
from .common import *
from trezorlib import messages as proto
import trezorlib.ckd_public as bip32
from trezorlib import tx_api
from trezorlib.coins import tx_api
class TestMultisigChange(TrezorTest):
def setup_method(self, method):
super(TestMultisigChange, self).setup_method(method)
self.client.set_tx_api(tx_api.TxApiTestnet)
self.client.set_tx_api(tx_api['Testnet'])
node_ext1 = bip32.deserialize('tpubDADHV9u9Y6gkggintTdMjJE3be58zKNLhpxBQyuEM6Pwx3sN9JVLmMCMN4DNVwL9AKec27z5TaWcWuHzMXiGAtcra5DjwWbvppGX4gaEGVN')
# m/1 => 02c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e

View File

@ -8,7 +8,7 @@ def test_nem_basic():
"amount": 1000000,
"fee": 1000000,
"recipient": "TALICE2GMA34CXHD7XLJQ536NM5UNKQHTORNNT2J",
"type": nem.TYPE_MOSAIC_TRANSFER,
"type": nem.TYPE_TRANSACTION_TRANSFER,
"deadline": 76895615,
"version": (0x98 << 24),
"message": {

View File

@ -18,8 +18,11 @@
import os
from trezorlib import coins
from trezorlib import tx_api
from trezorlib.tx_api import TxApiBitcoin, TxApiTestnet
TxApiBitcoin = coins.tx_api['Bitcoin']
TxApiTestnet = coins.tx_api['Testnet']
tests_dir = os.path.dirname(os.path.abspath(__file__))

View File

@ -115,4 +115,4 @@ def get_transport(path=None, prefix_search=False):
if transports:
return transports[0].find_by_path(path, prefix_search=prefix_search)
raise Exception("Unknown path prefix '%s'" % prefix)
raise Exception("Could not find device by path: {}".format(path))

View File

@ -19,6 +19,7 @@
import time
import hid
import os
import sys
from ..protocol_v1 import ProtocolV1
from ..protocol_v2 import ProtocolV2
@ -39,7 +40,12 @@ class HidHandle:
def open(self):
if self.count == 0:
self.handle = hid.device()
self.handle.open_path(self.path)
try:
self.handle.open_path(self.path)
except (IOError, OSError) as e:
if sys.platform.startswith('linux'):
e.args = e.args + ('Do you have udev rules installed? https://github.com/trezor/trezor-common/blob/master/udev/51-trezor.rules', )
raise e
self.handle.set_nonblocking(True)
self.count += 1

View File

@ -67,7 +67,6 @@ class UdpTransport(Transport):
@classmethod
def enumerate(cls):
devices = []
default_path = '{}:{}'.format(cls.DEFAULT_HOST, cls.DEFAULT_PORT)
try:
return [cls._try_path(default_path)]

View File

@ -20,6 +20,7 @@ import time
import os
import atexit
import usb1
import sys
from ..protocol_v1 import ProtocolV1
from ..protocol_v2 import ProtocolV2
@ -46,7 +47,11 @@ class WebUsbHandle:
if self.count == 0:
self.handle = self.device.open()
if self.handle is None:
raise Exception('Cannot open device')
if sys.platform.startswith('linux'):
args = ('Do you have udev rules installed? https://github.com/trezor/trezor-common/blob/master/udev/51-trezor.rules', )
else:
args = ()
raise IOError('Cannot open device', *args)
self.handle.claimInterface(interface)
self.count += 1

View File

@ -115,40 +115,6 @@ class TxApiInsight(TxApi):
return t
class TxApiSmartbit(TxApi):
def get_tx(self, txhash):
data = self.fetch_json('tx', txhash)
data = data['transaction']
t = proto.TransactionType()
t.version = int(data['version'])
t.lock_time = data['locktime']
for vin in data['inputs']:
i = t.inputs.add()
if 'coinbase' in vin.keys():
i.prev_hash = b"\0" * 32
i.prev_index = 0xffffffff # signed int -1
i.script_sig = binascii.unhexlify(vin['coinbase'])
i.sequence = vin['sequence']
else:
i.prev_hash = binascii.unhexlify(vin['txid'])
i.prev_index = vin['vout']
i.script_sig = binascii.unhexlify(vin['script_sig']['hex'])
i.sequence = vin['sequence']
for vout in data['outputs']:
o = t.bin_outputs.add()
o.amount = int(Decimal(vout['value']) * 100000000)
o.script_pubkey = binascii.unhexlify(vout['script_pub_key']['hex'])
return t
class TxApiBlockCypher(TxApi):
def __init__(self, network, url, zcash=None):
@ -182,16 +148,3 @@ class TxApiBlockCypher(TxApi):
o.script_pubkey = binascii.unhexlify(vout['script'])
return t
TxApiBitcoin = TxApiInsight(network='insight_bitcoin', url='https://btc-bitcore1.trezor.io/api/')
TxApiTestnet = TxApiInsight(network='insight_testnet', url='https://testnet-bitcore3.trezor.io/api/')
TxApiLitecoin = TxApiInsight(network='insight_litecoin', url='https://ltc-bitcore1.trezor.io/api/')
TxApiDash = TxApiInsight(network='insight_dash', url='https://dash-bitcore1.trezor.io/api/')
TxApiZcash = TxApiInsight(network='insight_zcash', url='https://zec-bitcore1.trezor.io/api/', zcash=True)
TxApiBcash = TxApiInsight(network='insight_bcash', url='https://bch-bitcore2.trezor.io/api/')
TxApiBitcoinGold = TxApiInsight(network='insight_bitcoin_gold', url='https://btg-bitcore2.trezor.io/api/')
TxApiDecredTestnet = TxApiInsight(network='insight_decred_testnet', url='https://testnet.decred.org/api/')
TxApiDogecoin = TxApiBlockCypher(network='blockcypher_dogecoin', url='https://api.blockcypher.com/v1/doge/main/')
TxApiSegnet = TxApiSmartbit(network='smartbit_segnet', url='https://segnet-api.smartbit.com.au/v1/blockchain/')
TxApiMonacoin = TxApiInsight(network='insight_monacoin', url='https://mona.insight.monaco-ex.org/insight-api-monacoin/')

1
vendor/trezor-common vendored Submodule

@ -0,0 +1 @@
Subproject commit 9abe3a7c69000cc7ee3cda2ec940193fa9d62e6c