diff --git a/src/apps/lisk/get_address.py b/src/apps/lisk/get_address.py index b5228ec2ad..a273289d8b 100644 --- a/src/apps/lisk/get_address.py +++ b/src/apps/lisk/get_address.py @@ -1,11 +1,11 @@ +from apps.common import seed from apps.wallet.get_address import _show_address, _show_qr +from trezor.messages.LiskAddress import LiskAddress + from .helpers import LISK_CURVE, get_address_from_public_key async def layout_lisk_get_address(ctx, msg): - from trezor.messages.LiskAddress import LiskAddress - from ..common import seed - address_n = msg.address_n or () node = await seed.derive_node(ctx, address_n, LISK_CURVE) diff --git a/src/apps/lisk/get_public_key.py b/src/apps/lisk/get_public_key.py index 6973ac1246..d79ec6fb1e 100644 --- a/src/apps/lisk/get_public_key.py +++ b/src/apps/lisk/get_public_key.py @@ -1,11 +1,11 @@ +from apps.common import seed from apps.wallet.get_public_key import _show_pubkey +from trezor.messages.LiskPublicKey import LiskPublicKey + from .helpers import LISK_CURVE async def lisk_get_public_key(ctx, msg): - from trezor.messages.LiskPublicKey import LiskPublicKey - from ..common import seed - address_n = msg.address_n or () node = await seed.derive_node(ctx, address_n, LISK_CURVE) diff --git a/src/apps/lisk/helpers.py b/src/apps/lisk/helpers.py index 4371ca2c3c..87aa46aaa5 100644 --- a/src/apps/lisk/helpers.py +++ b/src/apps/lisk/helpers.py @@ -1,12 +1,13 @@ +from trezor.crypto.hashlib import sha256 LISK_CURVE = 'ed25519' -def get_address_from_public_key(public_key): - from trezor.crypto.hashlib import sha256 - public_key_hash = sha256(public_key).digest() - address = int.from_bytes(public_key_hash[:8], 'little') - return str(address) + "L" +def get_address_from_public_key(pubkey): + pubkeyhash = sha256(pubkey).digest() + address = int.from_bytes(pubkeyhash[:8], 'little') + return str(address) + 'L' + def get_votes_count(votes): plus, minus = 0, 0 @@ -17,6 +18,7 @@ def get_votes_count(votes): minus += 1 return plus, minus + def get_vote_tx_text(votes): plus, minus = get_votes_count(votes) text = [] @@ -26,5 +28,6 @@ def get_vote_tx_text(votes): text.append(_text_with_plural('Remove', minus)) return text + def _text_with_plural(txt, value): return '%s %s %s' % (txt, value, ('votes' if value != 1 else 'vote')) diff --git a/src/apps/lisk/layout.py b/src/apps/lisk/layout.py index 002622e92d..2847a4afd1 100644 --- a/src/apps/lisk/layout.py +++ b/src/apps/lisk/layout.py @@ -1,8 +1,10 @@ -from apps.common.confirm import * +from apps.common.confirm import require_confirm, require_hold_to_confirm +from apps.wallet.get_public_key import _show_pubkey from trezor import ui -from trezor.utils import chunks from trezor.messages import ButtonRequestType from trezor.ui.text import Text +from trezor.utils import chunks + from .helpers import get_vote_tx_text @@ -14,6 +16,7 @@ async def require_confirm_tx(ctx, to, value): icon_color=ui.GREEN) return await require_confirm(ctx, content, ButtonRequestType.SignTx) + async def require_confirm_delegate_registration(ctx, delegate_name): content = Text('Confirm transaction', ui.ICON_SEND, 'Do you really want to', @@ -22,26 +25,27 @@ async def require_confirm_delegate_registration(ctx, delegate_name): icon_color=ui.GREEN) return await require_confirm(ctx, content, ButtonRequestType.SignTx) + async def require_confirm_vote_tx(ctx, votes): content = Text('Confirm transaction', ui.ICON_SEND, *get_vote_tx_text(votes), icon_color=ui.GREEN) - return await require_confirm(ctx, content, ButtonRequestType.SignTx) + async def require_confirm_public_key(ctx, public_key): - from apps.wallet.get_public_key import _show_pubkey return await _show_pubkey(ctx, public_key) + async def require_confirm_multisig(ctx, multisignature): content = Text('Confirm transaction', ui.ICON_SEND, ('Keys group length: %s' % len(multisignature.keys_group)), ('Life time: %s' % multisignature.life_time), ('Min: %s' % multisignature.min), icon_color=ui.GREEN) - return await require_confirm(ctx, content, ButtonRequestType.SignTx) + async def require_confirm_fee(ctx, value, fee): content = Text('Confirm transaction', ui.ICON_SEND, ui.BOLD, format_amount(value), @@ -50,8 +54,10 @@ async def require_confirm_fee(ctx, value, fee): icon_color=ui.GREEN) await require_hold_to_confirm(ctx, content, ButtonRequestType.ConfirmOutput) + def format_amount(value): return '%s LSK' % (int(value) / 100000000) + def split_address(address): return chunks(address, 16) diff --git a/src/apps/lisk/sign_tx.py b/src/apps/lisk/sign_tx.py index 9da973cc29..28a0167c72 100644 --- a/src/apps/lisk/sign_tx.py +++ b/src/apps/lisk/sign_tx.py @@ -1,112 +1,39 @@ -from trezor import wire, ui +import ustruct +from apps.common import seed +from trezor import wire +from trezor.crypto.curve import ed25519 +from trezor.crypto.hashlib import sha256 +from trezor.messages import LiskTransactionType from trezor.messages.LiskSignedTx import LiskSignedTx -from trezor.messages.LiskTransactionType import * -from trezor.messages import FailureType from trezor.utils import HashWriter -from apps.lisk.layout import * -from ubinascii import unhexlify, hexlify + +from . import layout +from .helpers import LISK_CURVE, get_address_from_public_key async def lisk_sign_tx(ctx, msg): - from trezor.crypto.hashlib import sha256 - pubkey, seckey = await _get_keys(ctx, msg) - transaction = update_raw_tx(msg.transaction, pubkey) + transaction = _update_raw_tx(msg.transaction, pubkey) - # throw ValueError if transaction has not valid structure try: - await require_confirm_by_type(ctx, transaction) + await _require_confirm_by_type(ctx, transaction) except AttributeError: - raise ValueError(FailureType.DataError, 'The transaction has invalid asset data field') + raise wire.DataError('The transaction has invalid asset data field') - await require_confirm_fee(ctx, transaction.amount, transaction.fee) + await layout.require_confirm_fee(ctx, transaction.amount, transaction.fee) - sha = HashWriter(sha256) - transaction_bytes = _get_transaction_bytes(transaction) + txbytes = _get_transaction_bytes(transaction) + txhash = HashWriter(sha256) + for field in txbytes: + txhash.extend(field) + digest = txhash.get_digest() - for field in transaction_bytes: - sha.extend(field) - - digest = sha.get_digest() - - signature = await get_signature(seckey, digest) + signature = ed25519.sign(seckey, digest) return LiskSignedTx(signature=signature) -async def require_confirm_by_type(ctx, transaction): - if transaction.type == Transfer: - return await require_confirm_tx(ctx, transaction.recipient_id, transaction.amount) - if transaction.type == RegisterDelegate: - return await require_confirm_delegate_registration(ctx, transaction.asset.delegate.username) - if transaction.type == CastVotes: - return await require_confirm_vote_tx(ctx, transaction.asset.votes) - if transaction.type == RegisterSecondPassphrase: - return await require_confirm_public_key(ctx, transaction.asset.signature.public_key) - if transaction.type == RegisterMultisignatureAccount: - return await require_confirm_multisig(ctx, transaction.asset.multisignature) - raise ValueError(FailureType.DataError, 'Invalid transaction type') - -async def get_signature(seckey, digest): - from trezor.crypto.curve import ed25519 - signature = ed25519.sign(seckey, digest) - - return signature - -def _get_transaction_bytes(msg): - from ustruct import pack - - # Required transaction parameters - t_type = pack('Q', 0) - else: - # Lisk use big-endian for recipient_id - # string -> int -> bytes - t_recipient_id = pack('>Q', int(msg.recipient_id[:-1])) - - t_signature = msg.signature or b'' - - t_asset = _get_asset_data_bytes(msg) - - return t_type, t_timestamp, t_pubkey, t_requester_public_key, t_recipient_id, t_amount, t_asset, t_signature - -def _get_asset_data_bytes(msg): - from ustruct import pack - - if msg.type == Transfer: - # Transfer transaction have optional data field - if msg.asset.data is not None: - return bytes(msg.asset.data, "utf8") - else: - return b'' - - if msg.type == RegisterDelegate: - return bytes(msg.asset.delegate.username, "utf8") - - if msg.type == CastVotes: - return bytes("".join(msg.asset.votes), "utf8") - - if msg.type == RegisterSecondPassphrase: - return msg.asset.signature.public_key - - if msg.type == RegisterMultisignatureAccount: - data = b'' - data += pack('Q', 0) + else: + # Lisk uses big-endian for recipient_id, string -> int -> bytes + t_recipient_id = ustruct.pack('>Q', int(tx.recipient_id[:-1])) + + t_amount = ustruct.pack('