Compare commits

..

No commits in common. "master" and "v0.7.13" have entirely different histories.

295 changed files with 10341 additions and 11215 deletions

32
.flake8
View File

@ -1,32 +0,0 @@
[flake8]
filename =
*.py,
trezorctl
exclude =
.tox/,
build/,
dist/,
trezorlib/*_pb2.py
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 *
F403,
# F405 'foo' may be undefined, or defined from star imports
F405,
# E241: multiple spaces after ':'
E241,
# E402: module level import not at top of file
E402,
# E501: line too long
E501,
# E721: do not compare types, use 'isinstance()'
E721,
# E722: do not use bare except
E722,
# E741: ambiguous variable name
E741

5
.gitignore vendored
View File

@ -1,16 +1,13 @@
.project
.pydevproject
MANIFEST
build/
dist/
python_trezor.egg-info/
trezor.egg-info/
*.pyc
*.bin
*.png
*.py.cache
distribute-*.egg
distribute-*.tar.gz
docs/_build
docs/.docs-build-environment
.tox/
.cache/

View File

@ -15,28 +15,16 @@ addons:
- libusb-1.0-0-dev
python:
- "3.3"
- "2.7"
- "3.4"
- "3.5"
- "3.6"
before_install:
- pip install setuptools --upgrade
install:
# Optimisation: build requirements as wheels, which get cached by Travis
- pip install "pip>=7.0" wheel
- pip install "setuptools>=19.0"
- pip install tox-travis
- pip install flake8
script:
- python setup.py install
- flake8
- flake8 trezorctl
- tox
notifications:
webhooks:
urls:
- http://ci-bot.satoshilabs.com:5000/travis
on_success: always
on_failure: always
on_start: always

View File

@ -1,10 +0,0 @@
The changelog format is bound to change as we figure out a way to autogenerate it.
## version 0.9.1 (released 2018-03-05)
- proper support for Trezor model T
- gradually dropping Python 2 compatibility (pypi package will now be marked as Python 3 only)
- support for Monacoin
- improvements to `trezorctl`:
- add pretty-printing of features and protobuf debug dumps (fixes #199)
- support `TREZOR_PATH` environment variable to preselect a Trezor device.

View File

@ -1,3 +1,3 @@
recursive-include tests *.py *.sh *.json
recursive-include bash_completion.d *.sh
include trezorlib/tests/txcache/*.json
include COPYING

View File

@ -7,55 +7,66 @@ python-trezor
.. image:: https://badges.gitter.im/trezor/community.svg
:target: https://gitter.im/trezor/community
Python library and commandline client for communicating with TREZOR Hardware Wallet
Python library for communicating with TREZOR Hardware Wallet
See https://trezor.io for more information
Install
-------
Linux requirements:
(Run with sudo if not running in superuser mode under Linux)
.. code::
sudo apt-get install python3-dev cython3 libusb-1.0-0-dev libudev-dev git
pip install trezor
Linux & Mac Python requirements:
On Linux you might need to run these commands first:
.. code::
sudo -H pip3 install setuptools
sudo -H pip3 install -r requirements.txt
sudo -H pip3 install trezor
sudo apt-get install python-dev cython libusb-1.0-0-dev libudev-dev git
sudo pip install setuptools
On FreeBSD you can install the packages:
Example
-------
.. code::
also found in ``tools/helloworld.py``
pkg install security/py-trezor
.. code:: python
or build via ports:
#!/usr/bin/env python
.. code::
from trezorlib.client import TrezorClient
from trezorlib.transport_hid import HidTransport
cd /usr/ports/security/py-trezor
make install clean
def main():
# List all connected TREZORs on USB
devices = HidTransport.enumerate()
# Check whether we found any
if len(devices) == 0:
print('No TREZOR found')
return
Commandline client (trezorctl)
---------------------------
# Use first connected device
transport = HidTransport(devices[0])
The included ``trezorctl`` python script can perform various tasks such as changing setting in the Trezor, signing transactions, retrieving account info and addresses. See the `docs/ <docs/>`_ sub folder for detailed examples and options.
# Creates object for manipulating TREZOR
client = TrezorClient(transport)
NOTE: An older version of the ``trezorctl`` command is `available for Debian Stretch <https://packages.debian.org/en/stretch/python-trezor>`_ (and comes pre-installed on `Tails OS <https://tails.boum.org/>`_).
# Print out TREZOR's features and settings
print(client.features)
# Get the first address of first BIP44 account
# (should be the same address as shown in wallet.trezor.io)
bip32_path = client.expand_path("44'/0'/0'/0/0")
address = client.get_address('Bitcoin', bip32_path)
print('Bitcoin address:', address)
Python Library
--------------
You can use this python library to interact with a Bitcoin Trezor and use its capabilities in your application.
See examples here in the `tools/ <tools/>`_ sub folder.
client.close()
if __name__ == '__main__':
main()
PIN Entering
------------

11
build_pb.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
CURDIR=$(pwd)
cd $CURDIR/../trezor-common/protob
for i in messages types ; do
protoc --python_out=$CURDIR/trezorlib/ -I/usr/include -I. $i.proto
done
# hack to make output python 3 compatible
sed -i 's/^import types_pb2/from . import types_pb2/g' $CURDIR/trezorlib/messages_pb2.py

View File

@ -1,120 +0,0 @@
Examples demonstrating how to use trezorctl
===========================================
Show all available `options <OPTIONS.rst>`_:
.. code::
trezorctl --help
Retrieve features, settings and coin types supported by your device:
.. code::
trezorctl get_features
Bitcoin examples
----------------
Get first receiving address of first account for Bitcoin (Legacy / non-SegWit):
.. code::
trezorctl get_address --coin Bitcoin --script-type address --address "m/44'/0'/0'/0/0"
Get first receiving address of first account for Bitcoin (Bech32 native SegWit P2WPKH):
.. code::
trezorctl get_address --coin Bitcoin --script-type segwit --address "m/49'/0'/0'/0/0"
Get first receiving address of first account for Bitcoin (SegWit-in-P2SH):
.. code::
trezorctl get_address --coin Bitcoin --script-type p2shsegwit --address "m/49'/0'/0'/0/0"
Get Legacy Bitcoin ``xpub`` (can be used to create a watch-only wallet):
.. code::
trezorctl get_public_node --coin Bitcoin --address "m/44'/0'/0'"
Transaction signing
-------------------
You can use ``trezorctl`` to sign a transaction without it automatically being broadcast to the Bitcoin network.
You will need the following pieces of info:
1) Transaction ID containing the Output we want to spend (aka ``prevhash`` or ``a5ea715a...d201e64e`` in example below).
2) Index number of the Output being spent from the above tx (aka ``previndex`` or ``0`` in example below).
3) BIP32 path to the Node which can spend the above UTXO (eg ``Bitcoin/0'/0/0`` for the first).
4) Destination address where you want to send funds (eg ``3M8XGFBKwkf7miBzpkU3x2DoWwAVrD1mhk`` below).
5) Amount to send in satoshis - ``91305`` in the example below (multiply BTC amount 0.00091305 by 100,000,000).
6) Expected fee (``0.00019695`` BTC in example below). Note: the miner receives all satoshis left unspent from a transaction. If you want to receive some change, you need to send it to an address you own (otherwise it will go to miner). Fee is not needed below, we just want it as a sanity check.
There are many ways to retrieve the info above: from a watch-only wallet in Bitcoin Core, https://coinb.in (`screenshot <sign_tx-coinb.in.png>`_) etc. The easiest way is using the Trezor online wallet: https://beta-wallet.trezor.io
After authenticating, open the "Send" tab, fill-out all details, then open the "Show transaction details" menu to see the info needed above (`screenshot <sign_tx-trezor.io.png>`_). Once you have the required details, you can then perform the transaction signing using ``trezorctl`` as shown in the example below:
.. code::
trezorctl sign_tx -c Bitcoin
Input (prevhash:previndex, empty to move on): a5ea715aa99ca30516f3af6f622dfe7399d883d49ad74b1fe33fdf73d201e64e:0
Node path to sign with (e.g.- Bitcoin/0'/0/0): Bitcoin/0'/0/0
Input (prevhash:previndex, empty to move on):
Pay to address (empty to move on): 3M8XGFBKwkf7miBzpkU3x2DoWwAVrD1mhk
Amount (in satoshis): 91305
Pay to address (empty to move on):
Passphrase required:
Confirm your Passphrase:
RECEIVED PART OF SERIALIZED TX (152 BYTES)
RECEIVED PART OF SERIALIZED TX (37 BYTES)
SIGNED IN 52.538 SECONDS, CALLED 10 MESSAGES, 189 BYTES
Signed Transaction:
01000000014ee601d273df3fe31f4bd79ad483d89973fe2d626faff31605a39ca95a71eaa5000000006a47304402206386a0ad0f0b196d375a0805eee2aebe4644032c2998aaf00e43ce68a293986702202ad25964844657e10130f81201b7d87eb8047cf0c09dfdcbbe68a1a732e80ded012103b375a0dd50c8dbc4a6156a55e31274ee0537191e1bc824a09278a220fafba2dbffffffff01a96401000000000017a914d53d47ccd1579b93c284e9caf3c81f3f417871698700000000
Use the following form to broadcast it to the network:
https://btc-bitcore1.trezor.io/tx/send
The signed transaction text can then be inspected in Electrum (`screenshot <sign_tx-electrum2.png>`_), `coinb.in <https://coinb.in/?verify=01000000014ee601d273df3fe31f4bd79ad483d89973fe2d626faff31605a39ca95a71eaa5000000006a47304402206386a0ad0f0b196d375a0805eee2aebe4644032c2998aaf00e43ce68a293986702202ad25964844657e10130f81201b7d87eb8047cf0c09dfdcbbe68a1a732e80ded012103b375a0dd50c8dbc4a6156a55e31274ee0537191e1bc824a09278a220fafba2dbffffffff01a96401000000000017a914d53d47ccd1579b93c284e9caf3c81f3f417871698700000000#verify>`_ or another tool. If all info is correct, you can then broadcast the tx to the Bitcoin network via the URL provided by ``trezorctl`` or Electrum (Tools → Load transaction → From text. Here is a `screenshot <sign_tx-electrum1.png>`_). TIP: Electrum will only show the transaction fee if you previously imported the spending address (eg ``16ijWp48xn8hj6deD5ZHSJcgNjtYbpiki8`` from example tx above). Also, the final tx size (and therefore satoshis / byte) might be slightly different than the estimate shown on beta-wallet.trezor.io
The final broadcast and mined transaction can be seen here: https://blockchain.info/tx/270684c14be85efec9adafa50339fd120658381ed2300b9207d0a0df2a5f0bf9
Litecoin examples
-----------------
Get first receiving address of first account for Litecoin (Bech32 native SegWit P2WPKH):
.. code::
trezorctl get_address --coin Litecoin --script-type segwit --address "m/49'/2'/0'/0/0"
Get first receiving address of first account for Litecoin (SegWit-in-P2SH):
.. code::
trezorctl get_address --coin Litecoin --script-type p2shsegwit --address "m/49'/2'/0'/0/0"
Notes
-----
1. Bech32 native SegWit encoded addresses require `Trezor Firmware v1.6.0 <https://github.com/trezor/trezor-mcu/releases>`_ or later.

View File

@ -1,63 +0,0 @@
Commandline options for trezorctl
=================================
See `EXAMPLES.rst <EXAMPLES.rst>`_ for examples on how to use.
Use the following command to see all options:
.. code::
trezorctl --help
.. code::
Usage: trezorctl [OPTIONS] COMMAND [ARGS]...
Options:
-t, --transport [usb|udp|pipe|bridge]
Select transport used for communication.
-p, --path TEXT Select device by transport-specific path.
-v, --verbose Show communication messages.
-j, --json Print result as JSON object
--help Show this message and exit.
Commands:
backup_device Perform device seed backup.
change_pin Change new PIN or remove existing.
clear_session Clear session (remove cached PIN, passphrase,...
cosi_commit Ask device to commit to CoSi signing.
cosi_sign Ask device to sign using CoSi.
decrypt_keyvalue Decrypt value by given key and path.
decrypt_message Decrypt message.
disable_passphrase Disable passphrase.
enable_passphrase Enable passphrase.
encrypt_keyvalue Encrypt value by given key and path.
encrypt_message Encrypt message.
ethereum_get_address Get Ethereum address in hex encoding.
ethereum_sign_message Sign message with Ethereum address.
ethereum_sign_tx Sign (and optionally publish) Ethereum...
ethereum_verify_message Verify message signed with Ethereum address.
firmware_update Upload new firmware to device (must be in...
get_address Get address for specified path.
get_entropy Get example entropy.
get_features Retrieve device features and settings.
get_public_node Get public node of given path.
list List connected TREZOR devices.
list_coins List all supported coin types by the device.
load_device Load custom configuration to the device.
nem_get_address Get NEM address for specified path.
nem_sign_tx Sign (and optionally broadcast) NEM...
ping Send ping message.
recovery_device Start safe recovery workflow.
reset_device Perform device setup and generate new seed.
self_test Perform a self-test.
set_flags Set device flags.
set_homescreen Set new homescreen.
set_label Set new device label.
set_u2f_counter Set U2F counter.
sign_message Sign message using address of given path.
sign_tx Sign transaction.
verify_message Verify message.
version Show version of trezorctl/trezorlib.
wipe_device Reset device to factory defaults and remove...

View File

@ -1,5 +0,0 @@
Documentation for trezorctl commandline client
==============================================
* `EXAMPLES.rst <EXAMPLES.rst>`_ - Examples demonstrating how to use trezorctl
* `OPTIONS.rst <OPTIONS.rst>`_ - Commandline options for trezorctl

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,8 +1,4 @@
ecdsa>=0.9
protobuf>=2.6.1
mnemonic>=0.17
requests>=2.4.0
click>=6.2
pyblake2>=0.9.3
hidapi>=0.7.99.post20
libusb1>=1.6.4
rlp>=0.6.0

View File

@ -1,15 +1,7 @@
#!/usr/bin/env python3
#!/usr/bin/env python
from setuptools import setup
install_requires = [
'setuptools>=19.0',
'ecdsa>=0.9',
'mnemonic>=0.17',
'requests>=2.4.0',
'click>=6.2',
'pyblake2>=0.9.3',
'rlp>=0.6.0',
]
install_requires = ['ecdsa>=0.9', 'protobuf>=2.6.1', 'mnemonic>=0.17', 'setuptools>=19.0']
import sys
if '--disable-hidapi' in sys.argv:
@ -17,31 +9,32 @@ if '--disable-hidapi' in sys.argv:
else:
install_requires.append('hidapi>=0.7.99.post20')
if '--disable-libusb' in sys.argv:
sys.argv.remove('--disable-libusb')
else:
install_requires.append('libusb1>=1.6.4')
from trezorlib import __version__ as VERSION
setup(
name='trezor',
version=VERSION,
version='0.7.13',
author='TREZOR',
author_email='info@trezor.io',
description='Python library for communicating with TREZOR Hardware Wallet',
url='https://github.com/trezor/python-trezor',
packages=[
'trezorlib',
py_modules=[
'trezorlib.ckd_public',
'trezorlib.client',
'trezorlib.debuglink',
'trezorlib.mapping',
'trezorlib.messages_pb2',
'trezorlib.protobuf_json',
'trezorlib.qt.pinmatrix',
'trezorlib.tools',
'trezorlib.transport',
'trezorlib.messages',
'trezorlib.qt',
'trezorlib.tests.device_tests',
'trezorlib.tests.unit_tests',
'trezorlib.transport_bridge',
'trezorlib.transport_hid',
'trezorlib.transport_pipe',
'trezorlib.transport_udp',
'trezorlib.tx_api',
'trezorlib.types_pb2',
],
scripts=['trezorctl'],
scripts = ['trezorctl'],
install_requires=install_requires,
python_requires='>=3.3',
include_package_data=True,
zip_safe=False,
classifiers=[
@ -49,6 +42,5 @@ setup(
'Operating System :: POSIX :: Linux',
'Operating System :: Microsoft :: Windows',
'Operating System :: MacOS :: MacOS X',
'Programming Language :: Python :: 3 :: Only',
],
)

View File

@ -18,30 +18,24 @@
from __future__ import print_function
from binascii import hexlify, unhexlify
import pytest
import os
from trezorlib.client import TrezorClient, TrezorClientDebugLink
from trezorlib.transport import get_transport
import unittest
from trezorlib.client import TrezorClient, TrezorDebugClient
from trezorlib import tx_api
tests_dir = os.path.dirname(os.path.abspath(__file__))
tx_api.cache_dir = os.path.join(tests_dir, '../txcache')
import config
def get_device():
path = os.environ.get('TREZOR_PATH')
return get_transport(path)
tx_api.cache_dir = '../txcache'
class TrezorTest:
def setup_method(self, method):
wirelink = get_device()
debuglink = wirelink.find_debug()
self.client = TrezorClientDebugLink(wirelink)
self.client.set_debuglink(debuglink)
class TrezorTest(unittest.TestCase):
def setUp(self):
transport = config.TRANSPORT(*config.TRANSPORT_ARGS, **config.TRANSPORT_KWARGS)
if hasattr(config, 'DEBUG_TRANSPORT'):
debug_transport = config.DEBUG_TRANSPORT(*config.DEBUG_TRANSPORT_ARGS, **config.DEBUG_TRANSPORT_KWARGS)
self.client = TrezorDebugClient(transport)
self.client.set_debuglink(debug_transport)
else:
self.client = TrezorClient(transport)
self.client.set_tx_api(tx_api.TxApiBitcoin)
# self.client.set_buttonwait(3)
@ -56,11 +50,9 @@ class TrezorTest:
self.pin8 = '45678978'
self.client.wipe_device()
self.client.transport.session_begin()
def teardown_method(self, method):
self.client.transport.session_end()
self.client.close()
print("Setup finished")
print("--------------")
def setup_mnemonic_allallall(self):
self.client.load_device_by_mnemonic(mnemonic=self.mnemonic_all, pin='', passphrase_protection=False, label='test', language='english')
@ -68,42 +60,11 @@ class TrezorTest:
def setup_mnemonic_nopin_nopassphrase(self):
self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin='', passphrase_protection=False, label='test', language='english')
def setup_mnemonic_nopin_passphrase(self):
self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin='', passphrase_protection=True, label='test', language='english')
def setup_mnemonic_pin_nopassphrase(self):
self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin=self.pin4, passphrase_protection=False, label='test', language='english')
def setup_mnemonic_pin_passphrase(self):
self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin=self.pin4, passphrase_protection=True, label='test', language='english')
def generate_entropy(strength, internal_entropy, external_entropy):
'''
strength - length of produced seed. One of 128, 192, 256
random - binary stream of random data from external HRNG
'''
import hashlib
if strength not in (128, 192, 256):
raise ValueError("Invalid strength")
if not internal_entropy:
raise ValueError("Internal entropy is not provided")
if len(internal_entropy) < 32:
raise ValueError("Internal entropy too short")
if not external_entropy:
raise ValueError("External entropy is not provided")
if len(external_entropy) < 32:
raise ValueError("External entropy too short")
entropy = hashlib.sha256(internal_entropy + external_entropy).digest()
entropy_stripped = entropy[:strength // 8]
if len(entropy_stripped) * 8 != strength:
raise ValueError("Entropy length mismatch")
return entropy_stripped
def tearDown(self):
self.client.close()

View File

@ -0,0 +1,63 @@
# 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 sys
sys.path = ['../../'] + sys.path
from trezorlib.transport_pipe import PipeTransport
from trezorlib.transport_hid import HidTransport
from trezorlib.transport_udp import UdpTransport
def pipe_exists(path):
import os
try:
os.stat(path)
return True
except:
return False
devices = HidTransport.enumerate()
if len(devices) > 0:
print('Using TREZOR')
TRANSPORT = HidTransport
TRANSPORT_ARGS = (devices[0],)
TRANSPORT_KWARGS = {'debug_link': False}
DEBUG_TRANSPORT = HidTransport
DEBUG_TRANSPORT_ARGS = (devices[0],)
DEBUG_TRANSPORT_KWARGS = {'debug_link': True}
elif pipe_exists('/tmp/pipe.trezor.to'):
print('Using Emulator (v1=pipe)')
TRANSPORT = PipeTransport
TRANSPORT_ARGS = ('/tmp/pipe.trezor', False)
TRANSPORT_KWARGS = {}
DEBUG_TRANSPORT = PipeTransport
DEBUG_TRANSPORT_ARGS = ('/tmp/pipe.trezor_debug', False)
DEBUG_TRANSPORT_KWARGS = {}
elif True:
print('Using Emulator (v2=udp)')
TRANSPORT = UdpTransport
TRANSPORT_ARGS = ('', )
TRANSPORT_KWARGS = {}
DEBUG_TRANSPORT = UdpTransport
DEBUG_TRANSPORT_ARGS = ('', )
DEBUG_TRANSPORT_KWARGS = {}

View File

@ -0,0 +1,5 @@
#!/bin/bash
for i in test_*.py; do
echo Starting: $i
python $i > $i.out 2> $i.err
done

3
tests/device_tests/run.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
python -m unittest discover

View File

@ -16,21 +16,20 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import unittest
import common
from trezorlib import messages
from trezorlib import messages_pb2 as messages
class TestBasic(TrezorTest):
class TestBasic(common.TrezorTest):
def test_features(self):
f0 = self.client.features
f1 = self.client.call(messages.Initialize())
assert f0 == f1
features = self.client.call(messages.Initialize())
self.assertEqual(features, self.client.features)
def test_ping(self):
ping = self.client.call(messages.Ping(message='ahoj!'))
assert ping == messages.Success(message='ahoj!')
self.assertEqual(ping, messages.Success(message='ahoj!'))
def test_device_id_same(self):
id1 = self.client.get_device_id()
@ -38,10 +37,10 @@ class TestBasic(TrezorTest):
id2 = self.client.get_device_id()
# ID must be at least 12 characters
assert len(id1) >= 12
self.assertTrue(len(id1) >= 12)
# Every resulf of UUID must be the same
assert id1 == id2
self.assertEqual(id1, id2)
def test_device_id_different(self):
id1 = self.client.get_device_id()
@ -49,4 +48,7 @@ class TestBasic(TrezorTest):
id2 = self.client.get_device_id()
# Device ID must be fresh after every reset
assert id1 != id2
self.assertNotEqual(id1, id2)
if __name__ == '__main__':
unittest.main()

View File

@ -18,11 +18,12 @@
from __future__ import print_function
from .common import *
import unittest
import common
import time
from trezorlib import tools
class TestBip32Speed(TrezorTest):
class TestBip32Speed(common.TrezorTest):
def test_public_ckd(self):
self.setup_mnemonic_nopin_nopassphrase()
@ -35,7 +36,7 @@ class TestBip32Speed(TrezorTest):
delay = time.time() - start
expected = (depth + 1) * 0.26
print("DEPTH", depth, "EXPECTED DELAY", expected, "REAL DELAY", delay)
assert delay <= expected
self.assertLessEqual(delay, expected)
def test_private_ckd(self):
self.setup_mnemonic_nopin_nopassphrase()
@ -48,9 +49,8 @@ class TestBip32Speed(TrezorTest):
delay = time.time() - start
expected = (depth + 1) * 0.26
print("DEPTH", depth, "EXPECTED DELAY", expected, "REAL DELAY", delay)
assert delay <= expected
self.assertLessEqual(delay, expected)
@pytest.mark.skip_t2
def test_cache(self):
self.setup_mnemonic_nopin_nopassphrase()
@ -68,4 +68,7 @@ class TestBip32Speed(TrezorTest):
print("CACHED TIME", cache_time)
# Cached time expected to be at least 2x faster
assert cache_time <= nocache_time / 2.
self.assertLessEqual(cache_time, nocache_time / 2.)
if __name__ == '__main__':
unittest.main()

View File

@ -16,34 +16,45 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import time
import unittest
import common
import binascii
from trezorlib import messages as proto
from trezorlib import messages_pb2 as proto
from trezorlib import types_pb2 as types
from trezorlib.client import PinException
@pytest.mark.skip_t2
class TestDebuglink(TrezorTest):
class TestDebugLink(common.TrezorTest):
def test_layout(self):
layout = self.client.debug.read_layout()
assert len(layout) == 1024
self.assertEqual(len(layout), 1024)
def test_mnemonic(self):
self.setup_mnemonic_nopin_nopassphrase()
mnemonic = self.client.debug.read_mnemonic()
assert mnemonic == self.mnemonic12
self.assertEqual(mnemonic, self.mnemonic12)
def test_node(self):
self.setup_mnemonic_nopin_nopassphrase()
node = self.client.debug.read_node()
self.assertIsNotNone(node)
def test_pin(self):
self.setup_mnemonic_pin_passphrase()
# Manually trigger PinMatrixRequest
resp = self.client.call_raw(proto.Ping(message='test', pin_protection=True))
assert isinstance(resp, proto.PinMatrixRequest)
self.assertIsInstance(resp, proto.PinMatrixRequest)
pin = self.client.debug.read_pin()
assert pin[0] == '1234'
assert pin[1] != ''
self.assertEqual(pin[0], '1234')
self.assertNotEqual(pin[1], '')
pin_encoded = self.client.debug.read_pin_encoded()
resp = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
assert isinstance(resp, proto.Success)
self.assertIsInstance(resp, proto.Success)
if __name__ == '__main__':
unittest.main()

View File

@ -16,32 +16,30 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import time
import unittest
import common
from trezorlib import messages as proto
from trezorlib import messages_pb2 as proto
class TestMsgApplysettings(TrezorTest):
class TestMsgApplysettings(common.TrezorTest):
def test_apply_settings(self):
self.setup_mnemonic_pin_passphrase()
assert self.client.features.label == 'test'
self.assertEqual(self.client.features.label, 'test')
with self.client:
self.client.set_expected_responses([proto.PinMatrixRequest(),
proto.ButtonRequest(),
proto.Success(),
proto.Features()])
if self.client.features.major_version >= 2:
self.client.expected_responses.pop(0) # skip PinMatrixRequest
self.client.apply_settings(label='new label')
assert self.client.features.label == 'new label'
self.assertEqual(self.client.features.label, 'new label')
@pytest.mark.skip_t2
def test_invalid_language(self):
self.setup_mnemonic_pin_passphrase()
assert self.client.features.language == 'english'
self.assertEqual(self.client.features.language, 'english')
with self.client:
self.client.set_expected_responses([proto.PinMatrixRequest(),
@ -50,23 +48,21 @@ class TestMsgApplysettings(TrezorTest):
proto.Features()])
self.client.apply_settings(language='nonexistent')
assert self.client.features.language == 'english'
self.assertEqual(self.client.features.language, 'english')
def test_apply_settings_passphrase(self):
self.setup_mnemonic_pin_nopassphrase()
assert self.client.features.passphrase_protection is False
self.assertEqual(self.client.features.passphrase_protection, False)
with self.client:
self.client.set_expected_responses([proto.PinMatrixRequest(),
proto.ButtonRequest(),
proto.Success(),
proto.Features()])
if self.client.features.major_version >= 2:
self.client.expected_responses.pop(0) # skip PinMatrixRequest
self.client.apply_settings(use_passphrase=True)
assert self.client.features.passphrase_protection is True
self.assertEqual(self.client.features.passphrase_protection, True)
with self.client:
self.client.set_expected_responses([proto.ButtonRequest(),
@ -74,7 +70,7 @@ class TestMsgApplysettings(TrezorTest):
proto.Features()])
self.client.apply_settings(use_passphrase=False)
assert self.client.features.passphrase_protection is False
self.assertEqual(self.client.features.passphrase_protection, False)
with self.client:
self.client.set_expected_responses([proto.ButtonRequest(),
@ -82,9 +78,8 @@ class TestMsgApplysettings(TrezorTest):
proto.Features()])
self.client.apply_settings(use_passphrase=True)
assert self.client.features.passphrase_protection is True
self.assertEqual(self.client.features.passphrase_protection, True)
@pytest.mark.skip_t2
def test_apply_homescreen(self):
self.setup_mnemonic_pin_passphrase()
@ -96,3 +91,6 @@ class TestMsgApplysettings(TrezorTest):
proto.Success(),
proto.Features()])
self.client.apply_settings(homescreen=img)
if __name__ == '__main__':
unittest.main()

View File

@ -16,203 +16,207 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import time
import unittest
import common
from trezorlib import messages as proto
from trezorlib import messages_pb2 as proto
from trezorlib import types_pb2 as proto_types
@pytest.mark.skip_t2
class TestMsgChangepin(TrezorTest):
class TestMsgChangepin(common.TrezorTest):
def test_set_pin(self):
self.setup_mnemonic_nopin_nopassphrase()
features = self.client.call_raw(proto.Initialize())
assert features.pin_protection is False
self.assertFalse(features.pin_protection)
# Check that there's no PIN protection
ret = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(ret, proto.Success)
self.assertIsInstance(ret, proto.Success)
# Let's set new PIN
ret = self.client.call_raw(proto.ChangePin())
assert isinstance(ret, proto.ButtonRequest)
self.assertIsInstance(ret, proto.ButtonRequest)
# Press button
self.client.debug.press_yes()
ret = self.client.call_raw(proto.ButtonAck())
# Send the PIN for first time
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.encode_pin(self.pin6)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Send the PIN for second time
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.encode_pin(self.pin6)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Now we're done
assert isinstance(ret, proto.Success)
self.assertIsInstance(ret, proto.Success)
# Check that there's PIN protection now
features = self.client.call_raw(proto.Initialize())
assert features.pin_protection is True
self.assertTrue(features.pin_protection)
ret = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
self.client.call_raw(proto.Cancel())
# Check that the PIN is correct
assert self.client.debug.read_pin()[0] == self.pin6
self.assertEqual(self.client.debug.read_pin()[0], self.pin6)
def test_change_pin(self):
self.setup_mnemonic_pin_passphrase()
features = self.client.call_raw(proto.Initialize())
assert features.pin_protection is True
self.assertTrue(features.pin_protection)
# Check that there's PIN protection
ret = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
self.client.call_raw(proto.Cancel())
# Check current PIN value
assert self.client.debug.read_pin()[0] == self.pin4
self.assertEqual(self.client.debug.read_pin()[0], self.pin4)
# Let's change PIN
ret = self.client.call_raw(proto.ChangePin())
assert isinstance(ret, proto.ButtonRequest)
self.assertIsInstance(ret, proto.ButtonRequest)
# Press button
self.client.debug.press_yes()
ret = self.client.call_raw(proto.ButtonAck())
# Send current PIN
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.read_pin_encoded()
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Send new PIN for first time
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.encode_pin(self.pin6)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Send the PIN for second time
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.encode_pin(self.pin6)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Now we're done
assert isinstance(ret, proto.Success)
self.assertIsInstance(ret, proto.Success)
# Check that there's still PIN protection now
features = self.client.call_raw(proto.Initialize())
assert features.pin_protection is True
self.assertTrue(features.pin_protection)
ret = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
self.client.call_raw(proto.Cancel())
# Check that the PIN is correct
assert self.client.debug.read_pin()[0] == self.pin6
self.assertEqual(self.client.debug.read_pin()[0], self.pin6)
def test_remove_pin(self):
self.setup_mnemonic_pin_passphrase()
features = self.client.call_raw(proto.Initialize())
assert features.pin_protection is True
self.assertTrue(features.pin_protection)
# Check that there's PIN protection
ret = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
self.client.call_raw(proto.Cancel())
# Let's remove PIN
ret = self.client.call_raw(proto.ChangePin(remove=True))
assert isinstance(ret, proto.ButtonRequest)
self.assertIsInstance(ret, proto.ButtonRequest)
# Press button
self.client.debug.press_yes()
ret = self.client.call_raw(proto.ButtonAck())
# Send current PIN
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.read_pin_encoded()
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Now we're done
assert isinstance(ret, proto.Success)
self.assertIsInstance(ret, proto.Success)
# Check that there's no PIN protection now
features = self.client.call_raw(proto.Initialize())
assert features.pin_protection is False
self.assertFalse(features.pin_protection)
ret = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(ret, proto.Success)
self.assertIsInstance(ret, proto.Success)
def test_set_failed(self):
self.setup_mnemonic_nopin_nopassphrase()
features = self.client.call_raw(proto.Initialize())
assert features.pin_protection is False
self.assertFalse(features.pin_protection)
# Check that there's no PIN protection
ret = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(ret, proto.Success)
self.assertIsInstance(ret, proto.Success)
# Let's set new PIN
ret = self.client.call_raw(proto.ChangePin())
assert isinstance(ret, proto.ButtonRequest)
self.assertIsInstance(ret, proto.ButtonRequest)
# Press button
self.client.debug.press_yes()
ret = self.client.call_raw(proto.ButtonAck())
# Send the PIN for first time
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.encode_pin(self.pin6)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Send the PIN for second time, but with typo
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.encode_pin(self.pin4)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Now it should fail, because pins are different
assert isinstance(ret, proto.Failure)
self.assertIsInstance(ret, proto.Failure)
# Check that there's still no PIN protection now
features = self.client.call_raw(proto.Initialize())
assert features.pin_protection is False
self.assertFalse(features.pin_protection)
ret = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(ret, proto.Success)
self.assertIsInstance(ret, proto.Success)
def test_set_failed_2(self):
self.setup_mnemonic_pin_passphrase()
features = self.client.call_raw(proto.Initialize())
assert features.pin_protection is True
self.assertTrue(features.pin_protection)
# Let's set new PIN
ret = self.client.call_raw(proto.ChangePin())
assert isinstance(ret, proto.ButtonRequest)
self.assertIsInstance(ret, proto.ButtonRequest)
# Press button
self.client.debug.press_yes()
ret = self.client.call_raw(proto.ButtonAck())
# Send current PIN
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.read_pin_encoded()
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Send the PIN for first time
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.encode_pin(self.pin6)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Send the PIN for second time, but with typo
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
pin_encoded = self.client.debug.encode_pin(self.pin6 + '3')
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Now it should fail, because pins are different
assert isinstance(ret, proto.Failure)
self.assertIsInstance(ret, proto.Failure)
# Check that there's still old PIN protection
features = self.client.call_raw(proto.Initialize())
assert features.pin_protection is True
assert self.client.debug.read_pin()[0] == self.pin4
self.assertTrue(features.pin_protection)
self.assertEqual(self.client.debug.read_pin()[0], self.pin4)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,92 @@
# 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 unittest
import common
import binascii
from trezorlib.client import CallException
class TestMsgCipherkeyvalue(common.TrezorTest):
def test_encrypt(self):
self.setup_mnemonic_nopin_nopassphrase()
# different ask values
res = self.client.encrypt_keyvalue([0, 1, 2], b"test", b"testing message!", ask_on_encrypt=True, ask_on_decrypt=True)
self.assertEqual(binascii.hexlify(res), b'676faf8f13272af601776bc31bc14e8f')
res = self.client.encrypt_keyvalue([0, 1, 2], b"test", b"testing message!", ask_on_encrypt=True, ask_on_decrypt=False)
self.assertEqual(binascii.hexlify(res), b'5aa0fbcb9d7fa669880745479d80c622')
res = self.client.encrypt_keyvalue([0, 1, 2], b"test", b"testing message!", ask_on_encrypt=False, ask_on_decrypt=True)
self.assertEqual(binascii.hexlify(res), b'958d4f63269b61044aaedc900c8d6208')
res = self.client.encrypt_keyvalue([0, 1, 2], b"test", b"testing message!", ask_on_encrypt=False, ask_on_decrypt=False)
self.assertEqual(binascii.hexlify(res), b'e0cf0eb0425947000eb546cc3994bc6c')
# different key
res = self.client.encrypt_keyvalue([0, 1, 2], b"test2", b"testing message!", ask_on_encrypt=True, ask_on_decrypt=True)
self.assertEqual(binascii.hexlify(res), b'de247a6aa6be77a134bb3f3f925f13af')
# different message
res = self.client.encrypt_keyvalue([0, 1, 2], b"test", b"testing message! it is different", ask_on_encrypt=True, ask_on_decrypt=True)
self.assertEqual(binascii.hexlify(res), b'676faf8f13272af601776bc31bc14e8f3ae1c88536bf18f1b44f1e4c2c4a613d')
# different path
res = self.client.encrypt_keyvalue([0, 1, 3], b"test", b"testing message!", ask_on_encrypt=True, ask_on_decrypt=True)
self.assertEqual(binascii.hexlify(res), b'b4811a9d492f5355a5186ddbfccaae7b')
def test_decrypt(self):
self.setup_mnemonic_nopin_nopassphrase()
# different ask values
res = self.client.decrypt_keyvalue([0, 1, 2], b"test", binascii.unhexlify("676faf8f13272af601776bc31bc14e8f"), ask_on_encrypt=True, ask_on_decrypt=True)
self.assertEqual(res, b'testing message!')
res = self.client.decrypt_keyvalue([0, 1, 2], b"test", binascii.unhexlify("5aa0fbcb9d7fa669880745479d80c622"), ask_on_encrypt=True, ask_on_decrypt=False)
self.assertEqual(res, b'testing message!')
res = self.client.decrypt_keyvalue([0, 1, 2], b"test", binascii.unhexlify("958d4f63269b61044aaedc900c8d6208"), ask_on_encrypt=False, ask_on_decrypt=True)
self.assertEqual(res, b'testing message!')
res = self.client.decrypt_keyvalue([0, 1, 2], b"test", binascii.unhexlify("e0cf0eb0425947000eb546cc3994bc6c"), ask_on_encrypt=False, ask_on_decrypt=False)
self.assertEqual(res, b'testing message!')
# different key
res = self.client.decrypt_keyvalue([0, 1, 2], b"test2", binascii.unhexlify("de247a6aa6be77a134bb3f3f925f13af"), ask_on_encrypt=True, ask_on_decrypt=True)
self.assertEqual(res, b'testing message!')
# different message
res = self.client.decrypt_keyvalue([0, 1, 2], b"test", binascii.unhexlify("676faf8f13272af601776bc31bc14e8f3ae1c88536bf18f1b44f1e4c2c4a613d"), ask_on_encrypt=True, ask_on_decrypt=True)
self.assertEqual(res, b'testing message! it is different')
# different path
res = self.client.decrypt_keyvalue([0, 1, 3], b"test", binascii.unhexlify("b4811a9d492f5355a5186ddbfccaae7b"), ask_on_encrypt=True, ask_on_decrypt=True)
self.assertEqual(res, b'testing message!')
def test_encrypt_badlen(self):
self.setup_mnemonic_nopin_nopassphrase()
self.assertRaises(Exception, self.client.encrypt_keyvalue, [0, 1, 2], b"test", b"testing")
def test_decrypt_badlen(self):
self.setup_mnemonic_nopin_nopassphrase()
self.assertRaises(Exception, self.client.decrypt_keyvalue, [0, 1, 2], b"test", b"testing")
if __name__ == '__main__':
unittest.main()

View File

@ -16,38 +16,42 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import time
import unittest
import common
from trezorlib import messages as proto
from trezorlib import messages_pb2 as proto
from trezorlib import types_pb2 as proto_types
@pytest.mark.skip_t2
class TestMsgClearsession(TrezorTest):
class TestMsgClearsession(common.TrezorTest):
def test_clearsession(self):
self.setup_mnemonic_pin_passphrase()
with self.client:
self.client.set_expected_responses([proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success()])
self.client.set_expected_responses([proto.ButtonRequest(code=proto_types.ButtonRequest_ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success()])
res = self.client.ping('random data', button_protection=True, pin_protection=True, passphrase_protection=True)
assert res == 'random data'
self.assertEqual(res, 'random data')
with self.client:
# pin and passphrase are cached
self.client.set_expected_responses([proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success()])
self.client.set_expected_responses([proto.ButtonRequest(code=proto_types.ButtonRequest_ProtectCall), proto.Success()])
res = self.client.ping('random data', button_protection=True, pin_protection=True, passphrase_protection=True)
assert res == 'random data'
self.assertEqual(res, 'random data')
self.client.clear_session()
# session cache is cleared
with self.client:
self.client.set_expected_responses([proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success()])
self.client.set_expected_responses([proto.ButtonRequest(code=proto_types.ButtonRequest_ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success()])
res = self.client.ping('random data', button_protection=True, pin_protection=True, passphrase_protection=True)
assert res == 'random data'
self.assertEqual(res, 'random data')
with self.client:
# pin and passphrase are cached
self.client.set_expected_responses([proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success()])
self.client.set_expected_responses([proto.ButtonRequest(code=proto_types.ButtonRequest_ProtectCall), proto.Success()])
res = self.client.ping('random data', button_protection=True, pin_protection=True, passphrase_protection=True)
assert res == 'random data'
self.assertEqual(res, 'random data')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,52 @@
# 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 unittest
import common
import binascii
import trezorlib.messages_pb2 as proto
import trezorlib.types_pb2 as proto_types
from trezorlib.client import CallException
class TestMsgEstimatetxsize(common.TrezorTest):
def test_estimate_size(self):
self.setup_mnemonic_nopin_nopassphrase()
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
amount=390000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
est_size = self.client.estimate_tx_size('Bitcoin', [inp1, ], [out1, ])
self.assertEqual(est_size, 194)
(_, tx) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, ])
real_size = len(tx)
self.assertGreaterEqual(est_size, real_size)
if __name__ == '__main__':
unittest.main()

View File

@ -16,15 +16,20 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import unittest
import common
import trezorlib.ckd_public as bip32
import binascii
class TestMsgEthereumGetaddress(TrezorTest):
class TestMsgEthereumGetaddress(common.TrezorTest):
def test_ethereum_getaddress(self):
self.setup_mnemonic_nopin_nopassphrase()
assert hexlify(self.client.ethereum_get_address([])) == b'1d1c328764a41bda0492b66baa30c4a339ff85ef'
assert hexlify(self.client.ethereum_get_address([1])) == b'437207ca3cf43bf2e47dea0756d736c5df4f597a'
assert hexlify(self.client.ethereum_get_address([0, -1])) == b'e5d96dfa07bcf1a3ae43677840c31394258861bf'
assert hexlify(self.client.ethereum_get_address([-9, 0])) == b'f68804ac9eca9483ab4241d3e4751590d2c05102'
assert hexlify(self.client.ethereum_get_address([0, 9999999])) == b'7a6366ecfcaf0d5dcc1539c171696c6cdd1eb8ed'
self.assertEqual(binascii.hexlify(self.client.ethereum_get_address([])), '1d1c328764a41bda0492b66baa30c4a339ff85ef')
self.assertEqual(binascii.hexlify(self.client.ethereum_get_address([1])), '437207ca3cf43bf2e47dea0756d736c5df4f597a')
self.assertEqual(binascii.hexlify(self.client.ethereum_get_address([0, -1])), 'e5d96dfa07bcf1a3ae43677840c31394258861bf')
self.assertEqual(binascii.hexlify(self.client.ethereum_get_address([-9, 0])), 'f68804ac9eca9483ab4241d3e4751590d2c05102')
self.assertEqual(binascii.hexlify(self.client.ethereum_get_address([0, 9999999])), '7a6366ecfcaf0d5dcc1539c171696c6cdd1eb8ed')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,239 @@
# 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 unittest
import common
import binascii
import trezorlib.messages_pb2 as proto
import trezorlib.types_pb2 as proto_types
from rlp.utils import int_to_big_endian
class TestMsgEthereumSigntx(common.TrezorTest):
def test_ethereum_signtx_nodata(self):
self.setup_mnemonic_nopin_nopassphrase()
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0, 0],
nonce=0,
gas_price=20,
gas_limit=20,
to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
value=10)
self.assertEqual(sig_v, 27)
self.assertEqual(binascii.hexlify(sig_r), '9b61192a161d056c66cfbbd331edb2d783a0193bd4f65f49ee965f791d898f72')
self.assertEqual(binascii.hexlify(sig_s), '49c0bbe35131592c6ed5c871ac457feeb16a1493f64237387fab9b83c1a202f7')
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0, 0],
nonce=123456,
gas_price=20000,
gas_limit=20000,
to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
value=12345678901234567890)
self.assertEqual(sig_v, 28)
self.assertEqual(binascii.hexlify(sig_r), '6de597b8ec1b46501e5b159676e132c1aa78a95bd5892ef23560a9867528975a')
self.assertEqual(binascii.hexlify(sig_s), '6e33c4230b1ecf96a8dbb514b4aec0a6d6ba53f8991c8143f77812aa6daa993f')
def test_ethereum_signtx_data(self):
self.setup_mnemonic_nopin_nopassphrase()
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0, 0],
nonce=0,
gas_price=20,
gas_limit=20,
to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
value=10,
data='abcdefghijklmnop' * 16)
self.assertEqual(sig_v, 28)
self.assertEqual(binascii.hexlify(sig_r), '6da89ed8627a491bedc9e0382f37707ac4e5102e25e7a1234cb697cedb7cd2c0')
self.assertEqual(binascii.hexlify(sig_s), '691f73b145647623e2d115b208a7c3455a6a8a83e3b4db5b9c6d9bc75825038a')
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0, 0],
nonce=123456,
gas_price=20000,
gas_limit=20000,
to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
value=12345678901234567890,
data='ABCDEFGHIJKLMNOP' * 256 + '!!!')
self.assertEqual(sig_v, 28)
self.assertEqual(binascii.hexlify(sig_r), '4e90b13c45c6a9bf4aaad0e5427c3e62d76692b36eb727c78d332441b7400404')
self.assertEqual(binascii.hexlify(sig_s), '3ff236e7d05f0f9b1ee3d70599bb4200638f28388a8faf6bb36db9e04dc544be')
def test_ethereum_signtx_message(self):
self.setup_mnemonic_nopin_nopassphrase()
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0, 0],
nonce=0,
gas_price=20000,
gas_limit=20000,
to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
value=0,
data='ABCDEFGHIJKLMNOP' * 256 + '!!!')
self.assertEqual(sig_v, 28)
self.assertEqual(binascii.hexlify(sig_r), '070e9dafda4d9e733fa7b6747a75f8a4916459560efb85e3e73cd39f31aa160d')
self.assertEqual(binascii.hexlify(sig_s), '7842db33ef15c27049ed52741db41fe3238a6fa3a6a0888fcfb74d6917600e41')
def test_ethereum_signtx_newcontract(self):
self.setup_mnemonic_nopin_nopassphrase()
# contract creation without data should fail.
self.assertRaises(Exception, self.client.ethereum_sign_tx,
n=[0, 0],
nonce=123456,
gas_price=20000,
gas_limit=20000,
to='',
value=12345678901234567890)
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0, 0],
nonce=0,
gas_price=20000,
gas_limit=20000,
to='',
value=12345678901234567890,
data='ABCDEFGHIJKLMNOP' * 256 + '!!!')
self.assertEqual(sig_v, 28)
self.assertEqual(binascii.hexlify(sig_r), 'b401884c10ae435a2e792303b5fc257a09f94403b2883ad8c0ac7a7282f5f1f9')
self.assertEqual(binascii.hexlify(sig_s), '4742fc9e6a5fa8db3db15c2d856914a7f3daab21603a6c1ce9e9927482f8352e')
def test_ethereum_sanity_checks(self):
# gas overflow
self.assertRaises(Exception, self.client.ethereum_sign_tx,
n=[0, 0],
nonce=123456,
gas_price=0xffffffffffffffffffffffffffffffff,
gas_limit=0xffffffffffffffffffffffffffffff,
to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
value=12345678901234567890)
# no gas price
self.assertRaises(Exception, self.client.ethereum_sign_tx,
n=[0, 0],
nonce=123456,
gas_limit=10000,
to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
value=12345678901234567890)
# no gas limit
self.assertRaises(Exception, self.client.ethereum_sign_tx,
n=[0, 0],
nonce=123456,
gas_price=10000,
to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
value=12345678901234567890)
# no nonce
self.assertRaises(Exception, self.client.ethereum_sign_tx,
n=[0, 0],
gas_price=10000,
gas_limit=123456,
to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
value=12345678901234567890)
def test_ethereum_signtx_nodata_eip155(self):
self.setup_mnemonic_allallall()
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0x80000000 | 44, 0x80000000 | 1, 0x80000000, 0, 0],
nonce=0,
gas_price=20000000000,
gas_limit=21000,
to=binascii.unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
value=100000000000000000,
chain_id=3)
self.assertEqual(sig_v, 41)
self.assertEqual(binascii.hexlify(sig_r), 'a90d0bc4f8d63be69453dd62f2bb5fff53c610000abf956672564d8a654d401a')
self.assertEqual(binascii.hexlify(sig_s), '544a2e57bc8b4da18660a1e6036967ea581cc635f5137e3ba97a750867c27cf2')
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0x80000000 | 44, 0x80000000 | 1, 0x80000000, 0, 0],
nonce=1,
gas_price=20000000000,
gas_limit=21000,
to=binascii.unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
value=100000000000000000,
chain_id=3)
self.assertEqual(sig_v, 42)
self.assertEqual(binascii.hexlify(sig_r), '699428a6950e23c6843f1bf3754f847e64e047e829978df80d55187d19a401ce')
self.assertEqual(binascii.hexlify(sig_s), '087343d0a3a2f10842218ffccb146b59a8431b6245ab389fde22dc833f171e6e')
def test_ethereum_signtx_data_eip155(self):
self.setup_mnemonic_allallall()
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0x80000000 | 44, 0x80000000 | 1, 0x80000000, 0, 0],
nonce=2,
gas_price=20000000000,
gas_limit=21004,
to=binascii.unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
value=100000000000000000,
data='\0',
chain_id=3)
self.assertEqual(sig_v, 42)
self.assertEqual(binascii.hexlify(sig_r), 'ba85b622a8bb82606ba96c132e81fa8058172192d15bc41d7e57c031bca17df4')
self.assertEqual(binascii.hexlify(sig_s), '6473b75997634b6f692f8d672193591d299d5bf1c2d6e51f1a14ed0530b91c7d')
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0x80000000 | 44, 0x80000000 | 1, 0x80000000, 0, 0],
nonce=3,
gas_price=20000000000,
gas_limit=299732,
to=binascii.unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
value=100000000000000000,
data='ABCDEFGHIJKLMNOP' * 256 + '!!!',
chain_id=3)
self.assertEqual(sig_v, 42)
self.assertEqual(binascii.hexlify(sig_r), 'd021c98f92859c8db5e4de2f0e410a8deb0c977eb1a631e323ebf7484bd0d79a')
self.assertEqual(binascii.hexlify(sig_s), '2c0e9defc9b1e895dc9520ff25ba3c635b14ad70aa86a5ad6c0a3acb82b569b6')
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0x80000000 | 44, 0x80000000 | 1, 0x80000000, 0, 0],
nonce=4,
gas_price=20000000000,
gas_limit=21004,
to=binascii.unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
value=0,
data='\0',
chain_id=3)
self.assertEqual(sig_v, 42)
self.assertEqual(binascii.hexlify(sig_r), 'dd52f026972a83c56b7dea356836fcfc70a68e3b879cdc8ef2bb5fea23e0a7aa')
self.assertEqual(binascii.hexlify(sig_s), '079285fe579c9a2da25c811b1c5c0a74cd19b6301ee42cf20ef7b3b1353f7242')
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0x80000000 | 44, 0x80000000 | 1, 0x80000000, 0, 0],
nonce=5,
gas_price=0,
gas_limit=21004,
to=binascii.unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
value=0,
data='\0',
chain_id=3)
self.assertEqual(sig_v, 42)
self.assertEqual(binascii.hexlify(sig_r), 'f7505f709d5999343aea3c384034c62d0514336ff6c6af65582006f708f81503')
self.assertEqual(binascii.hexlify(sig_s), '44e09e29a4b6247000b46ddc94fe391e94deb2b39ad6ac6398e6db5bec095ba9')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,62 @@
# 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 unittest
import common
import trezorlib.ckd_public as bip32
class TestMsgGetaddress(common.TrezorTest):
def test_btc(self):
self.setup_mnemonic_nopin_nopassphrase()
self.assertEqual(self.client.get_address('Bitcoin', []), '1EfKbQupktEMXf4gujJ9kCFo83k1iMqwqK')
self.assertEqual(self.client.get_address('Bitcoin', [1]), '1CK7SJdcb8z9HuvVft3D91HLpLC6KSsGb')
self.assertEqual(self.client.get_address('Bitcoin', [0, -1]), '1JVq66pzRBvqaBRFeU9SPVvg3er4ZDgoMs')
self.assertEqual(self.client.get_address('Bitcoin', [-9, 0]), '1F4YdQdL9ZQwvcNTuy5mjyQxXkyCfMcP2P')
self.assertEqual(self.client.get_address('Bitcoin', [0, 9999999]), '1GS8X3yc7ntzwGw9vXwj9wqmBWZkTFewBV')
def test_ltc(self):
self.setup_mnemonic_nopin_nopassphrase()
self.assertEqual(self.client.get_address('Litecoin', []), 'LYtGrdDeqYUQnTkr5sHT2DKZLG7Hqg7HTK')
self.assertEqual(self.client.get_address('Litecoin', [1]), 'LKRGNecThFP3Q6c5fosLVA53Z2hUDb1qnE')
self.assertEqual(self.client.get_address('Litecoin', [0, -1]), 'LcinMK8pVrAtpz7Qpc8jfWzSFsDLgLYfG6')
self.assertEqual(self.client.get_address('Litecoin', [-9, 0]), 'LZHVtcwAEDf1BR4d67551zUijyLUpDF9EX')
self.assertEqual(self.client.get_address('Litecoin', [0, 9999999]), 'Laf5nGHSCT94C5dK6fw2RxuXPiw2ZuRR9S')
def test_tbtc(self):
self.setup_mnemonic_nopin_nopassphrase()
self.assertEqual(self.client.get_address('Testnet', [111, 42]), 'moN6aN6NP1KWgnPSqzrrRPvx2x1UtZJssa')
def test_public_ckd(self):
self.setup_mnemonic_nopin_nopassphrase()
node = self.client.get_public_node([]).node
node_sub1 = self.client.get_public_node([1]).node
node_sub2 = bip32.public_ckd(node, [1])
self.assertEqual(node_sub1.chain_code, node_sub2.chain_code)
self.assertEqual(node_sub1.public_key, node_sub2.public_key)
address1 = self.client.get_address('Bitcoin', [1])
address2 = bip32.get_address(node_sub2, 0)
self.assertEqual(address2, '1CK7SJdcb8z9HuvVft3D91HLpLC6KSsGb')
self.assertEqual(address1, address2)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,67 @@
# 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 unittest
import common
import trezorlib.ckd_public as bip32
import trezorlib.types_pb2 as proto_types
import binascii
class TestMsgGetaddress(common.TrezorTest):
def test_show(self):
self.setup_mnemonic_nopin_nopassphrase()
self.assertEqual(self.client.get_address('Bitcoin', [1], show_display=True), '1CK7SJdcb8z9HuvVft3D91HLpLC6KSsGb')
self.assertEqual(self.client.get_address('Bitcoin', [2], show_display=True), '15AeAhtNJNKyowK8qPHwgpXkhsokzLtUpG')
self.assertEqual(self.client.get_address('Bitcoin', [3], show_display=True), '1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5')
def test_show_multisig_3(self):
self.setup_mnemonic_nopin_nopassphrase()
node = bip32.deserialize('xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy')
multisig = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=node, address_n=[1]),
proto_types.HDNodePathType(node=node, address_n=[2]),
proto_types.HDNodePathType(node=node, address_n=[3])],
signatures=[b'', b'', b''],
m=2,
)
for i in [1, 2, 3]:
self.assertEqual(self.client.get_address('Bitcoin', [i], show_display=True, multisig=multisig), '3E7GDtuHqnqPmDgwH59pVC7AvySiSkbibz')
def test_show_multisig_15(self):
self.setup_mnemonic_nopin_nopassphrase()
node = bip32.deserialize('xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy')
pubs = []
for x in range(15):
pubs.append(proto_types.HDNodePathType(node=node, address_n=[x]))
multisig = proto_types.MultisigRedeemScriptType(
pubkeys=pubs,
signatures=[b''] * 15,
m=15,
)
for i in range(15):
self.assertEqual(self.client.get_address('Bitcoin', [i], show_display=True, multisig=multisig), '3QaKF8zobqcqY8aS6nxCD5ZYdiRfL3RCmU')
if __name__ == '__main__':
unittest.main()

View File

@ -18,11 +18,12 @@
from __future__ import print_function
import unittest
import common
import math
from .common import *
import trezorlib.messages as proto
import trezorlib.messages_pb2 as proto
import trezorlib.types_pb2 as proto_types
def entropy(data):
counts = {}
@ -37,13 +38,15 @@ def entropy(data):
e -= p * math.log(p, 256)
return e
class TestMsgGetentropy(TrezorTest):
class TestMsgGetentropy(common.TrezorTest):
def test_entropy(self):
for l in [0, 1, 2, 3, 4, 5, 8, 9, 16, 17, 32, 33, 64, 65, 128, 129, 256, 257, 512, 513, 1024]:
with self.client:
self.client.set_expected_responses([proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Entropy()])
self.client.set_expected_responses([proto.ButtonRequest(code=proto_types.ButtonRequest_ProtectCall), proto.Entropy()])
ent = self.client.get_entropy(l)
assert len(ent) == l
self.assertTrue(len(ent) >= l)
print('entropy = ', entropy(ent))
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,46 @@
# 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 unittest
import common
import trezorlib.ckd_public as bip32
class TestMsgGetpublic_key(common.TrezorTest):
def test_btc(self):
self.setup_mnemonic_nopin_nopassphrase()
self.assertEqual(bip32.serialize(self.client.get_public_node([]).node, 0x0488B21E), 'xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy')
self.assertEqual(bip32.serialize(self.client.get_public_node([1]).node, 0x0488B21E), 'xpub68zNxjsTrV8y9AadThLW7dTAqEpZ7xBLFSyJ3X9pjTv6Njg6kxgjXJkzxq8u3ttnjBw1jupQHMP3gpGZzZqd1eh5S4GjkaMhPR18vMyUi8N')
self.assertEqual(bip32.serialize(self.client.get_public_node([0, -1]).node, 0x0488B21E), 'xpub6A3FoZqYXj1AbW4thRwBh26YwZWbmoyjTaZwwxJjY1oKUpefLepL3RFS9DHKQrjAfxDrzDepYMDZPqXN6upQm3bHQ9xaXD5a3mqni3goF4v')
self.assertEqual(bip32.serialize(self.client.get_public_node([-9, 0]).node, 0x0488B21E), 'xpub6A2h5mzLDfYginoD7q7wCWbq18wTbN9gducRr2w5NRTwdLeoT3cJSwefFqW7uXTpVFGtpUyDMBNYs3DNvvXx6NPjF9YEbUQrtxFSWnPtVrv')
self.assertEqual(bip32.serialize(self.client.get_public_node([0, 9999999]).node, 0x0488B21E), 'xpub6A3FoZqQEK6iwLZ4HFkqSo5fb35BH4bpjC4SPZ63prfLdGYPwYxEuC6o91bUvFFdMzKWe5rs3axHRUjxJaSvBnKKFtnfLwDACRxPxabsv2r')
def test_ltc(self):
self.setup_mnemonic_nopin_nopassphrase()
self.assertEqual(bip32.serialize(self.client.get_public_node([]).node, 0x019dA462), 'Ltub2SSUS19CirucVPGDKDBatBDBEM2s9UbH66pBURfaKrMocCPLhQ7Z7hecy5VYLHA5fRdXwB2e61j2VJCNzVsqKTCVEU1vECjqi5EyczFX9xp')
self.assertEqual(bip32.serialize(self.client.get_public_node([1]).node, 0x019dA462), 'Ltub2VRVRP5VjvSyPXra4BLVyVZPv397sjhUNjBGsbtw6xko77JuQyBULxFSKheviJJ3KQLbL3Cx8P2RnudguTw4raUVjCACRG7jsumUptYx55C')
self.assertEqual(bip32.serialize(self.client.get_public_node([0, -1]).node, 0x019dA462), 'Ltub2WUNGD3aRAKAqsLqHuwBYtCn2MqAXbVsarmvn33quWe2DCHTzfK4s4jsW5oM5G8RGAdSaM3NPNrwVvtV1ourbyNhhHr3BtqcYGc8caf5GoT')
self.assertEqual(bip32.serialize(self.client.get_public_node([-9, 0]).node, 0x019dA462), 'Ltub2WToYRCN76rgyA59iK7w4Ni45wG2M9fpmBpQg7gBjvJeMiHc7473Gb96ci29Zvs55TgUQcMmCD1vy8aVqpdPwJB9YHRhGAAuPT1nRLLXmFu')
self.assertEqual(bip32.serialize(self.client.get_public_node([0, 9999999]).node, 0x019dA462), 'Ltub2WUNGD3S7kQjBhpzsjkqJfBtfqPk2r7xrUGRDdqACMW3MeBCbZSyiqbEVt7WaeesxCj6EDFQtcbfXa75DUYN2i6jZ2g81cyCgvijs9J2u2n')
def test_tbtc(self):
self.setup_mnemonic_nopin_nopassphrase()
self.assertEqual(bip32.serialize(self.client.get_public_node([111, 42]).node, 0x043587CF), 'tpubDAgixSyai5PWbc8N1mBkHDR5nLgAnHFtY7r4y5EzxqAxrt9YUDpZL3kaRoHVvCfrcwNo31c2isBP2uTHcZxEosuKbyJhCAbrvGoPuLUZ7Mz')
if __name__ == '__main__':
unittest.main()

View File

@ -16,41 +16,63 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import unittest
import common
from trezorlib import messages_pb2 as messages
class TestDeviceLoad(common.TrezorTest):
@pytest.mark.skip_t2
class TestDeviceLoad(TrezorTest):
def test_load_device_1(self):
self.setup_mnemonic_nopin_nopassphrase()
mnemonic = self.client.debug.read_mnemonic()
assert mnemonic == self.mnemonic12
self.assertEqual(mnemonic, self.mnemonic12)
pin = self.client.debug.read_pin()[0]
assert pin is None
self.assertEqual(pin, '')
passphrase_protection = self.client.debug.read_passphrase_protection()
assert passphrase_protection is False
self.assertEqual(passphrase_protection, False)
address = self.client.get_address('Bitcoin', [])
assert address == '1EfKbQupktEMXf4gujJ9kCFo83k1iMqwqK'
self.assertEqual(address, '1EfKbQupktEMXf4gujJ9kCFo83k1iMqwqK')
def test_load_device_2(self):
self.setup_mnemonic_pin_passphrase()
self.client.set_passphrase('passphrase')
mnemonic = self.client.debug.read_mnemonic()
assert mnemonic == self.mnemonic12
self.assertEqual(mnemonic, self.mnemonic12)
pin = self.client.debug.read_pin()[0]
assert pin == self.pin4
self.assertEqual(pin, self.pin4)
passphrase_protection = self.client.debug.read_passphrase_protection()
assert passphrase_protection is True
self.assertEqual(passphrase_protection, True)
address = self.client.get_address('Bitcoin', [])
assert address == '15fiTDFwZd2kauHYYseifGi9daH2wniDHH'
self.assertEqual(address, '15fiTDFwZd2kauHYYseifGi9daH2wniDHH')
def test_load_device_3(self):
self.client.load_device_by_xprv(xprv='xprv9s21ZrQH143K2JF8RafpqtKiTbsbaxEeUaMnNHsm5o6wCW3z8ySyH4UxFVSfZ8n7ESu7fgir8imbZKLYVBxFPND1pniTZ81vKfd45EHKX73', pin='', passphrase_protection=False, label='test', language='english')
passphrase_protection = self.client.debug.read_passphrase_protection()
self.assertEqual(passphrase_protection, False)
address = self.client.get_address('Bitcoin', [])
self.assertEqual(address, '128RdrAkJDmqasgvfRf6MC5VcX4HKqH4mR')
def test_load_device_4(self):
self.client.load_device_by_xprv(xprv='xprv9s21ZrQH143K2JF8RafpqtKiTbsbaxEeUaMnNHsm5o6wCW3z8ySyH4UxFVSfZ8n7ESu7fgir8imbZKLYVBxFPND1pniTZ81vKfd45EHKX73', pin='', passphrase_protection=True, label='test', language='english')
self.client.set_passphrase('passphrase')
passphrase_protection = self.client.debug.read_passphrase_protection()
self.assertEqual(passphrase_protection, True)
address = self.client.get_address('Bitcoin', [])
self.assertEqual(address, '1CHUbFa4wTTPYgkYaw2LHSd5D4qJjMU8ri')
def test_load_device_utf(self):
words_nfkd = u'Pr\u030ci\u0301s\u030cerne\u030c z\u030clut\u030couc\u030cky\u0301 ku\u030an\u030c u\u0301pe\u030cl d\u030ca\u0301belske\u0301 o\u0301dy za\u0301ker\u030cny\u0301 uc\u030cen\u030c be\u030cz\u030ci\u0301 pode\u0301l zo\u0301ny u\u0301lu\u030a'
@ -83,6 +105,9 @@ class TestDeviceLoad(TrezorTest):
self.client.set_passphrase(passphrase_nfd)
address_nfd = self.client.get_address('Bitcoin', [])
assert address_nfkd == address_nfc
assert address_nfkd == address_nfkc
assert address_nfkd == address_nfd
self.assertEqual(address_nfkd, address_nfc)
self.assertEqual(address_nfkd, address_nfkc)
self.assertEqual(address_nfkd, address_nfd)
if __name__ == '__main__':
unittest.main()

View File

@ -16,13 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import time
import unittest
import common
from trezorlib import messages as proto
from trezorlib import messages_pb2 as proto
from trezorlib import types_pb2 as proto_types
@pytest.mark.skip_t2
class TestMsgPing(TrezorTest):
class TestPing(common.TrezorTest):
def test_ping(self):
self.setup_mnemonic_pin_passphrase()
@ -30,33 +31,36 @@ class TestMsgPing(TrezorTest):
with self.client:
self.client.set_expected_responses([proto.Success()])
res = self.client.ping('random data')
assert res == 'random data'
self.assertEqual(res, 'random data')
with self.client:
self.client.set_expected_responses([proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success()])
self.client.set_expected_responses([proto.ButtonRequest(code=proto_types.ButtonRequest_ProtectCall), proto.Success()])
res = self.client.ping('random data', button_protection=True)
assert res == 'random data'
self.assertEqual(res, 'random data')
with self.client:
self.client.set_expected_responses([proto.PinMatrixRequest(), proto.Success()])
res = self.client.ping('random data', pin_protection=True)
assert res == 'random data'
self.assertEqual(res, 'random data')
with self.client:
self.client.set_expected_responses([proto.PassphraseRequest(), proto.Success()])
res = self.client.ping('random data', passphrase_protection=True)
assert res == 'random data'
self.assertEqual(res, 'random data')
def test_ping_caching(self):
self.setup_mnemonic_pin_passphrase()
with self.client:
self.client.set_expected_responses([proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success()])
self.client.set_expected_responses([proto.ButtonRequest(code=proto_types.ButtonRequest_ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success()])
res = self.client.ping('random data', button_protection=True, pin_protection=True, passphrase_protection=True)
assert res == 'random data'
self.assertEqual(res, 'random data')
with self.client:
# pin and passphrase are cached
self.client.set_expected_responses([proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success()])
self.client.set_expected_responses([proto.ButtonRequest(code=proto_types.ButtonRequest_ProtectCall), proto.Success()])
res = self.client.ping('random data', button_protection=True, pin_protection=True, passphrase_protection=True)
assert res == 'random data'
self.assertEqual(res, 'random data')
if __name__ == '__main__':
unittest.main()

View File

@ -18,13 +18,12 @@
from __future__ import print_function
from .common import *
from trezorlib import messages as proto
import unittest
import common
from trezorlib import messages_pb2 as proto
@pytest.mark.skip_t2
class TestMsgRecoverydevice(TrezorTest):
class TestDeviceRecovery(common.TrezorTest):
def test_pin_passphrase(self):
mnemonic = self.mnemonic12.split(' ')
ret = self.client.call_raw(proto.RecoveryDevice(word_count=12,
@ -34,12 +33,12 @@ class TestMsgRecoverydevice(TrezorTest):
language='english',
enforce_wordlist=True))
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
# Enter PIN for first time
pin_encoded = self.client.debug.encode_pin(self.pin6)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
# Enter PIN for second time
pin_encoded = self.client.debug.encode_pin(self.pin6)
@ -47,7 +46,7 @@ class TestMsgRecoverydevice(TrezorTest):
fakes = 0
for _ in range(int(12 * 2)):
assert isinstance(ret, proto.WordRequest)
self.assertIsInstance(ret, proto.WordRequest)
(word, pos) = self.client.debug.read_recovery_word()
if pos != 0:
@ -60,27 +59,27 @@ class TestMsgRecoverydevice(TrezorTest):
print(mnemonic)
# Workflow succesfully ended
assert isinstance(ret, proto.Success)
self.assertIsInstance(ret, proto.Success)
# 12 expected fake words and all words of mnemonic are used
assert fakes == 12
assert mnemonic == [None] * 12
self.assertEqual(fakes, 12)
self.assertEqual(mnemonic, [None] * 12)
# Mnemonic is the same
self.client.init_device()
assert self.client.debug.read_mnemonic() == self.mnemonic12
self.assertEqual(self.client.debug.read_mnemonic(), self.mnemonic12)
assert self.client.features.pin_protection is True
assert self.client.features.passphrase_protection is True
self.assertTrue(self.client.features.pin_protection)
self.assertTrue(self.client.features.passphrase_protection)
# Do passphrase-protected action, PassphraseRequest should be raised
resp = self.client.call_raw(proto.Ping(passphrase_protection=True))
assert isinstance(resp, proto.PassphraseRequest)
self.assertIsInstance(resp, proto.PassphraseRequest)
self.client.call_raw(proto.Cancel())
# Do PIN-protected action, PinRequest should be raised
resp = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(resp, proto.PinMatrixRequest)
self.assertIsInstance(resp, proto.PinMatrixRequest)
self.client.call_raw(proto.Cancel())
def test_nopin_nopassphrase(self):
@ -94,7 +93,7 @@ class TestMsgRecoverydevice(TrezorTest):
fakes = 0
for _ in range(int(12 * 2)):
assert isinstance(ret, proto.WordRequest)
self.assertIsInstance(ret, proto.WordRequest)
(word, pos) = self.client.debug.read_recovery_word()
if pos != 0:
@ -107,26 +106,26 @@ class TestMsgRecoverydevice(TrezorTest):
print(mnemonic)
# Workflow succesfully ended
assert isinstance(ret, proto.Success)
self.assertIsInstance(ret, proto.Success)
# 12 expected fake words and all words of mnemonic are used
assert fakes == 12
assert mnemonic == [None] * 12
self.assertEqual(fakes, 12)
self.assertEqual(mnemonic, [None] * 12)
# Mnemonic is the same
self.client.init_device()
assert self.client.debug.read_mnemonic() == self.mnemonic12
self.assertEqual(self.client.debug.read_mnemonic(), self.mnemonic12)
assert self.client.features.pin_protection is False
assert self.client.features.passphrase_protection is False
self.assertFalse(self.client.features.pin_protection)
self.assertFalse(self.client.features.passphrase_protection)
# Do passphrase-protected action, PassphraseRequest should NOT be raised
resp = self.client.call_raw(proto.Ping(passphrase_protection=True))
assert isinstance(resp, proto.Success)
self.assertIsInstance(resp, proto.Success)
# Do PIN-protected action, PinRequest should NOT be raised
resp = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(resp, proto.Success)
self.assertIsInstance(resp, proto.Success)
def test_word_fail(self):
ret = self.client.call_raw(proto.RecoveryDevice(word_count=12,
@ -136,12 +135,12 @@ class TestMsgRecoverydevice(TrezorTest):
language='english',
enforce_wordlist=True))
assert isinstance(ret, proto.WordRequest)
self.assertIsInstance(ret, proto.WordRequest)
for _ in range(int(12 * 2)):
(word, pos) = self.client.debug.read_recovery_word()
if pos != 0:
ret = self.client.call_raw(proto.WordAck(word='kwyjibo'))
assert isinstance(ret, proto.Failure)
self.assertIsInstance(ret, proto.Failure)
break
else:
self.client.call_raw(proto.WordAck(word=word))
@ -154,21 +153,23 @@ class TestMsgRecoverydevice(TrezorTest):
language='english',
enforce_wordlist=True))
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
# Enter PIN for first time
pin_encoded = self.client.debug.encode_pin(self.pin4)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
# Enter PIN for second time, but different one
pin_encoded = self.client.debug.encode_pin(self.pin6)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Failure should be raised
assert isinstance(ret, proto.Failure)
self.assertIsInstance(ret, proto.Failure)
def test_already_initialized(self):
self.setup_mnemonic_nopin_nopassphrase()
with pytest.raises(Exception):
self.client.recovery_device(12, False, False, 'label', 'english')
self.assertRaises(Exception, self.client.recovery_device, 12, False, False, 'label', 'english')
if __name__ == '__main__':
unittest.main()

View File

@ -16,32 +16,56 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import unittest
import common
import hashlib
from trezorlib import messages as proto
from trezorlib import messages_pb2 as proto
from mnemonic import Mnemonic
def generate_entropy(strength, internal_entropy, external_entropy):
'''
strength - length of produced seed. One of 128, 192, 256
random - binary stream of random data from external HRNG
'''
if strength not in (128, 192, 256):
raise Exception("Invalid strength")
@pytest.mark.skip_t2
class TestMsgResetDevice(TrezorTest):
if not internal_entropy:
raise Exception("Internal entropy is not provided")
if len(internal_entropy) < 32:
raise Exception("Internal entropy too short")
if not external_entropy:
raise Exception("External entropy is not provided")
if len(external_entropy) < 32:
raise Exception("External entropy too short")
entropy = hashlib.sha256(internal_entropy + external_entropy).digest()
entropy_stripped = entropy[:strength // 8]
if len(entropy_stripped) * 8 != strength:
raise Exception("Entropy length mismatch")
return entropy_stripped
class TestDeviceReset(common.TrezorTest):
def test_reset_device(self):
# No PIN, no passphrase
external_entropy = b'zlutoucky kun upel divoke ody' * 2
strength = 128
ret = self.client.call_raw(proto.ResetDevice(
display_random=False,
strength=strength,
passphrase_protection=False,
pin_protection=False,
language='english',
label='test'
))
ret = self.client.call_raw(proto.ResetDevice(display_random=False,
strength=strength,
passphrase_protection=False,
pin_protection=False,
language='english',
label='test'))
# Provide entropy
assert isinstance(ret, proto.EntropyRequest)
self.assertIsInstance(ret, proto.EntropyRequest)
internal_entropy = self.client.debug.read_reset_entropy()
ret = self.client.call_raw(proto.EntropyAck(entropy=external_entropy))
@ -50,8 +74,8 @@ class TestMsgResetDevice(TrezorTest):
expected_mnemonic = Mnemonic('english').to_mnemonic(entropy)
mnemonic = []
for _ in range(strength // 32 * 3):
assert isinstance(ret, proto.ButtonRequest)
for _ in range(strength//32*3):
self.assertIsInstance(ret, proto.ButtonRequest)
mnemonic.append(self.client.debug.read_reset_word())
self.client.debug.press_yes()
self.client.call_raw(proto.ButtonAck())
@ -59,67 +83,63 @@ class TestMsgResetDevice(TrezorTest):
mnemonic = ' '.join(mnemonic)
# Compare that device generated proper mnemonic for given entropies
assert mnemonic == expected_mnemonic
self.assertEqual(mnemonic, expected_mnemonic)
mnemonic = []
for _ in range(strength // 32 * 3):
assert isinstance(ret, proto.ButtonRequest)
for _ in range(strength//32*3):
self.assertIsInstance(ret, proto.ButtonRequest)
mnemonic.append(self.client.debug.read_reset_word())
self.client.debug.press_yes()
resp = self.client.call_raw(proto.ButtonAck())
assert isinstance(resp, proto.Success)
self.assertIsInstance(resp, proto.Success)
mnemonic = ' '.join(mnemonic)
# Compare that second pass printed out the same mnemonic once again
assert mnemonic == expected_mnemonic
self.assertEqual(mnemonic, expected_mnemonic)
# Check if device is properly initialized
resp = self.client.call_raw(proto.Initialize())
assert resp.initialized is True
assert resp.needs_backup is False
assert resp.pin_protection is False
assert resp.passphrase_protection is False
self.assertFalse(resp.pin_protection)
self.assertFalse(resp.passphrase_protection)
# Do passphrase-protected action, PassphraseRequest should NOT be raised
resp = self.client.call_raw(proto.Ping(passphrase_protection=True))
assert isinstance(resp, proto.Success)
self.assertIsInstance(resp, proto.Success)
# Do PIN-protected action, PinRequest should NOT be raised
resp = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(resp, proto.Success)
self.assertIsInstance(resp, proto.Success)
def test_reset_device_pin(self):
external_entropy = b'zlutoucky kun upel divoke ody' * 2
strength = 128
ret = self.client.call_raw(proto.ResetDevice(
display_random=True,
strength=strength,
passphrase_protection=True,
pin_protection=True,
language='english',
label='test'
))
ret = self.client.call_raw(proto.ResetDevice(display_random=True,
strength=strength,
passphrase_protection=True,
pin_protection=True,
language='english',
label='test'))
assert isinstance(ret, proto.ButtonRequest)
self.assertIsInstance(ret, proto.ButtonRequest)
self.client.debug.press_yes()
ret = self.client.call_raw(proto.ButtonAck())
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
# Enter PIN for first time
pin_encoded = self.client.debug.encode_pin('654')
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
# Enter PIN for second time
pin_encoded = self.client.debug.encode_pin('654')
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
# Provide entropy
assert isinstance(ret, proto.EntropyRequest)
self.assertIsInstance(ret, proto.EntropyRequest)
internal_entropy = self.client.debug.read_reset_entropy()
ret = self.client.call_raw(proto.EntropyAck(entropy=external_entropy))
@ -128,8 +148,8 @@ class TestMsgResetDevice(TrezorTest):
expected_mnemonic = Mnemonic('english').to_mnemonic(entropy)
mnemonic = []
for _ in range(strength // 32 * 3):
assert isinstance(ret, proto.ButtonRequest)
for _ in range(strength//32*3):
self.assertIsInstance(ret, proto.ButtonRequest)
mnemonic.append(self.client.debug.read_reset_word())
self.client.debug.press_yes()
self.client.call_raw(proto.ButtonAck())
@ -137,70 +157,68 @@ class TestMsgResetDevice(TrezorTest):
mnemonic = ' '.join(mnemonic)
# Compare that device generated proper mnemonic for given entropies
assert mnemonic == expected_mnemonic
self.assertEqual(mnemonic, expected_mnemonic)
mnemonic = []
for _ in range(strength // 32 * 3):
assert isinstance(ret, proto.ButtonRequest)
for _ in range(strength//32*3):
self.assertIsInstance(ret, proto.ButtonRequest)
mnemonic.append(self.client.debug.read_reset_word())
self.client.debug.press_yes()
resp = self.client.call_raw(proto.ButtonAck())
assert isinstance(resp, proto.Success)
self.assertIsInstance(resp, proto.Success)
mnemonic = ' '.join(mnemonic)
# Compare that second pass printed out the same mnemonic once again
assert mnemonic == expected_mnemonic
self.assertEqual(mnemonic, expected_mnemonic)
# Check if device is properly initialized
resp = self.client.call_raw(proto.Initialize())
assert resp.initialized is True
assert resp.needs_backup is False
assert resp.pin_protection is True
assert resp.passphrase_protection is True
self.assertTrue(resp.pin_protection)
self.assertTrue(resp.passphrase_protection)
# Do passphrase-protected action, PassphraseRequest should be raised
resp = self.client.call_raw(proto.Ping(passphrase_protection=True))
assert isinstance(resp, proto.PassphraseRequest)
self.assertIsInstance(resp, proto.PassphraseRequest)
self.client.call_raw(proto.Cancel())
# Do PIN-protected action, PinRequest should be raised
resp = self.client.call_raw(proto.Ping(pin_protection=True))
assert isinstance(resp, proto.PinMatrixRequest)
self.assertIsInstance(resp, proto.PinMatrixRequest)
self.client.call_raw(proto.Cancel())
def test_failed_pin(self):
# external_entropy = b'zlutoucky kun upel divoke ody' * 2
external_entropy = b'zlutoucky kun upel divoke ody' * 2
strength = 128
ret = self.client.call_raw(proto.ResetDevice(
display_random=True,
strength=strength,
passphrase_protection=True,
pin_protection=True,
language='english',
label='test'
))
ret = self.client.call_raw(proto.ResetDevice(display_random=True,
strength=strength,
passphrase_protection=True,
pin_protection=True,
language='english',
label='test'))
assert isinstance(ret, proto.ButtonRequest)
self.assertIsInstance(ret, proto.ButtonRequest)
self.client.debug.press_yes()
ret = self.client.call_raw(proto.ButtonAck())
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
# Enter PIN for first time
pin_encoded = self.client.debug.encode_pin(self.pin4)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
assert isinstance(ret, proto.PinMatrixRequest)
self.assertIsInstance(ret, proto.PinMatrixRequest)
# Enter PIN for second time
pin_encoded = self.client.debug.encode_pin(self.pin6)
ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
assert isinstance(ret, proto.Failure)
self.assertIsInstance(ret, proto.Failure)
def test_already_initialized(self):
self.setup_mnemonic_nopin_nopassphrase()
with pytest.raises(Exception):
self.client.reset_device(False, 128, True, True, 'label', 'english')
self.assertRaises(Exception, self.client.reset_device, False, 128, True, True, 'label', 'english')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,91 @@
# 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 unittest
import common
import binascii
import hashlib
import struct
from trezorlib.client import CallException
import trezorlib.types_pb2 as proto_types
def check_path(identity):
m = hashlib.sha256()
m.update(struct.pack("<I", identity.index))
uri = ''
if identity.proto: uri += identity.proto + '://'
if identity.user: uri += identity.user + '@'
if identity.host: uri += identity.host
if identity.port: uri += ':' + identity.port
if identity.path: uri += identity.path
m.update(uri)
print('hash:', m.hexdigest())
(a, b, c, d, _, _, _, _) = struct.unpack('<8I', m.digest())
address_n = [0x80000000 | 13, 0x80000000 | a, 0x80000000 | b, 0x80000000 | c, 0x80000000 | d]
print('path:', 'm/' + '/'.join([str(x) for x in address_n]))
class TestMsgSignidentity(common.TrezorTest):
def test_sign(self):
self.setup_mnemonic_nopin_nopassphrase()
hidden = binascii.unhexlify('cd8552569d6e4509266ef137584d1e62c7579b5b8ed69bbafa4b864c6521e7c2')
visual = '2015-03-23 17:39:22'
# URI : https://satoshi@bitcoin.org/login
# hash : d0e2389d4c8394a9f3e32de01104bf6e8db2d9e2bb0905d60fffa5a18fd696db
# path : m/2147483661/2637750992/2845082444/3761103859/4005495825
identity = proto_types.IdentityType(proto='https', user='satoshi', host='bitcoin.org', port='', path='/login', index=0)
sig = self.client.sign_identity(identity, hidden, visual)
self.assertEqual(sig.address, '17F17smBTX9VTZA9Mj8LM5QGYNZnmziCjL')
self.assertEqual(binascii.hexlify(sig.public_key), b'023a472219ad3327b07c18273717bb3a40b39b743756bf287fbd5fa9d263237f45')
self.assertEqual(binascii.hexlify(sig.signature), b'20f2d1a42d08c3a362be49275c3ffeeaa415fc040971985548b9f910812237bb41770bf2c8d488428799fbb7e52c11f1a3404011375e4080e077e0e42ab7a5ba02')
# URI : ftp://satoshi@bitcoin.org:2323/pub
# hash : 79a6b53831c6ff224fb283587adc4ebae8fb0d734734a46c876838f52dff53f3
# path : m/2147483661/3098912377/2734671409/3632509519/3125730426
identity = proto_types.IdentityType(proto='ftp', user='satoshi', host='bitcoin.org', port='2323', path='/pub', index=3)
sig = self.client.sign_identity(identity, hidden, visual)
self.assertEqual(sig.address, '1KAr6r5qF2kADL8bAaRQBjGKYEGxn9WrbS')
self.assertEqual(binascii.hexlify(sig.public_key), b'0266cf12d2ba381c5fd797da0d64f59c07a6f1b034ad276cca6bf2729e92b20d9c')
self.assertEqual(binascii.hexlify(sig.signature), b'20bbd12dc657d534fc0f7e40186e22c447e0866a016f654f380adffa9a84e9faf412a1bb0ae908296537838cf91145e77da08681c63d07b7dca40728b9e6cb17cf')
# URI : ssh://satoshi@bitcoin.org
# hash : 5fa612f558a1a3b1fb7f010b2ea0a25cb02520a0ffa202ce74a92fc6145da5f3
# path : m/2147483661/4111640159/2980290904/2332131323/3701645358
identity = proto_types.IdentityType(proto='ssh', user='satoshi', host='bitcoin.org', port='', path='', index=47)
sig = self.client.sign_identity(identity, hidden, visual, ecdsa_curve_name='nist256p1')
self.assertEqual(sig.address, '')
self.assertEqual(binascii.hexlify(sig.public_key), b'0373f21a3da3d0e96fc2189f81dd826658c3d76b2d55bd1da349bc6c3573b13ae4')
self.assertEqual(binascii.hexlify(sig.signature), b'005122cebabb852cdd32103b602662afa88e54c0c0c1b38d7099c64dcd49efe908288114e66ed2d8c82f23a70b769a4db723173ec53840c08aafb840d3f09a18d3')
# URI : ssh://satoshi@bitcoin.org
# hash : 5fa612f558a1a3b1fb7f010b2ea0a25cb02520a0ffa202ce74a92fc6145da5f3
# path : m/2147483661/4111640159/2980290904/2332131323/3701645358
identity = proto_types.IdentityType(proto='ssh', user='satoshi', host='bitcoin.org', port='', path='', index=47)
sig = self.client.sign_identity(identity, hidden, visual, ecdsa_curve_name='ed25519')
self.assertEqual(sig.address, '')
self.assertEqual(binascii.hexlify(sig.public_key), b'010fac2a491e0f5b871dc48288a4cae551bac5cb0ed19df0764d6e721ec5fade18')
self.assertEqual(binascii.hexlify(sig.signature), b'00f05e5085e666429de397c70a081932654369619c0bd2a6579ea6c1ef2af112ef79998d6c862a16b932d44b1ac1b83c8cbcd0fbda228274fde9e0d0ca6e9cb709')
if __name__ == '__main__':
unittest.main()

View File

@ -16,28 +16,32 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import unittest
import common
import binascii
from trezorlib.client import CallException
class TestMsgSignmessage(TrezorTest):
class TestMsgSignmessage(common.TrezorTest):
def test_sign(self):
self.setup_mnemonic_nopin_nopassphrase()
sig = self.client.sign_message('Bitcoin', [0], "This is an example of a signed message.")
assert sig.address == '14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e'
assert hexlify(sig.signature) == b'209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80'
self.assertEqual(sig.address, '14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e')
self.assertEqual(binascii.hexlify(sig.signature), b'209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80')
def test_sign_testnet(self):
self.setup_mnemonic_nopin_nopassphrase()
sig = self.client.sign_message('Testnet', [0], "This is an example of a signed message.")
assert sig.address == 'mirio8q3gtv7fhdnmb3TpZ4EuafdzSs7zL'
assert hexlify(sig.signature) == b'209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80'
self.assertEqual(sig.address, 'mirio8q3gtv7fhdnmb3TpZ4EuafdzSs7zL')
self.assertEqual(binascii.hexlify(sig.signature), b'209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80')
def test_sign_long(self):
self.setup_mnemonic_nopin_nopassphrase()
sig = self.client.sign_message('Bitcoin', [0], "VeryLongMessage!" * 64)
assert sig.address == '14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e'
assert hexlify(sig.signature) == b'205ff795c29aef7538f8b3bdb2e8add0d0722ad630a140b6aefd504a5a895cbd867cbb00981afc50edd0398211e8d7c304bb8efa461181bc0afa67ea4a720a89ed'
self.assertEqual(sig.address, '14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e')
self.assertEqual(binascii.hexlify(sig.signature), b'205ff795c29aef7538f8b3bdb2e8add0d0722ad630a140b6aefd504a5a895cbd867cbb00981afc50edd0398211e8d7c304bb8efa461181bc0afa67ea4a720a89ed')
def test_sign_utf(self):
self.setup_mnemonic_nopin_nopassphrase()
@ -46,9 +50,12 @@ class TestMsgSignmessage(TrezorTest):
words_nfc = u'P\u0159\xed\u0161ern\u011b \u017elu\u0165ou\u010dk\xfd k\u016f\u0148 \xfap\u011bl \u010f\xe1belsk\xe9 \xf3dy z\xe1ke\u0159n\xfd u\u010de\u0148 b\u011b\u017e\xed pod\xe9l z\xf3ny \xfal\u016f'
sig_nfkd = self.client.sign_message('Bitcoin', [0], words_nfkd)
assert sig_nfkd.address == '14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e'
assert hexlify(sig_nfkd.signature) == b'20d0ec02ed8da8df23e7fe9e680e7867cc290312fe1c970749d8306ddad1a1eda41c6a771b13d495dd225b13b0a9d0f915a984ee3d0703f92287bf8009fbb9f7d6'
self.assertEqual(sig_nfkd.address, '14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e')
self.assertEqual(binascii.hexlify(sig_nfkd.signature), b'20d0ec02ed8da8df23e7fe9e680e7867cc290312fe1c970749d8306ddad1a1eda41c6a771b13d495dd225b13b0a9d0f915a984ee3d0703f92287bf8009fbb9f7d6')
sig_nfc = self.client.sign_message('Bitcoin', [0], words_nfc)
assert sig_nfc.address == '14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e'
assert hexlify(sig_nfc.signature) == b'20d0ec02ed8da8df23e7fe9e680e7867cc290312fe1c970749d8306ddad1a1eda41c6a771b13d495dd225b13b0a9d0f915a984ee3d0703f92287bf8009fbb9f7d6'
self.assertEqual(sig_nfc.address, '14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e')
self.assertEqual(binascii.hexlify(sig_nfc.signature), b'20d0ec02ed8da8df23e7fe9e680e7867cc290312fe1c970749d8306ddad1a1eda41c6a771b13d495dd225b13b0a9d0f915a984ee3d0703f92287bf8009fbb9f7d6')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,615 @@
# 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 unittest
import common
import binascii
import trezorlib.messages_pb2 as proto
import trezorlib.types_pb2 as proto_types
from trezorlib.client import CallException
from trezorlib.tx_api import TxApiTestnet
class TestMsgSigntx(common.TrezorTest):
def test_one_one_fee(self):
self.setup_mnemonic_nopin_nopassphrase()
# tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
# input 0: 0.0039 BTC
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=binascii.unhexlify(b'd5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
amount=390000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, ])
# Accepted by network: tx fd79435246dee76b2f159d2db08032d666c95adc544de64c8c49f474df4a7fee
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000182488650ef25a58fef6788bd71b8212038d7f2bbe4750bc7bcb44701e85ef6d5000000006b4830450221009a0b7be0d4ed3146ee262b42202841834698bb3ee39c24e7437df208b8b7077102202b79ab1e7736219387dffe8d615bbdba87e11477104b867ef47afed1a5ede7810121023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43dffffffff0160cc0500000000001976a914de9b2a8da088824e8fe51debea566617d851537888ac00000000')
def test_testnet_one_two_fee(self):
self.setup_mnemonic_nopin_nopassphrase()
# tx: 6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54
# input 1: 10.00000000 BTC
inp1 = proto_types.TxInputType(address_n=[0], # mirio8q3gtv7fhdnmb3TpZ4EuafdzSs7zL
# amount=1000000000,
prev_hash=binascii.unhexlify(b'6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54'),
prev_index=1,
)
out1 = proto_types.TxOutputType(address='mfiGQVPcRcaEvQPYDErR34DcCovtxYvUUV',
amount=1000000000 - 500000000 - 10000000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(address_n=[2],
amount=500000000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_tx_api(TxApiTestnet)
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Testnet', [inp1, ], [out1, out2])
self.assertEqual(binascii.hexlify(serialized_tx), b'0100000001549d2977998f899a63c0a9da30dedb2841e33fef561097b05822eccbc7f3906f010000006b4830450221009c2d30385519fdb13dce13d5ac038be07d7b2dad0b0f7b2c1c339d7255bcf553022056a2f5bceab3cd0ffed4d388387e631f419d67ff9ce7798e3d7dfe6a6d6ec4bd0121023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43dffffffff0280ce341d000000001976a9140223b1a09138753c9cb0baf95a0a62c82711567a88ac0065cd1d000000001976a9142db345c36563122e2fd0f5485fb7ea9bbf7cb5a288ac00000000')
def test_testnet_fee_too_high(self):
self.setup_mnemonic_nopin_nopassphrase()
# tx: 6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54
# input 1: 10.00000000 BTC
inp1 = proto_types.TxInputType(address_n=[0], # mirio8q3gtv7fhdnmb3TpZ4EuafdzSs7zL
# amount=1000000000,
prev_hash=binascii.unhexlify('6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54'),
prev_index=1,
)
out1 = proto_types.TxOutputType(address='mfiGQVPcRcaEvQPYDErR34DcCovtxYvUUV',
amount=1000000000 - 500000000 - 100000000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(address_n=[2],
amount=500000000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_tx_api(TxApiTestnet)
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_FeeOverThreshold),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Testnet', [inp1, ], [out1, out2])
self.assertEqual(binascii.hexlify(serialized_tx), b'0100000001549d2977998f899a63c0a9da30dedb2841e33fef561097b05822eccbc7f3906f010000006a47304402205ea68e9d52d4be14420ccecf7f2e11489d49b86bedb79ee99b5e9b7188884150022056219cb3384a5df8048cca286a9533403dbda1571afd84b51379cdaee6a6dea80121023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43dffffffff020084d717000000001976a9140223b1a09138753c9cb0baf95a0a62c82711567a88ac0065cd1d000000001976a9142db345c36563122e2fd0f5485fb7ea9bbf7cb5a288ac00000000')
def test_one_two_fee(self):
self.setup_mnemonic_nopin_nopassphrase()
# tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
# input 0: 0.0039 BTC
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
amount=390000 - 80000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(address_n=[1],
amount=80000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, out2])
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000182488650ef25a58fef6788bd71b8212038d7f2bbe4750bc7bcb44701e85ef6d5000000006b483045022100c1400d8485d3bdcae7413e123148f35ece84806fc387ab88c66b469df89aef1702201d481d04216b319dc549ffe2333143629ba18828a4e2d1783ab719a6aa263eb70121023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43dffffffff02e0930400000000001976a914de9b2a8da088824e8fe51debea566617d851537888ac80380100000000001976a9140223b1a09138753c9cb0baf95a0a62c82711567a88ac00000000')
def test_one_three_fee(self):
self.setup_mnemonic_nopin_nopassphrase()
# tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
# input 0: 0.0039 BTC
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
amount=390000 - 80000 - 12000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(address='13uaUYn6XAooo88QvAqAVsiVvr2mAXutqP',
amount=12000,
script_type=proto_types.PAYTOADDRESS,
)
out3 = proto_types.TxOutputType(address_n=[1],
amount=80000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=2)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=2)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=2)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, out2, out3])
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000182488650ef25a58fef6788bd71b8212038d7f2bbe4750bc7bcb44701e85ef6d5000000006b483045022100e695e2c530c7c0fc32e6b79b7cff56a7f70a8c9da787534f46b4204070f914fc02207b0879a81408a11e23b11d4c7965c62b5fc6d5c2d92340f5ee2da7b40e99314a0121023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43dffffffff0300650400000000001976a914de9b2a8da088824e8fe51debea566617d851537888ace02e0000000000001976a9141fe1d337fb81afca42818051e12fd18245d1b17288ac80380100000000001976a9140223b1a09138753c9cb0baf95a0a62c82711567a88ac00000000')
def test_two_two(self):
self.setup_mnemonic_nopin_nopassphrase()
# tx: c6be22d34946593bcad1d2b013e12f74159e69574ffea21581dad115572e031c
# input 1: 0.0010 BTC
# tx: 58497a7757224d1ff1941488d23087071103e5bf855f4c1c44e5c8d9d82ca46e
# input 1: 0.0011 BTC
inp1 = proto_types.TxInputType(address_n=[1], # 1CK7SJdcb8z9HuvVft3D91HLpLC6KSsGb
# amount=100000,
prev_hash=binascii.unhexlify('c6be22d34946593bcad1d2b013e12f74159e69574ffea21581dad115572e031c'),
prev_index=1,
)
inp2 = proto_types.TxInputType(address_n=[2], # 15AeAhtNJNKyowK8qPHwgpXkhsokzLtUpG
# amount=110000,
prev_hash=binascii.unhexlify('58497a7757224d1ff1941488d23087071103e5bf855f4c1c44e5c8d9d82ca46e'),
prev_index=1,
)
out1 = proto_types.TxOutputType(address='15Jvu3nZNP7u2ipw2533Q9VVgEu2Lu9F2B',
amount=210000 - 100000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(address_n=[3], # 1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5
amount=100000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"c6be22d34946593bcad1d2b013e12f74159e69574ffea21581dad115572e031c"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"c6be22d34946593bcad1d2b013e12f74159e69574ffea21581dad115572e031c"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"c6be22d34946593bcad1d2b013e12f74159e69574ffea21581dad115572e031c"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"c6be22d34946593bcad1d2b013e12f74159e69574ffea21581dad115572e031c"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"58497a7757224d1ff1941488d23087071103e5bf855f4c1c44e5c8d9d82ca46e"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"58497a7757224d1ff1941488d23087071103e5bf855f4c1c44e5c8d9d82ca46e"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"58497a7757224d1ff1941488d23087071103e5bf855f4c1c44e5c8d9d82ca46e"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"58497a7757224d1ff1941488d23087071103e5bf855f4c1c44e5c8d9d82ca46e"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, inp2], [out1, out2])
# Accepted by network: tx c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000021c032e5715d1da8115a2fe4f57699e15742fe113b0d2d1ca3b594649d322bec6010000006b483045022100f773c403b2f85a5c1d6c9c4ad69c43de66930fff4b1bc818eb257af98305546a0220443bde4be439f276a6ce793664b463580e210ec6c9255d68354449ac0443c76501210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6ffffffff6ea42cd8d9c8e5441c4c5f85bfe50311078730d2881494f11f4d2257777a4958010000006b48304502210090cff1c1911e771605358a8cddd5ae94c7b60cc96e50275908d9bf9d6367c79f02202bfa72e10260a146abd59d0526e1335bacfbb2b4401780e9e3a7441b0480c8da0121038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3ffffffff02a0860100000000001976a9142f4490d5263906e4887ca2996b9e207af3e7824088aca0860100000000001976a914812c13d97f9159e54e326b481b8f88a73df8507a88ac00000000')
"""
def test_lots_of_inputs(self):
self.setup_mnemonic_nopin_nopassphrase()
# Tests if device implements serialization of len(inputs) correctly
# tx 4a7b7e0403ae5607e473949cfa03f09f2cd8b0f404bf99ce10b7303d86280bf7 : 100 UTXO for spending for unittests
inputs = []
for i in range(100):
inputs.append( proto_types.TxInputType(address_n=[4], # 1NwN6UduuVkJi6sw3gSiKZaCY5rHgVXC2h
prev_hash=binascii.unhexlify('4a7b7e0403ae5607e473949cfa03f09f2cd8b0f404bf99ce10b7303d86280bf7'),
prev_index=i) )
out = proto_types.TxOutputType(address='19dvDdyxxptP9dGvozYe8BP6tgFV9L4jg5',
amount=100 * 26000 - 15 * 10000,
script_type=proto_types.PAYTOADDRESS)
with self.client:
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', inputs, [out])
# Accepted by network: tx 23d9d8eecf3abf6c0f0f3f8b0976a04792d7f1c9a4ea9b0a8931734949e27c92
# too big put in unit test
"""
def test_lots_of_outputs(self):
self.setup_mnemonic_nopin_nopassphrase()
# Tests if device implements serialization of len(outputs) correctly
# tx: c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb
# index 1: 0.0010 BTC
# tx: 39a29e954977662ab3879c66fb251ef753e0912223a83d1dcb009111d28265e5
# index 1: 0.0254 BTC
inp1 = proto_types.TxInputType(address_n=[3], # 1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5
# amount=100000,
prev_hash=binascii.unhexlify('c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb'),
prev_index=1,
)
inp2 = proto_types.TxInputType(address_n=[3], # 1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5
# amount=2540000,
prev_hash=binascii.unhexlify('39a29e954977662ab3879c66fb251ef753e0912223a83d1dcb009111d28265e5'),
prev_index=1,
)
outputs = []
cnt = 255
for _ in range(cnt):
out = proto_types.TxOutputType(address='1NwN6UduuVkJi6sw3gSiKZaCY5rHgVXC2h',
amount=(100000 + 2540000 - 39000) // cnt,
script_type=proto_types.PAYTOADDRESS,
)
outputs.append(out)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"39a29e954977662ab3879c66fb251ef753e0912223a83d1dcb009111d28265e5"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"39a29e954977662ab3879c66fb251ef753e0912223a83d1dcb009111d28265e5"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"39a29e954977662ab3879c66fb251ef753e0912223a83d1dcb009111d28265e5"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"39a29e954977662ab3879c66fb251ef753e0912223a83d1dcb009111d28265e5"))),
] + [
item for items in zip(
[proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=I)) for I in range(cnt)],
[proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput)] * cnt
) for item in items
] + [
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
] + [
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=I)) for I in range(cnt)
] + [
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
] + [
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=I)) for I in range(cnt)
] + [
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=I)) for I in range(cnt)
] + [
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, inp2], outputs)
if cnt == 255:
self.assertEqual(binascii.hexlify(serialized_tx), b'0100000002fb792f470a58993e14964c9bd46cdf37cb4bbc3f61540cb651580c82ed243ec6010000006b483045022100969da46f94a81f34f3717b014e0c3e1826eda1b0022ec2f9ce39f3d750ab9235022026da269770993211a1503413566a339bbb4389a482fffcf8e1f76713fc3b94f5012103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a7902ffffffffe56582d2119100cb1d3da8232291e053f71e25fb669c87b32a667749959ea239010000006a473044022052e1419bb237b9db400ab5e3df16db6355619d545fde9030924a360763ae9ad40220704beab04d72ecaeb42eca7d98faca7a0941e65f2e1341f183be2b83e6b09e1c012103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a7902fffffffffdff00' + b'd8270000000000001976a914f0a2b64e56ee2ff57126232f84af6e3a41d4055088ac' * cnt + b'00000000')
def test_fee_too_high(self):
self.setup_mnemonic_nopin_nopassphrase()
# tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
# input 0: 0.0039 BTC
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
amount=390000 - 250000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_FeeOverThreshold),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, ])
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000182488650ef25a58fef6788bd71b8212038d7f2bbe4750bc7bcb44701e85ef6d5000000006b483045022100a3b17b37de3bfecca47f0d49f7bb0d0f68d45df7defe45713d57e83731f5e3d902205404b14630cea6a88b23a5f7c3a1b88494757a8ca5e1c0b0b93cf3c38231c3bd0121023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43dffffffff01e0220200000000001976a914de9b2a8da088824e8fe51debea566617d851537888ac00000000')
def test_not_enough_funds(self):
self.setup_mnemonic_nopin_nopassphrase()
# tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
# input 0: 0.0039 BTC
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
amount=400000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.Failure(code=proto_types.Failure_NotEnoughFunds)
])
try:
self.client.sign_tx('Bitcoin', [inp1, ], [out1, ])
except CallException as e:
self.assertEqual(e.args[0], proto_types.Failure_NotEnoughFunds)
else:
self.assert_(False, "types.Failure_NotEnoughFunds expected")
def test_p2sh(self):
self.setup_mnemonic_nopin_nopassphrase()
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=400000,
prev_hash=binascii.unhexlify('54aa5680dea781f45ebb536e53dffc526d68c0eb5c00547e323b2c32382dfba3'),
prev_index=1,
)
out1 = proto_types.TxOutputType(address='3DKGE1pvPpBAgZj94MbCinwmksewUNNYVR', # p2sh
amount=400000 - 10000,
script_type=proto_types.PAYTOSCRIPTHASH,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"54aa5680dea781f45ebb536e53dffc526d68c0eb5c00547e323b2c32382dfba3"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"54aa5680dea781f45ebb536e53dffc526d68c0eb5c00547e323b2c32382dfba3"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"54aa5680dea781f45ebb536e53dffc526d68c0eb5c00547e323b2c32382dfba3"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify(b"54aa5680dea781f45ebb536e53dffc526d68c0eb5c00547e323b2c32382dfba3"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, ])
# Accepted by network: tx 8cc1f4adf7224ce855cf535a5104594a0004cb3b640d6714fdb00b9128832dd5
self.assertEqual(binascii.hexlify(serialized_tx), b'0100000001a3fb2d38322c3b327e54005cebc0686d52fcdf536e53bb5ef481a7de8056aa54010000006b4830450221009e020b0390ccad533b73b552f8a99a9d827212c558e4f755503674d07c92ad4502202d606f7316990e0461c51d4add25054f19c697aa3e3c2ced4d568f0b2c57e62f0121023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43dffffffff0170f305000000000017a9147f844bdb0b8fd54b64e3d16c85dc1170f1ff97c18700000000')
def test_attack_change_outputs(self):
# This unit test attempts to modify data sent during ping-pong of streaming signing.
# Because device is asking for human confirmation only during first pass (first input),
# device must detect that data has been modified during other passes and fail to sign
# such modified data (which has not been confirmed by the user).
# Test firstly prepare normal transaction and send it to device. Then it send the same
# transaction again, but change amount of output 1 during signing the second input.
self.setup_mnemonic_nopin_nopassphrase()
inp1 = proto_types.TxInputType(address_n=[1], # 1CK7SJdcb8z9HuvVft3D91HLpLC6KSsGb
# amount=100000,
prev_hash=binascii.unhexlify('c6be22d34946593bcad1d2b013e12f74159e69574ffea21581dad115572e031c'),
prev_index=1,
)
inp2 = proto_types.TxInputType(address_n=[2], # 15AeAhtNJNKyowK8qPHwgpXkhsokzLtUpG
# amount=110000,
prev_hash=binascii.unhexlify('58497a7757224d1ff1941488d23087071103e5bf855f4c1c44e5c8d9d82ca46e'),
prev_index=1,
)
out1 = proto_types.TxOutputType(address='15Jvu3nZNP7u2ipw2533Q9VVgEu2Lu9F2B',
amount=210000 - 100000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(address_n=[3], # 1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5
amount=100000,
script_type=proto_types.PAYTOADDRESS,
)
global run_attack
run_attack = False
def attack_processor(req, msg):
global run_attack
if req.details.tx_hash != b'':
return msg
if req.details.request_index != 1:
return msg
if not run_attack:
run_attack = True
return msg
msg.outputs[0].amount = 9999999 # Sign output with another amount
return msg
# Test if the transaction can be signed normally
(_, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, inp2], [out1, out2])
# Accepted by network: tx c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000021c032e5715d1da8115a2fe4f57699e15742fe113b0d2d1ca3b594649d322bec6010000006b483045022100f773c403b2f85a5c1d6c9c4ad69c43de66930fff4b1bc818eb257af98305546a0220443bde4be439f276a6ce793664b463580e210ec6c9255d68354449ac0443c76501210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6ffffffff6ea42cd8d9c8e5441c4c5f85bfe50311078730d2881494f11f4d2257777a4958010000006b48304502210090cff1c1911e771605358a8cddd5ae94c7b60cc96e50275908d9bf9d6367c79f02202bfa72e10260a146abd59d0526e1335bacfbb2b4401780e9e3a7441b0480c8da0121038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3ffffffff02a0860100000000001976a9142f4490d5263906e4887ca2996b9e207af3e7824088aca0860100000000001976a914812c13d97f9159e54e326b481b8f88a73df8507a88ac00000000')
# Now run the attack, must trigger the exception
self.assertRaises(CallException, self.client.sign_tx, 'Bitcoin', [inp1, inp2], [out1, out2], debug_processor=attack_processor)
def test_spend_coinbase(self):
# 25 TEST generated to m/1 (mfiGQVPcRcaEvQPYDErR34DcCovtxYvUUV)
# tx: d6da21677d7cca5f42fbc7631d062c9ae918a0254f7c6c22de8e8cb7fd5b8236
# input 0: 25.0027823 BTC
self.setup_mnemonic_nopin_nopassphrase()
inp1 = proto_types.TxInputType(address_n=[1], # mfiGQVPcRcaEvQPYDErR34DcCovtxYvUUV
# amount=390000,
prev_hash=binascii.unhexlify('d6da21677d7cca5f42fbc7631d062c9ae918a0254f7c6c22de8e8cb7fd5b8236'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='mm6FM31rM5Vc3sw5D7kztiBg3jHUzyqF1g',
amount=2500278230 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_tx_api(TxApiTestnet)
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"d6da21677d7cca5f42fbc7631d062c9ae918a0254f7c6c22de8e8cb7fd5b8236"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d6da21677d7cca5f42fbc7631d062c9ae918a0254f7c6c22de8e8cb7fd5b8236"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"d6da21677d7cca5f42fbc7631d062c9ae918a0254f7c6c22de8e8cb7fd5b8236"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Testnet', [inp1, ], [out1, ])
# Accepted by network: tx
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000136825bfdb78c8ede226c7c4f25a018e99a2c061d63c7fb425fca7c7d6721dad6000000006a473044022047845c366eb24f40be315c7815a154513c444c7989eb80f7ce7ff6aeb703d26a022007c1f5efadf67c5889634fd7ac39a7ce78bffac291673e8772ecd8389c901d9f01210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6ffffffff01c6100795000000001976a9143d2496e67f5f57a924353da42d4725b318e7a8ea88ac00000000')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,165 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2017 Jochen Hoenicke <hoenicke@gmail.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 unittest
import common
import binascii
import trezorlib.messages_pb2 as proto
import trezorlib.types_pb2 as proto_types
from trezorlib.client import CallException
from trezorlib.tx_api import TxApiTestnet
class TestMsgSigntxSegwit(common.TrezorTest):
def test_send_p2sh(self):
self.setup_mnemonic_allallall()
self.client.set_tx_api(TxApiTestnet)
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("49'/1'/0'/1/0"),
# 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
amount=123456789,
prev_hash=binascii.unhexlify('20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'),
prev_index=0,
script_type=proto_types.SPENDP2SHWITNESS,
)
out1 = proto_types.TxOutputType(address='QWywnqNMsMNavbCgMYiQLa91ApvsVRoaqt1i',
amount=12300000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(
#address_n=self.client.expand_path("49'/1'/0'/1/0"),
#script_type=proto_types.PAYTOP2SHWITNESS,
address='2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX',
script_type=proto_types.PAYTOADDRESS,
amount=123456789 - 11000 - 12300000,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1, out2])
self.assertEqual(binascii.hexlify(serialized_tx), b'0100000000010137c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02e0aebb00000000001600140099a7ecbd938ed1839f5f6bf6d50933c6db9d5c3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca8702483045022100bd3d8b8ad35c094e01f6282277300e575f1021678fc63ec3f9945d6e35670da3022052e26ef0dd5f3741c9d5939d1dec5464c15ab5f2c85245e70a622df250d4eb7c012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000')
def test_send_native(self):
self.setup_mnemonic_allallall()
self.client.set_tx_api(TxApiTestnet)
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("49'/1'/0'/0/0"),
# QWywnqNMsMNavbCgMYiQLa91ApvsVRoaqt1i
amount=12300000,
prev_hash=binascii.unhexlify('09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a'),
prev_index=0,
script_type=proto_types.SPENDWITNESS,
)
out1 = proto_types.TxOutputType(address='2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp',
amount=5000000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(
#address_n=self.client.expand_path("49'/1'/0'/1/0"),
#script_type=proto_types.PAYTOWITNESS,
address='QWzGpyMkAEvmkSVprBzRRVQMP6UPp17q4kQn',
script_type=proto_types.PAYTOADDRESS,
amount=12300000 - 11000 - 5000000,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1, out2 ])
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000001018a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090000000000ffffffff02404b4c000000000017a9147a55d61848e77ca266e79a39bfc85c580a6426c987a8386f0000000000160014d16b8c0680c61fc6ed2e407455715055e41052f502483045022100a7ca8f097525f9044e64376dc0a0f5d4aeb8d15d66808ba97979a0475b06b66502200597c8ebcef63e047f9aeef1a8001d3560470cf896c12f6990eec4faec599b950121033add1f0e8e3c3136f7428dd4a4de1057380bd311f5b0856e2269170b4ffa65bf00000000')
def test_send_both(self):
self.setup_mnemonic_allallall()
self.client.set_tx_api(TxApiTestnet)
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("49'/1'/0'/1/0"),
# 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
amount=111145789,
prev_hash=binascii.unhexlify('09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a'),
prev_index=1,
script_type=proto_types.SPENDP2SHWITNESS,
)
inp2 = proto_types.TxInputType(address_n=self.client.expand_path("49'/1'/0'/1/0"),
# QWzGpyMkAEvmkSVprBzRRVQMP6UPp17q4kQn
amount=7289000,
prev_hash=binascii.unhexlify('65b811d3eca0fe6915d9f2d77c86c5a7f19bf66b1b1253c2c51cb4ae5f0c017b'),
prev_index=1,
script_type=proto_types.SPENDWITNESS,
)
out1 = proto_types.TxOutputType(address='QWzCpc1NeTN7hNDzK9sQQ9yrTQP8zh5Hef5J',
amount=12300000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(
#address_n=self.client.expand_path("44'/1'/0'/0/0"),
#script_type=proto_types.PAYTOP2SHWITNESS,
address='2N6UeBoqYEEnybg4cReFYDammpsyDw8R2Mc',
script_type=proto_types.PAYTOADDRESS,
amount=45600000,
)
out3 = proto_types.TxOutputType(address='mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q',
amount=111145789 + 7289000 - 11000 - 12300000 - 45600000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=2)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=2)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Testnet', [inp1, inp2], [out1, out2, out3 ])
# 0e480a97c7a545c85e101a2f13c9af0e115d43734e1448f0cac3e55fe8e7399d
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000001028a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090100000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff7b010c5faeb41cc5c253121b6bf69bf1a7c5867cd7f2d91569fea0ecd311b8650100000000ffffffff03e0aebb0000000000160014a579388225827d9f2fe9014add644487808c695d00cdb7020000000017a91491233e24a9bf8dbb19c1187ad876a9380c12e787870d859b03000000001976a914a579388225827d9f2fe9014add644487808c695d88ac02483045022100ead79ee134f25bb585b48aee6284a4bb14e07f03cc130253e83450d095515e5202201e161e9402c8b26b666f2b67e5b668a404ef7e57858ae9a6a68c3837e65fdc69012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7902483045022100b4099ec4c7b3123795b3c080a86f4b745f3784eb3f77de79bef1d8da319cbee5022039766865d448a4a3e435a95d0df3ff56ebc6532bf538988a7e8a679b40ec41b6012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,72 @@
# 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 unittest
import common
import binascii
import trezorlib.messages_pb2 as proto
import trezorlib.types_pb2 as proto_types
from trezorlib.client import CallException
from trezorlib.tx_api import TxApiZcashTestnet
class TestMsgSigntx(common.TrezorTest):
def test_one_one_fee(self):
self.setup_mnemonic_allallall()
# tx: 93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c
# input 0: 1.234567 TAZ
inp1 = proto_types.TxInputType(address_n=[2147483692, 2147483649, 2147483648, 0, 0], # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu
# amount=123456700,
prev_hash=binascii.unhexlify(b'93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='tmJ1xYxP8XNTtCoDgvdmQPSrxh5qZJgy65Z',
amount=123456700 - 1940,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_tx_api(TxApiZcashTestnet)
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify(b"93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c"))),
proto.TxRequest(request_type=proto_types.TXEXTRADATA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c"),extra_data_offset=0, extra_data_len=1024)),
proto.TxRequest(request_type=proto_types.TXEXTRADATA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c"),extra_data_offset=1024, extra_data_len=1024)),
proto.TxRequest(request_type=proto_types.TXEXTRADATA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c"),extra_data_offset=2048, extra_data_len=1024)),
proto.TxRequest(request_type=proto_types.TXEXTRADATA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify(b"93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c"),extra_data_offset=3072, extra_data_len=629)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Zcash Testnet', [inp1, ], [out1, ])
# Accepted by network: tx dcc2a10894e0e8a785c2afd4de2d958207329b9acc2b987fd768a09c5efc4547
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000015c2f725c959f9b0c66db42f185a9ebb51b51d675d79a047d4a6c62cc633e3793000000006a4730440220670b2b63d749a7038f9aea6ddf0302fe63bdcad93dafa4a89a1f0e7300ae2484022002c50af43fd867490cea0c527273c5828ff1b9a5115678f155a1830737cf29390121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff0128c55b07000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac00000000')
if __name__ == '__main__':
unittest.main()

View File

@ -16,31 +16,34 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import unittest
import common
import binascii
import base64
from trezorlib.client import CallException
class TestMsgVerifymessage(TrezorTest):
class TestMsgVerifymessage(common.TrezorTest):
def test_message_long(self):
self.setup_mnemonic_nopin_nopassphrase()
ret = self.client.verify_message(
'Bitcoin',
'14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e',
unhexlify('205ff795c29aef7538f8b3bdb2e8add0d0722ad630a140b6aefd504a5a895cbd867cbb00981afc50edd0398211e8d7c304bb8efa461181bc0afa67ea4a720a89ed'),
'1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T',
binascii.unhexlify('1bddc0aed9cf4e10dc9f57770934f4fb72a27c4510a0f4a81e09c163552416f799cd3f211ffeed0f411e9af9b927407d67115fb6d0ab1897137048efe33417fcc1'),
"VeryLongMessage!" * 64
)
assert ret is True
self.assertTrue(ret)
def test_message_testnet(self):
self.setup_mnemonic_nopin_nopassphrase()
sig = base64.b64decode('IFP/nvQalDo9lWCI7kScOzRkz/fiiScdkw7tFAKPoGbl6S8AY3wEws43s2gR57AfwZP8/8y7+F+wvGK9phQghN4=')
ret = self.client.verify_message(
'Testnet',
'mirio8q3gtv7fhdnmb3TpZ4EuafdzSs7zL',
unhexlify('209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80'),
'This is an example of a signed message.'
)
assert ret is True
'moRDikgmxcpouFtqnKnVVzLYgkDD2gQ3sk',
sig,
'Ahoj')
self.assertTrue(ret)
def test_message_verify(self):
self.setup_mnemonic_nopin_nopassphrase()
@ -49,92 +52,93 @@ class TestMsgVerifymessage(TrezorTest):
res = self.client.verify_message(
'Bitcoin',
'1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T',
unhexlify('1ba77e01a9e17ba158b962cfef5f13dfed676ffc2b4bada24e58f784458b52b97421470d001d53d5880cf5e10e76f02be3e80bf21e18398cbd41e8c3b4af74c8c2'),
binascii.unhexlify('1ba77e01a9e17ba158b962cfef5f13dfed676ffc2b4bada24e58f784458b52b97421470d001d53d5880cf5e10e76f02be3e80bf21e18398cbd41e8c3b4af74c8c2'),
'This is an example of a signed message.'
)
assert res is True
self.assertTrue(res)
# uncompressed pubkey - FAIL - wrong sig
res = self.client.verify_message(
'Bitcoin',
'1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T',
unhexlify('1ba77e01a9e17ba158b962cfef5f13dfed676ffc2b4bada24e58f784458b52b97421470d001d53d5880cf5e10e76f02be3e80bf21e18398cbd41e8c3b4af74c800'),
binascii.unhexlify('1ba77e01a9e17ba158b96200000000dfed676ffc2b4bada24e58f784458b52b97421470d001d53d5880cf5e10e76f02be3e80bf21e18398cbd41e8c3b4af74c8c2'),
'This is an example of a signed message.'
)
assert res is False
self.assertFalse(res)
# uncompressed pubkey - FAIL - wrong msg
res = self.client.verify_message(
'Bitcoin',
'1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T',
unhexlify('1ba77e01a9e17ba158b962cfef5f13dfed676ffc2b4bada24e58f784458b52b97421470d001d53d5880cf5e10e76f02be3e80bf21e18398cbd41e8c3b4af74c8c2'),
binascii.unhexlify('1ba77e01a9e17ba158b962cfef5f13dfed676ffc2b4bada24e58f784458b52b97421470d001d53d5880cf5e10e76f02be3e80bf21e18398cbd41e8c3b4af74c8c2'),
'This is an example of a signed message!'
)
assert res is False
self.assertFalse(res)
# compressed pubkey - OK
res = self.client.verify_message(
'Bitcoin',
'1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8',
unhexlify('1f44e3e461f7ca9f57c472ce1a28214df1de1dadefb6551a32d1907b80c74d5a1fbfd6daaba12dd8cb06699ce3f6941fbe0f3957b5802d13076181046e741eaaaf'),
binascii.unhexlify('1f44e3e461f7ca9f57c472ce1a28214df1de1dadefb6551a32d1907b80c74d5a1fbfd6daaba12dd8cb06699ce3f6941fbe0f3957b5802d13076181046e741eaaaf'),
'This is an example of a signed message.')
assert res is True
self.assertTrue(res)
# compressed pubkey - FAIL - wrong sig
res = self.client.verify_message(
'Bitcoin',
'1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8',
unhexlify('1f44e3e461f7ca9f57c472ce1a28214df1de1dadefb6551a32d1907b80c74d5a1fbfd6daaba12dd8cb06699ce3f6941fbe0f3957b5802d13076181046e741eaa00'),
binascii.unhexlify('1f44e3e461f7ca9f57c472000000004df1de1dadefb6551a32d1907b80c74d5a1fbfd6daaba12dd8cb06699ce3f6941fbe0f3957b5802d13076181046e741eaaaf'),
'This is an example of a signed message.'
)
assert res is False
self.assertFalse(res)
# compressed pubkey - FAIL - wrong msg
res = self.client.verify_message(
'Bitcoin',
'1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8',
unhexlify('1f44e3e461f7ca9f57c472ce1a28214df1de1dadefb6551a32d1907b80c74d5a1fbfd6daaba12dd8cb06699ce3f6941fbe0f3957b5802d13076181046e741eaaaf'),
binascii.unhexlify('1f44e3e461f7ca9f57c472ce1a28214df1de1dadefb6551a32d1907b80c74d5a1fbfd6daaba12dd8cb06699ce3f6941fbe0f3957b5802d13076181046e741eaaaf'),
'This is an example of a signed message!')
assert res is False
self.assertFalse(res)
# trezor pubkey - OK
res = self.client.verify_message(
'Bitcoin',
'14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e',
unhexlify('209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80'),
binascii.unhexlify('209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80'),
'This is an example of a signed message.'
)
assert res is True
self.assertTrue(res)
# trezor pubkey - FAIL - wrong sig
res = self.client.verify_message(
'Bitcoin',
'14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e',
unhexlify('209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be00'),
binascii.unhexlify('209e23edf0e4e47ff1de000002cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80'),
'This is an example of a signed message.'
)
assert res is False
self.assertFalse(res)
# trezor pubkey - FAIL - wrong msg
res = self.client.verify_message(
'Bitcoin',
'14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e',
unhexlify('209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80'),
binascii.unhexlify('209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80'),
'This is an example of a signed message!'
)
assert res is False
self.assertFalse(res)
"""
def test_verify_bitcoind(self):
self.setup_mnemonic_nopin_nopassphrase()
res = self.client.verify_message(
'Bitcoin',
'1KzXE97kV7DrpxCViCN3HbGbiKhzzPM7TQ',
unhexlify('1cc694f0f23901dfe3603789142f36a3fc582d0d5c0ec7215cf2ccd641e4e37228504f3d4dc3eea28bbdbf5da27c49d4635c097004d9f228750ccd836a8e1460c0'),
binascii.unhexlify('1cc694f0f23901dfe3603789142f36a3fc582d0d5c0ec7215cf2ccd641e4e37228504f3d4dc3eea28bbdbf5da27c49d4635c097004d9f228750ccd836a8e1460c0'),
u'\u017elu\u0165ou\u010dk\xfd k\u016f\u0148 \xfap\u011bl \u010f\xe1belsk\xe9 \xf3dy'
)
assert res is True
self.assertTrue(res)
def test_verify_utf(self):
self.setup_mnemonic_nopin_nopassphrase()
@ -145,16 +149,20 @@ class TestMsgVerifymessage(TrezorTest):
res_nfkd = self.client.verify_message(
'Bitcoin',
'14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e',
unhexlify('20d0ec02ed8da8df23e7fe9e680e7867cc290312fe1c970749d8306ddad1a1eda41c6a771b13d495dd225b13b0a9d0f915a984ee3d0703f92287bf8009fbb9f7d6'),
binascii.unhexlify('1fd0ec02ed8da8df23e7fe9e680e7867cc290312fe1c970749d8306ddad1a1eda4e39588e4ec2b6a22dda4ec4f562f06e91129eea9a844a7193812de82d47c496b'),
words_nfkd
)
res_nfc = self.client.verify_message(
'Bitcoin',
'14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e',
unhexlify('20d0ec02ed8da8df23e7fe9e680e7867cc290312fe1c970749d8306ddad1a1eda41c6a771b13d495dd225b13b0a9d0f915a984ee3d0703f92287bf8009fbb9f7d6'),
binascii.unhexlify('1fd0ec02ed8da8df23e7fe9e680e7867cc290312fe1c970749d8306ddad1a1eda4e39588e4ec2b6a22dda4ec4f562f06e91129eea9a844a7193812de82d47c496b'),
words_nfc
)
assert res_nfkd is True
assert res_nfc is True
self.assertTrue(res_nfkd)
self.assertTrue(res_nfc)
"""
if __name__ == '__main__':
unittest.main()

View File

@ -16,26 +16,28 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
import unittest
import common
from trezorlib import messages as proto
class TestMsgWipedevice(TrezorTest):
from trezorlib import messages_pb2 as proto
class TestDeviceWipe(common.TrezorTest):
def test_wipe_device(self):
self.setup_mnemonic_pin_passphrase()
features = self.client.call_raw(proto.Initialize())
assert features.initialized is True
assert features.pin_protection is True
assert features.passphrase_protection is True
self.assertEqual(features.initialized, True)
self.assertEqual(features.pin_protection, True)
self.assertEqual(features.passphrase_protection, True)
device_id = features.device_id
self.client.wipe_device()
features = self.client.call_raw(proto.Initialize())
assert features.initialized is False
assert features.pin_protection is False
assert features.passphrase_protection is False
assert features.device_id != device_id
self.assertEqual(features.initialized, False)
self.assertEqual(features.pin_protection, False)
self.assertEqual(features.passphrase_protection, False)
self.assertNotEqual(features.device_id, device_id)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,242 @@
# 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 unittest
import common
import binascii
import itertools
import trezorlib.messages_pb2 as proto
import trezorlib.ckd_public as bip32
import trezorlib.types_pb2 as proto_types
from trezorlib.client import CallException
# Multisig howto:
#
# https://sx.dyne.org/multisig.html
#
class TestMultisig(common.TrezorTest):
def test_2_of_3(self):
self.setup_mnemonic_nopin_nopassphrase()
#key1 = self.client.get_public_node([1])
#key2 = self.client.get_public_node([2])
#key3 = self.client.get_public_node([3])
# xpub:
# print(bip32.serialize(self.client.get_public_node([]).node))
# xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy
# pubkeys:
# xpub/1: 0338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6
# xpub/2: 038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3
# xpub/3: 03477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a7902
# redeem script:
# 52210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a621038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e32103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a790253ae
# multisig address: 3E7GDtuHqnqPmDgwH59pVC7AvySiSkbibz
# tx: c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52
# input 1: 0.001 BTC
node = bip32.deserialize('xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy')
multisig = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=node, address_n=[1]),
proto_types.HDNodePathType(node=node, address_n=[2]),
proto_types.HDNodePathType(node=node, address_n=[3])],
signatures=[b'', b'', b''],
m=2,
)
# Let's go to sign with key 1
inp1 = proto_types.TxInputType(address_n=[1],
prev_hash=binascii.unhexlify('c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52'),
prev_index=1,
script_type=proto_types.SPENDMULTISIG,
multisig=multisig,
)
out1 = proto_types.TxOutputType(address='12iyMbUb4R2K3gre4dHSrbu5azG5KaqVss',
amount=100000,
script_type=proto_types.PAYTOADDRESS)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify("c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify("c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify("c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify("c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
# Now we have first signature
(signatures1, _) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, ])
self.assertEqual(binascii.hexlify(signatures1[0]), b'3045022100985cc1ba316d140eb4b2d4028d8cd1c451f87bff8ff679858732e516ad04cd3402207af6edda99972af0baa7702a3b7448517c8242e7bca669f6861771cdd16ee058')
# ---------------------------------------
# Let's do second signature using 3rd key
multisig = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=node, address_n=[1]),
proto_types.HDNodePathType(node=node, address_n=[2]),
proto_types.HDNodePathType(node=node, address_n=[3])],
signatures=[signatures1[0], b'', b''], # Fill signature from previous signing process
m=2,
)
# Let's do a second signature with key 3
inp3 = proto_types.TxInputType(address_n=[3],
prev_hash=binascii.unhexlify('c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52'),
prev_index=1,
script_type=proto_types.SPENDMULTISIG,
multisig=multisig,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify("c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify("c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify("c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify("c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures2, serialized_tx) = self.client.sign_tx('Bitcoin', [inp3, ], [out1, ])
self.assertEqual(binascii.hexlify(signatures2[0]), b'3045022100f5428fe0531b3095675b40d87cab607ee036fac823b22e8dcec35b65aff6e52b022032129b4577ff923d321a1c70db5a6cec5bcc142cb2c51901af8b989cced23e0d')
# Accepted by network: tx 8382a2b2e3ec8788800c1d46d285dfa9dd4051edddd75982fad166b9273e5ac6
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000152ba4dfcde9c4bed88f55479cdea03e711ae586e9a89352a98230c4cdf1a09c601000000fdfe0000483045022100985cc1ba316d140eb4b2d4028d8cd1c451f87bff8ff679858732e516ad04cd3402207af6edda99972af0baa7702a3b7448517c8242e7bca669f6861771cdd16ee05801483045022100f5428fe0531b3095675b40d87cab607ee036fac823b22e8dcec35b65aff6e52b022032129b4577ff923d321a1c70db5a6cec5bcc142cb2c51901af8b989cced23e0d014c6952210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a621038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e32103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a790253aeffffffff01a0860100000000001976a91412e8391ad256dcdc023365978418d658dfecba1c88ac00000000')
def test_15_of_15(self):
self.setup_mnemonic_nopin_nopassphrase()
"""
pubs = []
for x in range(15):
pubs.append(binascii.hexlify(self.client.get_public_node([x]).node.public_key))
"""
# xpub:
# print(bip32.serialize(self.client.get_public_node([]).node))
# xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy
node = bip32.deserialize('xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy')
pubs = []
for x in range(15):
pubs.append(proto_types.HDNodePathType(node=node, address_n=[x]))
# redeeemscript
# 5f21023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43d210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a621038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e32103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a79022103fe91eca10602d7dad4c9dab2b2a0858f71e25a219a6940749ce7a48118480dae210234716c01c2dd03fa7ee302705e2b8fbd1311895d94b1dca15e62eedea9b0968f210341fb2ead334952cf60f4481ba435c4693d0be649be01d2cfe9b02018e483e7bd2102dad8b2bce360a705c16e74a50a36459b4f8f4b78f9cd67def29d54ef6f7c7cf9210222dbe3f5f197a34a1d50e2cbe2a1085cac2d605c9e176f9a240e0fd0c669330d2103fb41afab56c9cdb013fda63d777d4938ddc3cb2ad939712da688e3ed333f95982102435f177646bdc717cb3211bf46656ca7e8d642726144778c9ce816b8b8c36ccf2102158d8e20095364031d923c7e9f7f08a14b1be1ddee21fe1a5431168e31345e5521026259794892428ca0818c8fb61d2d459ddfe20e57f50803c7295e6f4e2f5586652102815f910a8689151db627e6e262e0a2075ad5ec2993a6bc1b876a9d420923d681210318f54647f645ff01bd49fedc0219343a6a22d3ea3180a3c3d3097e4b888a8db45fae
# multisig address
# 3QaKF8zobqcqY8aS6nxCD5ZYdiRfL3RCmU
signatures = [b''] * 15
out1 = proto_types.TxOutputType(address='17kTB7qSk3MupQxWdiv5ZU3zcrZc2Azes1',
amount=10000,
script_type=proto_types.PAYTOADDRESS)
for x in range(15):
multisig = proto_types.MultisigRedeemScriptType(
pubkeys=pubs,
signatures=signatures,
m=15,
)
inp1 = proto_types.TxInputType(address_n=[x],
prev_hash=binascii.unhexlify('6189e3febb5a21cee8b725aa1ef04ffce7e609448446d3a8d6f483c634ef5315'),
prev_index=1,
script_type=proto_types.SPENDMULTISIG,
multisig=multisig,
)
with self.client:
(sig, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, ])
signatures[x] = sig[0]
# Accepted as tx id dd320786d1f58c095be0509dc56b277b6de8f2fb5517f519c6e6708414e3300b
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000011553ef34c683f4d6a8d346844409e6e7fc4ff01eaa25b7e8ce215abbfee3896101000000fd43060048304502210098e23085ad7282de988bf98afa1e9add9c9830009132f8902a9fa4624d5dc98b0220733216e70ab67791aa64be5c83d2050cb4ed9ff7eda2a1acc35da024d2ab2a670147304402201f8c11fb6e90fd616e484986e9451929797eba039882a9abcc203210948060b9022044da031530de7d9747d3c5a8e7cec04b04b7af495c9120b854ce7362af7fa05a01483045022100ea67c70186acef019bdf1551881bf38e6f88186501b64d3a756a2ce18e4ba18002201c35110325653e21e448b60053a4b5dda46b61096faf701a1faca61fcde91f00014730440220315598992f156d2f9d7b4275395fa067aa61ea95829fa17730885c86df4de70d02203eda9ade1656e2198c668603b17e197acb0969ed183ab0841303ea261205618901473044022060fdd6621edde9b8cf6776bc4eef26ace9b57514d725b7214ba11d333520a30e022044c30744f94484aec0f896233c5613a3256878ec0379f566226906b6d1b6061401483045022100b1d907e3574f60f7834c7e9f2e367998ce0461dad7d742d84ef8917d713f41f902203b3ac54f7bb2f7fb8685f582d2a94f7213a37cb508acffe29090cc06ae01588b01483045022100e3bf90ff3ad6395e42f46002f253f94ca0e8ffaa0620f2ceb4fa21493abdca4d02201d4c28b10b740bb2dc4b3695b4205c18f8c0dad2bb69540eb8a36576463cd5280147304402202cfaf9fab7dc1c9f0c3c23bd46bd6d5cea0664d914139fc9add80766ce998808022012db2802c07853e4cbe147afdf0b47e60bdcbcd31f9df19e04c177ed9aa66c6d0147304402207cbc2d83f351eee5ee91df26bb0c7e1cb07fe328cbbcdb0bb9656d37922c497302201b3435d4c71ffd1b34d45892f2a487bd79c8c7f57cc04373287642bb9610cb840147304402202dc3eab30ccb06553703e794212f43ee9a659f5e787a8374e9ea0bf6de0def7402201a70e970c21a807783313ed102bf4f0a3406ac7c84f94bc8194c5e209464d7230147304402206b04530c190c46a879d7771a6ad53acd33547e0d7fd320d5ad0b5b1fdeb5d4c202207b812be81c3419daadc942cca0c55aa32c7759fa7566c6dc35f030ca87a1c5be01483045022100ce523dddd6eef73d5ae7c44c870466e1ac5a7a77d43475e8def024af68977a1e022028be0276435bfa2ea887d6cf89fa829f96c1c7a55edc57bb3fd667d523fd3bf601473044022019410b20ebcd8eb3ee7ec1eff6bf0f9cbfaea82116811c61f3cf24af7e4434b1022009e5823f3349f695be09ae40754185300d8442a22715ddb5ffa17c4213140e7201483045022100964ef26a9074c3cdafffcfbe4bd445933f8c842ba11fd887922adcf7fabe0c82022023055d94c75ab223c767fbaa825c917e9beecbc7d5758cccf20d886c63d4b72a0147304402207aa3a98197697d258a8baae681f0b4c0ee682982f4205534e6c95a37dabaddd60220517a7ed5c03da2f242e17ccfdae0d81d6f454d7f9ea931fc62df6c0eab922186014d01025f21023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43d210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a621038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e32103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a79022103fe91eca10602d7dad4c9dab2b2a0858f71e25a219a6940749ce7a48118480dae210234716c01c2dd03fa7ee302705e2b8fbd1311895d94b1dca15e62eedea9b0968f210341fb2ead334952cf60f4481ba435c4693d0be649be01d2cfe9b02018e483e7bd2102dad8b2bce360a705c16e74a50a36459b4f8f4b78f9cd67def29d54ef6f7c7cf9210222dbe3f5f197a34a1d50e2cbe2a1085cac2d605c9e176f9a240e0fd0c669330d2103fb41afab56c9cdb013fda63d777d4938ddc3cb2ad939712da688e3ed333f95982102435f177646bdc717cb3211bf46656ca7e8d642726144778c9ce816b8b8c36ccf2102158d8e20095364031d923c7e9f7f08a14b1be1ddee21fe1a5431168e31345e5521026259794892428ca0818c8fb61d2d459ddfe20e57f50803c7295e6f4e2f5586652102815f910a8689151db627e6e262e0a2075ad5ec2993a6bc1b876a9d420923d681210318f54647f645ff01bd49fedc0219343a6a22d3ea3180a3c3d3097e4b888a8db45faeffffffff0110270000000000001976a9144a087d89f8ad16ca029c675b037c02fd1c5f9aec88ac00000000')
def test_missing_pubkey(self):
self.setup_mnemonic_nopin_nopassphrase()
#key1 = self.client.get_public_node([1])
#key2 = self.client.get_public_node([2])
#key3 = self.client.get_public_node([3])
# pubkeys:
# 0338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6
# 038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3
# 03477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a7902
# multisig address: 3E7GDtuHqnqPmDgwH59pVC7AvySiSkbibz
# xpub:
# print(bip32.serialize(self.client.get_public_node([]).node))
# xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy
node = bip32.deserialize('xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy')
multisig = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=node, address_n=[1]),
proto_types.HDNodePathType(node=node, address_n=[2]),
proto_types.HDNodePathType(node=node, address_n=[3])],
signatures=[b'', b'', b''],
m=2,
)
# Let's go to sign with key 10, which is NOT in pubkeys
inp1 = proto_types.TxInputType(address_n=[10],
prev_hash=binascii.unhexlify('c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52'),
prev_index=1,
script_type=proto_types.SPENDMULTISIG,
multisig=multisig,
)
out1 = proto_types.TxOutputType(address='12iyMbUb4R2K3gre4dHSrbu5azG5KaqVss',
amount=100000,
script_type=proto_types.PAYTOADDRESS)
with self.client:
# It should throw Failure 'Pubkey not found in multisig script'
self.assertRaises(CallException, self.client.sign_tx, 'Bitcoin', [inp1, ], [out1, ])
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,373 @@
# 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 unittest
import common
import binascii
import itertools
import trezorlib.messages_pb2 as proto
import trezorlib.ckd_public as bip32
import trezorlib.types_pb2 as proto_types
from trezorlib.client import CallException
class TestMultisigChange(common.TrezorTest):
node_ext1 = bip32.deserialize('xpub6E2LkiC2h7icfcjXPFDmwufDRaaTjTRYcS2nD7eGQeFx1WwZxxvCya5GefiJND6ddJnAjzzMusLcCnu6WyhZPrF6e5G71MWjNJVfs6u9csg')
# m/1 => 02c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e
node_ext2 = bip32.deserialize('xpub6FKKCwdfD85eHmKn7d3mmbhqsHnGkB2n7Hmre29gbnR1cR4U1wrtf2akh1VVqjcTdfkxmwPjQyYPhLLgwBijfFPAYqTZzcjj4awB1BMUxq2')
# m/1 => 0388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1
node_ext3 = bip32.deserialize('xpub69rsKg2fef3GzETrukhsR3U9i4nL3dXKy3cjSpm44Cg8waqrnyupanaLQt4bYjn2HTmH1NusFt9DAh6absMQqE4E66q7EYTyEsorZKXdWWx')
# m/1 => 02e0c21e2a7cf00b94c5421725acff97f9826598b91f2340c5ddda730caca7d648
node_int = bip32.deserialize('xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy')
# m/1 => 0338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6
# ext1 + ext2 + int
# redeemscript (2 of 3): 522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653ae
# multisig address: 3Gj7y1FdTppx2JEDqYqAEZFnKCA4GRysKF
# tx: d1d08ea63255af4ad16b098e9885a252632086fa6be53301521d05253ce8a73d
# input 0: 0.001 BTC
# ext1 + int + ext2
# redeemscript (2 of 3): 522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c153ae
# multisig address: 3QsvfB6d1LzYcpm8xyhS1N1HBRrzHTgLHB
# tx: a6e2829d089cee47e481b1a753a53081b40738cc87e38f1d9b23ab57d9ad4396
# input 0: 0.001 BTC
# ext1 + ext3 + int
# redeemscript (2 of 3): 522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e2102e0c21e2a7cf00b94c5421725acff97f9826598b91f2340c5ddda730caca7d648210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653ae
# multisig address: 37LvC1Q5CyKbMbKMncEJdXxqGhHxrBEgPE
# tx: e4bc1ae5e5007a08f2b3926fe11c66612e8f73c6b00c69c7027213b84d259be3
# input 1: 0.001 BTC
multisig_in1 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=node_ext1, address_n=[1]),
proto_types.HDNodePathType(node=node_ext2, address_n=[1]),
proto_types.HDNodePathType(node=node_int, address_n=[1])],
signatures=[b'', b'', b''],
m=2,
)
multisig_in2 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=node_ext1, address_n=[1]),
proto_types.HDNodePathType(node=node_int, address_n=[1]),
proto_types.HDNodePathType(node=node_ext2, address_n=[1])],
signatures=[b'', b'', b''],
m=2,
)
multisig_in3 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=node_ext1, address_n=[1]),
proto_types.HDNodePathType(node=node_ext3, address_n=[1]),
proto_types.HDNodePathType(node=node_int, address_n=[1])],
signatures=[b'', b'', b''],
m=2,
)
inp1 = proto_types.TxInputType(address_n=[1],
prev_hash=binascii.unhexlify('d1d08ea63255af4ad16b098e9885a252632086fa6be53301521d05253ce8a73d'),
prev_index=0,
script_type=proto_types.SPENDMULTISIG,
multisig=multisig_in1,
)
inp2 = proto_types.TxInputType(address_n=[1],
prev_hash=binascii.unhexlify('a6e2829d089cee47e481b1a753a53081b40738cc87e38f1d9b23ab57d9ad4396'),
prev_index=0,
script_type=proto_types.SPENDMULTISIG,
multisig=multisig_in2,
)
inp3 = proto_types.TxInputType(address_n=[1],
prev_hash=binascii.unhexlify('e4bc1ae5e5007a08f2b3926fe11c66612e8f73c6b00c69c7027213b84d259be3'),
prev_index=1,
script_type=proto_types.SPENDMULTISIG,
multisig=multisig_in3,
)
def _responses(self, inp1, inp2, change=0):
resp = [
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=inp1.prev_hash)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=inp2.prev_hash)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=inp2.prev_hash)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=inp2.prev_hash)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=inp2.prev_hash)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
]
if change != 1:
resp.append(
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput)
)
resp.append(
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1))
)
if change != 2:
resp.append(
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput)
)
resp += [
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
]
return resp
# both outputs are external
def test_external_external(self):
self.setup_mnemonic_nopin_nopassphrase()
out1 = proto_types.TxOutputType(address='12iyMbUb4R2K3gre4dHSrbu5azG5KaqVss',
amount=100000,
script_type=proto_types.PAYTOADDRESS)
out2 = proto_types.TxOutputType(address='17kTB7qSk3MupQxWdiv5ZU3zcrZc2Azes1',
amount=100000,
script_type=proto_types.PAYTOADDRESS)
with self.client:
self.client.set_expected_responses(self._responses(self.inp1, self.inp2))
(_, serialized_tx) = self.client.sign_tx('Bitcoin', [self.inp1, self.inp2, ], [out1, out2, ])
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000023da7e83c25051d520133e56bfa86206352a285988e096bd14aaf5532a68ed0d100000000b500483045022100c4116c9a584083021dacb690d4d4938027cc3f2085dc15157162b589f2a0b52f02200bdec59f76376255afc7b76f759106f6f00edf0134db2a0ae5d28000ea517fd2014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653aeffffffff9643add957ab239b1d8fe387cc3807b48130a553a7b181e447ee9c089d82e2a600000000b400473044022044e77c67a5a78c8eb4f304cf23972a7763cce6f7dc3587d6e77e2aa05212ea6402200be874d39c32ad2475d03342cb0b164ec618297231c519186e3d0efde7a3374d014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c153aeffffffff02a0860100000000001976a91412e8391ad256dcdc023365978418d658dfecba1c88aca0860100000000001976a9144a087d89f8ad16ca029c675b037c02fd1c5f9aec88ac00000000')
# first external, second internal
def test_external_internal(self):
self.setup_mnemonic_nopin_nopassphrase()
out1 = proto_types.TxOutputType(address='12iyMbUb4R2K3gre4dHSrbu5azG5KaqVss',
amount=100000,
script_type=proto_types.PAYTOADDRESS)
out2 = proto_types.TxOutputType(address_n=[4],
amount=100000,
script_type=proto_types.PAYTOADDRESS)
with self.client:
self.client.set_expected_responses(self._responses(self.inp1, self.inp2, change=2))
(_, serialized_tx) = self.client.sign_tx('Bitcoin', [self.inp1, self.inp2, ], [out1, out2, ])
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000023da7e83c25051d520133e56bfa86206352a285988e096bd14aaf5532a68ed0d100000000b5004830450221008f48ee3c6e69f8d2aeea9c482e3e80233fc83d78eb1ac7416362b25ae57d3eee02207f6b568f8f611efb17bd6bf8d0b32d334aa4110a2cc97a06f48aba4d045b7cd4014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653aeffffffff9643add957ab239b1d8fe387cc3807b48130a553a7b181e447ee9c089d82e2a600000000b40047304402206c5f93cbedc06ac1bae846d850a27c56b0e6f75ef247d3d67a10bbe8ea9da90302203d64f4803c0cbe5703268d58a80d54a3ad72cb1b856f19a6c6c999aad011a5b9014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c153aeffffffff02a0860100000000001976a91412e8391ad256dcdc023365978418d658dfecba1c88aca0860100000000001976a914f0a2b64e56ee2ff57126232f84af6e3a41d4055088ac00000000')
# first internal, second external
def test_internal_external(self):
self.setup_mnemonic_nopin_nopassphrase()
out1 = proto_types.TxOutputType(address_n=[4],
amount=100000,
script_type=proto_types.PAYTOADDRESS)
out2 = proto_types.TxOutputType(address='17kTB7qSk3MupQxWdiv5ZU3zcrZc2Azes1',
amount=100000,
script_type=proto_types.PAYTOADDRESS)
with self.client:
self.client.set_expected_responses(self._responses(self.inp1, self.inp2, change=1))
(_, serialized_tx) = self.client.sign_tx('Bitcoin', [self.inp1, self.inp2, ], [out1, out2, ])
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000023da7e83c25051d520133e56bfa86206352a285988e096bd14aaf5532a68ed0d100000000b4004730440220740f305af9cd10f290b0d5dd27968d3c08f313d58e70feb260e076bd57d427bd02202c0296b38e82993983b971196589a2c74cdc4931a2da88aa2c2bd89e58a3fdb2014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653aeffffffff9643add957ab239b1d8fe387cc3807b48130a553a7b181e447ee9c089d82e2a600000000b400473044022042f53a8cd53762fb95113d11f56f050dab9dead9a2026807c728d5c42ed62e9902202e708162a50ca16f5fac082c1a2a5350fcb74cbfce39968e76300a36457f45a7014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c153aeffffffff02a0860100000000001976a914f0a2b64e56ee2ff57126232f84af6e3a41d4055088aca0860100000000001976a9144a087d89f8ad16ca029c675b037c02fd1c5f9aec88ac00000000')
# both outputs are external
def test_multisig_external_external(self):
self.setup_mnemonic_nopin_nopassphrase()
multisig_out1 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=self.node_ext1, address_n=[1]),
proto_types.HDNodePathType(node=self.node_ext2, address_n=[1]),
proto_types.HDNodePathType(node=self.node_ext3, address_n=[1])],
signatures=[b'', b'', b''],
m=2,
)
multisig_out2 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=self.node_ext1, address_n=[2]),
proto_types.HDNodePathType(node=self.node_ext2, address_n=[2]),
proto_types.HDNodePathType(node=self.node_ext3, address_n=[2])],
signatures=[b'', b'', b''],
m=2,
)
out1 = proto_types.TxOutputType(multisig=multisig_out1,
amount=100000,
script_type=proto_types.PAYTOMULTISIG)
out2 = proto_types.TxOutputType(multisig=multisig_out2,
amount=100000,
script_type=proto_types.PAYTOMULTISIG)
with self.client:
self.client.set_expected_responses(self._responses(self.inp1, self.inp2))
(_, serialized_tx) = self.client.sign_tx('Bitcoin', [self.inp1, self.inp2, ], [out1, out2, ])
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000023da7e83c25051d520133e56bfa86206352a285988e096bd14aaf5532a68ed0d100000000b500483045022100915e3761efb41895d40fa3bf8d3a68be7eb949e2411ec5655e231bbb334925ea02205814166b786a912f8f47315c9ede4955d2dfc70bb0b51230fccaaacf5a39a0ae014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653aeffffffff9643add957ab239b1d8fe387cc3807b48130a553a7b181e447ee9c089d82e2a600000000b400473044022018ca5516ee127eeeb8c70f10c267dd803b599688eade659e3b210bbf1712fffe02206c1adb35e672e67ee102dc232456ac5edc86f58f83d698995981e68d2a2a4294014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c153aeffffffff02a08601000000000017a9143bc72e27ec21644ace15b367ef7ba491f2507eb587a08601000000000017a9147615527d78854293edadf83682ea26937f8a51bb8700000000')
# inputs match, change matches (first is change)
def test_multisig_change_match_first(self):
self.setup_mnemonic_nopin_nopassphrase()
multisig_out1 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=self.node_int, address_n=[1]),
proto_types.HDNodePathType(node=self.node_ext1, address_n=[1]),
proto_types.HDNodePathType(node=self.node_ext2, address_n=[1])],
signatures=[b'', b'', b''],
m=2,
)
multisig_out2 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=self.node_ext1, address_n=[2]),
proto_types.HDNodePathType(node=self.node_ext2, address_n=[2]),
proto_types.HDNodePathType(node=self.node_ext3, address_n=[2])],
signatures=[b'', b'', b''],
m=2,
)
out1 = proto_types.TxOutputType(multisig=multisig_out1,
amount=100000,
script_type=proto_types.PAYTOMULTISIG)
out2 = proto_types.TxOutputType(multisig=multisig_out2,
amount=100000,
script_type=proto_types.PAYTOMULTISIG)
with self.client:
self.client.set_expected_responses(self._responses(self.inp1, self.inp2, change=1))
(_, serialized_tx) = self.client.sign_tx('Bitcoin', [self.inp1, self.inp2, ], [out1, out2, ])
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000023da7e83c25051d520133e56bfa86206352a285988e096bd14aaf5532a68ed0d100000000b40047304402203cb26eac850f590951b12b513a5369c0b301c6d3ae1cd251aa837ce35427bdec0220289834c8c5cb837351ae06498d77fa6707611c09d628864a1f0a7e1d381bddd8014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653aeffffffff9643add957ab239b1d8fe387cc3807b48130a553a7b181e447ee9c089d82e2a600000000b40047304402207c2e39254d1e9cff42b523bcc0bf5ab66ae0c584deb2413759d9b269b1fe9e6f02205bc93a1884625b2359247c15a57e4e80b184b21a5f95e7f5ce846323236e30ac014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c153aeffffffff02a08601000000000017a914b69a5c6a63c01a09a90eb690031963f737cf96ed87a08601000000000017a9147615527d78854293edadf83682ea26937f8a51bb8700000000')
# inputs match, change matches (second is change)
def test_multisig_change_match_second(self):
self.setup_mnemonic_nopin_nopassphrase()
multisig_out1 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=self.node_ext1, address_n=[1]),
proto_types.HDNodePathType(node=self.node_ext1, address_n=[1]),
proto_types.HDNodePathType(node=self.node_ext2, address_n=[1])],
signatures=[b'', b'', b''],
m=2,
)
multisig_out2 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=self.node_int, address_n=[2]),
proto_types.HDNodePathType(node=self.node_ext1, address_n=[2]),
proto_types.HDNodePathType(node=self.node_ext2, address_n=[2])],
signatures=[b'', b'', b''],
m=2,
)
out1 = proto_types.TxOutputType(multisig=multisig_out1,
amount=100000,
script_type=proto_types.PAYTOMULTISIG)
out2 = proto_types.TxOutputType(multisig=multisig_out2,
amount=100000,
script_type=proto_types.PAYTOMULTISIG)
with self.client:
self.client.set_expected_responses(self._responses(self.inp1, self.inp2, change=2))
(_, serialized_tx) = self.client.sign_tx('Bitcoin', [self.inp1, self.inp2, ], [out1, out2, ])
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000023da7e83c25051d520133e56bfa86206352a285988e096bd14aaf5532a68ed0d100000000b5004830450221008d5710ba7df3c32358a723c69458acc81a296646cad262217975ba00b24fdc6402201623a3e3778e6abad9025343cef6fad361a054463f928509324ee862a2e84e6a014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653aeffffffff9643add957ab239b1d8fe387cc3807b48130a553a7b181e447ee9c089d82e2a600000000b400473044022014d07e6a67c14a81d1042be2990d4c4ac29d9a46ba051168a9ccc09e987d97e202203cfe6714cff04421a90d5a4507f875515a1357fc2df306a44617ae7f88c7fcd1014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c153aeffffffff02a08601000000000017a9143fdb3ed6e85c87d77f263be3b0d0abc508fe4e3787a08601000000000017a914021809d0cb4a6fcf436e6b8cc743511b09d183218700000000')
# inputs match, change mismatches (second is change)
def test_multisig_mismatch_change(self):
self.setup_mnemonic_nopin_nopassphrase()
multisig_out1 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=self.node_ext1, address_n=[1]),
proto_types.HDNodePathType(node=self.node_ext2, address_n=[1]),
proto_types.HDNodePathType(node=self.node_ext3, address_n=[1])],
signatures=[b'', b'', b''],
m=2,
)
multisig_out2 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=self.node_int, address_n=[2]),
proto_types.HDNodePathType(node=self.node_ext1, address_n=[2]),
proto_types.HDNodePathType(node=self.node_ext3, address_n=[2])],
signatures=[b'', b'', b''],
m=2,
)
out1 = proto_types.TxOutputType(multisig=multisig_out1,
amount=100000,
script_type=proto_types.PAYTOMULTISIG)
out2 = proto_types.TxOutputType(multisig=multisig_out2,
amount=100000,
script_type=proto_types.PAYTOMULTISIG)
with self.client:
self.client.set_expected_responses(self._responses(self.inp1, self.inp2))
(_, serialized_tx) = self.client.sign_tx('Bitcoin', [self.inp1, self.inp2, ], [out1, out2, ])
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000023da7e83c25051d520133e56bfa86206352a285988e096bd14aaf5532a68ed0d100000000b40047304402202a6238e8c9955a3d01609cbdaafcf47b0a53b2eabe2e28cf942fe9e253457eba02207f67afb4c35a8d28603e71a0696d0c123c0ca2370d78076c692ca3036c0a2c35014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653aeffffffff9643add957ab239b1d8fe387cc3807b48130a553a7b181e447ee9c089d82e2a600000000b40047304402200e87ee683b27f3995a2f8c9e9b4b17e24399d43a4c69ce5402105b6b93ac63cf0220201ba91db1f4ca2768f9277c115e95c2297bbe40969dcf9d10d0836a75c8ac9c014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c153aeffffffff02a08601000000000017a9143bc72e27ec21644ace15b367ef7ba491f2507eb587a08601000000000017a9143f22da0a6d4a4341be319e48e7b51b5a113fda208700000000')
# inputs mismatch, change matches with first input
def test_multisig_mismatch_inputs(self):
self.setup_mnemonic_nopin_nopassphrase()
multisig_out1 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=self.node_ext1, address_n=[1]),
proto_types.HDNodePathType(node=self.node_ext2, address_n=[1]),
proto_types.HDNodePathType(node=self.node_int, address_n=[1])],
signatures=[b'', b'', b''],
m=2,
)
multisig_out2 = proto_types.MultisigRedeemScriptType(
pubkeys=[proto_types.HDNodePathType(node=self.node_ext1, address_n=[2]),
proto_types.HDNodePathType(node=self.node_ext2, address_n=[2]),
proto_types.HDNodePathType(node=self.node_ext3, address_n=[2])],
signatures=[b'', b'', b''],
m=2,
)
out1 = proto_types.TxOutputType(multisig=multisig_out1,
amount=100000,
script_type=proto_types.PAYTOMULTISIG)
out2 = proto_types.TxOutputType(multisig=multisig_out2,
amount=100000,
script_type=proto_types.PAYTOMULTISIG)
with self.client:
self.client.set_expected_responses(self._responses(self.inp1, self.inp3))
(_, serialized_tx) = self.client.sign_tx('Bitcoin', [self.inp1, self.inp3, ], [out1, out2, ])
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000023da7e83c25051d520133e56bfa86206352a285988e096bd14aaf5532a68ed0d100000000b40047304402204b7d6c7e9feef91209cbdf4deaf855696dc22a40e57bd3eafd5e00b0ee41d9de0220262c5a05d0b46ef98fddfef3831b3ebb6841ffbeb10666f8fb6f8d2e3023e30d014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653aeffffffffe39b254db8137202c7690cb0c6738f2e61661ce16f92b3f2087a00e5e51abce401000000b500483045022100bb2118da21c8a84f115b655f640f269a40be77ae2c0af9c5ffd8260a85dbfc7702202e7b5b6c05b8f50bd879dbee88828e80e85448d686b63a1a50e99d921923f6f5014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e2102e0c21e2a7cf00b94c5421725acff97f9826598b91f2340c5ddda730caca7d648210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653aeffffffff02a08601000000000017a914a4efc33d43d7a8a0040182c76ab624ff862f50d287a08601000000000017a9147615527d78854293edadf83682ea26937f8a51bb8700000000')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,109 @@
# 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 unittest
import common
import binascii
import itertools
import trezorlib.messages_pb2 as proto
import trezorlib.types_pb2 as proto_types
from trezorlib.client import CallException
class TestOpReturn(common.TrezorTest):
def test_opreturn(self):
self.setup_mnemonic_nopin_nopassphrase()
# tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
# input 0: 0.0039 BTC
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
amount=390000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
out2 = proto_types.TxOutputType(op_return_data=b'test of the op_return data',
amount=0,
script_type=proto_types.PAYTOOPRETURN,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, out2])
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000182488650ef25a58fef6788bd71b8212038d7f2bbe4750bc7bcb44701e85ef6d5000000006a4730440220187b7b9c340a32fc8445418ad11fb3827d2e8bac7d730e1c9ad800353e7ba62f02206c0c5820ba8882c82923a39aee8d36d6d32e13daed73f7a3d6199de5f8e7ddfd0121023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43dffffffff0260cc0500000000001976a914de9b2a8da088824e8fe51debea566617d851537888ac00000000000000001c6a1a74657374206f6620746865206f705f72657475726e206461746100000000')
def test_nonzero_opreturn(self):
self.setup_mnemonic_nopin_nopassphrase()
# tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
# input 0: 0.0039 BTC
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
amount=390000 - 10000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
out1 = proto_types.TxOutputType(op_return_data=b'test of the op_return data',
amount=10000,
script_type=proto_types.PAYTOOPRETURN,
)
with self.client:
self.client.set_expected_responses([
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.Failure()
])
self.assertRaises(CallException, self.client.sign_tx, 'Bitcoin', [inp1, ], [out1, ])
if __name__ == '__main__':
unittest.main()

View File

@ -19,25 +19,24 @@
from __future__ import print_function
import time
from .common import *
from trezorlib import messages as proto
import unittest
import common
from trezorlib import messages_pb2 as proto
from trezorlib import types_pb2 as types
from trezorlib.client import PinException, CallException
# FIXME TODO Add passphrase tests
@pytest.mark.skip_t2
class TestProtectCall(TrezorTest):
class TestProtectCall(common.TrezorTest):
def _some_protected_call(self, button, pin, passphrase):
# This method perform any call which have protection in the device
res = self.client.ping(
'random data',
button_protection=button,
pin_protection=pin,
passphrase_protection=passphrase
)
assert res == 'random data'
res = self.client.ping('random data',
button_protection=button,
pin_protection=pin,
passphrase_protection=passphrase)
self.assertEqual(res, 'random data')
"""
def test_expected_responses(self):
@ -49,14 +48,12 @@ class TestProtectCall(TrezorTest):
with self.client:
# Scenario 1 - Received unexpected message
self.client.set_expected_responses([])
with pytest.raises(CallException):
self._some_protected_call(True, True, True)
self.assertRaises(CallException, self._some_protected_call, True, True, True)
with self.client:
# Scenario 2 - Received other than expected message
self.client.set_expected_responses([proto.Success()])
with pytest.raises(CallException):
self._some_protected_call(True, True, True)
self.assertRaises(CallException, self._some_protected_call, True, True, True)
def scenario3():
with self.client:
@ -65,8 +62,7 @@ class TestProtectCall(TrezorTest):
proto.Success(),
proto.Success()]) # This is expected, but not received
self._some_protected_call(True, False, False)
with pytest.raises(Exception):
scenario3()
self.assertRaises(Exception, scenario3)
with self.client:
# Scenario 4 - Received what expected
@ -82,15 +78,14 @@ class TestProtectCall(TrezorTest):
self.client.set_expected_responses([proto.ButtonRequest(),
proto.Success(message='wrong data')])
self._some_protected_call(True, True, True)
with pytest.raises(CallException):
scenario5()
self.assertRaises(CallException, scenario5)
"""
def test_no_protection(self):
self.setup_mnemonic_nopin_nopassphrase()
with self.client:
assert self.client.debug.read_pin()[0] is None
self.assertEqual(self.client.debug.read_pin()[0], '')
self.client.set_expected_responses([proto.Success()])
self._some_protected_call(False, True, True)
@ -98,7 +93,7 @@ class TestProtectCall(TrezorTest):
self.setup_mnemonic_pin_passphrase()
with self.client:
assert self.client.debug.read_pin()[0] == self.pin4
self.assertEqual(self.client.debug.read_pin()[0], self.pin4)
self.client.setup_debuglink(button=True, pin_correct=True)
self.client.set_expected_responses([proto.ButtonRequest(),
proto.PinMatrixRequest(),
@ -108,14 +103,12 @@ class TestProtectCall(TrezorTest):
def test_incorrect_pin(self):
self.setup_mnemonic_pin_passphrase()
self.client.setup_debuglink(button=True, pin_correct=False)
with pytest.raises(PinException):
self._some_protected_call(False, True, False)
self.assertRaises(PinException, self._some_protected_call, False, True, False)
def test_cancelled_pin(self):
self.setup_mnemonic_pin_passphrase()
self.client.setup_debuglink(button=True, pin_correct=False) # PIN cancel
with pytest.raises(PinException):
self._some_protected_call(False, True, False)
self.assertRaises(PinException, self._some_protected_call, False, True, False)
def test_exponential_backoff_with_reboot(self):
self.setup_mnemonic_pin_passphrase()
@ -126,15 +119,17 @@ class TestProtectCall(TrezorTest):
if attempts <= 1:
expected = 0
else:
expected = (2 ** (attempts - 1)) - 1
got = round(time.time() - start, 2)
expected = (2 ** (attempts - 2))
got = time.time() - start
msg = "Pin delay expected to be at least %s seconds, got %s" % (expected, got)
print(msg)
assert got >= expected
self.assertLessEqual(expected, got, msg)
for attempt in range(1, 6):
start = time.time()
with pytest.raises(PinException):
self._some_protected_call(False, True, False)
self.assertRaises(PinException, self._some_protected_call, False, True, False)
test_backoff(attempt, start)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,215 @@
# 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 unittest
import common
import binascii
from trezorlib import messages_pb2 as proto
from trezorlib import types_pb2 as proto_types
class TestProtectionLevels(common.TrezorTest):
def test_initialize(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.Features()])
self.client.init_device()
def test_apply_settings(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.PinMatrixRequest(),
proto.ButtonRequest(),
proto.Success(),
proto.Features()]) # TrezorClient reinitializes device
self.client.apply_settings(label='nazdar')
def test_change_pin(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.ButtonRequest(),
proto.PinMatrixRequest(),
proto.PinMatrixRequest(),
proto.PinMatrixRequest(),
proto.Success(),
proto.Features()])
self.client.change_pin()
def test_ping(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.ButtonRequest(),
proto.PinMatrixRequest(),
proto.PassphraseRequest(),
proto.Success()])
self.client.ping('msg', True, True, True)
def test_get_entropy(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.ButtonRequest(),
proto.Entropy()])
self.client.get_entropy(10)
def test_get_public_key(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.PinMatrixRequest(),
proto.PassphraseRequest(),
proto.PublicKey()])
self.client.get_public_node([])
def test_get_address(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.PinMatrixRequest(),
proto.PassphraseRequest(),
proto.Address()])
self.client.get_address('Bitcoin', [])
def test_wipe_device(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.ButtonRequest(),
proto.Success(),
proto.Features()])
self.client.wipe_device()
def test_load_device(self):
with self.client:
self.client.set_expected_responses([proto.ButtonRequest(),
proto.Success(),
proto.Features()])
self.client.load_device_by_mnemonic('this is mnemonic', '1234', True, 'label', 'english', skip_checksum=True)
# This must fail, because device is already initialized
self.assertRaises(Exception, self.client.load_device_by_mnemonic,
'this is mnemonic', '1234', True, 'label', 'english', skip_checksum=True)
def test_reset_device(self):
with self.client:
self.client.set_expected_responses([proto.EntropyRequest()] + \
[proto.ButtonRequest()] * 24 + \
[proto.Success(),
proto.Features()])
self.client.reset_device(False, 128, True, False, 'label', 'english')
# This must fail, because device is already initialized
self.assertRaises(Exception, self.client.reset_device, False, 128, True, False, 'label', 'english')
def test_recovery_device(self):
with self.client:
self.client.set_mnemonic(self.mnemonic12)
self.client.set_expected_responses([proto.WordRequest()] * 24 + \
[proto.Success(),
proto.Features()])
self.client.recovery_device(12, False, False, 'label', 'english')
# This must fail, because device is already initialized
self.assertRaises(Exception, self.client.recovery_device, 12, False, False, 'label', 'english')
def test_sign_message(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.ButtonRequest(),
proto.PinMatrixRequest(),
proto.PassphraseRequest(),
proto.MessageSignature()])
self.client.sign_message('Bitcoin', [], 'testing message')
def test_verify_message(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.ButtonRequest(),proto.Success()])
self.client.verify_message(
'Bitcoin',
'14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e',
binascii.unhexlify('209e23edf0e4e47ff1dec27f32cd78c50e74ef018ee8a6adf35ae17c7a9b0dd96f48b493fd7dbab03efb6f439c6383c9523b3bbc5f1a7d158a6af90ab154e9be80'),
'This is an example of a signed message.')
def test_estimate_txsize(self):
with self.client:
self.setup_mnemonic_pin_passphrase()
self.client.set_expected_responses([proto.TxSize()])
self.client.estimate_tx_size('Bitcoin', [], [])
"""
def test_simplesigntx(self):
self.setup_mnemonic_pin_passphrase()
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
amount=390000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_expected_responses([proto.PinMatrixRequest(),
proto.PassphraseRequest(),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXFINISHED)])
self.client.simple_sign_tx('Bitcoin', [inp1, ], [out1, ])
"""
def test_signtx(self):
self.setup_mnemonic_pin_passphrase()
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
amount=390000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
with self.client:
self.client.set_expected_responses([
proto.PinMatrixRequest(),
proto.PassphraseRequest(),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXMETA, details=proto_types.TxRequestDetailsType(tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=binascii.unhexlify("d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"))),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.ButtonRequest(code=proto_types.ButtonRequest_ConfirmOutput),
proto.ButtonRequest(code=proto_types.ButtonRequest_SignTx),
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
proto.TxRequest(request_type=proto_types.TXFINISHED),
])
self.client.sign_tx('Bitcoin', [inp1, ], [out1, ])
# def test_firmware_erase(self):
# pass
# def test_firmware_upload(self):
# pass
if __name__ == '__main__':
unittest.main()

View File

@ -18,92 +18,96 @@
from __future__ import print_function
import unittest
import common
import binascii
import sys
from .common import *
from trezorlib import messages as proto
TXHASH_d5f65e = unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882')
import trezorlib.messages_pb2 as proto
import trezorlib.types_pb2 as proto_types
if sys.version_info < (3,):
def byteindex(data, index):
return ord(data[index])
else:
byteindex = lambda data, index: data[index]
# address_n = [177] < 68
# address_n = [16518] < 66
class TestZerosig(TrezorTest):
class TestZeroSig(common.TrezorTest):
'''
def test_mine_zero_signature(self):
# tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
# input 0: 0.0039 BTC
inp1 = proto.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=TXHASH_d5f65e,
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
msg = self.client._prepare_sign_tx('Bitcoin', [inp1, ], [])
for n in range(3500, 200000):
out1 = proto.TxOutputType(address_n=[n],
out1 = proto_types.TxOutputType(address_n=[n],
amount=390000 - 10000,
script_type=proto.OutputScriptType.PAYTOADDRESS,
script_type=proto_types.PAYTOADDRESS,
)
msg.ClearField('outputs')
msg.outputs.extend([out1, ])
tx = self.client.call(msg)
siglen = tx.serialized_tx[44]
siglen = byteindex(tx.serialized_tx, 44)
print(siglen)
if siglen < 67:
print("!!!!", n)
print(hexlify(tx.serialized_tx))
print(binascii.hexlify(tx.serialized_tx))
return
'''
def test_one_zero_signature(self):
self.setup_mnemonic_nopin_nopassphrase()
inp1 = proto.TxInputType(
address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=TXHASH_d5f65e,
prev_index=0,
)
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
# Following address_n has been mined by 'test_mine_zero_signature'
out1 = proto.TxOutputType(
address_n=[177],
amount=390000 - 10000,
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
out1 = proto_types.TxOutputType(address_n=[177],
amount=390000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, ])
siglen = serialized_tx[44]
siglen = byteindex(serialized_tx, 44)
# TREZOR must strip leading zero from signature
assert siglen == 67
self.assertEqual(siglen, 67)
def test_two_zero_signature(self):
self.setup_mnemonic_nopin_nopassphrase()
inp1 = proto.TxInputType(
address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=TXHASH_d5f65e,
prev_index=0,
)
inp1 = proto_types.TxInputType(address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
# amount=390000,
prev_hash=binascii.unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
prev_index=0,
)
# Following address_n has been mined by 'test_mine_zero_signature'
out1 = proto.TxOutputType(
address_n=[16518],
amount=390000 - 10000,
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
out1 = proto_types.TxOutputType(address_n=[16518],
amount=390000 - 10000,
script_type=proto_types.PAYTOADDRESS,
)
(signatures, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, ], [out1, ])
siglen = serialized_tx[44]
siglen = byteindex(serialized_tx, 44)
# TREZOR must strip leading zero from signature
assert siglen == 66
self.assertEqual(siglen, 66)
if __name__ == '__main__':
unittest.main()

View File

@ -1,6 +1,7 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2017 Saleem Rashid <trezor@saleemrashid.com>
# 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
@ -15,13 +16,11 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from .common import *
from __future__ import print_function
import sys
sys.path = ['../../'] + sys.path
@pytest.mark.skip_t2
class TestMsgNEMGetaddress(TrezorTest):
from trezorlib import tx_api
def test_nem_getaddress(self):
self.setup_mnemonic_nopin_nopassphrase()
assert self.client.nem_get_address(self.client.expand_path("m/44'/1'/0'/0'/0'"), 0x68) == "NB3JCHVARQNGDS3UVGAJPTFE22UQFGMCQGHUBWQN"
assert self.client.nem_get_address(self.client.expand_path("m/44'/1'/0'/0'/0'"), 0x98) == "TB3JCHVARQNGDS3UVGAJPTFE22UQFGMCQHSBNBMF"
tx_api.cache_dir = '../txcache'

View File

@ -0,0 +1,39 @@
# 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 common
import unittest
from trezorlib import ckd_public
class TestCkdPublic(unittest.TestCase):
def test_ckd(self):
xpub1 = 'xpub661MyMwAqRbcEnKbXcCqD2GT1di5zQxVqoHPAgHNe8dv5JP8gWmDproS6kFHJnLZd23tWevhdn4urGJ6b264DfTGKr8zjmYDjyDTi9U7iyT'
node1 = ckd_public.deserialize(xpub1)
node2 = ckd_public.public_ckd(node1, [0])
node3 = ckd_public.public_ckd(node1, [0, 0])
xpub2 = ckd_public.serialize(node2)
xpub3 = ckd_public.serialize(node3)
self.assertEqual(xpub2, 'xpub67ymn1YTdE2iSGXitxUEZeUdHF2FsejJATroeAxVMtzTAK9o3vjmFLrE7TqE1X76iobkVc3p8h3gNzNRTwPeQGYW3CCmYCG8n5ThVkXaQzs')
self.assertEqual(xpub3, 'xpub6BD2MwdEg5PJPqiGetL9DJs7oDo6zP3XwAABX2vAQb5eLpY3QhHGUEm25V4nkQhnFMsqEVfTwtax2gKz8EFrt1PnBN6xQjE9jGmWDR6modu')
if __name__ == '__main__':
unittest.main()

View File

@ -16,15 +16,21 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from trezorlib import ckd_public
import common
import unittest
from trezorlib.protobuf_json import json2pb, pb2json
import trezorlib.messages_pb2 as msg
def test_ckd_public():
xpub1 = 'xpub661MyMwAqRbcEnKbXcCqD2GT1di5zQxVqoHPAgHNe8dv5JP8gWmDproS6kFHJnLZd23tWevhdn4urGJ6b264DfTGKr8zjmYDjyDTi9U7iyT'
node1 = ckd_public.deserialize(xpub1)
node2 = ckd_public.public_ckd(node1, [0])
node3 = ckd_public.public_ckd(node1, [0, 0])
xpub2 = ckd_public.serialize(node2)
xpub3 = ckd_public.serialize(node3)
assert xpub2 == 'xpub67ymn1YTdE2iSGXitxUEZeUdHF2FsejJATroeAxVMtzTAK9o3vjmFLrE7TqE1X76iobkVc3p8h3gNzNRTwPeQGYW3CCmYCG8n5ThVkXaQzs'
assert xpub3 == 'xpub6BD2MwdEg5PJPqiGetL9DJs7oDo6zP3XwAABX2vAQb5eLpY3QhHGUEm25V4nkQhnFMsqEVfTwtax2gKz8EFrt1PnBN6xQjE9jGmWDR6modu'
class TestProtobufJson(unittest.TestCase):
def test_pb2json(self):
m = msg.Features()
m.device_id = '1234'
j = pb2json(m)
self.assertEqual(j, {'device_id': u'1234'} )
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,45 @@
# 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 common
import unittest
from trezorlib.tx_api import TxApiBitcoin, TxApiTestnet
class TestTxApi(unittest.TestCase):
def test_get(self):
tx = TxApiBitcoin.get_tx('39a29e954977662ab3879c66fb251ef753e0912223a83d1dcb009111d28265e5')
tx = TxApiBitcoin.get_tx('54aa5680dea781f45ebb536e53dffc526d68c0eb5c00547e323b2c32382dfba3')
tx = TxApiBitcoin.get_tx('58497a7757224d1ff1941488d23087071103e5bf855f4c1c44e5c8d9d82ca46e')
tx = TxApiBitcoin.get_tx('6189e3febb5a21cee8b725aa1ef04ffce7e609448446d3a8d6f483c634ef5315')
tx = TxApiBitcoin.get_tx('a6e2829d089cee47e481b1a753a53081b40738cc87e38f1d9b23ab57d9ad4396')
tx = TxApiBitcoin.get_tx('c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52')
tx = TxApiBitcoin.get_tx('c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb')
tx = TxApiBitcoin.get_tx('c6be22d34946593bcad1d2b013e12f74159e69574ffea21581dad115572e031c')
tx = TxApiBitcoin.get_tx('d1d08ea63255af4ad16b098e9885a252632086fa6be53301521d05253ce8a73d')
tx = TxApiBitcoin.get_tx('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882')
tx = TxApiBitcoin.get_tx('e4bc1ae5e5007a08f2b3926fe11c66612e8f73c6b00c69c7027213b84d259be3')
tx = TxApiTestnet.get_tx('6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54')
tx = TxApiTestnet.get_tx('d6da21677d7cca5f42fbc7631d062c9ae918a0254f7c6c22de8e8cb7fd5b8236')
if __name__ == '__main__':
unittest.main()

View File

@ -1,32 +0,0 @@
#!/bin/bash
CURDIR=$(pwd)
PB2DIR=$CURDIR/pb2
OUTDIR=../trezorlib/messages
INDEX=$OUTDIR/__init__.py
rm -f $OUTDIR/[A-Z]*.py
mkdir -p $OUTDIR
mkdir -p $PB2DIR
touch $PB2DIR/__init__.py
rm -f $INDEX
echo '# Automatically generated by pb2py' >> $INDEX
echo 'from __future__ import absolute_import' >> $INDEX
echo '' >> $INDEX
for i in types messages ; do
# Compile .proto files to python2 modules using google protobuf library
cd $CURDIR/../../trezor-common/protob
protoc --python_out=$PB2DIR -I/usr/include -I. $i.proto
done
# hack to make output python 3 compatible
sed -i 's/^import types_pb2/from . import types_pb2/g' $CURDIR/pb2/messages_pb2.py
for i in types messages ; do
# Convert google protobuf library to trezor's internal format
cd $CURDIR
./pb2py -p $CURDIR -l $INDEX $i $OUTDIR
done
rm -rf $PB2DIR

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
'''
@ -15,45 +15,51 @@ import json
import hashlib
import binascii
from trezorlib.client import TrezorClient
from trezorlib.transport import enumerate_devices
from trezorlib.client import TrezorClient, TrezorClientDebug
from trezorlib.transport_hid import HidTransport
# Python2 vs Python3
try:
input = raw_input
except NameError:
pass
def wait_for_devices():
devices = enumerate_devices()
devices = HidTransport.enumerate()
while not len(devices):
sys.stderr.write("Please connect TREZOR to computer and press Enter...")
input()
devices = enumerate_devices()
devices = HidTransport.enumerate()
return devices
def choose_device(devices):
if not len(devices):
raise RuntimeError("No TREZOR connected!")
raise Exception("No TREZOR connected!")
if len(devices) == 1:
try:
return devices[0]
return HidTransport(devices[0])
except IOError:
raise RuntimeError("Device is currently in use")
raise Exception("Device is currently in use")
i = 0
sys.stderr.write("----------------------------\n")
sys.stderr.write("Available devices:\n")
for d in devices:
try:
client = TrezorClient(d)
t = HidTransport(d)
except IOError:
sys.stderr.write("[-] <device is currently in use>\n")
continue
client = TrezorClient(t)
if client.features.label:
sys.stderr.write("[%d] %s\n" % (i, client.features.label))
else:
sys.stderr.write("[%d] <no label>\n" % i)
client.close()
t.close()
i += 1
sys.stderr.write("----------------------------\n")
@ -61,14 +67,13 @@ def choose_device(devices):
try:
device_id = int(input())
return devices[device_id]
return HidTransport(devices[device_id])
except:
raise ValueError("Invalid choice, exiting...")
raise Exception("Invalid choice, exiting...")
def main():
if 'encfs_root' not in os.environ:
if not 'encfs_root' in os.environ:
sys.stderr.write('\nThis is not a standalone script and is not meant to be run independently.\n')
sys.stderr.write('\nUsage: encfs --standard --extpass=./encfs_aes_getpass.py ~/.crypt ~/crypt\n')
sys.exit(1)
@ -95,7 +100,7 @@ def main():
passw = hashlib.sha256(trezor_entropy + urandom_entropy).digest()
if len(passw) != 32:
raise ValueError("32 bytes password expected")
raise Exception("32 bytes password expected")
bip32_path = [10, 0]
passw_encrypted = client.encrypt_keyvalue(bip32_path, label, passw, False, True)
@ -117,6 +122,5 @@ def main():
print(passw)
if __name__ == '__main__':
main()

View File

@ -1,11 +1,20 @@
#!/usr/bin/env python3
from trezorlib.client import TrezorClient
from trezorlib.transport import get_transport
#!/usr/bin/env python
from __future__ import print_function
from trezorlib.client import TrezorClient
from trezorlib.transport_hid import HidTransport
def main():
# List all connected TREZORs on USB
devices = HidTransport.enumerate()
# Check whether we found any
if len(devices) == 0:
print('No TREZOR found')
return
# Use first connected device
transport = get_transport()
transport = HidTransport(devices[0])
# Creates object for manipulating TREZOR
client = TrezorClient(transport)
@ -21,6 +30,5 @@ def main():
client.close()
if __name__ == '__main__':
main()

View File

@ -1,48 +0,0 @@
#!/usr/bin/env python3
from trezorlib.debuglink import DebugLink
from trezorlib.client import TrezorClient
from trezorlib.transport import enumerate_devices
import binascii
import sys
sectoraddrs = [0x8000000, 0x8004000, 0x8008000, 0x800c000,
0x8010000, 0x8020000, 0x8040000, 0x8060000,
0x8080000, 0x80a0000, 0x80c0000, 0x80f0000]
sectorlens = [0x4000, 0x4000, 0x4000, 0x4000,
0x8000, 0x10000, 0x10000, 0x10000,
0x10000, 0x10000, 0x10000, 0x10000]
def main():
# List all debuggable TREZORs
devices = [device for device in enumerate_devices() if hasattr(device, 'find_debug')]
# Check whether we found any
if len(devices) == 0:
print('No TREZOR found')
return
# Use first connected device
transport = devices[0]
debug_transport = devices[0].find_debug()
# Creates object for manipulating TREZOR
client = TrezorClient(transport)
debug = DebugLink(debug_transport)
sector = int(sys.argv[1])
f = open(sys.argv[2], "rb")
content = f.read(sectorlens[sector])
if (len(content) != sectorlens[sector]):
print("Not enough bytes in file")
return
debug.flash_erase(sector)
step = 0x400
for offset in range(0, sectorlens[sector], step):
debug.memory_write(sectoraddrs[sector] + offset, content[offset:offset + step], flash=True)
client.close()
if __name__ == '__main__':
main()

View File

@ -1,7 +1,10 @@
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
from trezorlib.debuglink import DebugLink
from trezorlib.client import TrezorClient
from trezorlib.transport import enumerate_devices
from trezorlib.client import TrezorClient, TrezorDebugClient
from trezorlib.transport_hid import HidTransport
import binascii
import sys
# usage examples
@ -12,10 +15,9 @@ import sys
# note that in order for this to work, your trezor device must
# be running a firmware that was built with debug link enabled
def main():
# List all debuggable TREZORs
devices = [device for device in enumerate_devices() if hasattr(device, 'find_debug')]
# List all connected TREZORs on USB
devices = HidTransport.enumerate()
# Check whether we found any
if len(devices) == 0:
@ -23,10 +25,10 @@ def main():
return
# Use first connected device
transport = devices[0]
debug_transport = devices[0].find_debug()
transport = HidTransport(devices[0])
# Creates object for manipulating TREZOR
debug_transport = HidTransport(devices[0], **{'debug_link': True})
client = TrezorClient(transport)
debug = DebugLink(debug_transport)
@ -34,16 +36,15 @@ def main():
arg2 = int(sys.argv[2], 16)
step = 0x400 if arg2 >= 0x400 else arg2
f = open('memory.dat', 'wb')
f = open('memory.dat', 'w')
for addr in range(arg1, arg1 + arg2, step):
mem = debug.memory_read(addr, step)
f.write(mem)
mem = debug.memory_read(addr, step)
f.write(mem)
f.close()
client.close()
if __name__ == '__main__':
main()

View File

@ -1,14 +1,15 @@
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
from trezorlib.debuglink import DebugLink
from trezorlib.client import TrezorClient
from trezorlib.transport import enumerate_devices
from trezorlib.client import TrezorClient, TrezorDebugClient
from trezorlib.transport_hid import HidTransport
import binascii
import sys
def main():
# List all debuggable TREZORs
devices = [device for device in enumerate_devices() if hasattr(device, 'find_debug')]
# List all connected TREZORs on USB
devices = HidTransport.enumerate()
# Check whether we found any
if len(devices) == 0:
@ -16,16 +17,15 @@ def main():
return
# Use first connected device
transport = devices[0]
debug_transport = devices[0].find_debug()
transport = HidTransport(devices[0])
# Creates object for manipulating TREZOR
debug_transport = HidTransport(devices[0], **{'debug_link': True})
client = TrezorClient(transport)
debug = DebugLink(debug_transport)
debug.memory_write(int(sys.argv[1], 16), binascii.unhexlify(sys.argv[2]), flash=True)
mem = debug.memory_write(int(sys.argv[1],16), binascii.unhexlify(sys.argv[2]), flash=True)
client.close()
if __name__ == '__main__':
main()

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import binascii
import hashlib
import mnemonic
@ -15,6 +16,11 @@ __doc__ = '''
without an internet connection).
'''
# Python2 vs Python3
try:
input = raw_input
except NameError:
pass
def generate_entropy(strength, internal_entropy, external_entropy):
'''
@ -22,29 +28,28 @@ def generate_entropy(strength, internal_entropy, external_entropy):
random - binary stream of random data from external HRNG
'''
if strength not in (128, 192, 256):
raise ValueError("Invalid strength")
raise Exception("Invalid strength")
if not internal_entropy:
raise ValueError("Internal entropy is not provided")
raise Exception("Internal entropy is not provided")
if len(internal_entropy) < 32:
raise ValueError("Internal entropy too short")
raise Exception("Internal entropy too short")
if not external_entropy:
raise ValueError("External entropy is not provided")
raise Exception("External entropy is not provided")
if len(external_entropy) < 32:
raise ValueError("External entropy too short")
raise Exception("External entropy too short")
entropy = hashlib.sha256(internal_entropy + external_entropy).digest()
entropy_stripped = entropy[:strength // 8]
if len(entropy_stripped) * 8 != strength:
raise ValueError("Entropy length mismatch")
raise Exception("Entropy length mismatch")
return entropy_stripped
def main():
print(__doc__)
@ -67,6 +72,5 @@ def main():
print("Generated mnemonic is:", words)
if __name__ == '__main__':
main()

View File

@ -1,216 +0,0 @@
#!/usr/bin/env python3
# Converts Google's protobuf python definitions of TREZOR wire messages
# to plain-python objects as used in TREZOR Core and python-trezor
import sys
import os
import argparse
from google.protobuf.internal.enum_type_wrapper import EnumTypeWrapper
def process_type(t, cls, msg_id, indexfile, is_upy):
print(" * type %s" % t)
imports = []
out = ["", "", "class %s(p.MessageType):" % t, ]
if cls.DESCRIPTOR.fields_by_name:
out.append(" FIELDS = {")
elif msg_id is None:
out.append(" pass")
for v in sorted(cls.DESCRIPTOR.fields_by_name.values(), key=lambda x: x.number):
number = v.number
fieldname = v.name
type = None
repeated = v.label == 3
required = v.label == 2
# print v.has_default_value, v.default_value
if v.type in (4, 13, 14):
# TYPE_UINT64 = 4
# TYPE_UINT32 = 13
# TYPE_ENUM = 14
type = 'p.UVarintType'
elif v.type in (17,):
# TYPE_SINT32 = 17
type = 'p.Sint32Type'
elif v.type in (18,):
# TYPE_SINT64 = 18
type = 'p.Sint64Type'
elif v.type == 9:
# TYPE_STRING = 9
type = 'p.UnicodeType'
elif v.type == 8:
# TYPE_BOOL = 8
type = 'p.BoolType'
elif v.type == 12:
# TYPE_BYTES = 12
type = 'p.BytesType'
elif v.type == 11:
# TYPE_MESSAGE = 1
type = v.message_type.name
imports.append("from .%s import %s" %
(v.message_type.name, v.message_type.name))
else:
raise Exception("Unknown field type %s for field %s" %
(v.type, fieldname))
if required:
comment = ' # required'
elif v.has_default_value:
comment = ' # default=%s' % repr(v.default_value)
else:
comment = ''
if repeated:
flags = 'p.FLAG_REPEATED'
else:
flags = '0'
out.append(" %d: ('%s', %s, %s),%s" %
(number, fieldname, type, flags, comment))
# print fieldname, number, type, repeated, comment
# print v.__dict__
# print v.CPPTYPE_STRING
# print v.LABEL_REPEATED
# print v.enum_type
# v.has_default_value, v.default_value
# v.label == 3 # repeated
# print v.number
if cls.DESCRIPTOR.fields_by_name:
out.append(" }")
if msg_id is not None:
out.append(" MESSAGE_WIRE_TYPE = %d" % msg_id)
if indexfile is not None:
if is_upy:
indexfile.write("%s = const(%d)\n" % (t, msg_id))
else:
indexfile.write("%s = %d\n" % (t, msg_id))
# Remove duplicate imports
imports = sorted(list(set(imports)))
if is_upy:
imports = ['import protobuf as p'] + imports
else:
imports = ['from __future__ import absolute_import',
'from .. import protobuf as p'] + imports
return imports + out
def process_enum(t, cls, is_upy):
out = []
if is_upy:
out += ("from micropython import const", "")
print(" * enum %s" % t)
for k, v in cls.items():
# Remove type name from the beginning of the constant
# For example "PinMatrixRequestType_Current" -> "Current"
if k.startswith("%s_" % t):
k = k.replace("%s_" % t, '')
# If type ends with *Type, but constant use type name without *Type, remove it too :)
# For example "ButtonRequestType & ButtonRequest_Other" => "Other"
if t.endswith("Type") and k.startswith("%s_" % t.replace("Type", '')):
k = k.replace("%s_" % t.replace("Type", ''), '')
if is_upy:
out.append("%s = const(%s)" % (k, v))
else:
out.append("%s = %s" % (k, v))
return out
def find_msg_type(msg_types, t):
for k, v in msg_types:
msg_name = k.replace('MessageType_', '')
if msg_name == t:
return v
def process_module(mod, genpath, indexfile, modlist, is_upy):
print("Processing module %s" % mod.__name__)
types = dict([(name, cls)
for name, cls in mod.__dict__.items() if isinstance(cls, type)])
msg_types = __import__('pb2', globals(), locals(), [
'messages_pb2', ]).messages_pb2.MessageType.items()
for t, cls in sorted(types.items()):
# Find message type for given class
msg_id = find_msg_type(msg_types, t)
out = process_type(t, cls, msg_id, indexfile, is_upy)
write_to_file(genpath, t, out)
if modlist:
modlist.write("from .%s import *\n" % t)
enums = dict([(name, cls) for name, cls in mod.__dict__.items()
if isinstance(cls, EnumTypeWrapper)])
for t, cls in enums.items():
out = process_enum(t, cls, is_upy)
write_to_file(genpath, t, out)
if modlist:
modlist.write("from . import %s\n" % t)
def write_to_file(genpath, t, out):
# Write generated sourcecode to given file
f = open(os.path.join(genpath, "%s.py" % t), 'w')
out = ["# Automatically generated by pb2py"] + out
data = "\n".join(out) + "\n"
f.write(data)
f.close()
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('modulename', type=str, help="Name of module to generate")
parser.add_argument('genpath', type=str, help="Directory for generated source code")
parser.add_argument('-i', '--indexfile', type=str, help="[optional] Generate index file of wire types")
parser.add_argument('-l', '--modlist', type=str, help="[optional] Generate list of modules")
parser.add_argument('-p', '--protopath', type=str, help="[optional] Path to search for pregenerated Google's python sources")
parser.add_argument('-m', '--micropython', action='store_true', help="Use micropython-favoured source code")
args = parser.parse_args()
if args.indexfile:
indexfile = open(args.indexfile, 'a')
else:
indexfile = None
if args.modlist:
modlist = open(args.modlist, 'a')
else:
modlist = None
if args.protopath:
sys.path.append(args.protopath)
# Dynamically load module from argv[1]
tmp = __import__('pb2', globals(), locals(), ['%s_pb2' % args.modulename])
mod = getattr(tmp, "%s_pb2" % args.modulename)
process_module(mod, args.genpath, indexfile, modlist, args.micropython)

View File

@ -1,176 +0,0 @@
#!/usr/bin/env python3
from binascii import hexlify, unhexlify
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import hmac
import hashlib
import json
import os
from urllib.parse import urlparse
from trezorlib.client import TrezorClient
from trezorlib.transport import get_transport
# Return path by BIP-32
def getPath(client):
return client.expand_path("10016'/0")
# Deriving master key
def getMasterKey(client):
bip32_path = getPath(client)
ENC_KEY = 'Activate TREZOR Password Manager?'
ENC_VALUE = unhexlify('2d650551248d792eabf628f451200d7f51cb63e46aadcbb1038aacb05e8c8aee2d650551248d792eabf628f451200d7f51cb63e46aadcbb1038aacb05e8c8aee')
key = hexlify(client.encrypt_keyvalue(
bip32_path,
ENC_KEY,
ENC_VALUE,
True,
True
))
return key
# Deriving file name and encryption key
def getFileEncKey(key):
filekey, enckey = key[:len(key) // 2], key[len(key) // 2:]
FILENAME_MESS = b'5f91add3fa1c3c76e90c90a3bd0999e2bd7833d06a483fe884ee60397aca277a'
digest = hmac.new(filekey, FILENAME_MESS, hashlib.sha256).hexdigest()
filename = digest + '.pswd'
return [filename, filekey, enckey]
# File level decryption and file reading
def decryptStorage(path, key):
cipherkey = unhexlify(key)
with open(path, 'rb') as f:
iv = f.read(12)
tag = f.read(16)
cipher = Cipher(algorithms.AES(cipherkey), modes.GCM(iv, tag), backend=default_backend())
decryptor = cipher.decryptor()
data = ''
while True:
block = f.read(16)
# data are not authenticated yet
if block:
data = data + decryptor.update(block).decode()
else:
break
# throws exception when the tag is wrong
data = data + decryptor.finalize().decode()
return json.loads(data)
def decryptEntryValue(nonce, val):
cipherkey = unhexlify(nonce)
iv = val[:12]
tag = val[12:28]
cipher = Cipher(algorithms.AES(cipherkey), modes.GCM(iv, tag), backend=default_backend())
decryptor = cipher.decryptor()
data = ''
inputData = val[28:]
while True:
block = inputData[:16]
inputData = inputData[16:]
if block:
data = data + decryptor.update(block).decode()
else:
break
# throws exception when the tag is wrong
data = data + decryptor.finalize().decode()
return json.loads(data)
# Decrypt give entry nonce
def getDecryptedNonce(client, entry):
print()
print('Waiting for TREZOR input ...')
print()
if 'item' in entry:
item = entry['item']
else:
item = entry['title']
pr = urlparse(item)
if pr.scheme and pr.netloc:
item = pr.netloc
ENC_KEY = 'Unlock %s for user %s?' % (item, entry['username'])
ENC_VALUE = entry['nonce']
decrypted_nonce = hexlify(client.decrypt_keyvalue(
getPath(client),
ENC_KEY,
unhexlify(ENC_VALUE),
False,
True
))
return decrypted_nonce
# Pretty print of list
def printEntries(entries):
print('Password entries')
print('================')
print()
for k, v in entries.items():
print('Entry id: #%s' % k)
print('-------------')
for kk, vv in v.items():
if kk in ['nonce', 'safe_note', 'password']:
continue # skip these fields
print('*', kk, ': ', vv)
print()
return
def main():
try:
transport = get_transport()
except Exception as e:
print(e)
return
client = TrezorClient(transport)
print()
print('Confirm operation on TREZOR')
print()
masterKey = getMasterKey(client)
# print('master key:', masterKey)
fileName = getFileEncKey(masterKey)[0]
# print('file name:', fileName)
path = os.path.expanduser('~/Dropbox/Apps/TREZOR Password Manager/')
# print('path to file:', path)
encKey = getFileEncKey(masterKey)[2]
# print('enckey:', encKey)
full_path = path + fileName
parsed_json = decryptStorage(full_path, encKey)
# list entries
entries = parsed_json['entries']
printEntries(entries)
entry_id = input('Select entry number to decrypt: ')
entry_id = str(entry_id)
plain_nonce = getDecryptedNonce(client, entries[entry_id])
pwdArr = entries[entry_id]['password']['data']
pwdHex = ''.join([hex(x)[2:].zfill(2) for x in pwdArr])
print('password: ', decryptEntryValue(plain_nonce, unhexlify(pwdHex)))
safeNoteArr = entries[entry_id]['safe_note']['data']
safeNoteHex = ''.join([hex(x)[2:].zfill(2) for x in safeNoteArr])
print('safe_note:', decryptEntryValue(plain_nonce, unhexlify(safeNoteHex)))
return
if __name__ == '__main__':
main()

View File

@ -1,34 +1,39 @@
#!/usr/bin/env python3
#!/usr/bin/env python
# example usage: ./rng_entropy_collector.py stm32_rng_1.dat 1048576
# note: for reading large amounts of entropy, compile a firmware
# that has DEBUG_RNG == 1 as that will disable the user button
# push confirmation
from __future__ import print_function
import binascii
import io
import sys
from trezorlib.client import TrezorClient
from trezorlib.transport import get_transport
from trezorlib.transport_hid import HidTransport
def get_client():
devices = HidTransport.enumerate() # List all connected TREZORs on USB
if len(devices) == 0: # Check whether we found any
return None
transport = HidTransport(devices[0]) # Use first connected device
return TrezorClient(transport) # Creates object for communicating with TREZOR
def main():
try:
client = TrezorClient(get_transport())
except Exception as e:
print(e)
client = get_client()
if not client:
print('No TREZOR connected')
return
arg1 = sys.argv[1] # output file
arg2 = int(sys.argv[2], 10) # total number of how many bytes of entropy to read
step = 1024 if arg2 >= 1024 else arg2 # trezor will only return 1KB at a time
arg1 = sys.argv[1] # output file
arg2 = int(sys.argv[2], 10) # total number of how many bytes of entropy to read
step = 1024 if arg2 >= 1024 else arg2 # trezor will only return 1KB at a time
with io.open(arg1, 'wb') as f:
for i in range(0, arg2, step):
for i in xrange(0, arg2, step):
entropy = client.get_entropy(step)
f.write(entropy)
client.close()
if __name__ == '__main__':
main()

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
from __future__ import print_function
import binascii
import os
import random
@ -9,23 +10,22 @@ import trezorlib.ckd_public as bip32
import hashlib
from trezorlib.client import TrezorClient
from trezorlib.client import TrezorClientDebug
from trezorlib.tx_api import TxApiTestnet
from trezorlib.tx_api import TxApiBitcoin
from trezorlib.transport import get_transport
from trezorlib.transport_hid import HidTransport
from trezorlib.transport_bridge import BridgeTransport
def hash160(x):
h = hashlib.new("ripemd160")
h.update(hashlib.sha256(x).digest())
return h.digest()
def pack_varint(x):
if (x < 0xfd):
return chr(x)
else:
return '\xfd' + chr(x & 0xff) + chr((x >> 8) & 0xff)
return '\xfd'+chr(x & 0xff) + chr((x >> 8) & 0xff)
def int_to_string(x, pad):
result = ['\x00'] * pad
@ -36,7 +36,6 @@ def int_to_string(x, pad):
x >>= 8
return ''.join(result)
def string_to_int(s):
result = 0
for c in s:
@ -45,7 +44,6 @@ def string_to_int(s):
result = (result << 8) + c
return result
class MyTxApiBitcoin(object):
def set_publickey(self, node):
@ -70,6 +68,7 @@ class MyTxApiBitcoin(object):
ser = ser + int_to_string(tx.lock_time, 4)[::-1]
return ser
def create_inputs(self, numinputs, txsize):
idx = 0
sum = 0
@ -81,16 +80,16 @@ class MyTxApiBitcoin(object):
t.lock_time = 0
i = t.inputs.add()
i.prev_hash = os.urandom(32)
i.prev_index = random.randint(0, 4)
i.prev_index = random.randint(0,4)
i.script_sig = os.urandom(100)
i.sequence = 0xffffffff
if nr % 50 == 0:
if (nr % 50 == 0):
print(nr)
myout = random.randint(0, txsize - 1)
segwit = random.randint(0, 2)
myout = random.randint(0, txsize-1)
segwit = random.randint(0,2)
for vout in range(txsize):
o = t.bin_outputs.add()
o.amount = random.randint(10000, 1000000)
o.amount = random.randint(10000,1000000)
if vout == myout:
amount = o.amount
sum = sum + o.amount
@ -101,10 +100,10 @@ class MyTxApiBitcoin(object):
pubkey = tools.hash_160(node.public_key)
else:
pubkey = os.urandom(20)
if segwit == 2:
if (segwit == 2):
# p2sh segwit
o.script_pubkey = b'\xa9\x14' + hash160(b'\x00\x14' + pubkey) + b'\x87'
elif segwit == 1:
elif (segwit == 1):
o.script_pubkey = b'\x00\x14' + pubkey
else:
o.script_pubkey = b'\x76\xa9\x14' + pubkey + b'\x88\xac'
@ -113,18 +112,16 @@ class MyTxApiBitcoin(object):
txhash = tools.Hash(txser)[::-1]
outi = self.inputs.append(
proto_types.TxInputType(
address_n=self.client.expand_path("44'/0'/0'/0/%d" % idx),
script_type=(
proto_types.SPENDWITNESS if segwit == 1 else
proto_types.SPENDP2SHWITNESS if segwit == 2 else
proto_types.SPENDADDRESS
),
address_n=self.client.expand_path("44'/0'/0'/0/"+str(idx)),
script_type = (proto_types.SPENDWITNESS if segwit == 1 else
proto_types.SPENDP2SHWITNESS if segwit == 2 else
proto_types.SPENDADDRESS),
prev_hash=txhash,
prev_index=myout,
amount=amount if segwit > 0 else 0
prev_index = myout,
amount = amount if segwit > 0 else 0
))
# print(binascii.hexlify(txser))
# print(binascii.hexlify(txhash))
#print(binascii.hexlify(txser))
#print(binascii.hexlify(txhash))
self.txs[binascii.hexlify(txhash)] = t
self.outputs = [
@ -142,35 +139,38 @@ class MyTxApiBitcoin(object):
def get_tx(self, txhash):
t = self.txs[txhash]
# print(t)
#print(t)
return t
def main():
numinputs = 100
sizeinputtx = 10
# Use first connected device
try:
transport = get_transport()
except Exception as e:
print(e)
# List all connected TREZORs on USB
devices = HidTransport.enumerate()
# Check whether we found any
if len(devices) == 0:
print('No TREZOR found')
return
print(transport)
# Use first connected device
print(devices[0][0])
# transport = BridgeTransport(devices[0][0])
transport = HidTransport(devices[0])
txstore = MyTxApiBitcoin()
# Creates object for manipulating TREZOR
client = TrezorClient(transport)
# client.set_tx_api(TxApiTestnet)
# client.set_tx_api(TxApiTestnet)
txstore.set_client(client)
txstore.set_publickey(client.get_public_node(client.expand_path("44'/0'/0'")))
print("creating input txs")
txstore.create_inputs(numinputs, sizeinputtx)
print("go")
client.set_tx_api(txstore)
# client.set_tx_api(MyTxApiBitcoin())
# client.set_tx_api(MyTxApiBitcoin())
# Print out TREZOR's features and settings
print(client.features)
@ -183,36 +183,36 @@ def main():
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',
# 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',
# ),
# 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)
@ -221,6 +221,5 @@ def main():
client.close()
if __name__ == '__main__':
main()

108
tools/tx_sign_tool.py Executable file
View File

@ -0,0 +1,108 @@
#!/usr/bin/env python2
#
# Copyright (C) 2017 mruddy
#
# 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 binascii
from trezorlib.client import TrezorClient
from trezorlib.transport_hid import HidTransport
from trezorlib.tx_api import *
from trezorlib import types_pb2 as types
def get_client():
devices = HidTransport.enumerate() # List all connected TREZORs on USB
if len(devices) == 0: # Check whether we found any
return None
transport = HidTransport(devices[0]) # Use first connected device
return TrezorClient(transport) # Creates object for communicating with TREZOR
def get_txapi():
coin = raw_input('Which coin {Bitcoin, Testnet, Litecoin}? ').strip()
if coin not in {'Bitcoin', 'Testnet', 'Litecoin'}:
return None, None
txapi_lookup = {
'Bitcoin': TxApiBitcoin,
'Testnet': TxApiTestnet,
'Litecoin': TxApiLitecoin
}
return coin, txapi_lookup[coin]
def main():
client = get_client()
if not client:
print('No TREZOR connected')
return
print()
print('Welcome to the user-unfriendly transaction signing tool')
print('USE AT YOUR OWN RISK!!!')
print()
coin, txapi = get_txapi()
if not txapi:
print('Coin not supported')
return
client.set_tx_api(txapi)
inputs = []
while True:
print()
prev_in_hash = raw_input('Previous input hash (empty to move on): ').strip()
if prev_in_hash == '':
break
prev_in_vout = raw_input('Previous input index: ').strip()
addrn = raw_input("Node path to sign with (e.g.- %s/0'/0/0): " % coin).strip()
inputs.append(types.TxInputType(
prev_hash = binascii.unhexlify(prev_in_hash),
prev_index = int(prev_in_vout, 10),
address_n = client.expand_path(addrn)
))
outputs = []
while True:
print()
out_addr = raw_input('Pay to address (empty to move on): ').strip()
if out_addr == '':
break
out_amount = raw_input('Amount (in satoshis): ').strip()
outputs.append(types.TxOutputType(
amount = int(out_amount, 10),
script_type = types.PAYTOADDRESS,
address = out_addr
))
(signatures, serialized_tx) = client.sign_tx(coin, inputs, outputs)
client.close()
print()
print('Signed Transaction:', binascii.hexlify(serialized_tx))
# note: these api's are useful for checking and sending the output of this tool:
# https://btc.blockr.io/tx/push -or- https://live.blockcypher.com/btc/pushtx/
# https://tbtc.blockr.io/tx/push -or- https://live.blockcypher.com/btc-testnet/pushtx/
# https://ltc.blockr.io/tx/push -or - https://live.blockcypher.com/ltc/pushtx/
if __name__ == '__main__':
main()

21
tox.ini
View File

@ -1,16 +1,23 @@
# To test against multiple python versions
#
# 1. Install those Python versions.
# On Ubuntu we suggest the deadsnakes PPA
# https://launchpad.net/~fkrull/+archive/ubuntu/deadsnakes
#
# 2. Install Tox (e.g. with pip)
# pip install Tox
#
# 3. Run Tox
# tox
[tox]
envlist =
py33,
py27,
py34,
py35,
py36,
[testenv]
deps =
-rrequirements.txt
pytest
mock
commands =
python -m compileall trezorlib/
python trezorctl --help
python -m pytest --pyarg trezorlib.tests.unit_tests
python -c 'import trezorlib'

1364
trezorctl

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
__version__ = '0.9.1'

View File

@ -28,25 +28,30 @@ from ecdsa.curves import SECP256k1
from ecdsa.ellipticcurve import Point, INFINITY
from . import tools
from . import messages as proto
from . import types_pb2 as proto_types
PRIME_DERIVATION_FLAG = 0x80000000
if sys.version_info < (3,):
def byteindex(data, index):
return ord(data[index])
else:
byteindex = lambda data, index: data[index]
def point_to_pubkey(point):
order = SECP256k1.order
x_str = number_to_string(point.x(), order)
y_str = number_to_string(point.y(), order)
vk = x_str + y_str
return struct.pack('B', (vk[63] & 1) + 2) + vk[0:32] # To compressed key
return struct.pack('B', (byteindex(vk, 63) & 1) + 2) + vk[0:32] # To compressed key
def sec_to_public_pair(pubkey):
"""Convert a public key in sec binary format to a public pair."""
x = string_to_number(pubkey[1:33])
sec0 = pubkey[:1]
if sec0 not in (b'\2', b'\3'):
raise ValueError("Compressed pubkey expected")
raise Exception("Compressed pubkey expected")
def public_pair_for_x(generator, x, is_even):
curve = generator.curve()
@ -59,24 +64,20 @@ def sec_to_public_pair(pubkey):
return public_pair_for_x(ecdsa.ecdsa.generator_secp256k1, x, is_even=(sec0 == b'\2'))
def is_prime(n):
return (bool)(n & PRIME_DERIVATION_FLAG)
def fingerprint(pubkey):
return string_to_number(tools.hash_160(pubkey)[:4])
def get_address(public_node, address_type):
return tools.public_key_to_bc_address(public_node.public_key, address_type)
def public_ckd(public_node, n):
if not isinstance(n, list):
raise ValueError('Parameter must be a list')
raise Exception('Parameter must be a list')
node = proto.HDNodeType()
node = proto_types.HDNodeType()
node.CopyFrom(public_node)
for i in n:
@ -84,13 +85,12 @@ def public_ckd(public_node, n):
return node
def get_subnode(node, i):
# Public Child key derivation (CKD) algorithm of BIP32
i_as_bytes = struct.pack(">L", i)
if is_prime(i):
raise ValueError("Prime derivation not supported")
raise Exception("Prime derivation not supported")
# Public derivation
data = node.public_key + i_as_bytes
@ -98,7 +98,7 @@ def get_subnode(node, i):
I64 = hmac.HMAC(key=node.chain_code, msg=data, digestmod=hashlib.sha512).digest()
I_left_as_exponent = string_to_number(I64[:32])
node_out = proto.HDNodeType()
node_out = proto_types.HDNodeType()
node_out.depth = node.depth + 1
node_out.child_num = i
node_out.chain_code = I64[32:]
@ -106,17 +106,17 @@ def get_subnode(node, i):
# BIP32 magic converts old public key to new public point
x, y = sec_to_public_pair(node.public_key)
point = I_left_as_exponent * SECP256k1.generator + Point(SECP256k1.curve, x, y, SECP256k1.order)
point = I_left_as_exponent * SECP256k1.generator + \
Point(SECP256k1.curve, x, y, SECP256k1.order)
if point == INFINITY:
raise ValueError("Point cannot be INFINITY")
raise Exception("Point cannot be INFINITY")
# Convert public point to compressed public key
node_out.public_key = point_to_pubkey(point)
return node_out
def serialize(node, version=0x0488B21E):
s = b''
s += struct.pack('>I', version)
@ -131,21 +131,20 @@ def serialize(node, version=0x0488B21E):
s += tools.Hash(s)[:4]
return tools.b58encode(s)
def deserialize(xpub):
data = tools.b58decode(xpub, None)
if tools.Hash(data[:-4])[:4] != data[-4:]:
raise ValueError("Checksum failed")
raise Exception("Checksum failed")
node = proto.HDNodeType()
node = proto_types.HDNodeType()
node.depth = struct.unpack('>B', data[4:5])[0]
node.fingerprint = struct.unpack('>I', data[5:9])[0]
node.child_num = struct.unpack('>I', data[9:13])[0]
node.chain_code = data[13:45]
key = data[45:-4]
if key[0] == 0:
if byteindex(key, 0) == 0:
node.private_key = key[1:]
else:
node.public_key = key

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +0,0 @@
from .tx_api import TxApiBitcoin, TxApiTestnet, TxApiLitecoin, TxApiZcash, TxApiDash, TxApiBcash, TxApiDecredTestnet, TxApiDogecoin, TxApiMonacoin, TxApiBitcoinGold, TxApiBitcoinPrivate
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,
'Bitcoin Private': 183,
}
coins_txapi = {
'Bitcoin': TxApiBitcoin,
'Testnet': TxApiTestnet,
'Litecoin': TxApiLitecoin,
'Dash': TxApiDash,
'Zcash': TxApiZcash,
'Bcash': TxApiBcash,
'Decred Testnet': TxApiDecredTestnet,
'Dogecoin': TxApiDogecoin,
'Monacoin': TxApiMonacoin,
'Bitcoin Gold': TxApiBitcoinGold,
'Bitcoin Private': TxApiBitcoinPrivate,
}

View File

@ -18,21 +18,18 @@
from __future__ import print_function
from . import messages as proto
from . import messages_pb2 as proto
from .transport import NotImplementedException
def pin_info(pin):
print("Device asks for PIN %s" % pin)
def button_press(yes_no):
print("User pressed", '"y"' if yes_no else '"n"')
def pprint(msg):
return "<%s> (%d bytes):\n%s" % (msg.__class__.__name__, msg.ByteSize(), msg)
class DebugLink(object):
def __init__(self, transport, pin_func=pin_info, button_func=button_press):
self.transport = transport
@ -43,13 +40,14 @@ class DebugLink(object):
def close(self):
self.transport.session_end()
self.transport.close()
def _call(self, msg, nowait=False):
print("DEBUGLINK SEND", pprint(msg))
self.transport.write(msg)
if nowait:
return
ret = self.transport.read()
ret = self.transport.read_blocking()
print("DEBUGLINK RECV", pprint(ret))
return ret
@ -128,4 +126,4 @@ class DebugLink(object):
self._call(proto.DebugLinkMemoryWrite(address=address, memory=memory, flash=flash), nowait=True)
def flash_erase(self, sector):
self._call(proto.DebugLinkFlashErase(sector=sector), nowait=True)
obj = self._call(proto.DebugLinkFlashErase(sector=sector), nowait=True)

View File

@ -1,39 +0,0 @@
# This file is part of the TREZOR project.
#
# Copyright (C) 2012-2017 Marek Palatinus <slush@satoshilabs.com>
# Copyright (C) 2012-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/>.
import warnings
from .transport import enumerate_devices, get_transport
class TrezorDevice:
'''
This class is deprecated. (There is no reason for it to exist in the first
place, it is nothing but a collection of two functions.)
Instead, please use functions from the ``trezorlib.transport`` module.
'''
@classmethod
def enumerate(cls):
warnings.warn('TrezorDevice is deprecated.', DeprecationWarning)
return enumerate_devices()
@classmethod
def find_by_path(cls, path):
warnings.warn('TrezorDevice is deprecated.', DeprecationWarning)
return get_transport(path, prefix_search=False)

View File

@ -1,89 +0,0 @@
import sys
from functools import reduce
import binascii
from . import ed25519raw
def combine_keys(pks):
P = [ed25519raw.decodepoint(pk) for pk in pks]
combine = reduce(ed25519raw.edwards, P)
return ed25519raw.encodepoint(combine)
def combine_sig(R, sigs):
S = [ed25519raw.decodeint(si) for si in sigs]
s = sum(S) % ed25519raw.l
sig = R + ed25519raw.encodeint(s)
return sig
def get_nonce(sk, data, ctr):
h = ed25519raw.H(sk)
b = ed25519raw.b
r = ed25519raw.Hint(bytes([h[i] for i in range(b >> 3, b >> 2)]) + data + binascii.unhexlify('%08x' % ctr))
R = ed25519raw.scalarmult(ed25519raw.B, r)
return r, ed25519raw.encodepoint(R)
def self_test(digest):
def to_hex(by):
return binascii.hexlify(by).decode()
N = 3
keyset = [0, 2]
digest = binascii.unhexlify(digest)
print('Digest: %s' % to_hex(digest))
sks = []
pks = []
nonces = []
commits = []
sigs = []
for i in range(0, N):
print('----- Key %d ------' % (i + 1))
seckey = (chr(0x41 + i) * 32).encode()
pubkey = ed25519raw.publickey(seckey)
print('Secret Key: %s' % to_hex(seckey))
print('Public Key: %s' % to_hex(pubkey))
sks.append(seckey)
pks.append(pubkey)
ctr = 0
r, R = get_nonce(seckey, digest, ctr)
print('Local nonce: %s' % to_hex(ed25519raw.encodeint(r)))
print('Local commit: %s' % to_hex(R))
nonces.append(r)
commits.append(R)
global_pk = combine_keys([pks[i] for i in keyset])
global_R = combine_keys([commits[i] for i in keyset])
print('-----------------')
print('Global pubkey: %s' % to_hex(global_pk))
print('Global commit: %s' % to_hex(global_R))
print('-----------------')
for i in range(0, N):
seckey = sks[i]
pubkey = pks[i]
r = nonces[i]
R = commits[i]
h = ed25519raw.H(seckey)
b = ed25519raw.b
a = 2**(b - 2) + sum(2**i * ed25519raw.bit(h, i) for i in range(3, b - 2))
S = (r + ed25519raw.Hint(global_R + global_pk + digest) * a) % ed25519raw.l
print('Local sig %d: %s' % (i + 1, to_hex(ed25519raw.encodeint(S))))
sigs.append(ed25519raw.encodeint(S))
print('-----------------')
sig = combine_sig(global_R, [sigs[i] for i in keyset])
print('Global sig: %s' % to_hex(sig))
ed25519raw.checkvalid(sig, digest, global_pk)
print('Valid Signature!')
if __name__ == '__main__':
if len(sys.argv) > 1:
self_test(digest=sys.argv[1])
else:
self_test(digest='4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b')

View File

@ -1,138 +0,0 @@
# orignal version downloaded from https://ed25519.cr.yp.to/python/ed25519.py
# modified for Python 3 by Jochen Hoenicke <hoenicke@gmail.com>
import sys
import hashlib
b = 256
q = 2 ** 255 - 19
l = 2 ** 252 + 27742317777372353535851937790883648493
def H(m):
return hashlib.sha512(m).digest()
def expmod(b, e, m):
if e < 0:
raise ValueError('negative exponent')
if e == 0:
return 1
t = expmod(b, e >> 1, m) ** 2 % m
if e & 1:
t = (t * b) % m
return t
def inv(x):
return expmod(x, q - 2, q)
d = -121665 * inv(121666)
I = expmod(2, (q - 1) >> 2, q)
def xrecover(y):
xx = (y * y - 1) * inv(d * y * y + 1)
x = expmod(xx, (q + 3) >> 3, q)
if (x * x - xx) % q != 0:
x = (x * I) % q
if x % 2 != 0:
x = q - x
return x
By = 4 * inv(5)
Bx = xrecover(By)
B = [Bx % q, By % q]
def edwards(P, Q):
x1 = P[0]
y1 = P[1]
x2 = Q[0]
y2 = Q[1]
x3 = (x1 * y2 + x2 * y1) * inv(1 + d * x1 * x2 * y1 * y2)
y3 = (y1 * y2 + x1 * x2) * inv(1 - d * x1 * x2 * y1 * y2)
return [x3 % q, y3 % q]
def scalarmult(P, e):
if e == 0:
return [0, 1]
Q = scalarmult(P, e >> 1)
Q = edwards(Q, Q)
if e & 1:
Q = edwards(Q, P)
return Q
def encodeint(y):
bits = [(y >> i) & 1 for i in range(b)]
return bytes([sum([bits[i * 8 + j] << j for j in range(8)]) for i in range(b >> 3)])
def encodepoint(P):
x = P[0]
y = P[1]
bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1]
return bytes([sum([bits[i * 8 + j] << j for j in range(8)]) for i in range(b >> 3)])
def bit(h, i):
return (h[i >> 3] >> (i & 7)) & 1
def publickey(sk):
h = H(sk)
a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
A = scalarmult(B, a)
return encodepoint(A)
def Hint(m):
h = H(m)
return sum(2 ** i * bit(h, i) for i in range(2 * b))
def signature(m, sk, pk):
h = H(sk)
a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
r = Hint(bytes([h[i] for i in range(b >> 3, b >> 2)]) + m)
R = scalarmult(B, r)
S = (r + Hint(encodepoint(R) + pk + m) * a) % l
return encodepoint(R) + encodeint(S)
def isoncurve(P):
x = P[0]
y = P[1]
return (-x * x + y * y - 1 - d * x * x * y * y) % q == 0
def decodeint(s):
return sum(2 ** i * bit(s, i) for i in range(0, b))
def decodepoint(s):
y = sum(2 ** i * bit(s, i) for i in range(0, b - 1))
x = xrecover(y)
if x & 1 != bit(s, b - 1):
x = q - x
P = [x, y]
if not isoncurve(P):
raise ValueError('decoding point that is not on curve')
return P
def checkvalid(s, m, pk):
if len(s) != b >> 2:
raise ValueError('signature length is wrong')
if len(pk) != b >> 3:
raise ValueError('public-key length is wrong')
R = decodepoint(s[0:b >> 3])
A = decodepoint(pk)
S = decodeint(s[b >> 3:b >> 2])
h = Hint(encodepoint(R) + pk + m)
if scalarmult(B, S) != edwards(R, scalarmult(A, h)):
raise ValueError('signature does not pass verification')

View File

@ -2,7 +2,6 @@
#
# Copyright (C) 2012-2016 Marek Palatinus <slush@satoshilabs.com>
# Copyright (C) 2012-2016 Pavol Rusnak <stick@satoshilabs.com>
# Copyright (C) 2016 Jochen Hoenicke <hoenicke@gmail.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
@ -17,37 +16,18 @@
# 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 . import messages
from . import protobuf
from . import messages_pb2 as proto
map_type_to_class = {}
map_class_to_type = {}
def build_map():
for msg_name in dir(messages.MessageType):
if msg_name.startswith('__'):
continue
try:
msg_class = getattr(messages, msg_name)
except AttributeError:
raise ValueError("Implementation of protobuf message '%s' is missing" % msg_name)
if msg_class.MESSAGE_WIRE_TYPE != getattr(messages.MessageType, msg_name):
raise ValueError("Inconsistent wire type and MessageType record for '%s'" % msg_class)
register_message(msg_class)
def register_message(msg_class):
if msg_class.MESSAGE_WIRE_TYPE in map_type_to_class:
raise Exception("Message for wire type %s is already registered by %s" %
(msg_class.MESSAGE_WIRE_TYPE, get_class(msg_class.MESSAGE_WIRE_TYPE)))
map_class_to_type[msg_class] = msg_class.MESSAGE_WIRE_TYPE
map_type_to_class[msg_class.MESSAGE_WIRE_TYPE] = msg_class
for msg_type, i in proto.MessageType.items():
msg_name = msg_type.replace('MessageType_', '')
msg_class = getattr(proto, msg_name)
map_type_to_class[i] = msg_class
map_class_to_type[msg_class] = i
def get_type(msg):
return map_class_to_type[msg.__class__]
@ -56,5 +36,16 @@ def get_type(msg):
def get_class(t):
return map_type_to_class[t]
def check_missing():
from google.protobuf import reflection
types = [getattr(proto, item) for item in dir(proto)
if issubclass(getattr(proto, item).__class__, reflection.GeneratedProtocolMessageType)]
missing = list(set(types) - set(map_type_to_class.values()))
if len(missing):
raise Exception("Following protobuf messages are not defined in mapping: %s" % missing)
build_map()
check_missing()

View File

@ -1,10 +0,0 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class Address(p.MessageType):
FIELDS = {
1: ('address', p.UnicodeType, 0), # required
}
MESSAGE_WIRE_TYPE = 30

View File

@ -1,10 +0,0 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class ApplyFlags(p.MessageType):
FIELDS = {
1: ('flags', p.UVarintType, 0),
}
MESSAGE_WIRE_TYPE = 28

View File

@ -1,13 +0,0 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class ApplySettings(p.MessageType):
FIELDS = {
1: ('language', p.UnicodeType, 0),
2: ('label', p.UnicodeType, 0),
3: ('use_passphrase', p.BoolType, 0),
4: ('homescreen', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 25

View File

@ -1,7 +0,0 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class BackupDevice(p.MessageType):
MESSAGE_WIRE_TYPE = 34

View File

@ -1,7 +0,0 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class ButtonAck(p.MessageType):
MESSAGE_WIRE_TYPE = 27

View File

@ -1,11 +0,0 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class ButtonRequest(p.MessageType):
FIELDS = {
1: ('code', p.UVarintType, 0),
2: ('data', p.UnicodeType, 0),
}
MESSAGE_WIRE_TYPE = 26

View File

@ -1,15 +0,0 @@
# Automatically generated by pb2py
Other = 1
FeeOverThreshold = 2
ConfirmOutput = 3
ResetDevice = 4
ConfirmWord = 5
WipeDevice = 6
ProtectCall = 7
SignTx = 8
FirmwareCheck = 9
Address = 10
PublicKey = 11
MnemonicWordCount = 12
MnemonicInput = 13
PassphraseType = 14

View File

@ -1,7 +0,0 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class Cancel(p.MessageType):
MESSAGE_WIRE_TYPE = 20

Some files were not shown because too many files have changed in this diff Show More