mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-23 06:48:16 +00:00
Merge branch 'master' into matejcik/client-split
This commit is contained in:
commit
2bb7088281
42
README.md
42
README.md
@ -1,17 +1,13 @@
|
||||
python-trezor
|
||||
=============
|
||||
# python-trezor
|
||||
|
||||
[![image](https://travis-ci.org/trezor/python-trezor.svg?branch=master)](https://travis-ci.org/trezor/python-trezor)
|
||||
|
||||
[![image](https://badges.gitter.im/trezor/community.svg)](https://gitter.im/trezor/community)
|
||||
[![image](https://travis-ci.org/trezor/python-trezor.svg?branch=master)](https://travis-ci.org/trezor/python-trezor) [![repology](https://repology.org/badge/tiny-repos/python:trezor.svg)](https://repology.org/metapackage/python:trezor) [![image](https://badges.gitter.im/trezor/community.svg)](https://gitter.im/trezor/community)
|
||||
|
||||
Python library and commandline client for communicating with TREZOR
|
||||
Hardware Wallet
|
||||
|
||||
See <https://trezor.io> for more information
|
||||
|
||||
Install
|
||||
-------
|
||||
## Install
|
||||
|
||||
Python-trezor requires Python 3.3 or higher, and libusb 1.0. The easiest
|
||||
way to install it is with `pip`. The rest of this guide assumes you have
|
||||
@ -79,8 +75,7 @@ cd /usr/ports/security/py-trezor
|
||||
make install clean
|
||||
```
|
||||
|
||||
Command line client (trezorctl)
|
||||
------------------------------
|
||||
## Command line client (trezorctl)
|
||||
|
||||
The included `trezorctl` python script can perform various tasks such as
|
||||
changing setting in the Trezor, signing transactions, retrieving account
|
||||
@ -91,38 +86,35 @@ 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/)).
|
||||
|
||||
Python Library
|
||||
--------------
|
||||
## Python Library
|
||||
|
||||
You can use this python library to interact with a Bitcoin Trezor and
|
||||
use its capabilities in your application. See examples here in the
|
||||
[tools/](tools/) sub folder.
|
||||
|
||||
PIN Entering
|
||||
------------
|
||||
## PIN Entering
|
||||
|
||||
When you are asked for PIN, you have to enter scrambled PIN. Follow the
|
||||
numbers shown on TREZOR display and enter the their positions using the
|
||||
numeric keyboard mapping:
|
||||
|
||||
<table>
|
||||
<tr><td>7<td>8<td>9
|
||||
<tr><td>4<td>5<td>6
|
||||
<tr><td>1<td>2<td>3
|
||||
</table>
|
||||
| | | |
|
||||
|---|---|---|
|
||||
| 7 | 8 | 9 |
|
||||
| 4 | 5 | 6 |
|
||||
| 1 | 2 | 3 |
|
||||
|
||||
Example: your PIN is **1234** and TREZOR is displaying the following:
|
||||
|
||||
<table>
|
||||
<tr><td>2<td>8<td>3
|
||||
<tr><td>5<td>4<td>6
|
||||
<tr><td>7<td>9<td>1
|
||||
</table>
|
||||
| | | |
|
||||
|---|---|---|
|
||||
| 2 | 8 | 3 |
|
||||
| 5 | 4 | 6 |
|
||||
| 7 | 9 | 1 |
|
||||
|
||||
You have to enter: **3795**
|
||||
|
||||
Contributing
|
||||
------------
|
||||
## Contributing
|
||||
|
||||
Python-trezor pulls coins info and protobuf messages from
|
||||
[trezor-common](https://github.com/trezor/trezor-common) repository. If
|
||||
|
1
setup.py
1
setup.py
@ -69,6 +69,7 @@ class PrebuildCommand(Command):
|
||||
try:
|
||||
proto_srcs = glob.glob(os.path.join(TREZOR_COMMON, "protob", "*.proto"))
|
||||
subprocess.check_call([
|
||||
sys.executable,
|
||||
os.path.join(TREZOR_COMMON, "protob", "pb2py"),
|
||||
"-o", os.path.join(CWD, "trezorlib", "messages"),
|
||||
"-P", "..protobuf",
|
||||
|
44
trezorctl
44
trezorctl
@ -38,6 +38,7 @@ from trezorlib import messages as proto
|
||||
from trezorlib import protobuf
|
||||
from trezorlib import stellar
|
||||
from trezorlib import tools
|
||||
from trezorlib import ripple
|
||||
|
||||
|
||||
class ChoiceType(click.Choice):
|
||||
@ -575,6 +576,10 @@ def sign_tx(connect, coin):
|
||||
sequence = click.prompt('Sequence Number to use (RBF opt-in enabled by default)', type=int, default=0xfffffffd)
|
||||
script_type = click.prompt('Input type', type=CHOICE_INPUT_SCRIPT_TYPE, default=default_script_type(address_n))
|
||||
script_type = script_type if isinstance(script_type, int) else CHOICE_INPUT_SCRIPT_TYPE.typemap[script_type]
|
||||
if txapi.bip115:
|
||||
prev_output = txapi.get_tx(binascii.hexlify(prev_hash).decode("utf-8")).bin_outputs[prev_index]
|
||||
prev_blockhash = prev_output.block_hash
|
||||
prev_blockheight = prev_output.block_height
|
||||
inputs.append(proto.TxInputType(
|
||||
address_n=address_n,
|
||||
prev_hash=prev_hash,
|
||||
@ -582,8 +587,15 @@ def sign_tx(connect, coin):
|
||||
amount=amount,
|
||||
script_type=script_type,
|
||||
sequence=sequence,
|
||||
prev_block_hash_bip115=prev_blockhash,
|
||||
prev_block_height_bip115=prev_blockheight,
|
||||
))
|
||||
|
||||
if txapi.bip115:
|
||||
current_block_height = txapi.current_height()
|
||||
block_height = current_block_height - 300 # Zencash recommendation for the better protection
|
||||
block_hash = txapi.get_block_hash(block_height)
|
||||
|
||||
outputs = []
|
||||
while True:
|
||||
click.echo()
|
||||
@ -603,6 +615,8 @@ def sign_tx(connect, coin):
|
||||
address=address,
|
||||
amount=amount,
|
||||
script_type=script_type,
|
||||
block_hash_bip115=block_hash[::-1], # Blockhash passed in reverse order
|
||||
block_height_bip115=block_height
|
||||
))
|
||||
|
||||
tx_version = click.prompt('Transaction version', type=int, default=2)
|
||||
@ -1050,6 +1064,36 @@ def stellar_sign_transaction(connect, b64envelope, address, network_passphrase):
|
||||
|
||||
return base64.b64encode(resp.signature)
|
||||
|
||||
|
||||
#
|
||||
# Ripple functions
|
||||
#
|
||||
@cli.command(help='Get Ripple address')
|
||||
@click.option('-n', '--address', required=True, help="BIP-32 path to key, e.g. m/44'/144'/0'/0/0")
|
||||
@click.option('-d', '--show-display', is_flag=True)
|
||||
@click.pass_obj
|
||||
def ripple_get_address(connect, address, show_display):
|
||||
client = connect()
|
||||
address_n = tools.parse_path(address)
|
||||
return ripple.get_address(client, address_n, show_display)
|
||||
|
||||
|
||||
@cli.command(help='Sign Ripple transaction')
|
||||
@click.option('-n', '--address', required=True, help="BIP-32 path to key, e.g. m/44'/144'/0'/0/0")
|
||||
@click.option('-f', '--file', type=click.File('r'), default='-', help='Transaction in JSON format')
|
||||
@click.pass_obj
|
||||
def ripple_sign_tx(connect, address, file):
|
||||
client = connect()
|
||||
address_n = tools.parse_path(address)
|
||||
msg = ripple.create_sign_tx_msg(json.load(file))
|
||||
|
||||
result = ripple.sign_tx(client, address_n, msg)
|
||||
click.echo("Signature:")
|
||||
click.echo(binascii.hexlify(result.signature))
|
||||
click.echo()
|
||||
click.echo("Serialized tx including the signature:")
|
||||
click.echo(binascii.hexlify(result.serialized_tx))
|
||||
|
||||
#
|
||||
# Main
|
||||
#
|
||||
|
@ -39,8 +39,9 @@ def _insight_for_coin(coin):
|
||||
if not url:
|
||||
return None
|
||||
zcash = coin['coin_name'].lower().startswith('zcash')
|
||||
bip115 = coin['bip115']
|
||||
network = 'insight_{}'.format(coin['coin_name'].lower().replace(' ', '_'))
|
||||
return TxApiInsight(network=network, url=url, zcash=zcash)
|
||||
return TxApiInsight(network=network, url=url, zcash=zcash, bip115=bip115)
|
||||
|
||||
|
||||
# exported variables
|
||||
|
59
trezorlib/ripple.py
Normal file
59
trezorlib/ripple.py
Normal file
@ -0,0 +1,59 @@
|
||||
# This file is part of the Trezor project.
|
||||
#
|
||||
# Copyright (C) 2012-2018 SatoshiLabs and contributors
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License version 3
|
||||
# as published by the Free Software Foundation.
|
||||
#
|
||||
# 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 License along with this library.
|
||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
|
||||
import base64
|
||||
import struct
|
||||
|
||||
from . import messages
|
||||
from . import tools
|
||||
from .client import field
|
||||
from .client import expect
|
||||
|
||||
|
||||
@field('address')
|
||||
@expect(messages.RippleAddress)
|
||||
def get_address(client, address_n, show_display=False):
|
||||
return client.call(
|
||||
messages.RippleGetAddress(
|
||||
address_n=address_n, show_display=show_display))
|
||||
|
||||
|
||||
@expect(messages.RippleSignedTx)
|
||||
def sign_tx(client, address_n, msg: messages.RippleSignTx):
|
||||
msg.address_n = address_n
|
||||
return client.call(msg)
|
||||
|
||||
|
||||
def create_sign_tx_msg(transaction) -> messages.RippleSignTx:
|
||||
if not all(transaction.get(k) for k in ("Fee", "Sequence", "TransactionType", "Amount", "Destination")):
|
||||
raise ValueError("Some of the required fields missing (Fee, Sequence, TransactionType, Amount, Destination")
|
||||
if transaction["TransactionType"] != "Payment":
|
||||
raise ValueError("Only Payment transaction type is supported")
|
||||
|
||||
return messages.RippleSignTx(
|
||||
fee=transaction.get("Fee"),
|
||||
sequence=transaction.get("Sequence"),
|
||||
flags=transaction.get("Flags"),
|
||||
last_ledger_sequence=transaction.get("LastLedgerSequence"),
|
||||
payment=_create_payment(transaction),
|
||||
)
|
||||
|
||||
|
||||
def _create_payment(transaction) -> messages.RipplePayment:
|
||||
return messages.RipplePayment(
|
||||
amount=transaction.get("Amount"),
|
||||
destination=transaction.get("Destination")
|
||||
)
|
@ -83,9 +83,7 @@ def parse_transaction_bytes(tx_bytes):
|
||||
tx - a StellarSignTx describing the transaction header
|
||||
operations - an array of protobuf message objects for each operation
|
||||
"""
|
||||
tx = messages.StellarSignTx(
|
||||
protocol_version=1
|
||||
)
|
||||
tx = messages.StellarSignTx()
|
||||
unpacker = xdrlib.Unpacker(tx_bytes)
|
||||
|
||||
tx.source_account = _xdr_read_address(unpacker)
|
||||
|
@ -287,100 +287,3 @@ class TestMsgEthereumSigntx(TrezorTest):
|
||||
to=unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
|
||||
value=12345678901234567890
|
||||
)
|
||||
|
||||
def test_ethereum_signtx_nodata_eip155(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
with self.client:
|
||||
self.client.set_expected_responses([
|
||||
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
|
||||
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
|
||||
proto.EthereumTxRequest(),
|
||||
])
|
||||
|
||||
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=unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
|
||||
value=100000000000000000,
|
||||
chain_id=3)
|
||||
assert sig_v == 41
|
||||
assert hexlify(sig_r) == b'a90d0bc4f8d63be69453dd62f2bb5fff53c610000abf956672564d8a654d401a'
|
||||
assert hexlify(sig_s) == b'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=unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
|
||||
value=100000000000000000,
|
||||
chain_id=3)
|
||||
assert sig_v == 42
|
||||
assert hexlify(sig_r) == b'699428a6950e23c6843f1bf3754f847e64e047e829978df80d55187d19a401ce'
|
||||
assert hexlify(sig_s) == b'087343d0a3a2f10842218ffccb146b59a8431b6245ab389fde22dc833f171e6e'
|
||||
|
||||
def test_ethereum_signtx_data_eip155(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
with self.client:
|
||||
self.client.set_expected_responses([
|
||||
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
|
||||
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
|
||||
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
|
||||
proto.EthereumTxRequest(),
|
||||
])
|
||||
|
||||
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=unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
|
||||
value=100000000000000000,
|
||||
data=b'\0',
|
||||
chain_id=3)
|
||||
assert sig_v == 42
|
||||
assert hexlify(sig_r) == b'ba85b622a8bb82606ba96c132e81fa8058172192d15bc41d7e57c031bca17df4'
|
||||
assert hexlify(sig_s) == b'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=unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
|
||||
value=100000000000000000,
|
||||
data=b'ABCDEFGHIJKLMNOP' * 256 + b'!!!',
|
||||
chain_id=3)
|
||||
assert sig_v == 42
|
||||
assert hexlify(sig_r) == b'd021c98f92859c8db5e4de2f0e410a8deb0c977eb1a631e323ebf7484bd0d79a'
|
||||
assert hexlify(sig_s) == b'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=unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
|
||||
value=0,
|
||||
data=b'\0',
|
||||
chain_id=3)
|
||||
assert sig_v == 42
|
||||
assert hexlify(sig_r) == b'dd52f026972a83c56b7dea356836fcfc70a68e3b879cdc8ef2bb5fea23e0a7aa'
|
||||
assert hexlify(sig_s) == b'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=unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
|
||||
value=0,
|
||||
data=b'\0',
|
||||
chain_id=3)
|
||||
assert sig_v == 42
|
||||
assert hexlify(sig_r) == b'f7505f709d5999343aea3c384034c62d0514336ff6c6af65582006f708f81503'
|
||||
assert hexlify(sig_s) == b'44e09e29a4b6247000b46ddc94fe391e94deb2b39ad6ac6398e6db5bec095ba9'
|
||||
|
177
trezorlib/tests/device_tests/test_msg_ethereum_signtx_eip155.py
Normal file
177
trezorlib/tests/device_tests/test_msg_ethereum_signtx_eip155.py
Normal file
@ -0,0 +1,177 @@
|
||||
# This file is part of the Trezor project.
|
||||
#
|
||||
# Copyright (C) 2012-2018 SatoshiLabs and contributors
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License version 3
|
||||
# as published by the Free Software Foundation.
|
||||
#
|
||||
# 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 License along with this library.
|
||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
|
||||
from binascii import unhexlify, hexlify
|
||||
import pytest
|
||||
|
||||
from .common import TrezorTest
|
||||
from trezorlib import messages as proto
|
||||
|
||||
|
||||
@pytest.mark.ethereum
|
||||
class TestMsgEthereumSigntxChainId(TrezorTest):
|
||||
def test_ethereum_signtx_eip155(self):
|
||||
|
||||
# chain_id, nonce, sig_v, sig_r, sig_s, value, gas_limit, data
|
||||
VECTORS = [
|
||||
(
|
||||
3,
|
||||
0,
|
||||
41,
|
||||
b"a90d0bc4f8d63be69453dd62f2bb5fff53c610000abf956672564d8a654d401a",
|
||||
b"544a2e57bc8b4da18660a1e6036967ea581cc635f5137e3ba97a750867c27cf2",
|
||||
100000000000000000,
|
||||
21000,
|
||||
None,
|
||||
),
|
||||
(
|
||||
3,
|
||||
1,
|
||||
42,
|
||||
b"699428a6950e23c6843f1bf3754f847e64e047e829978df80d55187d19a401ce",
|
||||
b"087343d0a3a2f10842218ffccb146b59a8431b6245ab389fde22dc833f171e6e",
|
||||
100000000000000000,
|
||||
21000,
|
||||
None,
|
||||
),
|
||||
(
|
||||
3,
|
||||
2,
|
||||
42,
|
||||
b"ba85b622a8bb82606ba96c132e81fa8058172192d15bc41d7e57c031bca17df4",
|
||||
b"6473b75997634b6f692f8d672193591d299d5bf1c2d6e51f1a14ed0530b91c7d",
|
||||
100000000000000000,
|
||||
21004,
|
||||
b"\0",
|
||||
),
|
||||
(
|
||||
3,
|
||||
3,
|
||||
42,
|
||||
b"d021c98f92859c8db5e4de2f0e410a8deb0c977eb1a631e323ebf7484bd0d79a",
|
||||
b"2c0e9defc9b1e895dc9520ff25ba3c635b14ad70aa86a5ad6c0a3acb82b569b6",
|
||||
100000000000000000,
|
||||
299732,
|
||||
b"ABCDEFGHIJKLMNOP" * 256 + b"!!!",
|
||||
),
|
||||
(
|
||||
3,
|
||||
4,
|
||||
42,
|
||||
b"dd52f026972a83c56b7dea356836fcfc70a68e3b879cdc8ef2bb5fea23e0a7aa",
|
||||
b"079285fe579c9a2da25c811b1c5c0a74cd19b6301ee42cf20ef7b3b1353f7242",
|
||||
0,
|
||||
21004,
|
||||
b"\0",
|
||||
),
|
||||
(
|
||||
1,
|
||||
1,
|
||||
37,
|
||||
b"bae6198fdc87ccad6256e543617a34d052bfd17ae3be0bec7fbf8ea34bf9c930",
|
||||
b"7d12f625f3e54700b6ed14ab669f45a8a2b5552c39f0781b0ab3796f19e6b4d1",
|
||||
0,
|
||||
21004,
|
||||
b"\0",
|
||||
),
|
||||
(
|
||||
255,
|
||||
1,
|
||||
546,
|
||||
b"7597a40719509ae3850d2eba808b7b2f7d272fda316e1321e5ebcc911e9f1b0d",
|
||||
b"269dd69248273820f65b43d8824bb7aff1aa4e35ee663a5433a5df8f0c47dc31",
|
||||
0,
|
||||
21004,
|
||||
b"\0",
|
||||
),
|
||||
(
|
||||
256,
|
||||
1,
|
||||
547,
|
||||
b"64e9821db2001ff5dff13c9d8c7fb0701ff860f5f95155d378fb9fcc06088f28",
|
||||
b"4d03f339afed717e2155f044a6b0a895b5ac98343f1745e7525870c2046c36bc",
|
||||
0,
|
||||
21004,
|
||||
b"\0",
|
||||
),
|
||||
(
|
||||
65535,
|
||||
1,
|
||||
131106,
|
||||
b"6f2275808dc328184d7aa019d0a68f8dd8234969576a477670934145bb358969",
|
||||
b"2be1ff9045bccff9ba3d6d5c7789a52c52c9679526dd3ec349caa318c3d055ff",
|
||||
0,
|
||||
21004,
|
||||
b"\0",
|
||||
),
|
||||
(
|
||||
65536,
|
||||
1,
|
||||
131107,
|
||||
b"e16e35afe534a46e3e4cf09f355cbf02edc01937c2b444238162c2aca79037b8",
|
||||
b"1083b84e21b1cbad95c7ea9792818c18fa716aa25951c5341b48732d611a396a",
|
||||
0,
|
||||
21004,
|
||||
b"\0",
|
||||
),
|
||||
(
|
||||
16777215,
|
||||
1,
|
||||
33554466,
|
||||
b"f9753ee68cf2af20638cc753945d157039504f82d6d6fe0ec98806b64366c551",
|
||||
b"056b57a69d88a4b71fba993c580d8bbf04f2c857f97a8b7d4b2892b5dafa9114",
|
||||
0,
|
||||
21004,
|
||||
b"\0",
|
||||
),
|
||||
(
|
||||
16777216,
|
||||
1,
|
||||
33554468,
|
||||
b"23a5399650c6efa46a25a0a966a29119830d9c587b6b93da43cb0be6d3c69059",
|
||||
b"5a6eddffc62317a6a3801608071655a9c43423aef9705b2f5df4212942265c37",
|
||||
0,
|
||||
21004,
|
||||
b"\0",
|
||||
),
|
||||
(
|
||||
2147483629,
|
||||
1,
|
||||
4294967294,
|
||||
b"6a996586f1ea19afe9cb0ca44dec6bb8643cdf53b5cf148323c94a32a04b087d",
|
||||
b"0d086b208df6826657edf98010972b2649b323466a7ea4b67e7285fb9e829481",
|
||||
0,
|
||||
21004,
|
||||
b"\0",
|
||||
),
|
||||
]
|
||||
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
for ci, n, sv, sr, ss, v, gl, d in VECTORS:
|
||||
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
|
||||
n=[0x80000000 | 44, 0x80000000 | 1, 0x80000000, 0, 0],
|
||||
nonce=n,
|
||||
gas_price=20000000000,
|
||||
gas_limit=gl,
|
||||
to=unhexlify("8ea7a3fccc211ed48b763b4164884ddbcf3b0a98"),
|
||||
value=v,
|
||||
chain_id=ci,
|
||||
data=d,
|
||||
)
|
||||
assert sig_v == sv
|
||||
assert hexlify(sig_r) == sr
|
||||
assert hexlify(sig_s) == ss
|
54
trezorlib/tests/device_tests/test_msg_ripple_get_address.py
Normal file
54
trezorlib/tests/device_tests/test_msg_ripple_get_address.py
Normal file
@ -0,0 +1,54 @@
|
||||
# This file is part of the Trezor project.
|
||||
#
|
||||
# Copyright (C) 2012-2018 SatoshiLabs and contributors
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License version 3
|
||||
# as published by the Free Software Foundation.
|
||||
#
|
||||
# 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 License along with this library.
|
||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
|
||||
import pytest
|
||||
|
||||
from .common import TrezorTest
|
||||
from .conftest import TREZOR_VERSION
|
||||
from binascii import hexlify
|
||||
from trezorlib.client import CallException
|
||||
from trezorlib.ripple import get_address
|
||||
from trezorlib.tools import parse_path
|
||||
|
||||
|
||||
@pytest.mark.ripple
|
||||
@pytest.mark.skip_t1 # T1 support is not planned
|
||||
@pytest.mark.xfail(TREZOR_VERSION == 2, reason="T2 support is not yet finished")
|
||||
class TestMsgRippleGetAddress(TrezorTest):
|
||||
|
||||
def test_ripple_get_address(self):
|
||||
# data from https://iancoleman.io/bip39/#english
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
address = get_address(self.client, parse_path("m/44'/144'/0'/0/0"))
|
||||
assert address == 'rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H'
|
||||
address = get_address(self.client, parse_path("m/44'/144'/0'/0/1"))
|
||||
assert address == 'rBKz5MC2iXdoS3XgnNSYmF69K1Yo4NS3Ws'
|
||||
address = get_address(self.client, parse_path("m/44'/144'/1'/0/0"))
|
||||
assert address == 'rJX2KwzaLJDyFhhtXKi3htaLfaUH2tptEX'
|
||||
|
||||
def test_ripple_get_address_other(self):
|
||||
# data from https://github.com/you21979/node-ripple-bip32/blob/master/test/test.js
|
||||
self.client.load_device_by_mnemonic(
|
||||
mnemonic='armed bundle pudding lazy strategy impulse where identify submit weekend physical antenna flight social acoustic absurd whip snack decide blur unfold fiction pumpkin athlete',
|
||||
pin='',
|
||||
passphrase_protection=False,
|
||||
label='test',
|
||||
language='english')
|
||||
address = get_address(self.client, parse_path("m/44'/144'/0'/0/0"))
|
||||
assert address == 'r4ocGE47gm4G4LkA9mriVHQqzpMLBTgnTY'
|
||||
address = get_address(self.client, parse_path("m/44'/144'/0'/0/1"))
|
||||
assert address == 'rUt9ULSrUvfCmke8HTFU1szbmFpWzVbBXW'
|
86
trezorlib/tests/device_tests/test_msg_ripple_sign_tx.py
Normal file
86
trezorlib/tests/device_tests/test_msg_ripple_sign_tx.py
Normal file
@ -0,0 +1,86 @@
|
||||
# This file is part of the Trezor project.
|
||||
#
|
||||
# Copyright (C) 2012-2018 SatoshiLabs and contributors
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License version 3
|
||||
# as published by the Free Software Foundation.
|
||||
#
|
||||
# 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 License along with this library.
|
||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
|
||||
import pytest
|
||||
|
||||
from .common import TrezorTest
|
||||
from .conftest import TREZOR_VERSION
|
||||
from binascii import unhexlify
|
||||
from trezorlib import messages
|
||||
from trezorlib import ripple
|
||||
from trezorlib.client import CallException
|
||||
from trezorlib.tools import parse_path
|
||||
|
||||
|
||||
@pytest.mark.ripple
|
||||
@pytest.mark.skip_t1 # T1 support is not planned
|
||||
@pytest.mark.xfail(TREZOR_VERSION == 2, reason="T2 support is not yet finished")
|
||||
class TestMsgRippleSignTx(TrezorTest):
|
||||
|
||||
def test_ripple_sign_simple_tx(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
msg = ripple.create_sign_tx_msg({
|
||||
"TransactionType": "Payment",
|
||||
"Destination": "rBKz5MC2iXdoS3XgnNSYmF69K1Yo4NS3Ws",
|
||||
"Amount": 100000000,
|
||||
"Flags": 0x80000000,
|
||||
"Fee": 100000,
|
||||
"Sequence": 25,
|
||||
})
|
||||
resp = ripple.sign_tx(self.client, parse_path("m/44'/144'/0'/0/0"), msg)
|
||||
assert resp.signature == unhexlify('3045022100e243ef623675eeeb95965c35c3e06d63a9fc68bb37e17dc87af9c0af83ec057e02206ca8aa5eaab8396397aef6d38d25710441faf7c79d292ee1d627df15ad9346c0')
|
||||
assert resp.serialized_tx == unhexlify('12000022800000002400000019614000000005f5e1006840000000000186a0732102131facd1eab748d6cddc492f54b04e8c35658894f4add2232ebc5afe7521dbe474473045022100e243ef623675eeeb95965c35c3e06d63a9fc68bb37e17dc87af9c0af83ec057e02206ca8aa5eaab8396397aef6d38d25710441faf7c79d292ee1d627df15ad9346c081148fb40e1ffa5d557ce9851a535af94965e0dd098883147148ebebf7304ccdf1676fefcf9734cf1e780826')
|
||||
|
||||
msg = ripple.create_sign_tx_msg({
|
||||
"TransactionType": "Payment",
|
||||
"Destination": "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H",
|
||||
"Amount": 1,
|
||||
"Fee": 10,
|
||||
"Sequence": 1,
|
||||
})
|
||||
resp = ripple.sign_tx(self.client, parse_path("m/44'/144'/0'/0/2"), msg)
|
||||
assert resp.signature == unhexlify('3044022069900e6e578997fad5189981b74b16badc7ba8b9f1052694033fa2779113ddc002206c8006ada310edf099fb22c0c12073550c8fc73247b236a974c5f1144831dd5f')
|
||||
assert resp.serialized_tx == unhexlify('1200002280000000240000000161400000000000000168400000000000000a732103dbed1e77cb91a005e2ec71afbccce5444c9be58276665a3859040f692de8fed274463044022069900e6e578997fad5189981b74b16badc7ba8b9f1052694033fa2779113ddc002206c8006ada310edf099fb22c0c12073550c8fc73247b236a974c5f1144831dd5f8114bdf86f3ae715ba346b7772ea0e133f48828b766483148fb40e1ffa5d557ce9851a535af94965e0dd0988')
|
||||
|
||||
msg = ripple.create_sign_tx_msg({
|
||||
"TransactionType": "Payment",
|
||||
"Destination": "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H",
|
||||
"Amount": 100000009,
|
||||
"Flags": 0,
|
||||
"Fee": 100,
|
||||
"Sequence": 100,
|
||||
"LastLedgerSequence": 333111,
|
||||
})
|
||||
resp = ripple.sign_tx(self.client, parse_path("m/44'/144'/0'/0/2"), msg)
|
||||
assert resp.signature == unhexlify('30440220025a9cc2809527799e6ea5eb029488dc46c6632a8ca1ed7d3ca2d9211e80403a02202cfe8604e6c6d1d3c64246626cc1a1a9bd8a2163b969e561c6adda5dca8fc2a5')
|
||||
assert resp.serialized_tx == unhexlify('12000022800000002400000064201b00051537614000000005f5e109684000000000000064732103dbed1e77cb91a005e2ec71afbccce5444c9be58276665a3859040f692de8fed2744630440220025a9cc2809527799e6ea5eb029488dc46c6632a8ca1ed7d3ca2d9211e80403a02202cfe8604e6c6d1d3c64246626cc1a1a9bd8a2163b969e561c6adda5dca8fc2a58114bdf86f3ae715ba346b7772ea0e133f48828b766483148fb40e1ffa5d557ce9851a535af94965e0dd0988')
|
||||
|
||||
def test_ripple_sign_invalid_fee(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
msg = ripple.create_sign_tx_msg({
|
||||
"TransactionType": "Payment",
|
||||
"Destination": "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H",
|
||||
"Amount": 1,
|
||||
"Flags": 1,
|
||||
"Fee": 1,
|
||||
"Sequence": 1,
|
||||
})
|
||||
with pytest.raises(CallException) as exc:
|
||||
ripple.sign_tx(self.client, parse_path("m/44'/144'/0'/0/2"), msg)
|
||||
assert exc.value.args[0] == messages.FailureType.ProcessError
|
||||
assert exc.value.args[1].endswith('Fee must be in the range of 10 to 10,000 drops')
|
@ -26,7 +26,6 @@ from trezorlib.tools import parse_path
|
||||
|
||||
|
||||
@pytest.mark.stellar
|
||||
@pytest.mark.xfail(TREZOR_VERSION == 2, reason="T2 support is not yet finished")
|
||||
class TestMsgStellarGetAddress(TrezorTest):
|
||||
|
||||
def test_stellar_get_address(self):
|
||||
@ -47,7 +46,7 @@ class TestMsgStellarGetAddress(TrezorTest):
|
||||
address = self.client.stellar_get_address(parse_path(stellar.DEFAULT_BIP32_PATH))
|
||||
assert address == 'GDRXE2BQUC3AZNPVFSCEZ76NJ3WWL25FYFK6RGZGIEKWE4SOOHSUJUJ6'
|
||||
|
||||
address = self.client.stellar_get_address(parse_path("m/44h/148h/1h"))
|
||||
address = self.client.stellar_get_address(parse_path("m/44h/148h/1h"), show_display=True)
|
||||
assert address == 'GBAW5XGWORWVFE2XTJYDTLDHXTY2Q2MO73HYCGB3XMFMQ562Q2W2GJQX'
|
||||
|
||||
def test_stellar_get_address_get_pubkey(self):
|
||||
|
@ -20,20 +20,19 @@ from .common import TrezorTest
|
||||
from .conftest import TREZOR_VERSION
|
||||
from binascii import hexlify
|
||||
from trezorlib import stellar
|
||||
from trezorlib import messages as proto
|
||||
from trezorlib import messages
|
||||
from trezorlib.client import CallException
|
||||
from trezorlib.tools import parse_path
|
||||
|
||||
|
||||
@pytest.mark.stellar
|
||||
@pytest.mark.xfail(TREZOR_VERSION == 2, reason="T2 support is not yet finished")
|
||||
class TestMsgStellarGetPublicKey(TrezorTest):
|
||||
|
||||
def test_stellar_get_public_key(self):
|
||||
self.setup_mnemonic_nopin_nopassphrase()
|
||||
|
||||
# GAK5MSF74TJW6GLM7NLTL76YZJKM2S4CGP3UH4REJHPHZ4YBZW2GSBPW
|
||||
response = self.client.stellar_get_public_key(parse_path(stellar.DEFAULT_BIP32_PATH))
|
||||
response = self.client.stellar_get_public_key(parse_path(stellar.DEFAULT_BIP32_PATH), show_display=True)
|
||||
assert hexlify(response) == b'15d648bfe4d36f196cfb5735ffd8ca54cd4b8233f743f22449de7cf301cdb469'
|
||||
assert stellar.address_from_public_key(response) == 'GAK5MSF74TJW6GLM7NLTL76YZJKM2S4CGP3UH4REJHPHZ4YBZW2GSBPW'
|
||||
|
||||
@ -44,8 +43,8 @@ class TestMsgStellarGetPublicKey(TrezorTest):
|
||||
self.client.stellar_get_public_key(parse_path('m/0/1'))
|
||||
|
||||
if TREZOR_VERSION == 1:
|
||||
assert exc.value.args[0] == proto.FailureType.ProcessError
|
||||
assert exc.value.args[0] == messages.FailureType.ProcessError
|
||||
assert exc.value.args[1].endswith('Failed to derive private key')
|
||||
else:
|
||||
assert exc.value.args[0] == proto.FailureType.FirmwareError
|
||||
assert exc.value.args[0] == messages.FailureType.FirmwareError
|
||||
assert exc.value.args[1].endswith('Firmware error')
|
||||
|
@ -57,7 +57,6 @@ import pytest
|
||||
|
||||
|
||||
@pytest.mark.stellar
|
||||
@pytest.mark.xfail(TREZOR_VERSION == 2, reason="T2 support is not yet finished")
|
||||
class TestMsgStellarSignTransaction(TrezorTest):
|
||||
|
||||
ADDRESS_N = parse_path(stellar.DEFAULT_BIP32_PATH)
|
||||
@ -158,7 +157,6 @@ class TestMsgStellarSignTransaction(TrezorTest):
|
||||
|
||||
def _create_msg(self) -> proto.StellarSignTx:
|
||||
tx = proto.StellarSignTx()
|
||||
tx.protocol_version = 1
|
||||
tx.source_account = 'GAK5MSF74TJW6GLM7NLTL76YZJKM2S4CGP3UH4REJHPHZ4YBZW2GSBPW'
|
||||
tx.fee = 100
|
||||
tx.sequence_number = 0x100000000
|
||||
|
@ -18,9 +18,11 @@ import os
|
||||
|
||||
from trezorlib import coins
|
||||
from trezorlib import tx_api
|
||||
import binascii
|
||||
|
||||
TxApiBitcoin = coins.tx_api['Bitcoin']
|
||||
TxApiTestnet = tx_api.TxApiInsight("insight_testnet")
|
||||
TxApiZencash = coins.tx_api['Zencash']
|
||||
|
||||
tests_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
@ -42,3 +44,13 @@ def test_tx_api_gettx():
|
||||
|
||||
TxApiTestnet.get_tx('6f90f3c7cbec2258b0971056ef3fe34128dbde30daa9c0639a898f9977299d54')
|
||||
TxApiTestnet.get_tx('d6da21677d7cca5f42fbc7631d062c9ae918a0254f7c6c22de8e8cb7fd5b8236')
|
||||
|
||||
|
||||
def test_tx_api_current_block():
|
||||
height = TxApiZencash.current_height()
|
||||
assert height > 347041
|
||||
|
||||
|
||||
def test_tx_api_get_block_hash():
|
||||
hash = TxApiZencash.get_block_hash(110000)
|
||||
assert hash == binascii.unhexlify('000000003f5d6ba1385c6cd2d4f836dfc5adf7f98834309ad67e26faef462454')
|
||||
|
@ -33,6 +33,18 @@ class TxApi(object):
|
||||
url = '%s%s/%s' % (self.url, resource, resourceid)
|
||||
return url
|
||||
|
||||
def current_height(self):
|
||||
r = requests.get(self.url + '/status?q=getBlockCount')
|
||||
j = r.json(parse_float=str)
|
||||
block_height = j['info']['blocks']
|
||||
return block_height
|
||||
|
||||
def get_block_hash(self, block_number):
|
||||
r = requests.get(self.url + '/block-index/' + str(block_number))
|
||||
j = r.json(parse_float=str)
|
||||
block_hash = binascii.unhexlify(j['blockHash'])
|
||||
return block_hash
|
||||
|
||||
def fetch_json(self, resource, resourceid):
|
||||
global cache_dir
|
||||
if cache_dir:
|
||||
@ -65,11 +77,13 @@ class TxApi(object):
|
||||
|
||||
class TxApiInsight(TxApi):
|
||||
|
||||
def __init__(self, network, url=None, zcash=None):
|
||||
def __init__(self, network, url=None, zcash=None, bip115=False):
|
||||
super().__init__(network, url)
|
||||
self.zcash = zcash
|
||||
self.bip115 = bip115
|
||||
if url:
|
||||
self.pushtx_url = url.replace('/api/', '/tx/send')
|
||||
prefix, suffix = url.rsplit('/', maxsplit=1)
|
||||
self.pushtx_url = prefix + '/tx/send'
|
||||
|
||||
def get_tx(self, txhash):
|
||||
|
||||
@ -97,6 +111,12 @@ class TxApiInsight(TxApi):
|
||||
o = t._add_bin_outputs()
|
||||
o.amount = int(Decimal(vout['value']) * 100000000)
|
||||
o.script_pubkey = binascii.unhexlify(vout['scriptPubKey']['hex'])
|
||||
if self.bip115 and o.script_pubkey[-1] == 0xb4:
|
||||
# Verify if coin implements replay protection bip115 and script includes checkblockatheight opcode. 0xb4 - is op_code (OP_CHECKBLOCKATHEIGHT)
|
||||
# <OP_32> <32-byte block hash> <OP_3> <3-byte block height> <OP_CHECKBLOCKATHEIGHT>
|
||||
tail = o.script_pubkey[-38:]
|
||||
o.block_hash = tail[1:33] # <32-byte block hash>
|
||||
o.block_height = int.from_bytes(tail[34:37], byteorder='little') # <3-byte block height>
|
||||
|
||||
if self.zcash:
|
||||
t.overwintered = data.get('fOverwintered', False)
|
||||
|
2
vendor/trezor-common
vendored
2
vendor/trezor-common
vendored
@ -1 +1 @@
|
||||
Subproject commit 2301f7034c1b7a3d1b0be5d4447d432593649a1e
|
||||
Subproject commit 32850a62624ce1a6612ff545beb706560c3716da
|
Loading…
Reference in New Issue
Block a user