From 922748e348122eb461b8a0257fbd49c59d3bf1f3 Mon Sep 17 00:00:00 2001 From: Aleksey Popov Date: Wed, 6 Jun 2018 23:50:27 +0300 Subject: [PATCH] lisk: restore Lisk sign and verify message functionality --- trezorctl | 27 +++++++++ trezorlib/client.py | 14 +++++ trezorlib/messages/LiskMessageSignature.py | 18 ++++++ trezorlib/messages/LiskSignMessage.py | 23 ++++++++ trezorlib/messages/LiskVerifyMessage.py | 21 +++++++ trezorlib/messages/MessageType.py | 3 + trezorlib/messages/__init__.py | 3 + .../device_tests/test_msg_lisk_signmessage.py | 38 +++++++++++++ .../test_msg_lisk_verifymessage.py | 55 +++++++++++++++++++ 9 files changed, 202 insertions(+) create mode 100644 trezorlib/messages/LiskMessageSignature.py create mode 100644 trezorlib/messages/LiskSignMessage.py create mode 100644 trezorlib/messages/LiskVerifyMessage.py create mode 100644 trezorlib/tests/device_tests/test_msg_lisk_signmessage.py create mode 100644 trezorlib/tests/device_tests/test_msg_lisk_verifymessage.py diff --git a/trezorctl b/trezorctl index a309ea80f..2ed5dff3d 100755 --- a/trezorctl +++ b/trezorctl @@ -911,6 +911,33 @@ def lisk_sign_tx(connect, address, file): return payload +@cli.command(help='Sign message with Lisk address.') +@click.option('-n', '--address', required=True, help="BIP-32 path, e.g. m/44'/134'/0'/0'") +@click.argument('message') +@click.pass_obj +def lisk_sign_message(connect, address, message): + client = connect() + address_n = client.expand_path(address) + res = client.lisk_sign_message(address_n, message) + output = { + "message": message, + "public_key": binascii.hexlify(res.public_key).decode(), + "signature": binascii.hexlify(res.signature).decode() + } + return output + + +@cli.command(help='Verify message signed with Lisk address.') +@click.argument('pubkey') +@click.argument('signature') +@click.argument('message') +@click.pass_obj +def lisk_verify_message(connect, pubkey, signature, message): + signature = bytes.fromhex(signature) + pubkey = bytes.fromhex(pubkey) + return connect().lisk_verify_message(pubkey, signature, message) + + # # CoSi functions # diff --git a/trezorlib/client.py b/trezorlib/client.py index 57920eb57..8d288074e 100644 --- a/trezorlib/client.py +++ b/trezorlib/client.py @@ -559,6 +559,20 @@ class ProtocolMixin(object): n = self._convert_prime(n) return self.call(proto.LiskGetPublicKey(address_n=n, show_display=show_display)) + @expect(proto.LiskMessageSignature) + def lisk_sign_message(self, n, message): + n = self._convert_prime(n) + message = normalize_nfc(message) + return self.call(proto.LiskSignMessage(address_n=n, message=message)) + + def lisk_verify_message(self, pubkey, signature, message): + message = normalize_nfc(message) + try: + resp = self.call(proto.LiskVerifyMessage(signature=signature, public_key=pubkey, message=message)) + except CallException as e: + resp = e + return isinstance(resp, proto.Success) + @expect(proto.LiskSignedTx) def lisk_sign_tx(self, n, transaction): n = self._convert_prime(n) diff --git a/trezorlib/messages/LiskMessageSignature.py b/trezorlib/messages/LiskMessageSignature.py new file mode 100644 index 000000000..d0e370a92 --- /dev/null +++ b/trezorlib/messages/LiskMessageSignature.py @@ -0,0 +1,18 @@ +# Automatically generated by pb2py +from .. import protobuf as p + + +class LiskMessageSignature(p.MessageType): + MESSAGE_WIRE_TYPE = 119 + FIELDS = { + 1: ('public_key', p.BytesType, 0), + 2: ('signature', p.BytesType, 0), + } + + def __init__( + self, + public_key: bytes = None, + signature: bytes = None + ) -> None: + self.public_key = public_key + self.signature = signature diff --git a/trezorlib/messages/LiskSignMessage.py b/trezorlib/messages/LiskSignMessage.py new file mode 100644 index 000000000..4194c8a6b --- /dev/null +++ b/trezorlib/messages/LiskSignMessage.py @@ -0,0 +1,23 @@ +# Automatically generated by pb2py +from .. import protobuf as p +if __debug__: + try: + from typing import List + except ImportError: + List = None + + +class LiskSignMessage(p.MessageType): + MESSAGE_WIRE_TYPE = 118 + FIELDS = { + 1: ('address_n', p.UVarintType, p.FLAG_REPEATED), + 2: ('message', p.BytesType, 0), + } + + def __init__( + self, + address_n: List[int] = None, + message: bytes = None + ) -> None: + self.address_n = address_n if address_n is not None else [] + self.message = message diff --git a/trezorlib/messages/LiskVerifyMessage.py b/trezorlib/messages/LiskVerifyMessage.py new file mode 100644 index 000000000..235ac3b0f --- /dev/null +++ b/trezorlib/messages/LiskVerifyMessage.py @@ -0,0 +1,21 @@ +# Automatically generated by pb2py +from .. import protobuf as p + + +class LiskVerifyMessage(p.MessageType): + MESSAGE_WIRE_TYPE = 120 + FIELDS = { + 1: ('signature', p.BytesType, 0), + 2: ('public_key', p.BytesType, 0), + 3: ('message', p.BytesType, 0), + } + + def __init__( + self, + signature: bytes = None, + public_key: bytes = None, + message: bytes = None + ) -> None: + self.signature = signature + self.public_key = public_key + self.message = message diff --git a/trezorlib/messages/MessageType.py b/trezorlib/messages/MessageType.py index 66b278758..bed0c3541 100644 --- a/trezorlib/messages/MessageType.py +++ b/trezorlib/messages/MessageType.py @@ -88,6 +88,9 @@ LiskGetAddress = 114 LiskAddress = 115 LiskSignTx = 116 LiskSignedTx = 117 +LiskSignMessage = 118 +LiskMessageSignature = 119 +LiskVerifyMessage = 120 LiskGetPublicKey = 121 LiskPublicKey = 122 StellarGetPublicKey = 200 diff --git a/trezorlib/messages/__init__.py b/trezorlib/messages/__init__.py index a5687e28e..f69735fcc 100644 --- a/trezorlib/messages/__init__.py +++ b/trezorlib/messages/__init__.py @@ -95,9 +95,12 @@ from .Initialize import Initialize from .LiskAddress import LiskAddress from .LiskGetAddress import LiskGetAddress from .LiskGetPublicKey import LiskGetPublicKey +from .LiskMessageSignature import LiskMessageSignature from .LiskPublicKey import LiskPublicKey +from .LiskSignMessage import LiskSignMessage from .LiskSignTx import LiskSignTx from .LiskSignedTx import LiskSignedTx +from .LiskVerifyMessage import LiskVerifyMessage from .LoadDevice import LoadDevice from .MessageSignature import MessageSignature from .NEMAddress import NEMAddress diff --git a/trezorlib/tests/device_tests/test_msg_lisk_signmessage.py b/trezorlib/tests/device_tests/test_msg_lisk_signmessage.py new file mode 100644 index 000000000..aa09cdc74 --- /dev/null +++ b/trezorlib/tests/device_tests/test_msg_lisk_signmessage.py @@ -0,0 +1,38 @@ +# This file is part of the TREZOR project. +# +# Copyright (C) 2016-2017 Pavol Rusnak +# +# 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 . + +from binascii import hexlify +import pytest + +from .common import TrezorTest + + +@pytest.mark.lisk +@pytest.mark.skip_t1 +class TestMsgLiskSignmessage(TrezorTest): + + def test_sign(self): + self.setup_mnemonic_nopin_nopassphrase() + sig = self.client.lisk_sign_message([2147483692, 2147483782, 2147483648, 2147483648], 'This is an example of a signed message.') + assert hexlify(sig.public_key) == b'eb56d7bbb5e8ea9269405f7a8527fe126023d1db2c973cfac6f760b60ae27294' + assert hexlify(sig.signature) == b'7858ae7cd52ea6d4b17e800ca60144423db5560bfd618b663ffbf26ab66758563df45cbffae8463db22dc285dd94309083b8c807776085b97d05374d79867d05' + + def test_sign_long(self): + self.setup_mnemonic_nopin_nopassphrase() + sig = self.client.lisk_sign_message([2147483692, 2147483782, 2147483648], 'VeryLongMessage!' * 64) + assert hexlify(sig.public_key) == b'8bca6b65a1a877767b746ea0b3c4310d404aa113df99c1b554e1802d70185ab5' + assert hexlify(sig.signature) == b'458ca5896d0934866992268f7509b5e954d568b1251e20c19bd3149ee3c86ffb5a44d1c2a0abbb99a3ab4767272dbb0e419b4579e890a24919ebbbe6cc0f970f' diff --git a/trezorlib/tests/device_tests/test_msg_lisk_verifymessage.py b/trezorlib/tests/device_tests/test_msg_lisk_verifymessage.py new file mode 100644 index 000000000..bb97f258b --- /dev/null +++ b/trezorlib/tests/device_tests/test_msg_lisk_verifymessage.py @@ -0,0 +1,55 @@ +# This file is part of the TREZOR project. +# +# Copyright (C) 2016-2017 Pavol Rusnak +# +# 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 . + +from binascii import unhexlify +import pytest + +from .common import TrezorTest +from trezorlib import messages as proto + + +@pytest.mark.lisk +@pytest.mark.skip_t1 +class TestMsgLiskVerifymessage(TrezorTest): + + def test_verify(self): + self.setup_mnemonic_nopin_nopassphrase() + with self.client: + self.client.set_expected_responses([ + proto.ButtonRequest(code=proto.ButtonRequestType.Other), + proto.ButtonRequest(code=proto.ButtonRequestType.Other), + proto.Success(message='Message verified') + ]) + self.client.lisk_verify_message( + unhexlify('eb56d7bbb5e8ea9269405f7a8527fe126023d1db2c973cfac6f760b60ae27294'), + unhexlify('7858ae7cd52ea6d4b17e800ca60144423db5560bfd618b663ffbf26ab66758563df45cbffae8463db22dc285dd94309083b8c807776085b97d05374d79867d05'), + 'This is an example of a signed message.' + ) + + def test_verify_long(self): + self.setup_mnemonic_nopin_nopassphrase() + with self.client: + self.client.set_expected_responses([ + proto.ButtonRequest(code=proto.ButtonRequestType.Other), + proto.ButtonRequest(code=proto.ButtonRequestType.Other), + proto.Success(message='Message verified') + ]) + self.client.lisk_verify_message( + unhexlify('8bca6b65a1a877767b746ea0b3c4310d404aa113df99c1b554e1802d70185ab5'), + unhexlify('458ca5896d0934866992268f7509b5e954d568b1251e20c19bd3149ee3c86ffb5a44d1c2a0abbb99a3ab4767272dbb0e419b4579e890a24919ebbbe6cc0f970f'), + 'VeryLongMessage!' * 64 + )