mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-30 11:28:21 +00:00
refactor ethereum methods, show progress properly
This commit is contained in:
parent
1558d77ea0
commit
4e0a69b6ea
@ -2,6 +2,7 @@
|
|||||||
* This file is part of the TREZOR project.
|
* This file is part of the TREZOR project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 Alex Beregszaszi <alex@rtfs.hu>
|
* Copyright (C) 2016 Alex Beregszaszi <alex@rtfs.hu>
|
||||||
|
* Copyright (C) 2016 Pavol Rusnak <stick@satoshilabs.com>
|
||||||
*
|
*
|
||||||
* This library is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -30,68 +31,85 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
static bool signing = false;
|
static bool signing = false;
|
||||||
static size_t data_left;
|
static uint32_t data_total, data_left;
|
||||||
static EthereumTxRequest resp;
|
static EthereumTxRequest resp;
|
||||||
static uint8_t hash[32], sig[64], privkey[32];
|
static uint8_t hash[32], sig[64], privkey[32];
|
||||||
// FIXME: this is currently 400 bytes. Could be probably improved.
|
|
||||||
struct SHA3_CTX keccak_ctx;
|
struct SHA3_CTX keccak_ctx;
|
||||||
|
|
||||||
/*
|
static inline void hash_data(const uint8_t *buf, size_t size)
|
||||||
* Encode length according to RLP.
|
|
||||||
*/
|
|
||||||
static int rlp_encode_length(uint8_t *buf, int length, uint8_t firstbyte)
|
|
||||||
{
|
{
|
||||||
|
sha3_Update(&keccak_ctx, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Push an RLP encoded length to the hash buffer.
|
||||||
|
*/
|
||||||
|
static void hash_rlp_length(uint32_t length, uint8_t firstbyte)
|
||||||
|
{
|
||||||
|
uint8_t buf[4];
|
||||||
if (length == 1 && firstbyte == 0x00) {
|
if (length == 1 && firstbyte == 0x00) {
|
||||||
// extra-special case: null is encoded differently
|
// special case: null is encoded differently
|
||||||
buf[0] = 0x80;
|
buf[0] = 0x80;
|
||||||
return 1;
|
hash_data(buf, 1);
|
||||||
} else if (length == 1 && firstbyte <= 0x7f) {
|
} else if (length == 1 && firstbyte <= 0x7f) {
|
||||||
buf[0] = firstbyte;
|
buf[0] = firstbyte;
|
||||||
return 1;
|
hash_data(buf, 1);
|
||||||
} else if (length <= 55) {
|
} else if (length <= 55) {
|
||||||
buf[0] = 0x80 + length;
|
buf[0] = 0x80 + length;
|
||||||
return 1;
|
hash_data(buf, 1);
|
||||||
} else if (length <= 0xff) {
|
} else if (length <= 0xff) {
|
||||||
buf[0] = 0xb7 + 1;
|
buf[0] = 0xb7 + 1;
|
||||||
buf[1] = length;
|
buf[1] = length;
|
||||||
return 2;
|
hash_data(buf, 2);
|
||||||
} else if (length <= 0xffff) {
|
} else if (length <= 0xffff) {
|
||||||
buf[0] = 0xb7 + 2;
|
buf[0] = 0xb7 + 2;
|
||||||
buf[1] = length >> 8;
|
buf[1] = length >> 8;
|
||||||
buf[2] = length & 0xff;
|
buf[2] = length & 0xff;
|
||||||
return 3;
|
hash_data(buf, 3);
|
||||||
} else {
|
} else {
|
||||||
buf[0] = 0xb7 + 3;
|
buf[0] = 0xb7 + 3;
|
||||||
buf[1] = length >> 16;
|
buf[1] = length >> 16;
|
||||||
buf[2] = length >> 8;
|
buf[2] = length >> 8;
|
||||||
buf[3] = length & 0xff;
|
buf[3] = length & 0xff;
|
||||||
return 4;
|
hash_data(buf, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Encode list length according to RLP.
|
* Push an RLP encoded list length to the hash buffer.
|
||||||
*/
|
*/
|
||||||
static int rlp_encode_list_length(uint8_t *buf, int length)
|
static void hash_rlp_list_length(uint32_t length)
|
||||||
{
|
{
|
||||||
|
uint8_t buf[4];
|
||||||
if (length <= 55) {
|
if (length <= 55) {
|
||||||
buf[0] = 0xc0 + length;
|
buf[0] = 0xc0 + length;
|
||||||
return 1;
|
hash_data(buf, 1);
|
||||||
} else if (length <= 0xff) {
|
} else if (length <= 0xff) {
|
||||||
buf[0] = 0xf7 + 1;
|
buf[0] = 0xf7 + 1;
|
||||||
buf[1] = length;
|
buf[1] = length;
|
||||||
return 2;
|
hash_data(buf, 2);
|
||||||
} else if (length <= 0xffff) {
|
} else if (length <= 0xffff) {
|
||||||
buf[0] = 0xf7 + 2;
|
buf[0] = 0xf7 + 2;
|
||||||
buf[1] = length >> 8;
|
buf[1] = length >> 8;
|
||||||
buf[2] = length & 0xff;
|
buf[2] = length & 0xff;
|
||||||
return 3;
|
hash_data(buf, 3);
|
||||||
} else {
|
} else {
|
||||||
buf[0] = 0xf7 + 3;
|
buf[0] = 0xf7 + 3;
|
||||||
buf[1] = length >> 16;
|
buf[1] = length >> 16;
|
||||||
buf[2] = length >> 8;
|
buf[2] = length >> 8;
|
||||||
buf[3] = length & 0xff;
|
buf[3] = length & 0xff;
|
||||||
return 4;
|
hash_data(buf, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Push an RLP encoded length field and data to the hash buffer.
|
||||||
|
*/
|
||||||
|
static void hash_rlp_field(const uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
hash_rlp_length(size, buf[0]);
|
||||||
|
if (size > 1 || buf[0] >= 0x80) {
|
||||||
|
hash_data(buf, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +118,8 @@ static int rlp_encode_list_length(uint8_t *buf, int length)
|
|||||||
* NOTE: supports up to 16MB of data (how unlikely...)
|
* NOTE: supports up to 16MB of data (how unlikely...)
|
||||||
* FIXME: improve
|
* FIXME: improve
|
||||||
*/
|
*/
|
||||||
static int rlp_calculate_length(int length, uint8_t firstbyte) {
|
static int rlp_calculate_length(int length, uint8_t firstbyte)
|
||||||
|
{
|
||||||
if (length == 1 && firstbyte <= 0x7f) {
|
if (length == 1 && firstbyte <= 0x7f) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (length <= 55) {
|
} else if (length <= 55) {
|
||||||
@ -114,45 +133,10 @@ static int rlp_calculate_length(int length, uint8_t firstbyte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void hash_data(const uint8_t *buf, size_t size)
|
|
||||||
{
|
|
||||||
sha3_Update(&keccak_ctx, buf, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Push an RLP encoded length to the hash buffer.
|
|
||||||
*/
|
|
||||||
static void hash_rlp_length(int length, uint8_t firstbyte)
|
|
||||||
{
|
|
||||||
uint8_t buf[4];
|
|
||||||
size_t size = rlp_encode_length(buf, length, firstbyte);
|
|
||||||
hash_data(buf, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Push an RLP encoded list length to the hash buffer.
|
|
||||||
*/
|
|
||||||
static void hash_rlp_list_length(int length)
|
|
||||||
{
|
|
||||||
uint8_t buf[4];
|
|
||||||
size_t size = rlp_encode_list_length(buf, length);
|
|
||||||
hash_data(buf, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Push an RLP encoded length field and data to the hash buffer.
|
|
||||||
*/
|
|
||||||
static void hash_rlp_field(const uint8_t *buf, size_t size)
|
|
||||||
{
|
|
||||||
hash_rlp_length(size, buf[0]);
|
|
||||||
/* FIXME: this special case should be handled more nicely */
|
|
||||||
if (!(size == 1 && buf[0] <= 0x7f)) {
|
|
||||||
hash_data(buf, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_request_chunk(void)
|
static void send_request_chunk(void)
|
||||||
{
|
{
|
||||||
|
layoutProgress("Signing", 1000 - 800 * data_left / data_total);
|
||||||
resp.has_data_length = true;
|
resp.has_data_length = true;
|
||||||
resp.data_length = data_left <= 1024 ? data_left : 1024;
|
resp.data_length = data_left <= 1024 ? data_left : 1024;
|
||||||
msg_write(MessageType_MessageType_EthereumTxRequest, &resp);
|
msg_write(MessageType_MessageType_EthereumTxRequest, &resp);
|
||||||
@ -160,6 +144,7 @@ static void send_request_chunk(void)
|
|||||||
|
|
||||||
static void send_signature(void)
|
static void send_signature(void)
|
||||||
{
|
{
|
||||||
|
layoutProgress("Signing", 1000);
|
||||||
keccak_Final(&keccak_ctx, hash);
|
keccak_Final(&keccak_ctx, hash);
|
||||||
uint8_t v;
|
uint8_t v;
|
||||||
if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v) != 0) {
|
if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v) != 0) {
|
||||||
@ -318,6 +303,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
|
|||||||
ethereum_signing_abort();
|
ethereum_signing_abort();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
data_total = msg->data_length;
|
||||||
|
} else {
|
||||||
|
data_total = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutEthereumConfirmTx(msg->has_to ? msg->to.bytes : NULL, msg->has_value ? msg->value.bytes : NULL, msg->has_value ? msg->value.size : 0);
|
layoutEthereumConfirmTx(msg->has_to ? msg->to.bytes : NULL, msg->has_value ? msg->value.bytes : NULL, msg->has_value ? msg->value.size : 0);
|
||||||
@ -328,67 +316,21 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Stage 1: Calculate total RLP length */
|
/* Stage 1: Calculate total RLP length */
|
||||||
int total_rlp_length = 0;
|
uint32_t rlp_length = 0;
|
||||||
int total_data_length = 0;
|
|
||||||
|
|
||||||
if (msg->has_data_length) {
|
layoutProgress("Signing", 0);
|
||||||
total_data_length = msg->data_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
layoutProgress("Signing", 1);
|
rlp_length += msg->has_nonce ? rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]) : 1;
|
||||||
|
rlp_length += msg->has_gas_price ? rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]) : 1;
|
||||||
if (msg->has_nonce) {
|
rlp_length += msg->has_gas_limit ? rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]) : 1;
|
||||||
total_rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]);
|
rlp_length += msg->has_to ? rlp_calculate_length(msg->to.size, msg->to.bytes[0]) : 1;
|
||||||
} else {
|
rlp_length += msg->has_value ? rlp_calculate_length(msg->value.size, msg->value.bytes[0]) : 1;
|
||||||
total_rlp_length++;
|
rlp_length += (msg->has_data_length && msg->has_data_initial_chunk) ? rlp_calculate_length(msg->data_length, msg->data_initial_chunk.bytes[0]) : 1;
|
||||||
}
|
|
||||||
|
|
||||||
layoutProgress("Signing", 2);
|
|
||||||
|
|
||||||
if (msg->has_gas_price) {
|
|
||||||
total_rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]);
|
|
||||||
} else {
|
|
||||||
total_rlp_length++;
|
|
||||||
}
|
|
||||||
|
|
||||||
layoutProgress("Signing", 3);
|
|
||||||
|
|
||||||
if (msg->has_gas_limit) {
|
|
||||||
total_rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]);
|
|
||||||
} else {
|
|
||||||
total_rlp_length++;
|
|
||||||
}
|
|
||||||
|
|
||||||
layoutProgress("Signing", 4);
|
|
||||||
|
|
||||||
if (msg->has_to) {
|
|
||||||
total_rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]);
|
|
||||||
} else {
|
|
||||||
total_rlp_length++;
|
|
||||||
}
|
|
||||||
|
|
||||||
layoutProgress("Signing", 5);
|
|
||||||
|
|
||||||
if (msg->has_value) {
|
|
||||||
total_rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]);
|
|
||||||
} else {
|
|
||||||
total_rlp_length++;
|
|
||||||
}
|
|
||||||
|
|
||||||
layoutProgress("Signing", 6);
|
|
||||||
|
|
||||||
if (msg->has_data_initial_chunk) {
|
|
||||||
total_rlp_length += rlp_calculate_length(total_data_length, msg->data_initial_chunk.bytes[0]);
|
|
||||||
} else {
|
|
||||||
total_rlp_length++;
|
|
||||||
}
|
|
||||||
|
|
||||||
layoutProgress("Signing", 7);
|
|
||||||
|
|
||||||
/* Stage 2: Store header fields */
|
/* Stage 2: Store header fields */
|
||||||
hash_rlp_list_length(total_rlp_length);
|
hash_rlp_list_length(rlp_length);
|
||||||
|
|
||||||
layoutProgress("Signing", 8);
|
layoutProgress("Signing", 100);
|
||||||
|
|
||||||
if (msg->has_nonce) {
|
if (msg->has_nonce) {
|
||||||
hash_rlp_field(msg->nonce.bytes, msg->nonce.size);
|
hash_rlp_field(msg->nonce.bytes, msg->nonce.size);
|
||||||
@ -420,24 +362,22 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
|
|||||||
hash_rlp_length(1, 0);
|
hash_rlp_length(1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg->has_data_initial_chunk) {
|
if (msg->has_data_length && msg->has_data_initial_chunk) {
|
||||||
hash_rlp_length(total_data_length, msg->data_initial_chunk.bytes[0]);
|
hash_rlp_length(msg->data_length, msg->data_initial_chunk.bytes[0]);
|
||||||
hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size);
|
hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size);
|
||||||
} else {
|
} else {
|
||||||
hash_rlp_length(1, 0);
|
hash_rlp_length(1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutProgress("Signing", 9);
|
layoutProgress("Signing", 200);
|
||||||
|
|
||||||
/* FIXME: probably this shouldn't be done here, but at a later stage */
|
/* FIXME: probably this shouldn't be done here, but at a later stage */
|
||||||
memcpy(privkey, node->private_key, 32);
|
memcpy(privkey, node->private_key, 32);
|
||||||
|
|
||||||
if (msg->has_data_length && msg->data_length > 0) {
|
if (msg->has_data_length && msg->data_length > msg->data_initial_chunk.size) {
|
||||||
layoutProgress("Signing", 20);
|
|
||||||
data_left = msg->data_length - msg->data_initial_chunk.size;
|
data_left = msg->data_length - msg->data_initial_chunk.size;
|
||||||
send_request_chunk();
|
send_request_chunk();
|
||||||
} else {
|
} else {
|
||||||
layoutProgress("Signing", 50);
|
|
||||||
send_signature();
|
send_signature();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user