apps.ethereum: implement SignMessage/VerifyMessage

This commit is contained in:
Pavol Rusnak 2017-12-23 15:12:31 +01:00
parent e47aa9f0c4
commit d6593e710b
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
8 changed files with 100 additions and 4 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.cache/
*.pyc
.sconsign.dblite
.vscode/

View File

@ -24,7 +24,8 @@ CPPPATH_MOD += [
CPPDEFINES_MOD += [
'AES_128',
'AES_192',
'USE_KECCAK',
('USE_KECCAK', '1'),
('USE_ETHEREUM', '1'),
]
SOURCE_MOD += [
'embed/extmod/modtrezorcrypto/modtrezorcrypto.c',

View File

@ -25,7 +25,8 @@ CPPPATH_MOD += [
CPPDEFINES_MOD += [
'AES_128',
'AES_192',
'USE_KECCAK',
('USE_KECCAK', '1'),
('USE_ETHEREUM', '1'),
]
SOURCE_MOD += [
'embed/extmod/modtrezorcrypto/modtrezorcrypto.c',

View File

@ -298,6 +298,21 @@ STATIC mp_obj_t mod_trezorcrypto_HDNode_address(mp_obj_t self, mp_obj_t version)
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_address_obj, mod_trezorcrypto_HDNode_address);
/// def ethereum_pubkeyhash(self) -> bytes:
/// '''
/// Compute an Ethereum pubkeyhash (aka address) from the HD node.
/// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_ethereum_pubkeyhash(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
vstr_t vstr;
vstr_init_len(&vstr, 20);
hdnode_get_ethereum_pubkeyhash(&o->hdnode, (uint8_t *)vstr.buf);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_ethereum_pubkeyhash_obj, mod_trezorcrypto_HDNode_ethereum_pubkeyhash);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_HDNode_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_derive), MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_obj) },
{ MP_ROM_QSTR(MP_QSTR_derive_path), MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_path_obj) },
@ -312,6 +327,7 @@ STATIC const mp_rom_map_elem_t mod_trezorcrypto_HDNode_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_private_key), MP_ROM_PTR(&mod_trezorcrypto_HDNode_private_key_obj) },
{ MP_ROM_QSTR(MP_QSTR_public_key), MP_ROM_PTR(&mod_trezorcrypto_HDNode_public_key_obj) },
{ MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&mod_trezorcrypto_HDNode_address_obj) },
{ MP_ROM_QSTR(MP_QSTR_ethereum_pubkeyhash), MP_ROM_PTR(&mod_trezorcrypto_HDNode_ethereum_pubkeyhash_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_HDNode_locals_dict, mod_trezorcrypto_HDNode_locals_dict_table);

View File

@ -1,7 +1,7 @@
from trezor.wire import register, protobuf_workflow
from trezor.utils import unimport
from trezor.messages.wire_types import \
EthereumGetAddress, EthereumSignTx
EthereumGetAddress, EthereumSignTx, EthereumSignMessage, EthereumVerifyMessage
@unimport
@ -16,6 +16,20 @@ def dispatch_EthereumSignTx(*args, **kwargs):
return ethereum_sign_tx(*args, **kwargs)
@unimport
def dispatch_EthereumSignMessage(*args, **kwargs):
from .sign_message import ethereum_sign_message
return ethereum_sign_message(*args, **kwargs)
@unimport
def dispatch_EthereumVerifyMessage(*args, **kwargs):
from .verify_message import ethereum_verify_message
return ethereum_verify_message(*args, **kwargs)
def boot():
register(EthereumGetAddress, protobuf_workflow, dispatch_EthereumGetAddress)
register(EthereumSignTx, protobuf_workflow, dispatch_EthereumSignTx)
register(EthereumSignMessage, protobuf_workflow, dispatch_EthereumSignMessage)
register(EthereumVerifyMessage, protobuf_workflow, dispatch_EthereumVerifyMessage)

View File

@ -0,0 +1,34 @@
from trezor.utils import unimport
def message_digest(message):
from apps.wallet.sign_tx.signing import write_varint
from trezor.crypto.hashlib import sha3_256
from apps.common.hash_writer import HashWriter
h = HashWriter(sha3_256)
signed_message_header = 'Ethereum Signed Message:\n'
write_varint(h, len(signed_message_header))
h.extend(signed_message_header)
write_varint(h, len(message))
h.extend(message)
return h.get_digest(True)
@unimport
async def ethereum_sign_message(ctx, msg):
from trezor.messages.EthereumMessageSignature import EthereumMessageSignature
from trezor.crypto.curve import secp256k1
from ..common import seed
address_n = msg.address_n or ()
node = await seed.get_root(ctx)
node.derive_path(address_n)
signature = secp256k1.sign(node.private_key(), message_digest(msg.message), False)
sig = EthereumMessageSignature()
sig.address = node.ethereum_pubkeyhash()
sig.signature = signature[1:] + bytearray([signature[0]])
return sig

View File

@ -0,0 +1,30 @@
from trezor.utils import unimport
@unimport
async def ethereum_verify_message(ctx, msg):
from .sign_message import message_digest
from trezor.crypto.curve import secp256k1
from trezor.crypto.hashlib import sha3_256
from trezor import ui
from trezor.messages.Success import Success
digest = message_digest(msg.message)
sig = bytearray([msg.signature[64]]) + msg.signature[:64]
pubkey = secp256k1.verify_recover(sig, digest)
if not pubkey:
raise ValueError('Invalid signature')
pkh = sha3_256(pubkey[1:]).digest(True)[-20:]
if msg.address != pkh:
raise ValueError('Invalid signature')
ui.display.clear()
ui.display.text(10, 30, 'Verifying message',
ui.BOLD, ui.LIGHT_GREEN, ui.BG)
ui.display.text(10, 60, msg.message, ui.MONO, ui.FG, ui.BG)
ui.display.text(10, 80, msg.address, ui.MONO, ui.FG, ui.BG)
return Success(message='Message verified')

1
tests/.gitignore vendored
View File

@ -1 +0,0 @@
.cache/