ethereum/signing: all test passing, no data stream

This commit is contained in:
Tomas Susanka 2017-12-20 13:15:13 +01:00
parent dc02b322bf
commit 47b3baa30a
1 changed files with 43 additions and 16 deletions

View File

@ -3,6 +3,7 @@ from trezor.utils import unimport
from trezor.messages.EthereumSignTx import EthereumSignTx from trezor.messages.EthereumSignTx import EthereumSignTx
from trezor.messages.EthereumTxRequest import EthereumTxRequest from trezor.messages.EthereumTxRequest import EthereumTxRequest
from trezor.messages import ButtonRequestType from trezor.messages import ButtonRequestType
from trezor.messages import FailureType
from apps.common.confirm import confirm from apps.common.confirm import confirm
from trezor.ui.text import Text from trezor.ui.text import Text
from trezor.crypto import rlp from trezor.crypto import rlp
@ -15,16 +16,17 @@ MAX_CHAIN_ID = 2147483630
@unimport @unimport
async def ethereum_sign_tx(ctx, msg): async def ethereum_sign_tx(ctx, msg):
from ..common import seed
from trezor.crypto.hashlib import sha3_256 from trezor.crypto.hashlib import sha3_256
from trezor.crypto.curve import secp256k1
print(msg)
msg = sanitize(msg) msg = sanitize(msg)
check(msg) check(msg)
data_total = msg.data_length
# detect ERC - 20 token # detect ERC - 20 token
token = None token = None
if len(msg.to) == 20 and len(msg.value) == 0 and msg.data_length == 68 and len(msg.data_initial_chunk) == 68 \ if len(msg.to) == 20 and len(msg.value) == 0 and data_total == 68 and len(msg.data_initial_chunk) == 68 \
and msg.data_initial_chunk[:16] == b'a9059cbb000000000000000000000000': #todo x? and msg.data_initial_chunk[:16] == b'a9059cbb000000000000000000000000': #todo x?
token = tokens.token_by_chain_address(msg.chain_id, msg.to) token = tokens.token_by_chain_address(msg.chain_id, msg.to)
@ -39,19 +41,44 @@ async def ethereum_sign_tx(ctx, msg):
# todo layoutEthereumFee # todo layoutEthereumFee
# todo eip 155 replay protection data = bytearray()
# if chain_id != 0: data += msg.data_initial_chunk
# hash v=chain_id, r=0, s=0 data_left = data_total - len(msg.data_initial_chunk)
# hash_rlp_number(chain_id)
# hash_rlp_length(0, 0)
# hash_rlp_length(0, 0)
fields = [msg.nonce, msg.gas_price, msg.gas_limit, msg.to, msg.value, msg.data_initial_chunk] while data_left > 0:
resp = await send_request_chunk(ctx, data_left, data_total)
data += resp.data_chunk
data_left -= len(resp.data_chunk)
# todo stream
if msg.chain_id:
fields = [msg.nonce, msg.gas_price, msg.gas_limit, msg.to, msg.value, data, msg.chain_id, 0, 0]
else:
fields = [msg.nonce, msg.gas_price, msg.gas_limit, msg.to, msg.value, data]
rlp_encoded = rlp.encode(fields) rlp_encoded = rlp.encode(fields)
sha256 = sha3_256(rlp_encoded) sha256 = sha3_256()
sha256.update(rlp_encoded)
digest = sha256.digest(True) digest = sha256.digest(True)
return await send_signature(ctx, msg, digest)
async def send_request_chunk(ctx, data_left: int, data_total: int):
from trezor.messages.wire_types import EthereumTxAck
# todo layoutProgress ?
req = EthereumTxRequest()
if data_left <= 1024:
req.data_length = data_left
else:
req.data_length = 1024
return await ctx.call(req, EthereumTxAck)
async def send_signature(ctx, msg: EthereumSignTx, digest):
from trezor.crypto.curve import secp256k1
from ..common import seed
address_n = msg.address_n or () address_n = msg.address_n or ()
node = await seed.get_root(ctx) node = await seed.get_root(ctx)
node.derive_path(address_n) node.derive_path(address_n)
@ -81,17 +108,17 @@ def check(msg: EthereumSignTx):
if msg.data_length > 0: if msg.data_length > 0:
if not msg.data_initial_chunk: if not msg.data_initial_chunk:
raise ValueError(Failure.DataError, 'Data length provided, but no initial chunk') raise ValueError(FailureType.DataError, 'Data length provided, but no initial chunk')
# Our encoding only supports transactions up to 2^24 bytes. To # Our encoding only supports transactions up to 2^24 bytes. To
# prevent exceeding the limit we use a stricter limit on data length. # prevent exceeding the limit we use a stricter limit on data length.
if msg.data_length > 16000000: if msg.data_length > 16000000:
raise ValueError(Failure.DataError, 'Data length exceeds limit') raise ValueError(FailureType.DataError, 'Data length exceeds limit')
if len(msg.data_initial_chunk) > msg.data_length: if len(msg.data_initial_chunk) > msg.data_length:
raise ValueError(Failure.DataError, 'Invalid size of initial chunk') raise ValueError(FailureType.DataError, 'Invalid size of initial chunk')
# safety checks # safety checks
if not check_gas(msg) or not check_to(msg): if not check_gas(msg) or not check_to(msg):
raise ValueError(Failure.DataError, 'Safety check failed') raise ValueError(FailureType.DataError, 'Safety check failed')
def check_gas(msg: EthereumSignTx) -> bool: def check_gas(msg: EthereumSignTx) -> bool:
@ -104,7 +131,7 @@ def check_gas(msg: EthereumSignTx) -> bool:
def check_to(msg: EthereumTxRequest) -> bool: def check_to(msg: EthereumTxRequest) -> bool:
if msg.to == 0: if msg.to == b'':
if msg.data_length == 0: if msg.data_length == 0:
# sending transaction to address 0 (contract creation) without a data field # sending transaction to address 0 (contract creation) without a data field
return False return False