Compare commits
276 Commits
Author | SHA1 | Date |
---|---|---|
Chris Sulmone | 524c308844 | |
Roman Zeyde | ab5e4eee34 | |
matejcik | 6b51228090 | |
matejcik | 5edcea9ba6 | |
Tomas Susanka | 89eac8f157 | |
Tomas Susanka | 869af4498b | |
Pavol Rusnak | 683f383e90 | |
matejcik | d8c9c970f5 | |
matejcik | dd052d07b0 | |
matejcik | c0d2af557c | |
matejcik | a1dba05a46 | |
matejcik | 2c15a861dc | |
matejcik | 5422c40451 | |
matejcik | e1e419485f | |
matejcik | 9f2583f893 | |
matejcik | f75b90d260 | |
matejcik | 2752e6d046 | |
matejcik | 43c71ca8e0 | |
matejcik | f63b34dbea | |
matejcik | cd9bd06163 | |
matejcik | 52c2319822 | |
matejcik | db3767f7ef | |
matejcik | 07ceb9aacc | |
Jan Pochyla | 95603b85dd | |
Jan Pochyla | 4979c296b7 | |
Pavol Rusnak | db827bfe01 | |
matejcik | dc8eec1656 | |
matejcik | 967d479a19 | |
matejcik | ff80ca1b82 | |
Jan Pochyla | 0e065237c9 | |
matejcik | 2f1c15b588 | |
Jochen Hoenicke | 8a62d12217 | |
matejcik | 513e6aae08 | |
matejcik | 2a706a751a | |
matejcik | 6519657808 | |
matejcik | 55641dd8b5 | |
matejcik | d2913c20bd | |
matejcik | 49790d7bfe | |
Tomas Susanka | b24550c72f | |
matejcik | bc8120230a | |
matejcik | 473ea19570 | |
slush | e37e9bfebd | |
Pavol Rusnak | fd41db8a59 | |
Pavol Rusnak | b1a76e4a68 | |
Pavol Rusnak | 7841bbefbe | |
Pavol Rusnak | ce9da28a3d | |
matejcik | 8404bef6e3 | |
matejcik | 2d3e890c6b | |
Pavol Rusnak | 0d680944a4 | |
Pavol Rusnak | 4cfcd93d48 | |
Tomas Susanka | 6e1eb8e664 | |
Jan Pochyla | 6c8ccc0680 | |
Pavol Rusnak | a352f41f07 | |
Tomas Susanka | a8d34430a5 | |
Tomas Susanka | aec8f04f68 | |
Pavol Rusnak | 03b3ef10f4 | |
Pavol Rusnak | 8dffdd8f85 | |
Tomas Susanka | 55da3d9a9a | |
Tomas Susanka | 617ccc21d9 | |
Tomas Susanka | cbd3751bdb | |
Tomas Susanka | 0e2d5c8155 | |
Tomas Susanka | 1e8f2d1e72 | |
Tomas Susanka | d6f0c54d3e | |
Tomas Susanka | bc036bc857 | |
Pavol Rusnak | cb47dbd284 | |
Pavol Rusnak | a0c85bed12 | |
Jan Pochyla | 2c91a668aa | |
Pavol Rusnak | bccd61cb23 | |
Pavol Rusnak | e256281a99 | |
Tomas Susanka | 30e5c80956 | |
脇山P | 4cbf74f789 | |
Pavol Rusnak | 1c3b05a44b | |
Pavol Rusnak | ba8bb99097 | |
slush | 489b1eb074 | |
slush | e141a6f5d1 | |
slush | f00a689087 | |
slush | 6a22cf481c | |
Pavol Rusnak | d45cba1ddb | |
Pavol Rusnak | 272ad30898 | |
Pavol Rusnak | e9705c8208 | |
Roman Zeyde | 1b6873eb20 | |
Yash | 9ec331ed46 | |
slush | 9ebe1b5204 | |
slush | 81db1da68f | |
Karel Bilek | 29ad78d57b | |
slush | ac09c8d7de | |
slush | 03a11450c1 | |
slush | 562a19c812 | |
slush | a4cdae39af | |
slush | fae11f2996 | |
slush | b32b59cc51 | |
Pavol Rusnak | 1a046b524c | |
Pavol Rusnak | 646338c414 | |
Karel Bilek | 759316e96f | |
Pavol Rusnak | 7b844f0379 | |
slush | 11fd72890c | |
slush | ab42e93718 | |
Pavol Rusnak | 5b3e992521 | |
slush | 87cd375b35 | |
Anton Kolesnyk | a8cd90c3ad | |
Anton Kolesnyk | 28c9820b3d | |
Pavol Rusnak | c78c548752 | |
Pavol Rusnak | 694bc7ac11 | |
Pavol Rusnak | 8f6b2449be | |
Pavol Rusnak | 78d2c07d34 | |
Pavol Rusnak | 47cfa178e4 | |
Tomas Susanka | 0c517c1565 | |
Tomas Susanka | 4bbf5880ce | |
Pavol Rusnak | e618402429 | |
Pavol Rusnak | 0c5eac2f39 | |
Pavol Rusnak | f587135b8d | |
Tomas Susanka | 4e01971e4c | |
slush | c71f234a8b | |
Pavol Rusnak | 6b31ac9753 | |
Anton Kolesnyk | 956d5e7149 | |
mcudev | 4962207703 | |
Saleem Rashid | 79da872316 | |
Saleem Rashid | 881015ae5f | |
Saleem Rashid | 35db3c5efb | |
Pavol Rusnak | 888b6f9171 | |
Martin Skoviera | dac97ed5b6 | |
Pavol Rusnak | d94b68fd30 | |
Pavol Rusnak | 70e6d13c23 | |
Pavol Rusnak | 1881b0e6fd | |
Roman Zeyde | 31c4836073 | |
Roman Zeyde | f8a277dfba | |
Roman Zeyde | 8689440d90 | |
Saleem Rashid | b3ef649f64 | |
Saleem Rashid | 2df19127fd | |
Saleem Rashid | 0926ab9bc8 | |
Pavol Rusnak | 41b75c5655 | |
Saleem Rashid | 2c00526d23 | |
Pavol Rusnak | c550e5c703 | |
Pavol Rusnak | 8a37c28ed6 | |
Saleem Rashid | f20fd0d8cf | |
Saleem Rashid | 36c479c2c2 | |
Saleem Rashid | fcad6d0e28 | |
Saleem Rashid | 2996138341 | |
Saleem Rashid | 1c8f03968c | |
Saleem Rashid | 57ad0fe729 | |
Saleem Rashid | 34a8b90067 | |
Pavol Rusnak | 753e91dff0 | |
Pavol Rusnak | 094d0b6ffb | |
Pavol Rusnak | c1b1bedb8c | |
Pavol Rusnak | a9291e89c5 | |
Saleem Rashid | f2a52400c3 | |
Saleem Rashid | fd32c3aa84 | |
Saleem Rashid | 90c49e3386 | |
Saleem Rashid | feec0a572c | |
Saleem Rashid | 9229f8b80a | |
Saleem Rashid | d446e56375 | |
Saleem Rashid | 496bfc74fd | |
Saleem Rashid | c48724eca6 | |
Pavol Rusnak | 60329f0b65 | |
slush | 653ed4a67b | |
slush | da335049d7 | |
slush | 3fedf44bf5 | |
slush | a27217811b | |
Saleem Rashid | 1193b0ee85 | |
Pavol Rusnak | de95c44ad1 | |
Pavol Rusnak | b42fc6fb1f | |
Jochen Hoenicke | 6186822f14 | |
Jonathan Cross | 63038e6210 | |
Pavol Rusnak | 45835733bc | |
Pavol Rusnak | 8b9cba832c | |
slush | f5c1587396 | |
slush | 59ef832424 | |
Jonathan Cross | 29e4c6a05e | |
Pavol Rusnak | 116c3c0575 | |
Jonathan Cross | ab3d17b3df | |
slush | 8c00cda95a | |
Pavol Rusnak | ae663ffe0c | |
Jochen Hoenicke | 69067c9280 | |
Jonathan Cross | ffeb94f792 | |
Jochen Hoenicke | 2a5888b380 | |
Jochen Hoenicke | 99af1639a6 | |
Pavol Rusnak | 225160d7bd | |
Pavol Rusnak | 5730f00ff8 | |
Nicola Larosa | 62541cc55f | |
Nicola Larosa | 5d2d621055 | |
Pavol Rusnak | 0d9ee4376d | |
Jonathan Cross | 9e068ce903 | |
Jonathan Cross | fa6624129c | |
Jonathan Cross | a6562ccc15 | |
Jochen Hoenicke | 91a541e862 | |
Pavol Rusnak | b9b11fa265 | |
Jonathan Cross | 04bb0069c0 | |
Jonathan Cross | 972459281b | |
Pavol Rusnak | a5fc76d8c9 | |
Pavol Rusnak | 1ab602423c | |
Jochen Hoenicke | ebb9540ac2 | |
Jochen Hoenicke | 6d74c6c9df | |
Jan Pochyla | cc9ddcbc12 | |
Jan Pochyla | fcd793e6e4 | |
Pavol Rusnak | 6a777788ab | |
Pavol Rusnak | cef2ba0129 | |
Pavol Rusnak | 23d75bfc10 | |
Pavol Rusnak | 54426761c6 | |
Emanuel Haupt | fb648a241e | |
Pavol Rusnak | 0f722c1991 | |
Pavol Rusnak | 5057e022c0 | |
Pavol Rusnak | a71c33d123 | |
bithobbes | 54df69a407 | |
Jan Pochyla | 66ba2c20c0 | |
Jan Pochyla | ac0184413d | |
Pavol Rusnak | dffa93bee3 | |
Jan Pochyla | b60ab51f9b | |
Pavol Rusnak | 2a3f613242 | |
Jan Pochyla | 52f96b3792 | |
Jan Pochyla | 259a61878b | |
Jan Pochyla | 8202971109 | |
Jan Pochyla | 051f8e961b | |
Jan Pochyla | 3d3c2a29d0 | |
Jan Pochyla | c805284a86 | |
mruddy | 02437d166a | |
Pavol Rusnak | c20cea6389 | |
Saleem Rashid | 29a145154f | |
Saleem Rashid | eb1d66e27f | |
Saleem Rashid | 4f5d9c4323 | |
Saleem Rashid | 58b56bead6 | |
Saleem Rashid | 991d367416 | |
Jan Pochyla | 888a1edafa | |
Jan Pochyla | bc42eb68d6 | |
Jochen Hoenicke | 7019438a49 | |
Pavol Rusnak | a4a7aa8d85 | |
Jan Pochyla | e3c7146a80 | |
Jochen Hoenicke | 5cfa973a78 | |
Jochen Hoenicke | 600bcba69c | |
Jochen Hoenicke | 29f29626fc | |
Pavol Rusnak | ff157264a2 | |
Pavol Rusnak | 8a663f7ec3 | |
Pavol Rusnak | 32fa08f38b | |
Pavol Rusnak | b6dc73ce9c | |
Saleem Rashid | b469519e26 | |
Pavol Rusnak | 81d5170c10 | |
Pavol Rusnak | 8a1d211ee9 | |
Jan Pochyla | 6df01fbfa3 | |
Pavol Rusnak | 5309baf48e | |
Pavol Rusnak | 11bfacc9b3 | |
Jochen Hoenicke | 9917d9ebfc | |
Pavol Rusnak | efe36b3a2f | |
Pavol Rusnak | 11b686a9f2 | |
Pavol Rusnak | 8133317172 | |
Pavol Rusnak | de6402e95e | |
Pavol Rusnak | 36985519b5 | |
Pavol Rusnak | afdd27c551 | |
Pavol Rusnak | d865c0ea31 | |
Pavol Rusnak | 23ab43d612 | |
Pavol Rusnak | 20aebed394 | |
Pavol Rusnak | ee5f53d4be | |
Pavol Rusnak | c7a2c72a75 | |
Pavol Rusnak | 5ffc700f0c | |
Pavol Rusnak | 1727b9a9b6 | |
Pavol Rusnak | f73fc33439 | |
Pavol Rusnak | 2d643031ac | |
Pavol Rusnak | e6acf90f2b | |
Pavol Rusnak | 5a89a15935 | |
Pavol Rusnak | b335d30b8d | |
Pavol Rusnak | 0ee1667c6f | |
Pavol Rusnak | d33e9a178b | |
Pavol Rusnak | f18ec19aeb | |
Pavol Rusnak | bcf54dbe94 | |
Pavol Rusnak | b9293d6bcb | |
Pavol Rusnak | 9a709832a9 | |
Pavol Rusnak | cbce29163b | |
Pavol Rusnak | e9dbfc757c | |
Pavol Rusnak | 7f0f73d1c6 | |
Pavol Rusnak | 33f274d145 | |
Pavol Rusnak | 71996c1e43 | |
Pavol Rusnak | c51089803d | |
Roman Zeyde | 0d76936174 | |
Pavol Rusnak | f50d547ce4 | |
Pavol Rusnak | f880a09ae7 | |
Pavol Rusnak | e435920d6a | |
Pavol Rusnak | 609b8d4a4a | |
Pavol Rusnak | 564e6590c2 |
|
@ -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
|
|
@ -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/
|
||||
|
|
|
@ -15,7 +15,7 @@ addons:
|
|||
- libusb-1.0-0-dev
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
|
@ -25,9 +25,12 @@ install:
|
|||
- 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:
|
||||
|
|
|
@ -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.
|
|
@ -1,3 +1,3 @@
|
|||
recursive-include tests *.py *.sh *.json
|
||||
recursive-include bash_completion.d *.sh
|
||||
include trezorlib/tests/txcache/*.json
|
||||
include COPYING
|
||||
|
|
68
README.rst
68
README.rst
|
@ -7,83 +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
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
There is a command line tool called ``trezorctl`` which can perform various tasks. Use the following to learn about its commands:
|
||||
On FreeBSD you can install the packages:
|
||||
|
||||
.. code::
|
||||
|
||||
trezorctl --help
|
||||
pkg install security/py-trezor
|
||||
|
||||
or to learn options of a particular command:
|
||||
or build via ports:
|
||||
|
||||
.. code::
|
||||
|
||||
trezorctl commands --help
|
||||
cd /usr/ports/security/py-trezor
|
||||
make install clean
|
||||
|
||||
To use the library in your application look at the following example.
|
||||
|
||||
Example
|
||||
-------
|
||||
Commandline client (trezorctl)
|
||||
---------------------------
|
||||
|
||||
also found in ``tools/helloworld.py``
|
||||
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.
|
||||
|
||||
.. code:: python
|
||||
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/>`_).
|
||||
|
||||
#!/usr/bin/env python
|
||||
|
||||
from trezorlib.client import TrezorClient
|
||||
from trezorlib.transport_hid import HidTransport
|
||||
Python Library
|
||||
--------------
|
||||
|
||||
def main():
|
||||
# List all connected TREZORs on USB
|
||||
devices = HidTransport.enumerate()
|
||||
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.
|
||||
|
||||
# Check whether we found any
|
||||
if len(devices) == 0:
|
||||
print('No TREZOR found')
|
||||
return
|
||||
|
||||
# Use first connected device
|
||||
transport = HidTransport(devices[0])
|
||||
|
||||
# Creates object for manipulating TREZOR
|
||||
client = TrezorClient(transport)
|
||||
|
||||
# Print out TREZOR's features and settings
|
||||
print(client.features)
|
||||
|
||||
# Get the first address of first BIP44 account
|
||||
# (should be the same address as shown in wallet.trezor.io)
|
||||
bip32_path = client.expand_path("44'/0'/0'/0/0")
|
||||
address = client.get_address('Bitcoin', bip32_path)
|
||||
print('Bitcoin address:', address)
|
||||
|
||||
client.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
PIN Entering
|
||||
------------
|
||||
|
|
11
build_pb.sh
11
build_pb.sh
|
@ -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
|
|
@ -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.
|
|
@ -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...
|
|
@ -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
|
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -1,5 +1,8 @@
|
|||
ecdsa>=0.9
|
||||
protobuf>=3.1.0
|
||||
mnemonic>=0.17
|
||||
hidapi>=0.7.99.post20
|
||||
requests>=2.4.0
|
||||
click>=6.2
|
||||
pyblake2>=0.9.3
|
||||
hidapi>=0.7.99.post20
|
||||
libusb1>=1.6.4
|
||||
rlp>=0.6.0
|
||||
|
|
42
setup.py
42
setup.py
|
@ -1,12 +1,14 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
from setuptools import setup
|
||||
|
||||
install_requires = [
|
||||
'ecdsa>=0.9',
|
||||
'protobuf>=3.1.0',
|
||||
'mnemonic>=0.17',
|
||||
'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
|
||||
|
@ -15,32 +17,31 @@ if '--disable-hidapi' in sys.argv:
|
|||
else:
|
||||
install_requires.append('hidapi>=0.7.99.post20')
|
||||
|
||||
if '--disable-libusb' in sys.argv:
|
||||
sys.argv.remove('--disable-libusb')
|
||||
else:
|
||||
install_requires.append('libusb1>=1.6.4')
|
||||
|
||||
from trezorlib import __version__ as VERSION
|
||||
|
||||
setup(
|
||||
name='trezor',
|
||||
version='0.7.15',
|
||||
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'],
|
||||
install_requires=install_requires,
|
||||
python_requires='>=3.3',
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
classifiers=[
|
||||
|
@ -48,5 +49,6 @@ setup(
|
|||
'Operating System :: POSIX :: Linux',
|
||||
'Operating System :: Microsoft :: Windows',
|
||||
'Operating System :: MacOS :: MacOS X',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,84 +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
|
||||
|
||||
|
||||
try:
|
||||
from trezorlib.transport_hid import HidTransport
|
||||
HID_ENABLED = True
|
||||
except Exception as e:
|
||||
print('HID transport disabled:', e.message, e.args)
|
||||
HID_ENABLED = False
|
||||
|
||||
try:
|
||||
from trezorlib.transport_pipe import PipeTransport
|
||||
PIPE_ENABLED = True
|
||||
except Exception as e:
|
||||
print('PIPE transport disabled:', e.message, e.args)
|
||||
PIPE_ENABLED = False
|
||||
|
||||
try:
|
||||
from trezorlib.transport_udp import UdpTransport
|
||||
UDP_ENABLED = True
|
||||
except Exception as e:
|
||||
print('UDP transport disabled:', e.message, e.args)
|
||||
UDP_ENABLED = False
|
||||
|
||||
|
||||
def pipe_exists(path):
|
||||
import os, stat
|
||||
try:
|
||||
return stat.S_ISFIFO(os.stat(path).st_mode)
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
if HID_ENABLED and len(HidTransport.enumerate()) > 0:
|
||||
|
||||
devices = HidTransport.enumerate()
|
||||
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_ENABLED and 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 UDP_ENABLED:
|
||||
|
||||
print('Using Emulator (v2=udp)')
|
||||
TRANSPORT = UdpTransport
|
||||
TRANSPORT_ARGS = ('', )
|
||||
TRANSPORT_KWARGS = {}
|
||||
DEBUG_TRANSPORT = UdpTransport
|
||||
DEBUG_TRANSPORT_ARGS = ('', )
|
||||
DEBUG_TRANSPORT_KWARGS = {}
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/bash
|
||||
for i in test_*.py; do
|
||||
echo Starting: $i
|
||||
python $i > $i.out 2> $i.err
|
||||
done
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
python -m unittest discover
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -1,44 +0,0 @@
|
|||
import unittest
|
||||
import common
|
||||
import trezorlib.ckd_public as bip32
|
||||
import trezorlib.types_pb2 as proto_types
|
||||
import binascii
|
||||
|
||||
class TestMsgGetaddressSegwit(common.TrezorTest):
|
||||
|
||||
def test_show_segwit(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("49'/1'/0'/1/0"),
|
||||
True, None, script_type=proto_types.SPENDP2SHWITNESS),
|
||||
'2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX')
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("49'/1'/0'/0/0"),
|
||||
False, None, script_type=proto_types.SPENDP2SHWITNESS),
|
||||
'2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp')
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("44'/1'/0'/0/0"),
|
||||
False, None, script_type=proto_types.SPENDP2SHWITNESS),
|
||||
'2N6UeBoqYEEnybg4cReFYDammpsyDw8R2Mc')
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("44'/1'/0'/0/0"),
|
||||
False, None, script_type=proto_types.SPENDADDRESS),
|
||||
'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q')
|
||||
|
||||
def test_show_multisig_3(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
nodes = map(lambda index : self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)), range(1,4))
|
||||
multisig1 = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=bip32.deserialize(n.xpub), address_n=[2,0]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
multisig2 = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=bip32.deserialize(n.xpub), address_n=[2,1]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
for i in [1, 2, 3]:
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("999'/1'/%d'/2/0" % i),
|
||||
False, multisig1, script_type=proto_types.SPENDP2SHWITNESS),
|
||||
'2N2MxyAfifVhb3AMagisxaj3uij8bfXqf4Y');
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -1,47 +0,0 @@
|
|||
import unittest
|
||||
import common
|
||||
import trezorlib.ckd_public as bip32
|
||||
import trezorlib.types_pb2 as proto_types
|
||||
import binascii
|
||||
|
||||
class TestMsgGetaddressSegwitNative(common.TrezorTest):
|
||||
|
||||
def test_show_segwit(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("49'/1'/0'/0/0"),
|
||||
True, None, script_type=proto_types.SPENDWITNESS),
|
||||
'QWywnqNMsMNavbCgMYiQLa91ApvsVRoaqt1i')
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("49'/1'/0'/1/0"),
|
||||
False, None, script_type=proto_types.SPENDWITNESS),
|
||||
'QWzGpyMkAEvmkSVprBzRRVQMP6UPp17q4kQn')
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("44'/1'/0'/0/0"),
|
||||
False, None, script_type=proto_types.SPENDWITNESS),
|
||||
'QWzCpc1NeTN7hNDzK9sQQ9yrTQP8zh5Hef5J')
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("44'/1'/0'/0/0"),
|
||||
False, None, script_type=proto_types.SPENDADDRESS),
|
||||
'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q')
|
||||
|
||||
def test_show_multisig_3(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
nodes = map(lambda index : self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)), range(1,4))
|
||||
multisig1 = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=bip32.deserialize(n.xpub), address_n=[2,0]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
multisig2 = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=bip32.deserialize(n.xpub), address_n=[2,1]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
for i in [1, 2, 3]:
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("999'/1'/%d'/2/1" % i),
|
||||
False, multisig2, script_type=proto_types.SPENDWITNESS),
|
||||
'T7nZJt6QbGJy6Hok4EF2LqtJPcT7z7VFSrSysGS3tEqCfDPwizqy4')
|
||||
self.assertEqual(self.client.get_address("Testnet", self.client.expand_path("999'/1'/%d'/2/0" % i),
|
||||
False, multisig1, script_type=proto_types.SPENDWITNESS),
|
||||
'T7nY3A3kewpDKumsdhonP4TBDfTXFSc2RNhZxkqmeeszRDHjM5yUn')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -1,628 +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
|
||||
|
||||
|
||||
TXHASH_157041 = binascii.unhexlify(b'1570416eb4302cf52979afd5e6909e37d8fdd874301f7cc87e547e509cb1caa6')
|
||||
TXHASH_39a29e = binascii.unhexlify(b'39a29e954977662ab3879c66fb251ef753e0912223a83d1dcb009111d28265e5')
|
||||
TXHASH_4a7b7e = binascii.unhexlify(b'4a7b7e0403ae5607e473949cfa03f09f2cd8b0f404bf99ce10b7303d86280bf7')
|
||||
TXHASH_54aa56 = binascii.unhexlify(b'54aa5680dea781f45ebb536e53dffc526d68c0eb5c00547e323b2c32382dfba3')
|
||||
TXHASH_58497a = binascii.unhexlify(b'58497a7757224d1ff1941488d23087071103e5bf855f4c1c44e5c8d9d82ca46e')
|
||||
TXHASH_6f90f3 = binascii.unhexlify(b'6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54')
|
||||
TXHASH_c63e24 = binascii.unhexlify(b'c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb')
|
||||
TXHASH_c6be22 = binascii.unhexlify(b'c6be22d34946593bcad1d2b013e12f74159e69574ffea21581dad115572e031c')
|
||||
TXHASH_d5f65e = binascii.unhexlify(b'd5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882')
|
||||
TXHASH_d6da21 = binascii.unhexlify(b'd6da21677d7cca5f42fbc7631d062c9ae918a0254f7c6c22de8e8cb7fd5b8236')
|
||||
|
||||
|
||||
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=TXHASH_d5f65e,
|
||||
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=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e)),
|
||||
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=TXHASH_6f90f3,
|
||||
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=TXHASH_6f90f3)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_6f90f3)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_6f90f3)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_6f90f3)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_6f90f3)),
|
||||
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=TXHASH_6f90f3,
|
||||
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=TXHASH_6f90f3)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_6f90f3)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_6f90f3)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_6f90f3)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_6f90f3)),
|
||||
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=TXHASH_d5f65e,
|
||||
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=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e)),
|
||||
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=TXHASH_d5f65e,
|
||||
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=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e)),
|
||||
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=TXHASH_c6be22,
|
||||
prev_index=1,
|
||||
)
|
||||
|
||||
inp2 = proto_types.TxInputType(address_n=[2], # 15AeAhtNJNKyowK8qPHwgpXkhsokzLtUpG
|
||||
# amount=110000,
|
||||
prev_hash=TXHASH_58497a,
|
||||
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=TXHASH_c6be22)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_c6be22)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_c6be22)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_c6be22)),
|
||||
|
||||
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=TXHASH_58497a)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_58497a)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_58497a)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_58497a)),
|
||||
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=TXHASH_4a7b7e,
|
||||
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=TXHASH_c63e24,
|
||||
prev_index=1,
|
||||
)
|
||||
|
||||
inp2 = proto_types.TxInputType(address_n=[3], # 1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5
|
||||
# amount=2540000,
|
||||
prev_hash=TXHASH_39a29e,
|
||||
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=TXHASH_c63e24)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_c63e24)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_c63e24)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_c63e24)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_c63e24)),
|
||||
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=TXHASH_39a29e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_39a29e)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_39a29e)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_39a29e)),
|
||||
] + [
|
||||
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: 1570416eb4302cf52979afd5e6909e37d8fdd874301f7cc87e547e509cb1caa6
|
||||
# input 0: 1.0 BTC
|
||||
|
||||
inp1 = proto_types.TxInputType(address_n=[0], # 1HWDaLTpTCTtRWyWqZkzWx1wex5NKyncLW
|
||||
# amount=100000000,
|
||||
prev_hash=TXHASH_157041,
|
||||
prev_index=0,
|
||||
)
|
||||
|
||||
out1 = proto_types.TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
|
||||
amount=100000000 - 510000,
|
||||
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=TXHASH_157041)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_157041)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_157041)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_157041)),
|
||||
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'0100000001a6cab19c507e547ec87c1f3074d8fdd8379e90e6d5af7929f52c30b46e417015000000006b483045022100dc3531da7feb261575f03b5b9bbb35edc7f73bb081c92538827105de4102737002200161e34395f6a8ee93979200cb974fa75ccef6d7c14021511cf468eece90d6450121023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43dffffffff01d018ee05000000001976a914de9b2a8da088824e8fe51debea566617d851537888ac00000000')
|
||||
|
||||
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=TXHASH_d5f65e,
|
||||
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=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e)),
|
||||
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=TXHASH_54aa56,
|
||||
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=TXHASH_54aa56)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_54aa56)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_54aa56)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_54aa56)),
|
||||
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=TXHASH_c6be22,
|
||||
prev_index=1,
|
||||
)
|
||||
|
||||
inp2 = proto_types.TxInputType(address_n=[2], # 15AeAhtNJNKyowK8qPHwgpXkhsokzLtUpG
|
||||
# amount=110000,
|
||||
prev_hash=TXHASH_58497a,
|
||||
prev_index=1,
|
||||
)
|
||||
|
||||
out1 = proto_types.TxOutputType(address='15Jvu3nZNP7u2ipw2533Q9VVgEu2Lu9F2B',
|
||||
amount=210000 - 100000 - 10000,
|
||||
script_type=proto_types.PAYTOADDRESS,
|
||||
)
|
||||
|
||||
out2 = proto_types.TxOutputType(address_n=[3], # 1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5
|
||||
amount=100000,
|
||||
script_type=proto_types.PAYTOADDRESS,
|
||||
)
|
||||
|
||||
global run_attack
|
||||
run_attack = False
|
||||
|
||||
def attack_processor(req, msg):
|
||||
global run_attack
|
||||
|
||||
if req.details.tx_hash != b'':
|
||||
return msg
|
||||
|
||||
if req.details.request_index != 1:
|
||||
return msg
|
||||
|
||||
if not run_attack:
|
||||
run_attack = True
|
||||
return msg
|
||||
|
||||
msg.outputs[0].amount = 9999999 # Sign output with another amount
|
||||
return msg
|
||||
|
||||
# Test if the transaction can be signed normally
|
||||
(_, serialized_tx) = self.client.sign_tx('Bitcoin', [inp1, inp2], [out1, out2])
|
||||
|
||||
# Accepted by network: tx c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb
|
||||
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000021c032e5715d1da8115a2fe4f57699e15742fe113b0d2d1ca3b594649d322bec6010000006b483045022100f773c403b2f85a5c1d6c9c4ad69c43de66930fff4b1bc818eb257af98305546a0220443bde4be439f276a6ce793664b463580e210ec6c9255d68354449ac0443c76501210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6ffffffff6ea42cd8d9c8e5441c4c5f85bfe50311078730d2881494f11f4d2257777a4958010000006b48304502210090cff1c1911e771605358a8cddd5ae94c7b60cc96e50275908d9bf9d6367c79f02202bfa72e10260a146abd59d0526e1335bacfbb2b4401780e9e3a7441b0480c8da0121038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3ffffffff02a0860100000000001976a9142f4490d5263906e4887ca2996b9e207af3e7824088aca0860100000000001976a914812c13d97f9159e54e326b481b8f88a73df8507a88ac00000000')
|
||||
|
||||
# Now run the attack, must trigger the exception
|
||||
self.assertRaises(CallException, self.client.sign_tx, 'Bitcoin', [inp1, inp2], [out1, out2], debug_processor=attack_processor)
|
||||
|
||||
def test_spend_coinbase(self):
|
||||
# 25 TEST generated to m/1 (mfiGQVPcRcaEvQPYDErR34DcCovtxYvUUV)
|
||||
# tx: d6da21677d7cca5f42fbc7631d062c9ae918a0254f7c6c22de8e8cb7fd5b8236
|
||||
# input 0: 25.0027823 BTC
|
||||
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
|
||||
inp1 = proto_types.TxInputType(address_n=[1], # mfiGQVPcRcaEvQPYDErR34DcCovtxYvUUV
|
||||
# amount=390000,
|
||||
prev_hash=TXHASH_d6da21,
|
||||
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=TXHASH_d6da21)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d6da21)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d6da21)),
|
||||
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()
|
|
@ -1,156 +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
|
||||
from trezorlib.ckd_public import deserialize
|
||||
|
||||
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='mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC',
|
||||
amount=12300000,
|
||||
script_type=proto_types.PAYTOADDRESS,
|
||||
)
|
||||
out2 = proto_types.TxOutputType(
|
||||
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'0100000000010137c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02e0aebb00000000001976a91414fdede0ddc3be652a0ce1afbc1b509a55b6b94888ac3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca8702483045022100ccd253bfdf8a5593cd7b6701370c531199f0f05a418cd547dfc7da3f21515f0f02203fa08a0753688871c220648f9edadbdb98af42e5d8269364a326572cf703895b012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000')
|
||||
|
||||
def test_send_p2sh_change(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='mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC',
|
||||
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,
|
||||
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_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'0100000000010137c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02e0aebb00000000001976a91414fdede0ddc3be652a0ce1afbc1b509a55b6b94888ac3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca8702483045022100ccd253bfdf8a5593cd7b6701370c531199f0f05a418cd547dfc7da3f21515f0f02203fa08a0753688871c220648f9edadbdb98af42e5d8269364a326572cf703895b012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000')
|
||||
|
||||
def test_send_multisig_1(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
self.client.set_tx_api(TxApiTestnet)
|
||||
nodes = map(lambda index : self.client.get_public_node(self.client.expand_path("999'/1'/%d'" % index)), range(1,4))
|
||||
multisig = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[2,0]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
|
||||
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("999'/1'/1'/2/0"),
|
||||
prev_hash=binascii.unhexlify('9c31922be756c06d02167656465c8dc83bb553bf386a3f478ae65b5c021002be'),
|
||||
prev_index=1,
|
||||
script_type=proto_types.SPENDP2SHWITNESS,
|
||||
multisig=multisig,
|
||||
amount=1610436
|
||||
)
|
||||
|
||||
out1 = proto_types.TxOutputType(address='mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC',
|
||||
amount=1605000,
|
||||
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.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.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
|
||||
proto.TxRequest(request_type=proto_types.TXFINISHED),
|
||||
])
|
||||
(signatures1, _) = self.client.sign_tx('Testnet', [inp1], [out1 ])
|
||||
# store signature
|
||||
inp1.multisig.signatures[0] = signatures1[0]
|
||||
# sign with third key
|
||||
inp1.address_n[2] = 0x80000003
|
||||
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.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.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
|
||||
proto.TxRequest(request_type=proto_types.TXFINISHED),
|
||||
])
|
||||
(signatures2, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1 ])
|
||||
|
||||
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000000101be0210025c5be68a473f6a38bf53b53bc88d5c46567616026dc056e72b92319c01000000232200201e8dda334f11171190b3da72e526d441491464769679a319a2f011da5ad312a1ffffffff01887d1800000000001976a91414fdede0ddc3be652a0ce1afbc1b509a55b6b94888ac040047304402205b44c20cf2681690edaaf7cd2e30d4704124dd8b7eb1fb7f459d3906c3c374a602205ca359b6544ce2c101c979899c782f7d141c3b0454ea69202b1fb4c09d3b715701473044022052fafa64022554ae436dbf781e550bf0d326fef31eea1438350b3ff1940a180102202851bd19203b7fe8582a9ef52e82aa9f61cd52d4bcedfe6dcc0cf782468e6a8e01695221038e81669c085a5846e68e03875113ddb339ecbb7cb11376d4163bca5dc2e2a0c1210348c5c3be9f0e6cf1954ded1c0475beccc4d26aaa9d0cce2dd902538ff1018a112103931140ebe0fbbb7df0be04ed032a54e9589e30339ba7bbb8b0b71b15df1294da53ae00000000')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -1,455 +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
|
||||
from trezorlib.ckd_public import deserialize
|
||||
|
||||
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='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_p2sh_change(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,
|
||||
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_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='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_native_change(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,
|
||||
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_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')
|
||||
|
||||
def test_send_multisig_1(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
self.client.set_tx_api(TxApiTestnet)
|
||||
nodes = map(lambda index : self.client.get_public_node(self.client.expand_path("999'/1'/"+str(index)+"'")), range(1,4))
|
||||
multisig = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[2,0]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
|
||||
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("999'/1'/1'/2/0"),
|
||||
prev_hash=binascii.unhexlify('9c31922be756c06d02167656465c8dc83bb553bf386a3f478ae65b5c021002be'),
|
||||
prev_index=1,
|
||||
script_type=proto_types.SPENDP2SHWITNESS,
|
||||
multisig=multisig,
|
||||
amount=1610436
|
||||
)
|
||||
|
||||
out1 = proto_types.TxOutputType(address='T7nZJt6QbGJy6Hok4EF2LqtJPcT7z7VFSrSysGS3tEqCfDPwizqy4',
|
||||
amount=1605000,
|
||||
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.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.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
|
||||
proto.TxRequest(request_type=proto_types.TXFINISHED),
|
||||
])
|
||||
(signatures1, _) = self.client.sign_tx('Testnet', [inp1], [out1 ])
|
||||
# store signature
|
||||
inp1.multisig.signatures[0] = signatures1[0]
|
||||
# sign with third key
|
||||
inp1.address_n[2] = 0x80000003
|
||||
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.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.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
|
||||
proto.TxRequest(request_type=proto_types.TXFINISHED),
|
||||
])
|
||||
(signatures2, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1 ])
|
||||
|
||||
# f41cbedd8becee05a830f418d13aa665125464547db5c7a6cd28f21639fe1228
|
||||
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000000101be0210025c5be68a473f6a38bf53b53bc88d5c46567616026dc056e72b92319c01000000232200201e8dda334f11171190b3da72e526d441491464769679a319a2f011da5ad312a1ffffffff01887d180000000000220020c5f4a0a4ea7c0392efe0a9670a73264cffa90b19107cd8a8e9750ff93c77fdfb0400483045022100a9b681f324ff4cf419ab06820d07248cc4e359c77334bf448ae7b5cdf3995ddf022039811f91f55b602368b4ba08a217b82bfd62d1a97dc635deb1457e7cfcc1550b0147304402201ad86a795c3d26881d696fa0a0619c24c4d505718132a82965cc2a609c9d8798022067cd490ce1366cde77e307ced5b13040bbc04991619ea6f49e06cece9a83268b01695221038e81669c085a5846e68e03875113ddb339ecbb7cb11376d4163bca5dc2e2a0c1210348c5c3be9f0e6cf1954ded1c0475beccc4d26aaa9d0cce2dd902538ff1018a112103931140ebe0fbbb7df0be04ed032a54e9589e30339ba7bbb8b0b71b15df1294da53ae00000000')
|
||||
|
||||
def test_send_multisig_2(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
self.client.set_tx_api(TxApiTestnet)
|
||||
nodes = map(lambda index : self.client.get_public_node(self.client.expand_path("999'/1'/"+str(index)+"'")), range(1,4))
|
||||
multisig = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[2,1]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
|
||||
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("999'/1'/2'/2/1"),
|
||||
prev_hash=binascii.unhexlify('f41cbedd8becee05a830f418d13aa665125464547db5c7a6cd28f21639fe1228'),
|
||||
prev_index=0,
|
||||
script_type=proto_types.SPENDWITNESS,
|
||||
multisig=multisig,
|
||||
amount=1605000
|
||||
)
|
||||
|
||||
out1 = proto_types.TxOutputType(address='T7nY3A3kewpDKumsdhonP4TBDfTXFSc2RNhZxkqmeeszRDHjM5yUn',
|
||||
amount=1604000,
|
||||
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.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.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
|
||||
proto.TxRequest(request_type=proto_types.TXFINISHED),
|
||||
])
|
||||
(signatures1, _) = self.client.sign_tx('Testnet', [inp1], [out1 ])
|
||||
# store signature
|
||||
inp1.multisig.signatures[1] = signatures1[0]
|
||||
# sign with first key
|
||||
inp1.address_n[2] = 0x80000001
|
||||
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.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.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
|
||||
proto.TxRequest(request_type=proto_types.TXFINISHED),
|
||||
])
|
||||
(signatures2, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1 ])
|
||||
|
||||
# c9348040bbc2024e12dcb4a0b4806b0398646b91acf314da028c3f03dd0179fc
|
||||
self.assertEqual(binascii.hexlify(serialized_tx), b'010000000001012812fe3916f228cda6c7b57d5464541265a63ad118f430a805eeec8bddbe1cf40000000000ffffffff01a0791800000000002200201e8dda334f11171190b3da72e526d441491464769679a319a2f011da5ad312a10400483045022100cc97f21a7cabc543a9b4ac52424e8f7e420622903f2417a1c08a6af68058ec4a02200baca0b222fc825078d94e8e1b55f174c4828bed16697e4281cda2a0c799eecf01473044022009b8058dc30fa7a13310dd8f1a99c4341c4cd95f771c5a41c4381f956e2344c102205e829c560c0184fd4b4db8971f99711e2a87409afa4df0840b4f12a87b2c8afc0169522102740ec30d0af8591a0dd4a3e3b274e57f3f73bdc0638a9603f9ee6ade0475ba57210311aada919974e882abf0c67b5c0fba00000b26997312ca00345027d22359443021029382591271a79d4b12365fa27c67fad3753150d8eaa987e5a12dc5ba1bb2fa1653ae00000000')
|
||||
|
||||
def test_send_multisig_3_change(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
self.client.set_tx_api(TxApiTestnet)
|
||||
nodes = map(lambda index : self.client.get_public_node(self.client.expand_path("999'/1'/"+str(index)+"'")), range(1,4))
|
||||
multisig = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[2,0]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
multisig2 = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[1,1]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
|
||||
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("999'/1'/1'/2/0"),
|
||||
prev_hash=binascii.unhexlify('c9348040bbc2024e12dcb4a0b4806b0398646b91acf314da028c3f03dd0179fc'),
|
||||
prev_index=0,
|
||||
script_type=proto_types.SPENDWITNESS,
|
||||
multisig=multisig,
|
||||
amount=1604000
|
||||
)
|
||||
|
||||
out1 = proto_types.TxOutputType(address_n=self.client.expand_path("999'/1'/1'/1/1"),
|
||||
amount=1603000,
|
||||
multisig=multisig2,
|
||||
script_type=proto_types.PAYTOP2SHWITNESS)
|
||||
|
||||
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_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.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
|
||||
proto.TxRequest(request_type=proto_types.TXFINISHED),
|
||||
])
|
||||
(signatures1, _) = self.client.sign_tx('Testnet', [inp1], [out1 ])
|
||||
# store signature
|
||||
inp1.multisig.signatures[0] = signatures1[0]
|
||||
# sign with third key
|
||||
inp1.address_n[2] = 0x80000003
|
||||
out1.address_n[2] = 0x80000003
|
||||
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_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.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
|
||||
proto.TxRequest(request_type=proto_types.TXFINISHED),
|
||||
])
|
||||
(signatures2, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1 ])
|
||||
|
||||
# 31bc1c88ce6ae337a6b3057a16d5bad0b561ad1dfc047d0a7fbb8814668f91e5
|
||||
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000000101fc7901dd033f8c02da14f3ac916b6498036b80b4a0b4dc124e02c2bb408034c90000000000ffffffff01b87518000000000017a914a8655acf68f785125561158b0f4db9b5d0044047870400473044022057b571986c07f8ccb231811334ad06ee6f87b722495def2e9511c1da46f3433202207b6e95bdd99e7fc7d319486437cb930d40a4af3cd753c4cb960b330badbf7f35014730440220517ecc6d0a2544276921d8fc2077aec4285ab83b1b21f5eb73cdb6187a0583e4022043fb5ab942f8981c04a54c66a57c4d291fad8514d4a8afea09f01f2db7a8f32901695221038e81669c085a5846e68e03875113ddb339ecbb7cb11376d4163bca5dc2e2a0c1210348c5c3be9f0e6cf1954ded1c0475beccc4d26aaa9d0cce2dd902538ff1018a112103931140ebe0fbbb7df0be04ed032a54e9589e30339ba7bbb8b0b71b15df1294da53ae00000000')
|
||||
|
||||
def test_send_multisig_4_change(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
self.client.set_tx_api(TxApiTestnet)
|
||||
nodes = map(lambda index : self.client.get_public_node(self.client.expand_path("999'/1'/"+str(index)+"'")), range(1,4))
|
||||
multisig = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[1,1]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
multisig2 = proto_types.MultisigRedeemScriptType(
|
||||
pubkeys=map(lambda n : proto_types.HDNodePathType(node=deserialize(n.xpub), address_n=[1,2]), nodes),
|
||||
signatures=[b'', b'', b''],
|
||||
m=2,
|
||||
)
|
||||
|
||||
inp1 = proto_types.TxInputType(address_n=self.client.expand_path("999'/1'/1'/1/1"),
|
||||
prev_hash=binascii.unhexlify('31bc1c88ce6ae337a6b3057a16d5bad0b561ad1dfc047d0a7fbb8814668f91e5'),
|
||||
prev_index=0,
|
||||
script_type=proto_types.SPENDP2SHWITNESS,
|
||||
multisig=multisig,
|
||||
amount=1603000
|
||||
)
|
||||
|
||||
out1 = proto_types.TxOutputType(address_n=self.client.expand_path("999'/1'/1'/1/2"),
|
||||
amount=1602000,
|
||||
multisig=multisig2,
|
||||
script_type=proto_types.PAYTOWITNESS)
|
||||
|
||||
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_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.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
|
||||
proto.TxRequest(request_type=proto_types.TXFINISHED),
|
||||
])
|
||||
(signatures1, _) = self.client.sign_tx('Testnet', [inp1], [out1 ])
|
||||
# store signature
|
||||
inp1.multisig.signatures[0] = signatures1[0]
|
||||
# sign with third key
|
||||
inp1.address_n[2] = 0x80000003
|
||||
out1.address_n[2] = 0x80000003
|
||||
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_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.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0)),
|
||||
proto.TxRequest(request_type=proto_types.TXFINISHED),
|
||||
])
|
||||
(signatures2, serialized_tx) = self.client.sign_tx('Testnet', [inp1], [out1 ])
|
||||
|
||||
# c0bf56060a109624b4635222696d94a7d533cacea1b3f8245417a4348c045829
|
||||
self.assertEqual(binascii.hexlify(serialized_tx), b'01000000000101e5918f661488bb7f0a7d04fc1dad61b5d0bad5167a05b3a637e36ace881cbc3100000000232200205b9824093eaf5cdcf8247c00dc0b557a7720957828fcde8384ac11f80a91f403ffffffff01d071180000000000220020e77caf5fbef07b1e461475c02afd4aed877693263d69c81e14617304349b629a040047304402204832553b0da1009da496881e58e8e2e41010cfe5c0161623048093f1b1a817b7022020dad8bf887acf574af80bfe4b39cd24e95019fd5e6b8ae967471e21ddc67354014830450221009e5d60847e7275edcf4619ed8ee462c56a042eef75d17da2d44e6b13d78e50e50220665195492900ef87a5eb8a924fa0ac9afc4fc75ca704ff356dc3a213979970c80169522103f4040006e3561b3e76c6d4113225c84748ab9d55ffd23f9578ab4c18fb0c3b9721020975f2e6922897ff6b80da6412a8d6ebd67e33c9611d081656a53ef967964e5021026b0546f23a6ce6b756c2c30b4176ce6f1c3268744f7aca82668d5116c4f764e453ae00000000')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -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()
|
|
@ -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()
|
|
@ -1,332 +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
|
||||
# m/2 => 0375b9dfaad928ce1a7eed88df7c084e67d99e9ab74332419458a9a45779706801
|
||||
|
||||
node_ext2 = bip32.deserialize('xpub6FKKCwdfD85eHmKn7d3mmbhqsHnGkB2n7Hmre29gbnR1cR4U1wrtf2akh1VVqjcTdfkxmwPjQyYPhLLgwBijfFPAYqTZzcjj4awB1BMUxq2')
|
||||
# m/1 => 0388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1
|
||||
# m/2 => 03a04f945d5a3685729dde697d574076de4bdf38e904f813b22a851548e1110fc0
|
||||
|
||||
node_ext3 = bip32.deserialize('xpub69rsKg2fef3GzETrukhsR3U9i4nL3dXKy3cjSpm44Cg8waqrnyupanaLQt4bYjn2HTmH1NusFt9DAh6absMQqE4E66q7EYTyEsorZKXdWWx')
|
||||
# m/1 => 02e0c21e2a7cf00b94c5421725acff97f9826598b91f2340c5ddda730caca7d648
|
||||
# m/2 => 03928301ffb8c0d7a364b794914c716ba3107cc78a6fe581028b0d8638b22e8573
|
||||
|
||||
node_int = bip32.deserialize('xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy')
|
||||
# m/1 => 0338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6
|
||||
# m/2 => 038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3
|
||||
|
||||
# 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()
|
||||
|
||||
out1 = proto_types.TxOutputType(address='3796Q9jVirg2KY1WQRqtmHKXCoSk8MB7Td',
|
||||
amount=100000,
|
||||
script_type=proto_types.PAYTOADDRESS)
|
||||
|
||||
out2 = proto_types.TxOutputType(address='3CTPCg3ksh59jWt9zQpTPHCSQDCdJoQQ9d',
|
||||
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'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,
|
||||
)
|
||||
|
||||
out1 = proto_types.TxOutputType(address_n=[1],
|
||||
multisig=multisig_out1,
|
||||
amount=100000,
|
||||
script_type=proto_types.PAYTOMULTISIG)
|
||||
|
||||
out2 = proto_types.TxOutputType(address='3CTPCg3ksh59jWt9zQpTPHCSQDCdJoQQ9d',
|
||||
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'01000000023da7e83c25051d520133e56bfa86206352a285988e096bd14aaf5532a68ed0d100000000b40047304402203cb26eac850f590951b12b513a5369c0b301c6d3ae1cd251aa837ce35427bdec0220289834c8c5cb837351ae06498d77fa6707611c09d628864a1f0a7e1d381bddd8014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653aeffffffff9643add957ab239b1d8fe387cc3807b48130a553a7b181e447ee9c089d82e2a600000000b40047304402207c2e39254d1e9cff42b523bcc0bf5ab66ae0c584deb2413759d9b269b1fe9e6f02205bc93a1884625b2359247c15a57e4e80b184b21a5f95e7f5ce846323236e30ac014c69522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c153aeffffffff02a08601000000000017a914b69a5c6a63c01a09a90eb690031963f737cf96ed87a08601000000000017a9147615527d78854293edadf83682ea26937f8a51bb8700000000')
|
||||
|
||||
# inputs match, change matches (second is change)
|
||||
def test_multisig_change_match_second(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
|
||||
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(address='37Wf955dcCaFSJmiNaGpacczMwj7iC8JMx',
|
||||
amount=100000,
|
||||
script_type=proto_types.PAYTOADDRESS)
|
||||
|
||||
out2 = proto_types.TxOutputType(address_n=[2],
|
||||
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_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(address='3796Q9jVirg2KY1WQRqtmHKXCoSk8MB7Td',
|
||||
amount=100000,
|
||||
script_type=proto_types.PAYTOADDRESS)
|
||||
|
||||
out2 = proto_types.TxOutputType(address_n=[2],
|
||||
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,
|
||||
)
|
||||
|
||||
out1 = proto_types.TxOutputType(address_n=[1],
|
||||
multisig=multisig_out1,
|
||||
amount=100000,
|
||||
script_type=proto_types.PAYTOMULTISIG)
|
||||
|
||||
out2 = proto_types.TxOutputType(address='3CTPCg3ksh59jWt9zQpTPHCSQDCdJoQQ9d',
|
||||
amount=100000,
|
||||
script_type=proto_types.PAYTOADDRESS)
|
||||
|
||||
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()
|
|
@ -1,113 +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
|
||||
|
||||
|
||||
TXHASH_d5f65e = binascii.unhexlify(b'd5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882')
|
||||
|
||||
|
||||
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=TXHASH_d5f65e,
|
||||
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=TXHASH_d5f65e,
|
||||
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()
|
|
@ -1,219 +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
|
||||
|
||||
|
||||
TXHASH_d5f65e = binascii.unhexlify(b'd5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882')
|
||||
|
||||
|
||||
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(b'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=TXHASH_d5f65e,
|
||||
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=TXHASH_d5f65e,
|
||||
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=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXINPUT, details=proto_types.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_d5f65e)),
|
||||
proto.TxRequest(request_type=proto_types.TXOUTPUT, details=proto_types.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e)),
|
||||
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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
|
@ -1,10 +1,7 @@
|
|||
#!/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
|
||||
|
@ -15,9 +12,10 @@ import sys
|
|||
# note that in order for this to work, your trezor device must
|
||||
# be running a firmware that was built with debug link enabled
|
||||
|
||||
|
||||
def main():
|
||||
# List all 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:
|
||||
|
@ -25,10 +23,10 @@ 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)
|
||||
|
||||
|
@ -36,7 +34,7 @@ def main():
|
|||
arg2 = int(sys.argv[2], 16)
|
||||
step = 0x400 if arg2 >= 0x400 else arg2
|
||||
|
||||
f = open('memory.dat', 'w')
|
||||
f = open('memory.dat', 'wb')
|
||||
|
||||
for addr in range(arg1, arg1 + arg2, step):
|
||||
mem = debug.memory_read(addr, step)
|
||||
|
@ -46,5 +44,6 @@ def main():
|
|||
|
||||
client.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
|
@ -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()
|
|
@ -1,27 +1,21 @@
|
|||
#!/usr/bin/env python
|
||||
#!/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 binascii
|
||||
import io
|
||||
import sys
|
||||
from trezorlib.client import TrezorClient
|
||||
from trezorlib.transport_hid import HidTransport
|
||||
from trezorlib.transport import get_transport
|
||||
|
||||
def get_client():
|
||||
devices = HidTransport.enumerate() # List all connected TREZORs on USB
|
||||
if len(devices) == 0: # Check whether we found any
|
||||
return None
|
||||
transport = HidTransport(devices[0]) # Use first connected device
|
||||
return TrezorClient(transport) # Creates object for communicating with TREZOR
|
||||
|
||||
def main():
|
||||
client = get_client()
|
||||
if not client:
|
||||
print('No TREZOR connected')
|
||||
try:
|
||||
client = TrezorClient(get_transport())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
arg1 = sys.argv[1] # output file
|
||||
|
@ -29,11 +23,12 @@ def main():
|
|||
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 xrange(0, arg2, step):
|
||||
for i in range(0, arg2, step):
|
||||
entropy = client.get_entropy(step)
|
||||
f.write(entropy)
|
||||
|
||||
client.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
import binascii
|
||||
import os
|
||||
import random
|
||||
|
@ -10,23 +9,24 @@ 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)
|
||||
|
||||
|
||||
def int_to_string(x, pad):
|
||||
result = ['\x00'] * pad
|
||||
while x > 0:
|
||||
|
@ -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
|
||||
|
@ -83,7 +84,7 @@ class MyTxApiBitcoin(object):
|
|||
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)
|
||||
|
@ -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,10 +113,12 @@ 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
|
||||
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),
|
||||
proto_types.SPENDADDRESS
|
||||
),
|
||||
prev_hash=txhash,
|
||||
prev_index=myout,
|
||||
amount=amount if segwit > 0 else 0
|
||||
|
@ -142,22 +145,19 @@ class MyTxApiBitcoin(object):
|
|||
# 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()
|
||||
|
||||
|
@ -211,7 +211,7 @@ def main():
|
|||
# script_type=proto_types.PAYTOADDRESS,
|
||||
# # address_n=client.expand_path("44'/0'/0'/0/18"),
|
||||
# # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ',
|
||||
# address='1NcMqUvyWv1K3Zxwmx5sqfj7ZEmPCSdJFM',
|
||||
# # address='1NcMqUvyWv1K3Zxwmx5sqfj7ZEmPCSdJFM',
|
||||
# ),
|
||||
]
|
||||
|
||||
|
@ -221,5 +221,6 @@ def main():
|
|||
|
||||
client.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
#
|
||||
# Copyright (C) 2017 mruddy
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import binascii
|
||||
from trezorlib.client import TrezorClient
|
||||
from trezorlib.transport_hid import HidTransport
|
||||
from trezorlib.tx_api import *
|
||||
from trezorlib import types_pb2 as types
|
||||
|
||||
|
||||
def get_client():
|
||||
devices = HidTransport.enumerate() # List all connected TREZORs on USB
|
||||
if len(devices) == 0: # Check whether we found any
|
||||
return None
|
||||
transport = HidTransport(devices[0]) # Use first connected device
|
||||
return TrezorClient(transport) # Creates object for communicating with TREZOR
|
||||
|
||||
|
||||
def get_txapi():
|
||||
coin = raw_input('Which coin {Bitcoin, Testnet, Litecoin}? ').strip()
|
||||
if coin not in {'Bitcoin', 'Testnet', 'Litecoin'}:
|
||||
return None, None
|
||||
txapi_lookup = {
|
||||
'Bitcoin': TxApiBitcoin,
|
||||
'Testnet': TxApiTestnet,
|
||||
'Litecoin': TxApiLitecoin
|
||||
}
|
||||
return coin, txapi_lookup[coin]
|
||||
|
||||
|
||||
def main():
|
||||
client = get_client()
|
||||
if not client:
|
||||
print('No TREZOR connected')
|
||||
return
|
||||
|
||||
print()
|
||||
print('Welcome to the user-unfriendly transaction signing tool')
|
||||
print('USE AT YOUR OWN RISK!!!')
|
||||
print()
|
||||
|
||||
coin, txapi = get_txapi()
|
||||
if not txapi:
|
||||
print('Coin not supported')
|
||||
return
|
||||
|
||||
client.set_tx_api(txapi)
|
||||
|
||||
inputs = []
|
||||
|
||||
while True:
|
||||
print()
|
||||
prev_in_hash = raw_input('Previous input hash (empty to move on): ').strip()
|
||||
if prev_in_hash == '':
|
||||
break
|
||||
prev_in_vout = raw_input('Previous input index: ').strip()
|
||||
addrn = raw_input("Node path to sign with (e.g.- %s/0'/0/0): " % coin).strip()
|
||||
inputs.append(types.TxInputType(
|
||||
prev_hash = binascii.unhexlify(prev_in_hash),
|
||||
prev_index = int(prev_in_vout, 10),
|
||||
address_n = client.expand_path(addrn)
|
||||
))
|
||||
|
||||
outputs = []
|
||||
|
||||
while True:
|
||||
print()
|
||||
out_addr = raw_input('Pay to address (empty to move on): ').strip()
|
||||
if out_addr == '':
|
||||
break
|
||||
out_amount = raw_input('Amount (in satoshis): ').strip()
|
||||
outputs.append(types.TxOutputType(
|
||||
amount = int(out_amount, 10),
|
||||
script_type = types.PAYTOADDRESS,
|
||||
address = out_addr
|
||||
))
|
||||
|
||||
(signatures, serialized_tx) = client.sign_tx(coin, inputs, outputs)
|
||||
|
||||
client.close()
|
||||
|
||||
print()
|
||||
print('Signed Transaction:', binascii.hexlify(serialized_tx))
|
||||
|
||||
# note: these api's are useful for checking and sending the output of this tool:
|
||||
# https://btc.blockr.io/tx/push -or- https://live.blockcypher.com/btc/pushtx/
|
||||
# https://tbtc.blockr.io/tx/push -or- https://live.blockcypher.com/btc-testnet/pushtx/
|
||||
# https://ltc.blockr.io/tx/push -or - https://live.blockcypher.com/ltc/pushtx/
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
16
tox.ini
16
tox.ini
|
@ -1,6 +1,16 @@
|
|||
[tox]
|
||||
envlist = py27,py34,py35,py36
|
||||
envlist =
|
||||
py33,
|
||||
py34,
|
||||
py35,
|
||||
py36,
|
||||
|
||||
[testenv]
|
||||
deps = -rrequirements.txt
|
||||
commands = python -m compileall trezorlib/
|
||||
deps =
|
||||
-rrequirements.txt
|
||||
pytest
|
||||
mock
|
||||
commands =
|
||||
python -m compileall trezorlib/
|
||||
python trezorctl --help
|
||||
python -m pytest --pyarg trezorlib.tests.unit_tests
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
__version__ = '0.9.1'
|
|
@ -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
|
@ -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,
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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')
|
|
@ -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')
|
|
@ -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()
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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),
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue