Compare commits

...

329 Commits

Author SHA1 Message Date
Chris Sulmone 524c308844 Add Bitcoin Private Support 2018-03-12 01:42:37 -05:00
Roman Zeyde ab5e4eee34 tests: add test_msg_getecdhsessionkey.py (#233) 2018-03-11 22:51:14 +01:00
matejcik 6b51228090 use binascii.hexlify instead of bytearray.hex (which doesn't exist in python < 3.5) 2018-03-09 14:38:04 +01:00
matejcik 5edcea9ba6
transport: fix all_transports when required modules are missing (#232)
This lets the library work without libusb or hidapi (`--disable-libusb`, `--disable-hidapi`).
2018-03-09 10:58:24 +01:00
Tomas Susanka 89eac8f157 tests/device: more Bitcoin Gold tests
including segwit and multisig
updates https://github.com/trezor/trezor-core/issues/147
2018-03-08 14:35:56 +01:00
Tomas Susanka 869af4498b tests/device: Bitcoin Gold tests 2018-03-07 16:43:01 +01:00
Pavol Rusnak 683f383e90
tests: fix test_msg_getpublickey_curve.py (don't try public derivation for ed25519) 2018-03-07 15:46:09 +01:00
matejcik d8c9c970f5 flake8: clean up imports from last commit 2018-03-07 15:28:35 +01:00
matejcik dd052d07b0 better getch() functions, fixed windows version (fixes #207) 2018-03-07 15:18:32 +01:00
matejcik c0d2af557c further cleanup of normalize_nfc usage 2018-03-06 15:50:54 +01:00
matejcik a1dba05a46 travis: do not test python2 2018-03-06 15:50:54 +01:00
matejcik 2c15a861dc replace removed iterbytes with direct iteration 2018-03-06 15:50:54 +01:00
matejcik 5422c40451 start dropping py2 compatibility code 2018-03-06 15:50:54 +01:00
matejcik e1e419485f
Merge pull request #226 from matejcik/refactor-transport-nicediff
prefix search for `trezorctl -p`
2018-03-06 15:50:05 +01:00
matejcik 9f2583f893 webusb: check if a device is functional when enumerating
this fixes issue #223 on Windows, where a device would be returned in two copies, only one of which works
2018-03-06 13:32:51 +01:00
matejcik f75b90d260 Merge branch 'upstream' into refactor-transport-nicediff 2018-03-05 19:56:47 +01:00
matejcik 2752e6d046 bump version to 0.9.1 2018-03-05 19:14:04 +01:00
matejcik 43c71ca8e0 add changelog 2018-03-05 19:11:45 +01:00
matejcik f63b34dbea setup.py: add markers specifying Python 3 only compatibility 2018-03-05 19:11:16 +01:00
matejcik cd9bd06163 prettyprint: fix flake8 complaints 2018-03-05 19:10:54 +01:00
matejcik 52c2319822 omit Features message from debug dumps 2018-03-05 18:57:40 +01:00
matejcik db3767f7ef tweak prettyprint for some known elements 2018-03-05 18:57:40 +01:00
matejcik 07ceb9aacc pretty printing protobufs 2018-03-05 18:57:40 +01:00
Jan Pochyla 95603b85dd tests: enable segwit sign&verify tests for t2 2018-03-05 17:45:17 +01:00
Jan Pochyla 4979c296b7 tests: enable test_apply_settings, test_apply_settings_passphrase for t2 2018-03-05 17:45:17 +01:00
Pavol Rusnak db827bfe01
tests: update test_msg_getpublickey.py, add test_msg_getpublickey_curve.py 2018-03-05 17:37:56 +01:00
matejcik dc8eec1656 trezorlib/transport: for get_transport(None), raise exception from None if no trezor is found,
because the IndexError should not be part of the traceback
2018-03-05 17:31:11 +01:00
matejcik 967d479a19 update tools to use the new transport API
also drop some python2 compatibility things
2018-03-05 17:30:44 +01:00
matejcik ff80ca1b82 restore device.py as a deprecated compatibility wrapper 2018-03-05 16:18:32 +01:00
Jan Pochyla 0e065237c9 tests: disable TestBip32Speed::test_cache on t2 2018-03-05 15:49:04 +01:00
matejcik 2f1c15b588 trezorlib/transport: make flake8 happy 2018-03-05 14:25:37 +01:00
Jochen Hoenicke 8a62d12217 Update ethereum_sign_tx to python3 (#227) 2018-03-05 13:09:57 +01:00
matejcik 513e6aae08 better way for test suite to search for the right device,
that also respects TREZOR_PATH
2018-03-02 18:25:39 +01:00
matejcik 2a706a751a update trezorctl to use prefix search correctly
first, try exact path
second, try prefix search
last, fail :) with reporting used path (for people like me who forget to unset TREZOR_PATH
2018-03-02 18:24:05 +01:00
matejcik 6519657808 trezorlib/transport: smarter handling of prefix search
For UDP transport, it's useful to be able to specify a path that should be tried directly,
without enumerating first.
2018-03-02 18:22:33 +01:00
matejcik 55641dd8b5 make flake8 happy (#225) 2018-03-02 16:47:29 +01:00
matejcik d2913c20bd trezorlib/transport: move TrezorDevice functionality to transport and make it better ^_^ 2018-03-02 16:46:10 +01:00
matejcik 49790d7bfe install the new trasport subpackage 2018-03-02 16:43:41 +01:00
Tomas Susanka b24550c72f tests: ethereum sign/verify is skipped (#224) 2018-03-02 16:37:34 +01:00
matejcik bc8120230a trezorlib/transport: make changes to support being a separate submodule, move common functions to superclass 2018-03-02 15:44:24 +01:00
matejcik 473ea19570 trezorlib/transport: rename files as separate step (to make diffs nicer) 2018-03-02 15:35:56 +01:00
slush e37e9bfebd Fixing Origin header for Bridge 2.0.7 2018-03-01 10:33:47 +01:00
Pavol Rusnak fd41db8a59
trezorctl: don't always require internal entropy in reset_device 2018-03-01 05:07:27 +01:00
Pavol Rusnak b1a76e4a68
tests: revert basic tests 2018-03-01 00:07:27 +01:00
Pavol Rusnak 7841bbefbe
client: implement PassphraseStateRequest handling 2018-02-28 23:13:17 +01:00
Pavol Rusnak ce9da28a3d
update protobuf 2018-02-28 23:13:17 +01:00
matejcik 8404bef6e3 support TREZOR_PATH environment variable for selecting default path (#221) 2018-02-28 18:04:33 +01:00
matejcik 2d3e890c6b setup: add missing requirement for rlp (#220) 2018-02-28 18:03:27 +01:00
Pavol Rusnak 0d680944a4
txcache: add new tx 2018-02-28 00:56:55 +01:00
Pavol Rusnak 4cfcd93d48
transport: force V1 protocol for T2 for now 2018-02-27 18:30:09 +01:00
Tomas Susanka 6e1eb8e664 tests/device: ethereum erc20 tokens test 2018-02-27 17:41:18 +01:00
Jan Pochyla 6c8ccc0680 tests/device_tests: for t2, enable bch & multisig, disable load & reset 2018-02-27 16:29:59 +01:00
Pavol Rusnak a352f41f07
protob: update PassphraseAck 2018-02-27 15:41:59 +01:00
Tomas Susanka a8d34430a5 tests/device/bcash: fix attack amount test 2018-02-27 15:10:36 +01:00
Tomas Susanka aec8f04f68 tests/device: assert exception type and message 2018-02-27 15:08:00 +01:00
Pavol Rusnak 03b3ef10f4
update protobuf 2018-02-27 14:24:23 +01:00
Pavol Rusnak 8dffdd8f85
tests: fix test_basic (don't compare state in Features), add test_basic_state 2018-02-27 14:24:23 +01:00
Tomas Susanka 55da3d9a9a tests/device/signtx: assert exception type and message 2018-02-27 11:50:10 +01:00
Tomas Susanka 617ccc21d9 tests: deepcopy is required when debug_processor is invoked 2018-02-23 16:03:43 +01:00
Tomas Susanka cbd3751bdb tests/device: allow multiple output changes (treat second as a normal output)
based upon e716f7e84e
2018-02-23 13:14:10 +01:00
Tomas Susanka 0e2d5c8155 tests/device: change on main chain IS allowed
based upon e716f7e84e
2018-02-23 13:10:55 +01:00
Tomas Susanka 1e8f2d1e72 tests/device: change on main chain not allowed 2018-02-23 13:09:49 +01:00
Tomas Susanka d6f0c54d3e tests: CallException relaced with AssertionException in response validation
Generic exceptions are evil. When throwing a CallException in the
request check you can't distinguish in the tests if it is an Exception
that occured in during the execution (that's CallException) or during
some tests (that used to be CallException as well).
2018-02-22 16:51:34 +01:00
Tomas Susanka bc036bc857 tests/device: two output changes yield error
this test should fail on T1 after e716f7e84ecdb4732ad97b56e78d7407ec0b321e
2018-02-22 14:20:53 +01:00
Pavol Rusnak cb47dbd284
chmod +x tools/mem_flashblock.py 2018-02-21 16:48:40 +01:00
Pavol Rusnak a0c85bed12
tools: add pwd_reader from SLIP-0016 2018-02-21 16:46:18 +01:00
Jan Pochyla 2c91a668aa tests: fix udp debuglink 2018-02-21 15:31:32 +01:00
Pavol Rusnak bccd61cb23
client: implement PassphraseRequest.on_device handling 2018-02-14 19:11:21 +01:00
Pavol Rusnak e256281a99
rebuild protobuf to add {Initialize,Features}.state 2018-02-09 17:46:54 +01:00
Tomas Susanka 30e5c80956 Multisig tests enabled for t2 (#216) 2018-02-08 15:36:26 +01:00
脇山P 4cbf74f789 Support monacoin (#215) 2018-02-08 14:09:40 +01:00
Pavol Rusnak 1c3b05a44b
bump version to 0.9.0 2018-02-06 22:12:17 +01:00
Pavol Rusnak ba8bb99097
fix flake8 error 2018-02-06 21:39:02 +01:00
slush 489b1eb074 Removing unused transport_pipe.py 2018-02-06 21:30:13 +01:00
slush e141a6f5d1 Added get_path() to transports 2018-02-06 21:10:30 +01:00
slush f00a689087 Remove unnecessary logging 2018-02-06 20:52:45 +01:00
slush 6a22cf481c Fix handling of find_by_path in transports. 2018-02-06 18:40:07 +01:00
Pavol Rusnak d45cba1ddb
messages: add fw_vendor_keys to Features message 2018-02-06 16:25:30 +01:00
Pavol Rusnak 272ad30898
messages: add new fields to Features 2018-02-06 16:07:41 +01:00
Pavol Rusnak e9705c8208
webusb: don't create usb context on WebUsbTransport import 2018-02-04 12:05:03 +01:00
Roman Zeyde 1b6873eb20 Allow compatibility with Python 2 (#214)
Following https://github.com/romanz/trezor-agent/issues/195
2018-02-04 11:44:20 +01:00
Yash 9ec331ed46 Add in import for TransportException in transport_udp.py (#212) 2018-02-04 11:42:58 +01:00
slush 9ebe1b5204 Remove debug print 2018-02-02 20:18:30 +01:00
slush 81db1da68f Fix handling of bytes/str in transport paths 2018-02-02 20:17:10 +01:00
Karel Bilek 29ad78d57b Ignoring non-webusb devices 2018-02-02 19:30:11 +01:00
slush ac09c8d7de Make all transport prefixes lowercase. 2018-02-02 19:20:03 +01:00
slush 03a11450c1 Adding bridge transport to TrezorDevice, using as default transport 2018-02-02 19:17:48 +01:00
slush 562a19c812 Make examples working for all available transports. 2018-02-02 18:29:52 +01:00
slush a4cdae39af Introducing TrezorDevice, removing concept of transports from trezorctl 2018-02-02 18:29:20 +01:00
slush fae11f2996 Use python3 for setup 2018-02-02 16:36:29 +01:00
slush b32b59cc51 Use python3 in README 2018-02-02 16:34:30 +01:00
Pavol Rusnak 1a046b524c
setup: add dependency for libusb1 2018-02-02 01:22:16 +01:00
Pavol Rusnak 646338c414
small nits of last commit 2018-02-01 10:31:47 +01:00
Karel Bilek 759316e96f Add webusb to transports
V2 protocol with debug link is not tested.
2018-02-01 10:25:01 +01:00
Pavol Rusnak 7b844f0379
add Sint64 to protobuf 2018-01-30 15:04:24 +01:00
slush 11fd72890c trezorctl: Do not display PASSPHRASE on screen. 2018-01-29 18:09:42 +01:00
slush ab42e93718 trezorctl: Allow entering passphrase by environment variable PASSPHRASE. 2018-01-29 18:04:48 +01:00
Pavol Rusnak 5b3e992521
transport: update to new bridge API 2018-01-29 17:48:08 +01:00
slush 87cd375b35 Fixing string conversion in encrypt_keyvalue/decrypt_keyvalue. 2018-01-26 05:09:08 +01:00
Anton Kolesnyk a8cd90c3ad Add varying url to broadcast tx, depending on the api 2018-01-15 00:25:05 +01:00
Anton Kolesnyk 28c9820b3d Fixes for BlockCypher API and Dogecoin. 2018-01-14 16:14:39 +01:00
Pavol Rusnak c78c548752
protobuf: delete old messages first 2018-01-12 13:10:36 +01:00
Pavol Rusnak 694bc7ac11
protobuf: don't generate storage protobuf 2018-01-12 13:06:43 +01:00
Pavol Rusnak 8f6b2449be
sort imports in pb2py 2018-01-12 12:58:39 +01:00
Pavol Rusnak 78d2c07d34
regenerate pb messages 2018-01-12 12:54:06 +01:00
Pavol Rusnak 47cfa178e4
tests: fix test_msg_ethereum_signtx.py 2018-01-11 23:06:47 +01:00
Tomas Susanka 0c517c1565 tests/device: code style typos 2018-01-11 22:54:08 +01:00
Tomas Susanka 4bbf5880ce tests/device: ethereum sign tx with expected checks 2018-01-11 22:54:08 +01:00
Pavol Rusnak e618402429
trezorctl: firmware_update -e erases firmware (first 32K; rendering it unusable) 2018-01-09 12:12:32 +01:00
Pavol Rusnak 0c5eac2f39
skip None and empty ([]) fields in proto messages 2018-01-07 18:07:13 +01:00
Pavol Rusnak f587135b8d
fix last commit (also skip print statement) 2018-01-04 16:55:27 +01:00
Tomas Susanka 4e01971e4c client: expected field check fix 2018-01-04 16:48:16 +01:00
slush c71f234a8b Added deprecation warning for Python2
Removed dependency to google's protobuf in bridge transport
Fixed PinRequest handling
2017-12-29 19:19:18 +01:00
Pavol Rusnak 6b31ac9753
fix typo 2017-12-27 01:44:26 +01:00
Anton Kolesnyk 956d5e7149 Add sign_tx support for Dogecoin 2017-12-27 01:39:06 +01:00
mcudev 4962207703
sign_tx: add rbf opt-in enable, add locktime, add tx version 2017-12-27 01:28:59 +01:00
Saleem Rashid 79da872316 trezorctl: Guess script type from BIP-32 in sign_tx
Also add change output to sign_tx
2017-12-27 01:16:46 +01:00
Saleem Rashid 881015ae5f trezorctl: Ask for input script type in sign_tx 2017-12-27 01:16:46 +01:00
Saleem Rashid 35db3c5efb trezorctl: Add ChoiceType to replace click.Choice 2017-12-27 01:16:46 +01:00
Pavol Rusnak 888b6f9171
fix file flags 2017-12-24 22:37:24 +01:00
Martin Skoviera dac97ed5b6 Fixed enums in WordRequestType 2017-12-24 22:37:01 +01:00
Pavol Rusnak d94b68fd30
fix flake8 warning 2017-12-23 22:13:09 +01:00
Pavol Rusnak 70e6d13c23
device tests: simplify, drop unittest dependency 2017-12-23 22:03:24 +01:00
Pavol Rusnak 1881b0e6fd
device tests: re-enable ethereum tests for T2 again 2017-12-23 13:51:18 +01:00
Roman Zeyde 31c4836073 udp: fix __str__ method and allow simple enumeration 2017-12-23 13:43:51 +01:00
Roman Zeyde f8a277dfba transport_bridge: fix messages' module import 2017-12-23 13:43:51 +01:00
Roman Zeyde 8689440d90 client: fix PinMatrixRequestType enum usage 2017-12-23 13:43:51 +01:00
Saleem Rashid b3ef649f64 device_tests: Add test_decred_multisig_change 2017-12-23 13:42:59 +01:00
Saleem Rashid 2df19127fd device_tests: Add test_decred_send_change 2017-12-23 13:42:59 +01:00
Saleem Rashid 0926ab9bc8 device_tests: Clean up test_decred_send 2017-12-23 13:42:59 +01:00
Pavol Rusnak 41b75c5655
device_tests: use skip_t1 and skip_t2 markers 2017-12-19 19:24:40 +01:00
Saleem Rashid 2c00526d23 client: Remove DEFAULT_CURVE
The device should choose the default curve based on the coin or message.
2017-12-19 18:47:18 +01:00
Pavol Rusnak c550e5c703
revert bytes/str change in tools.py 2017-12-19 16:10:37 +01:00
Pavol Rusnak 8a37c28ed6
fix typos in test names 2017-12-19 15:54:07 +01:00
Saleem Rashid f20fd0d8cf trezorctl: Remove broken default in address_n click.prompt 2017-12-19 15:48:17 +01:00
Saleem Rashid 36c479c2c2 trezorctl: Change InputScriptType to OutputScriptType 2017-12-19 15:48:17 +01:00
Saleem Rashid fcad6d0e28 tox: Run trezorlib.tests.unit_tests 2017-12-19 13:16:22 +01:00
Saleem Rashid 2996138341 protobuf: Call _fill_missing in __init__ 2017-12-19 13:16:22 +01:00
Saleem Rashid 1c8f03968c tests: Move to trezorlib.tests 2017-12-19 13:16:22 +01:00
Saleem Rashid 57ad0fe729 unit_tests: Fix tx_api.cache_dir 2017-12-19 13:16:22 +01:00
Saleem Rashid 34a8b90067 device_tests: Fix tx_api.cache_dir 2017-12-19 13:16:22 +01:00
Pavol Rusnak 753e91dff0
protobuf: encode to utf-8 bytestream 2017-12-18 22:44:54 +01:00
Pavol Rusnak 094d0b6ffb
revert ckd_public.py removal of bytes/string handling 2017-12-18 22:40:11 +01:00
Pavol Rusnak c1b1bedb8c
ed25519: remove py2/py3 handling in ed25519 funcs as well 2017-12-18 22:34:15 +01:00
Pavol Rusnak a9291e89c5
no need to use byteindex/iterbytes anymore 2017-12-18 22:26:55 +01:00
Saleem Rashid f2a52400c3 device_tests: Round time in test_backoff
Fix random failures on emulator due to minimal communication overhead
2017-12-18 21:19:22 +01:00
Saleem Rashid fd32c3aa84 device_tests: Fix test_protect_call 2017-12-18 21:19:22 +01:00
Saleem Rashid 90c49e3386 setup: Use packages instead of py_modules
Fixes #176
2017-12-18 19:30:17 +01:00
Saleem Rashid feec0a572c device_tests: Add TestMsgSigntxDecred 2017-12-18 16:34:43 +01:00
Saleem Rashid 9229f8b80a coins: Add Decred Testnet 2017-12-18 16:34:43 +01:00
Saleem Rashid d446e56375 trezorctl: Fix sign_tx default BIP-32 path 2017-12-17 22:12:57 +01:00
Saleem Rashid 496bfc74fd trezorctl: Refactor sign_tx to use click.prompt
Fixes UnboundLocalError on Python 3
2017-12-17 22:12:57 +01:00
Saleem Rashid c48724eca6 client: Fix string encoding for Python 2 2017-12-17 22:10:40 +01:00
Pavol Rusnak 60329f0b65
fix typo 2017-12-17 03:23:37 +01:00
slush 653ed4a67b Added registering custom protobuf messages by application. 2017-12-17 03:17:37 +01:00
slush da335049d7 Removed excessive logging 2017-12-17 02:58:35 +01:00
slush 3fedf44bf5 Bump version to 0.9.0a 2017-12-17 02:31:43 +01:00
slush a27217811b Rework from Google's protobuf to pure-python protobuf implementation 2017-12-17 02:19:16 +01:00
Saleem Rashid 1193b0ee85 transport_udp: Support TREZOR_TRANSPORT_V1 2017-12-16 22:47:19 +01:00
Pavol Rusnak de95c44ad1
trezorctl: cleanup set_homescreen call 2017-12-16 21:29:52 +01:00
Pavol Rusnak b42fc6fb1f
trezorctl: set homescreen for T2 2017-12-13 02:37:59 +01:00
Jochen Hoenicke 6186822f14 Added tool to flash a sector
... and fixed some python3 stuff.
2017-12-12 21:44:30 +01:00
Jonathan Cross 63038e6210 Improve / simplify documentation 2017-12-07 21:57:23 +01:00
Pavol Rusnak 45835733bc
more cleanup 2017-12-02 22:06:44 +01:00
Pavol Rusnak 8b9cba832c
cleanup last commit 2017-12-02 22:02:39 +01:00
slush f5c1587396 Version moved from version.py to __init__.py 2017-12-02 18:48:44 +01:00
slush 59ef832424 Add 'trezorctl version' to track version of installed package 2017-12-02 18:31:57 +01:00
Jonathan Cross 29e4c6a05e Transaction signing example and explanation 2017-12-02 17:36:13 +01:00
Pavol Rusnak 116c3c0575
trezorctl: use click.echo instead of stderr.write 2017-12-02 15:34:06 +01:00
Jonathan Cross ab3d17b3df Better handling of user input for --coin in sign_tx 2017-12-02 15:27:40 +01:00
slush 8c00cda95a Ignore pydev IDE files 2017-12-02 15:21:37 +01:00
Pavol Rusnak ae663ffe0c
client: don't accept non-numerical values for PIN 2017-11-28 19:59:06 +01:00
Jochen Hoenicke 69067c9280 Parse json floats as string
With python-2.7 the float values are sometimes rounded to unacceptable
levels, e.g. stripping the last two digits for values over 100k BTC.
This change parses floats as strings to avoid rounding.

Refactored get_url out of fetch_json to make it easier to add
new tx_api with a different url scheme.
2017-11-28 19:55:31 +01:00
Jonathan Cross ffeb94f792 USAGE: Verbose args & adding native Bech32 segwit 2017-11-24 07:57:44 +01:00
Jochen Hoenicke 2a5888b380 Added missing cached tx for msg_signtx 2017-11-17 21:04:03 +01:00
Jochen Hoenicke 99af1639a6 Updated multisig change test
Use BIP-45 paths with correct change addresses.
This fixes #154.
2017-11-17 21:04:03 +01:00
Pavol Rusnak 225160d7bd
device_tests: op_return now requires confirmation by user 2017-11-15 15:42:28 +01:00
Pavol Rusnak 5730f00ff8
device_tests: disable signtx_zcash 2017-11-15 14:35:34 +01:00
Nicola Larosa 62541cc55f Fix encoding error in trezorlib.client.ProtocolMixin.load_device_by_mnemonic (#153) 2017-11-15 13:33:21 +01:00
Nicola Larosa 5d2d621055 Fix error when using trezorctl to connect to the trezor-core emulator. (#152)
* Fix error when using trezorctl to connect to the trezor-core emulator.

* Restore the ability to specify the host without the port
2017-11-13 22:15:09 +01:00
Pavol Rusnak 0d9ee4376d
use Mnemonic.normalize_string where possible 2017-11-13 22:13:32 +01:00
Jonathan Cross 9e068ce903 Adding xpub example (#149) 2017-11-13 21:54:33 +01:00
Jonathan Cross fa6624129c Adding note: trezorctl is installed on debian / tails (#148) 2017-11-09 17:01:05 +01:00
Jonathan Cross a6562ccc15 README.rst : Adding Mac requirements and simplifying Linux (#147) 2017-11-09 15:53:52 +01:00
Jochen Hoenicke 91a541e862 Expect confirm button for unusual change address (#138)
Changed two tests to different (existing) txs with correct change
address, changed the other tests to expect an additional button
confirmation.
2017-11-08 22:09:28 +01:00
Pavol Rusnak b9b11fa265
style: fix flake8 error 2017-11-08 21:25:15 +01:00
Jonathan Cross 04bb0069c0 USAGE: Adding more examples 2017-11-08 21:22:44 +01:00
Jonathan Cross 972459281b Fixing Bitcoin usage & adding note this is non-SegWit 2017-11-07 15:00:02 +01:00
Pavol Rusnak a5fc76d8c9
don't use generic Exception, but rather specific subclass 2017-11-06 11:10:23 +01:00
Pavol Rusnak 1ab602423c
requirements: add pyblake2 2017-11-06 11:10:23 +01:00
Jochen Hoenicke ebb9540ac2 Added unit tests for sign/verifymessage bech32 2017-11-03 18:32:45 +01:00
Jochen Hoenicke 6d74c6c9df Updated segwit_native tests to bech32 and python3 2017-11-03 18:32:45 +01:00
Jan Pochyla cc9ddcbc12 device_tests: wrap tests in a session 2017-10-31 17:04:27 +01:00
Jan Pochyla fcd793e6e4 transport_hid: force V1 transport with env var 2017-10-31 13:51:13 +01:00
Pavol Rusnak 6a777788ab
trezorctl: use better detection if raw_input replacement is needed 2017-10-25 21:33:33 +02:00
Pavol Rusnak cef2ba0129
flake: silence some new warnings 2017-10-24 01:00:08 +02:00
Pavol Rusnak 23d75bfc10
trezorctl: sign_tx command based on tx_sign_tool by mruddy 2017-10-24 00:50:01 +02:00
Pavol Rusnak 54426761c6
fix transport_hid for python2 2017-10-23 17:28:24 +02:00
Emanuel Haupt fb648a241e Add instructions for FreeBSD users
I've created a FreeBSD port:

537ae1b42c

Add instructions for FreeBSD users.
2017-10-12 10:47:41 +02:00
Pavol Rusnak 0f722c1991
tests: add device test for CoSi 2017-10-04 00:51:32 +02:00
Pavol Rusnak 5057e022c0
trezorlib: move ed25519cosi and ed25519raw from trezor-core 2017-10-04 00:38:53 +02:00
Pavol Rusnak a71c33d123
trezorctl+client: add support for CoSi commit/sign 2017-10-03 18:43:28 +02:00
bithobbes 54df69a407 client.py: matrix recovery info: mention backspace
It is not obvious that it is possible to go back by backspace. Knowing this makes data entry much more comfortable.
2017-09-13 17:54:42 +09:00
Jan Pochyla 66ba2c20c0 transport: add TransportException
Fixes #134
2017-09-05 17:16:04 +02:00
Jan Pochyla ac0184413d transport_hid: refcount for hid handle 2017-09-05 17:15:19 +02:00
Pavol Rusnak dffa93bee3
fix last commit (newline eof) 2017-09-04 17:40:15 +02:00
Jan Pochyla b60ab51f9b transport_hid: more strict interface detection 2017-09-04 17:30:07 +02:00
Pavol Rusnak 2a3f613242
hid: fix product_ids for v2 2017-09-04 14:31:15 +02:00
Jan Pochyla 52f96b3792 transport_hid: raise on missing debuglink 2017-09-04 13:44:19 +02:00
Jan Pochyla 259a61878b tools: update to new transport api 2017-09-04 13:36:31 +02:00
Jan Pochyla 8202971109 rework lazy connecting in client 2017-09-04 13:36:08 +02:00
Jan Pochyla 051f8e961b protocol: 2/3 compat fixes 2017-09-04 11:44:33 +02:00
Jan Pochyla 3d3c2a29d0 client: add missing close method
close() is implemented in some of the mixins to dispose of any resources.
2017-09-04 11:30:34 +02:00
Jan Pochyla c805284a86 tests: fix client init 2017-09-04 11:22:41 +02:00
mruddy 02437d166a fix v1 protocol 2017-09-03 19:34:01 +02:00
Pavol Rusnak c20cea6389
setup: add missing files 2017-09-03 19:15:34 +02:00
Saleem Rashid 29a145154f device_tests: Add test_msg_nem_getaddress 2017-09-03 19:05:29 +02:00
Saleem Rashid eb1d66e27f trezorlib: Add nem_get_address 2017-09-03 19:05:29 +02:00
Saleem Rashid 4f5d9c4323 device_tests: Add test_msg_nem_signtx 2017-09-03 19:05:29 +02:00
Saleem Rashid 58b56bead6 trezorctl: Add nem_sign_tx 2017-09-03 19:05:29 +02:00
Saleem Rashid 991d367416 trezorlib: Update Protocol Buffers 2017-09-03 19:05:29 +02:00
Jan Pochyla 888a1edafa fix style 2017-08-24 14:41:31 +02:00
Jan Pochyla bc42eb68d6 transports: refactor, split protocol code 2017-08-24 14:29:27 +02:00
Jochen Hoenicke 7019438a49 Make -n/--address parameter required.
If you really want to have the master public key, you can still just
give the empty string.
* Changed -address to --address everywhere.
* Added help for this parameter.
* Added required flag.
2017-08-20 16:33:49 +02:00
Pavol Rusnak a4a7aa8d85
trezorctl: fix hexlify calls on python3 2017-08-17 21:18:49 +02:00
Jan Pochyla e3c7146a80 tests: add multisig marker 2017-08-15 17:33:11 +02:00
Jochen Hoenicke 5cfa973a78 Fixed white-spaces 2017-08-13 20:49:23 +02:00
Jochen Hoenicke 600bcba69c Updated unit tests for BitcoinCash 2017-08-13 20:49:23 +02:00
Jochen Hoenicke 29f29626fc Added multisig test 2017-08-13 20:49:23 +02:00
Pavol Rusnak ff157264a2
trezorctl: print message name to output 2017-08-09 00:52:52 +02:00
Pavol Rusnak 8a663f7ec3
tests: rename BCC to BCH, Bitcoin Cash to Bcash 2017-07-31 15:29:11 +02:00
Pavol Rusnak 32fa08f38b
tests: remove estimate_tx_size 2017-07-31 14:00:26 +02:00
Pavol Rusnak b6dc73ce9c
tests: fix bytes/str problem in test_msg_ethereum_signtx 2017-07-31 13:56:25 +02:00
Saleem Rashid b469519e26 client: fix matrix recovery, use named enums, use isdigit(), ignore broken E721 test 2017-07-31 13:35:31 +02:00
Pavol Rusnak 81d5170c10
tests: start rewriting device tests to pytest 2017-07-28 18:07:20 +02:00
Pavol Rusnak 8a1d211ee9
tests: fix flake8 errors 2017-07-28 16:08:33 +02:00
Jan Pochyla 6df01fbfa3 TransportV2: adapt to recent changes
- remove checksum
- add sequence numbers
2017-07-28 15:58:20 +02:00
Pavol Rusnak 5309baf48e
tests: reduce unhexlify reuse 2017-07-28 15:24:18 +02:00
Pavol Rusnak 11bfacc9b3
tests: bytes are not necessary in unhexlify 2017-07-28 15:17:19 +02:00
Jochen Hoenicke 9917d9ebfc
New unit tests for signing (bitcoin cash) 2017-07-27 21:51:00 +02:00
Pavol Rusnak efe36b3a2f
unit_tests: rewrite from unittest to pytest 2017-07-26 14:48:20 +02:00
Pavol Rusnak 11b686a9f2
tests: add tests for Segwit SignMessage/VerifyMessage 2017-07-25 19:29:28 +02:00
Pavol Rusnak 8133317172
add SignMessage.script_type 2017-07-24 16:11:38 +02:00
Pavol Rusnak de6402e95e
implement set_flags (aka ApplyFlags) 2017-07-17 18:37:15 +02:00
Pavol Rusnak 36985519b5
tests: add test for ethereum sign/verify message 2017-07-17 14:40:35 +02:00
Pavol Rusnak afdd27c551
trezorctl: fix set_homescreen for python3 2017-07-16 15:03:01 +02:00
Pavol Rusnak d865c0ea31
trezorctl: load_device -s now loads SLIP-0014 mnemonic, --skip-checksum renamed to --ignore-checksum 2017-07-16 14:54:50 +02:00
Pavol Rusnak 23ab43d612
ethereum: implement EthereumSignMessage/EthereumVerifyMessage 2017-07-12 18:35:54 +02:00
Pavol Rusnak 20aebed394
trezorctl: seems that click.Choice is not friends with ints 2017-07-12 15:45:16 +02:00
Pavol Rusnak ee5f53d4be
fix ethereum_get_address for python3 2017-07-11 19:37:25 +02:00
Pavol Rusnak c7a2c72a75
simplify SelfTest.payload 2017-07-10 19:08:16 +02:00
Pavol Rusnak 5ffc700f0c
use isinstance to detect whether result is protobuf message 2017-07-10 18:20:32 +02:00
Pavol Rusnak 1727b9a9b6
add SelfTest.payload 2017-07-10 17:40:13 +02:00
Pavol Rusnak f73fc33439
drop internal use of protobuf_json, use json_format provided by google.protobuf 2017-07-10 15:36:44 +02:00
Pavol Rusnak 2d643031ac
change dependency to protobuf>=3.0.0 2017-07-10 14:41:56 +02:00
Pavol Rusnak e6acf90f2b
tests: add test for broken BackupDevice workflow 2017-07-05 13:03:06 +02:00
Pavol Rusnak 5a89a15935
trezorctl: use more idiomatic approach using resultcallback 2017-07-05 12:55:39 +02:00
Pavol Rusnak b335d30b8d
use click in trezorctl 2017-07-05 12:55:38 +02:00
Pavol Rusnak 0ee1667c6f
trezorctl: cleanup 2017-07-05 12:55:38 +02:00
Pavol Rusnak d33e9a178b
bump version to 0.8.0a0 2017-07-05 12:55:37 +02:00
Pavol Rusnak f18ec19aeb
bump version 2017-07-05 12:52:56 +02:00
Pavol Rusnak bcf54dbe94
trezorctl/client: add self_test 2017-07-03 18:49:03 +02:00
Pavol Rusnak b9293d6bcb
regenerate protobuf 2017-07-03 18:42:21 +02:00
Pavol Rusnak 9a709832a9
tests: unit test for ResetDevice_skipbackup (and subsequent BackupDevice) 2017-06-28 18:04:19 +02:00
Pavol Rusnak cbce29163b
tests: add test for RecoveryDevice.dry_run 2017-06-28 16:39:51 +02:00
Pavol Rusnak e9dbfc757c
add usage; add newlines to some tests 2017-06-28 13:42:44 +02:00
Pavol Rusnak 7f0f73d1c6
tests: fix style in tools/signtest.py 2017-06-25 18:10:05 +02:00
Pavol Rusnak 33f274d145
style: use flake8 2017-06-23 21:52:53 +02:00
Pavol Rusnak 71996c1e43
update protobuf, update tox.ini, prepare for BackupDevice 2017-06-23 19:26:35 +02:00
Pavol Rusnak c51089803d
trezorctl: add newline to failure print 2017-06-23 17:06:22 +02:00
Roman Zeyde 0d76936174 Allow testing recovery with an initialized device 2017-06-23 00:08:59 +02:00
Pavol Rusnak f50d547ce4
regenerate protobuf, added RecoveryDevice.dry_run 2017-06-22 12:38:57 +02:00
Pavol Rusnak f880a09ae7
add protoc version and trezor-common revision to autogenerated files 2017-06-21 13:44:26 +02:00
Pavol Rusnak e435920d6a
support v2 firmware in trezorctl 2017-06-20 17:19:37 +02:00
Pavol Rusnak 609b8d4a4a
fix stderr.write usage 2017-06-20 16:36:40 +02:00
Pavol Rusnak 564e6590c2
use FirmwareErase.length field 2017-06-20 16:32:54 +02:00
Pavol Rusnak c1fae7d19f
bump version 2017-06-19 00:00:50 +02:00
Pavol Rusnak e7a56899c6
more python3 compatibility 2017-06-19 00:00:26 +02:00
Pavol Rusnak bf1c580d85
bump version 2017-06-18 23:41:15 +02:00
Pavol Rusnak 65985b30f3
bump requirements for protobuf to 3.1.0 2017-06-18 23:19:15 +02:00
Pavol Rusnak de2f9e7c14
protob: regenerate, fix using old failure codes 2017-06-18 23:18:23 +02:00
Roman Zeyde e33f4d7612 Add 'requests' dependency 2017-06-15 16:51:28 +02:00
Pavol Rusnak 348db51775
add trezorctl to readme 2017-06-14 18:23:14 +02:00
Pavol Rusnak 4874f117f5
use travis-tox 2017-06-13 15:43:14 +02:00
Roman Zeyde 2e85aa6587 Add a test for running 'compileall' over trezorlib package 2017-06-13 15:16:12 +02:00
Roman Zeyde a2db5a57f2 Fix client.py and protobuf_json.py for Python 3 support 2017-06-13 15:16:12 +02:00
Pavol Rusnak 9f90179bef
update travis notification url 2017-06-12 14:38:07 +02:00
Pavol Rusnak e39021d7fd
add wire_tiny, wire_bootloader options 2017-05-29 14:07:48 +02:00
Pavol Rusnak 9311a45e97
refactor txhash ids 2017-05-15 14:14:45 +02:00
Pavol Rusnak a96fdd86be
fix test_msg_signtx.test_fee_too_high 2017-05-15 12:09:48 +02:00
Pavol Rusnak f484f69f88
move native segwit tests to segwit_native.py files (they fail now) 2017-05-13 00:59:39 +02:00
Pavol Rusnak 318355a896
update protobuf 2017-05-12 22:47:46 +02:00
Pavol Rusnak 5ffc2a1d7f
tests: split xprv loading into separate test 2017-05-08 22:15:24 +02:00
Pavol Rusnak 530954acdc
update test_msg_getentropy.py 2017-05-08 22:10:47 +02:00
Pavol Rusnak 6f092f323b
add new txcache files 2017-05-07 00:47:23 +02:00
Pavol Rusnak dbe95dc3cc
add setuptools requirement to travis.yml 2017-05-07 00:46:47 +02:00
Pavol Rusnak 91ffca595b
rework multisig tests to specify external outputs via address, not multisig structure 2017-05-06 19:58:21 +02:00
Pavol Rusnak 5fc76709b3
revert part of last commit 2017-05-04 18:10:17 +02:00
Jochen Hoenicke f9cd5da505
Segwit: Fixed Unittests and new tests.
- Wrong BIP-32 path in change address leads to ButtonRequest.
- Add tests for change address with segwit and correct bip32 path.
2017-05-03 19:16:47 +02:00
Jochen Hoenicke 1bee5f4de7
Segwit: Unit tests for getaddress 2017-05-03 19:16:46 +02:00
Jochen Hoenicke 0b4d56842e
Segwit: Added unit tests for multisig 2017-05-03 19:16:46 +02:00
Pavol Rusnak 2363db721a
fix stderr.write to use bytes 2017-05-03 17:50:37 +02:00
Pavol Rusnak 91222b4687
tests/config: fix usb hid logic 2017-05-03 17:35:49 +02:00
Pavol Rusnak 5860207e68
Revert "test_msg_signidentity: ed25519 pubkey starts with 1 not 0"
This reverts commit 30b13dba58.
2017-05-03 17:27:02 +02:00
Pavol Rusnak 4cba191997
fix logic in device tests config 2017-04-25 17:04:59 +02:00
Pavol Rusnak 58faa02263
print info on skipping transports 2017-04-25 16:55:59 +02:00
Pavol Rusnak e9958d115f
travis: add python 3.6 build 2017-04-25 16:50:56 +02:00
Pavol Rusnak 0840117033
update pipe_exists function 2017-04-25 16:47:30 +02:00
Pavol Rusnak 4999056678
make device tests work without hid 2017-04-25 16:37:27 +02:00
Pavol Rusnak 9c744a1c3d
fix test_msg_signtx.test_fee_too_high (make fee higher) 2017-04-25 15:50:00 +02:00
Peter Banik 44b51af1d8 -c <coin> CLI argument (#110) 2017-04-24 16:31:18 +02:00
Peter Banik a99e29a05f
Added coin_name argument to get_public_node and trezorctl (#108) 2017-04-21 19:23:59 +02:00
Peter Banik ca1d3e5f39 Added Decred to coin list (#109) 2017-04-21 19:14:04 +02:00
Tomas Rojas 637d45b196 Configure Bridge only once per process (#107)
This saves a lot of time on requests retrieving config_signed.bin and
reconfiguring the bridge for every device enumeration or transport
instantiation.
2017-04-20 13:16:15 +02:00
Pavol Rusnak 3cb4118850
bump version 2017-04-19 14:20:48 +02:00
Pavol Rusnak 504db8283b
add version and lock_time attributes to sign_tx function 2017-04-19 14:19:26 +02:00
Pavol Rusnak 30b13dba58
test_msg_signidentity: ed25519 pubkey starts with 1 not 0 2017-04-16 22:05:55 +02:00
Pavol Rusnak bee9af1f90
use v1 transport for T2 bootloader (for now) 2017-04-12 17:54:34 +02:00
Pavol Rusnak 29348f4098
add new firmware update method, update protobuf 2017-04-12 14:11:42 +02:00
Pavol Rusnak dccc1b08ed
update requirement for hidapi to 0.7.99.post20 2017-03-06 12:02:49 +01:00
Pavol Rusnak 4758eb7b07
add more coins to coin expansion 2017-03-04 16:20:38 +01:00
mruddy 3ccc412de4
add tool to aid in rng testing and evaluation (#104) 2017-02-28 19:11:28 +01:00
Pavol Rusnak 5e1526d286
refactor tx_sign_tool.py 2017-02-26 17:11:31 +01:00
mruddy 72ab93bd87 add a tx signing tool that handles bitcoin, testnet, and litecoin 2017-02-26 16:44:49 +01:00
mruddy b29331ca40
fix UnboundLocalError cache_file referenced before assignment (#102) 2017-02-26 16:38:56 +01:00
Pavol Rusnak 127d76a913
enable/disable passphrase protection via trezorctl 2017-02-23 11:56:54 +01:00
mruddy 3e8122ba28 bump version to 0.7.11 (#100) 2017-02-22 15:39:07 +01:00
Pavol Rusnak 18bd3e6197
update mnemonic requirement 2017-02-22 15:07:58 +01:00
mruddy 71d0c483f8 add tools support for reading bootloader from debug link enabled device (#99) 2017-02-20 14:36:00 +01:00
294 changed files with 11317 additions and 10066 deletions

32
.flake8 Normal file
View File

@ -0,0 +1,32 @@
[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,13 +1,16 @@
.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,16 +15,28 @@ addons:
- libusb-1.0-0-dev
python:
- "2.7"
- "3.3"
- "3.4"
- "3.5"
before_install:
- pip install setuptools --upgrade
- "3.6"
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

10
CHANGELOG.md Normal file
View File

@ -0,0 +1,10 @@
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,66 +7,55 @@ python-trezor
.. image:: https://badges.gitter.im/trezor/community.svg
:target: https://gitter.im/trezor/community
Python library for communicating with TREZOR Hardware Wallet
Python library and commandline client for communicating with TREZOR Hardware Wallet
See https://trezor.io for more information
Install
-------
(Run with sudo if not running in superuser mode under Linux)
Linux requirements:
.. code::
pip install trezor
sudo apt-get install python3-dev cython3 libusb-1.0-0-dev libudev-dev git
On Linux you might need to run these commands first:
Linux & Mac Python requirements:
.. code::
sudo apt-get install python-dev cython libusb-1.0-0-dev libudev-dev git
sudo pip install setuptools
sudo -H pip3 install setuptools
sudo -H pip3 install -r requirements.txt
sudo -H pip3 install trezor
Example
-------
On FreeBSD you can install the packages:
also found in ``tools/helloworld.py``
.. code::
.. code:: python
pkg install security/py-trezor
#!/usr/bin/env python
or build via ports:
from trezorlib.client import TrezorClient
from trezorlib.transport_hid import HidTransport
.. code::
def main():
# List all connected TREZORs on USB
devices = HidTransport.enumerate()
cd /usr/ports/security/py-trezor
make install clean
# Check whether we found any
if len(devices) == 0:
print('No TREZOR found')
return
# Use first connected device
transport = HidTransport(devices[0])
Commandline client (trezorctl)
---------------------------
# Creates object for manipulating TREZOR
client = TrezorClient(transport)
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.
# Print out TREZOR's features and settings
print(client.features)
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/>`_).
# Get the first address of first BIP44 account
# (should be the same address as shown in wallet.trezor.io)
bip32_path = client.expand_path("44'/0'/0'/0/0")
address = client.get_address('Bitcoin', bip32_path)
print('Bitcoin address:', address)
client.close()
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.
if __name__ == '__main__':
main()
PIN Entering
------------

View File

@ -1,11 +0,0 @@
#!/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

120
docs/EXAMPLES.rst Normal file
View File

@ -0,0 +1,120 @@
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.

63
docs/OPTIONS.rst Normal file
View File

@ -0,0 +1,63 @@
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...

5
docs/README.rst Normal file
View File

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

BIN
docs/sign_tx-coinb.in.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/sign_tx-electrum1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/sign_tx-electrum2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/sign_tx-trezor.io.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,4 +1,8 @@
ecdsa>=0.9
protobuf>=2.6.1
mnemonic>=0.16
hidapi>=0.7.99
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,40 +1,47 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from setuptools import setup
install_requires = ['ecdsa>=0.9', 'protobuf>=2.6.1', 'mnemonic>=0.16', 'setuptools>=19.0']
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',
]
import sys
if '--disable-hidapi' in sys.argv:
sys.argv.remove('--disable-hidapi')
else:
install_requires.append('hidapi>=0.7.99')
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='0.7.10',
version=VERSION,
author='TREZOR',
author_email='info@trezor.io',
description='Python library for communicating with TREZOR Hardware Wallet',
url='https://github.com/trezor/python-trezor',
py_modules=[
'trezorlib.ckd_public',
'trezorlib.client',
'trezorlib.debuglink',
'trezorlib.mapping',
'trezorlib.messages_pb2',
'trezorlib.protobuf_json',
'trezorlib.qt.pinmatrix',
'trezorlib.tools',
packages=[
'trezorlib',
'trezorlib.transport',
'trezorlib.transport_bridge',
'trezorlib.transport_hid',
'trezorlib.transport_pipe',
'trezorlib.transport_udp',
'trezorlib.tx_api',
'trezorlib.types_pb2',
'trezorlib.messages',
'trezorlib.qt',
'trezorlib.tests.device_tests',
'trezorlib.tests.unit_tests',
],
scripts = ['trezorctl'],
scripts=['trezorctl'],
install_requires=install_requires,
python_requires='>=3.3',
include_package_data=True,
zip_safe=False,
classifiers=[
@ -42,5 +49,6 @@ setup(
'Operating System :: POSIX :: Linux',
'Operating System :: Microsoft :: Windows',
'Operating System :: MacOS :: MacOS X',
'Programming Language :: Python :: 3 :: Only',
],
)

View File

@ -1,63 +0,0 @@
# 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

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

View File

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

View File

@ -1,92 +0,0 @@
# 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

@ -1,52 +0,0 @@
# 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

@ -1,239 +0,0 @@
# 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

@ -1,62 +0,0 @@
# 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

@ -1,67 +0,0 @@
# 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

@ -1,46 +0,0 @@
# 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

@ -1,91 +0,0 @@
# 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'000fac2a491e0f5b871dc48288a4cae551bac5cb0ed19df0764d6e721ec5fade18')
self.assertEqual(binascii.hexlify(sig.signature), b'00f05e5085e666429de397c70a081932654369619c0bd2a6579ea6c1ef2af112ef79998d6c862a16b932d44b1ac1b83c8cbcd0fbda228274fde9e0d0ca6e9cb709')
if __name__ == '__main__':
unittest.main()

View File

@ -1,615 +0,0 @@
# 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], 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

@ -1,165 +0,0 @@
# 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

@ -1,72 +0,0 @@
# 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

@ -1,242 +0,0 @@
# 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

@ -1,373 +0,0 @@
# 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

@ -1,109 +0,0 @@
# 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

@ -1,215 +0,0 @@
# 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

@ -1,39 +0,0 @@
# 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

@ -1,45 +0,0 @@
# 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()

32
tools/build_protobuf Executable file
View File

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

View File

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

48
tools/mem_flashblock.py Executable file
View File

@ -0,0 +1,48 @@
#!/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,15 +1,21 @@
#!/usr/bin/env python
from __future__ import print_function
#!/usr/bin/env python3
from trezorlib.debuglink import DebugLink
from trezorlib.client import TrezorClient, TrezorDebugClient
from trezorlib.transport_hid import HidTransport
import binascii
from trezorlib.client import TrezorClient
from trezorlib.transport import enumerate_devices
import sys
# usage examples
# read entire bootloader: ./mem_read.py 8000000 8000
# read initial stack pointer: ./mem_read.py 8000000 4
# an entire bootloader can be later disassembled with:
# arm-none-eabi-objdump -D -b binary -m arm -M force-thumb memory.dat
# 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 connected TREZORs on USB
devices = HidTransport.enumerate()
# 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:
@ -17,19 +23,27 @@ def main():
return
# Use first connected device
transport = HidTransport(devices[0])
transport = devices[0]
debug_transport = devices[0].find_debug()
# Creates object for manipulating TREZOR
debug_transport = HidTransport(devices[0], **{'debug_link': True})
client = TrezorClient(transport)
debug = DebugLink(debug_transport)
mem = debug.memory_read(int(sys.argv[1],16), int(sys.argv[2],16))
f = open('memory.dat', 'w')
f.write(mem)
arg1 = int(sys.argv[1], 16)
arg2 = int(sys.argv[2], 16)
step = 0x400 if arg2 >= 0x400 else arg2
f = open('memory.dat', 'wb')
for addr in range(arg1, arg1 + arg2, step):
mem = debug.memory_read(addr, step)
f.write(mem)
f.close()
client.close()
if __name__ == '__main__':
main()

View File

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

View File

@ -1,5 +1,4 @@
#!/usr/bin/env python
from __future__ import print_function
#!/usr/bin/env python3
import binascii
import hashlib
import mnemonic
@ -16,11 +15,6 @@ __doc__ = '''
without an internet connection).
'''
# Python2 vs Python3
try:
input = raw_input
except NameError:
pass
def generate_entropy(strength, internal_entropy, external_entropy):
'''
@ -28,28 +22,29 @@ 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 Exception("Invalid strength")
raise ValueError("Invalid strength")
if not internal_entropy:
raise Exception("Internal entropy is not provided")
raise ValueError("Internal entropy is not provided")
if len(internal_entropy) < 32:
raise Exception("Internal entropy too short")
raise ValueError("Internal entropy too short")
if not external_entropy:
raise Exception("External entropy is not provided")
raise ValueError("External entropy is not provided")
if len(external_entropy) < 32:
raise Exception("External entropy too short")
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 Exception("Entropy length mismatch")
raise ValueError("Entropy length mismatch")
return entropy_stripped
def main():
print(__doc__)
@ -72,5 +67,6 @@ def main():
print("Generated mnemonic is:", words)
if __name__ == '__main__':
main()

216
tools/pb2py Executable file
View File

@ -0,0 +1,216 @@
#!/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)

176
tools/pwd_reader.py Executable file
View File

@ -0,0 +1,176 @@
#!/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()

34
tools/rng_entropy_collector.py Executable file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
# 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 io
import sys
from trezorlib.client import TrezorClient
from trezorlib.transport import get_transport
def main():
try:
client = TrezorClient(get_transport())
except Exception as e:
print(e)
return
arg1 = sys.argv[1] # output file
arg2 = int(sys.argv[2], 10) # total number of how many bytes of entropy to read
step = 1024 if arg2 >= 1024 else arg2 # trezor will only return 1KB at a time
with io.open(arg1, 'wb') as f:
for i in range(0, arg2, step):
entropy = client.get_entropy(step)
f.write(entropy)
client.close()
if __name__ == '__main__':
main()

View File

@ -1,5 +1,4 @@
#!/usr/bin/env python
from __future__ import print_function
import binascii
import os
import random
@ -10,22 +9,23 @@ 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_hid import HidTransport
from trezorlib.transport_bridge import BridgeTransport
from trezorlib.transport import get_transport
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,6 +36,7 @@ def int_to_string(x, pad):
x >>= 8
return ''.join(result)
def string_to_int(s):
result = 0
for c in s:
@ -44,6 +45,7 @@ def string_to_int(s):
result = (result << 8) + c
return result
class MyTxApiBitcoin(object):
def set_publickey(self, node):
@ -68,7 +70,6 @@ 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
@ -80,16 +81,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
@ -100,10 +101,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'
@ -112,16 +113,18 @@ 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/"+str(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/%d" % 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 = [
@ -139,38 +142,35 @@ class MyTxApiBitcoin(object):
def get_tx(self, txhash):
t = self.txs[txhash]
#print(t)
# print(t)
return t
def main():
numinputs = 100
sizeinputtx = 10
# List all connected TREZORs on USB
devices = HidTransport.enumerate()
# Check whether we found any
if len(devices) == 0:
print('No TREZOR found')
# Use first connected device
try:
transport = get_transport()
except Exception as e:
print(e)
return
# Use first connected device
print(devices[0][0])
# transport = BridgeTransport(devices[0][0])
transport = HidTransport(devices[0])
print(transport)
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,5 +221,6 @@ def main():
client.close()
if __name__ == '__main__':
main()

21
tox.ini
View File

@ -1,23 +1,16 @@
# 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 =
py27,
py33,
py34,
py35,
py36,
[testenv]
deps =
-rrequirements.txt
pytest
mock
commands =
python -c 'import trezorlib'
python -m compileall trezorlib/
python trezorctl --help
python -m pytest --pyarg trezorlib.tests.unit_tests

1356
trezorctl

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -28,30 +28,25 @@ from ecdsa.curves import SECP256k1
from ecdsa.ellipticcurve import Point, INFINITY
from . import tools
from . import types_pb2 as proto_types
from . import messages as proto
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', (byteindex(vk, 63) & 1) + 2) + vk[0:32] # To compressed key
return struct.pack('B', (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 Exception("Compressed pubkey expected")
raise ValueError("Compressed pubkey expected")
def public_pair_for_x(generator, x, is_even):
curve = generator.curve()
@ -64,20 +59,24 @@ 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 Exception('Parameter must be a list')
raise ValueError('Parameter must be a list')
node = proto_types.HDNodeType()
node = proto.HDNodeType()
node.CopyFrom(public_node)
for i in n:
@ -85,12 +84,13 @@ 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 Exception("Prime derivation not supported")
raise ValueError("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_types.HDNodeType()
node_out = proto.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 Exception("Point cannot be INFINITY")
raise ValueError("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,20 +131,21 @@ 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 Exception("Checksum failed")
raise ValueError("Checksum failed")
node = proto_types.HDNodeType()
node = proto.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 byteindex(key, 0) == 0:
if key[0] == 0:
node.private_key = key[1:]
else:
node.public_key = key

File diff suppressed because it is too large Load Diff

33
trezorlib/coins.py Normal file
View File

@ -0,0 +1,33 @@
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,18 +18,21 @@
from __future__ import print_function
from . import messages_pb2 as proto
from .transport import NotImplementedException
from . import messages as proto
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
@ -40,14 +43,13 @@ 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_blocking()
ret = self.transport.read()
print("DEBUGLINK RECV", pprint(ret))
return ret
@ -126,4 +128,4 @@ class DebugLink(object):
self._call(proto.DebugLinkMemoryWrite(address=address, memory=memory, flash=flash), nowait=True)
def flash_erase(self, sector):
obj = self._call(proto.DebugLinkFlashErase(sector=sector), nowait=True)
self._call(proto.DebugLinkFlashErase(sector=sector), nowait=True)

39
trezorlib/device.py Normal file
View File

@ -0,0 +1,39 @@
# 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)

89
trezorlib/ed25519cosi.py Normal file
View File

@ -0,0 +1,89 @@
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')

138
trezorlib/ed25519raw.py Normal file
View File

@ -0,0 +1,138 @@
# 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,6 +2,7 @@
#
# 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
@ -16,18 +17,37 @@
# 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_pb2 as proto
from . import messages
from . import protobuf
map_type_to_class = {}
map_class_to_type = {}
def build_map():
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 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
def get_type(msg):
return map_class_to_type[msg.__class__]
@ -36,16 +56,5 @@ 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

@ -0,0 +1,10 @@
# 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

@ -0,0 +1,10 @@
# 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

@ -0,0 +1,13 @@
# 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

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

View File

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

View File

@ -0,0 +1,11 @@
# 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

@ -0,0 +1,15 @@
# 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

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

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class ChangePin(p.MessageType):
FIELDS = {
1: ('remove', p.BoolType, 0),
}
MESSAGE_WIRE_TYPE = 4

View File

@ -0,0 +1,16 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class CipherKeyValue(p.MessageType):
FIELDS = {
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
2: ('key', p.UnicodeType, 0),
3: ('value', p.BytesType, 0),
4: ('encrypt', p.BoolType, 0),
5: ('ask_on_encrypt', p.BoolType, 0),
6: ('ask_on_decrypt', p.BoolType, 0),
7: ('iv', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 23

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class CipheredKeyValue(p.MessageType):
FIELDS = {
1: ('value', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 48

View File

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

View File

@ -0,0 +1,19 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class CoinType(p.MessageType):
FIELDS = {
1: ('coin_name', p.UnicodeType, 0),
2: ('coin_shortcut', p.UnicodeType, 0),
3: ('address_type', p.UVarintType, 0), # default=0
4: ('maxfee_kb', p.UVarintType, 0),
5: ('address_type_p2sh', p.UVarintType, 0), # default=5
8: ('signed_message_header', p.UnicodeType, 0),
9: ('xpub_magic', p.UVarintType, 0), # default=76067358
10: ('xprv_magic', p.UVarintType, 0), # default=76066276
11: ('segwit', p.BoolType, 0),
12: ('forkid', p.UVarintType, 0),
13: ('force_bip143', p.BoolType, 0),
}

View File

@ -0,0 +1,11 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class CosiCommit(p.MessageType):
FIELDS = {
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
2: ('data', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 71

View File

@ -0,0 +1,11 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class CosiCommitment(p.MessageType):
FIELDS = {
1: ('commitment', p.BytesType, 0),
2: ('pubkey', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 72

View File

@ -0,0 +1,13 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class CosiSign(p.MessageType):
FIELDS = {
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
2: ('data', p.BytesType, 0),
3: ('global_commitment', p.BytesType, 0),
4: ('global_pubkey', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 73

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class CosiSignature(p.MessageType):
FIELDS = {
1: ('signature', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 74

View File

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

View File

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

View File

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

View File

@ -0,0 +1,12 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class DebugLinkLog(p.MessageType):
FIELDS = {
1: ('level', p.UVarintType, 0),
2: ('bucket', p.UnicodeType, 0),
3: ('text', p.UnicodeType, 0),
}
MESSAGE_WIRE_TYPE = 104

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class DebugLinkMemory(p.MessageType):
FIELDS = {
1: ('memory', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 111

View File

@ -0,0 +1,11 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class DebugLinkMemoryRead(p.MessageType):
FIELDS = {
1: ('address', p.UVarintType, 0),
2: ('length', p.UVarintType, 0),
}
MESSAGE_WIRE_TYPE = 110

View File

@ -0,0 +1,12 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class DebugLinkMemoryWrite(p.MessageType):
FIELDS = {
1: ('address', p.UVarintType, 0),
2: ('memory', p.BytesType, 0),
3: ('flash', p.BoolType, 0),
}
MESSAGE_WIRE_TYPE = 112

View File

@ -0,0 +1,20 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
from .HDNodeType import HDNodeType
class DebugLinkState(p.MessageType):
FIELDS = {
1: ('layout', p.BytesType, 0),
2: ('pin', p.UnicodeType, 0),
3: ('matrix', p.UnicodeType, 0),
4: ('mnemonic', p.UnicodeType, 0),
5: ('node', HDNodeType, 0),
6: ('passphrase_protection', p.BoolType, 0),
7: ('reset_word', p.UnicodeType, 0),
8: ('reset_entropy', p.BytesType, 0),
9: ('recovery_fake_word', p.UnicodeType, 0),
10: ('recovery_word_pos', p.UVarintType, 0),
}
MESSAGE_WIRE_TYPE = 102

View File

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

View File

@ -0,0 +1,13 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class DecryptMessage(p.MessageType):
FIELDS = {
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
2: ('nonce', p.BytesType, 0),
3: ('message', p.BytesType, 0),
4: ('hmac', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 51

View File

@ -0,0 +1,11 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class DecryptedMessage(p.MessageType):
FIELDS = {
1: ('message', p.BytesType, 0),
2: ('address', p.UnicodeType, 0),
}
MESSAGE_WIRE_TYPE = 52

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class ECDHSessionKey(p.MessageType):
FIELDS = {
1: ('session_key', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 62

View File

@ -0,0 +1,14 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class EncryptMessage(p.MessageType):
FIELDS = {
1: ('pubkey', p.BytesType, 0),
2: ('message', p.BytesType, 0),
3: ('display_only', p.BoolType, 0),
4: ('address_n', p.UVarintType, p.FLAG_REPEATED),
5: ('coin_name', p.UnicodeType, 0), # default='Bitcoin'
}
MESSAGE_WIRE_TYPE = 49

View File

@ -0,0 +1,12 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class EncryptedMessage(p.MessageType):
FIELDS = {
1: ('nonce', p.BytesType, 0),
2: ('message', p.BytesType, 0),
3: ('hmac', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 50

View File

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

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class EntropyAck(p.MessageType):
FIELDS = {
1: ('entropy', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 36

View File

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

View File

@ -0,0 +1,12 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class EstimateTxSize(p.MessageType):
FIELDS = {
1: ('outputs_count', p.UVarintType, 0), # required
2: ('inputs_count', p.UVarintType, 0), # required
3: ('coin_name', p.UnicodeType, 0), # default='Bitcoin'
}
MESSAGE_WIRE_TYPE = 43

View File

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

View File

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

View File

@ -0,0 +1,11 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class EthereumMessageSignature(p.MessageType):
FIELDS = {
1: ('address', p.BytesType, 0),
2: ('signature', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 66

View File

@ -0,0 +1,11 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class EthereumSignMessage(p.MessageType):
FIELDS = {
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
2: ('message', p.BytesType, 0), # required
}
MESSAGE_WIRE_TYPE = 64

View File

@ -0,0 +1,18 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class EthereumSignTx(p.MessageType):
FIELDS = {
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
2: ('nonce', p.BytesType, 0),
3: ('gas_price', p.BytesType, 0),
4: ('gas_limit', p.BytesType, 0),
5: ('to', p.BytesType, 0),
6: ('value', p.BytesType, 0),
7: ('data_initial_chunk', p.BytesType, 0),
8: ('data_length', p.UVarintType, 0),
9: ('chain_id', p.UVarintType, 0),
}
MESSAGE_WIRE_TYPE = 58

View File

@ -0,0 +1,10 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class EthereumTxAck(p.MessageType):
FIELDS = {
1: ('data_chunk', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 60

View File

@ -0,0 +1,13 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class EthereumTxRequest(p.MessageType):
FIELDS = {
1: ('data_length', p.UVarintType, 0),
2: ('signature_v', p.UVarintType, 0),
3: ('signature_r', p.BytesType, 0),
4: ('signature_s', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 59

View File

@ -0,0 +1,12 @@
# Automatically generated by pb2py
from __future__ import absolute_import
from .. import protobuf as p
class EthereumVerifyMessage(p.MessageType):
FIELDS = {
1: ('address', p.BytesType, 0),
2: ('signature', p.BytesType, 0),
3: ('message', p.BytesType, 0),
}
MESSAGE_WIRE_TYPE = 65

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