diff --git a/trezorctl b/trezorctl index 250fbe13de..00e8067887 100755 --- a/trezorctl +++ b/trezorctl @@ -876,6 +876,22 @@ def lisk_get_address(connect, address, show_display): return client.lisk_get_address(address_n, show_display) +@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, + 'address': res.address, + 'signature': binascii.hexlify(res.signature).decode() + } + return output + + # # CoSi functions # diff --git a/trezorlib/client.py b/trezorlib/client.py index da7d7f07b1..b095ab7f00 100644 --- a/trezorlib/client.py +++ b/trezorlib/client.py @@ -637,6 +637,12 @@ class ProtocolMixin(object): n = self._convert_prime(n) return self.call(proto.LiskGetAddress(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)) + @field('entropy') @expect(proto.Entropy) def get_entropy(self, size): 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 0000000000..72db0c9c50 --- /dev/null +++ b/trezorlib/tests/device_tests/test_msg_lisk_signmessage.py @@ -0,0 +1,35 @@ +# 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 .common import * + + +@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 sig.address == '7623396847864198749L' + assert hexlify(sig.signature) == b'af1d384cce25354b5af129662caed6f3514c6f1f6a206662d301fd56aa5549aa23c3f82009f213a7a4d9297015c2e5b06584273df7c42d78b4e531fe4d4fc80e' + + def test_sign_long(self): + self.setup_mnemonic_nopin_nopassphrase() + sig = self.client.lisk_sign_message([2147483692, 2147483782, 2147483648], 'VeryLongMessage!' * 64) + assert sig.address == '17563781916205589679L' + print(hexlify(sig.signature)) + assert hexlify(sig.signature) == b'a675152c2af34e85dbd75740681efb7d67bf910561d6c9d1e075be2f99d9bc544d62c52f6619756b0e329a2f2d82756ced53b4261a028fcee0d37d7e641ef404'