feat(core,legacy): add support for Ethereum 64-bit chain_id

* Changes from original PR

* Now that we are rejecting chain_ids of 0, we need to have the tests set the chain_ids to at least 1.

* Ran 'make gen' and uploaded changed files.

* Ran make style_check and fixed reported errors

* Added changelog files

* Reverted changes concerning chain_id 0 being rejected.

* Adds tests for MAX_CHAIN_ID and MAX_CHAIN_ID+1.  Also reverts MAX_CHAIN_ID to the previous value.

* Added missing whitespace around arithmetic operator.

Co-authored-by: Michael Hatton <michaelhatton@Michaels-Mini.fios-router.home>
pull/1804/head
arbitrarylink 3 years ago committed by matejcik
parent 4827969cc8
commit f051225730

@ -65,7 +65,7 @@ message EthereumSignTx {
optional bytes value = 6; // <=256 bit unsigned big endian (in wei) optional bytes value = 6; // <=256 bit unsigned big endian (in wei)
optional bytes data_initial_chunk = 7; // The initial data chunk (<= 1024 bytes) optional bytes data_initial_chunk = 7; // The initial data chunk (<= 1024 bytes)
optional uint32 data_length = 8; // Length of transaction payload optional uint32 data_length = 8; // Length of transaction payload
optional uint32 chain_id = 9; // Chain Id for EIP 155 optional uint64 chain_id = 9; // Chain Id for EIP 155
optional uint32 tx_type = 10; // Used for Wanchain optional uint32 tx_type = 10; // Used for Wanchain
} }
@ -77,17 +77,17 @@ message EthereumSignTx {
* @next Failure * @next Failure
*/ */
message EthereumSignTxEIP1559 { message EthereumSignTxEIP1559 {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
required bytes nonce = 2; // <=256 bit unsigned big endian required bytes nonce = 2; // <=256 bit unsigned big endian
required bytes max_gas_fee = 3; // <=256 bit unsigned big endian (in wei) required bytes max_gas_fee = 3; // <=256 bit unsigned big endian (in wei)
required bytes max_priority_fee = 4; // <=256 bit unsigned big endian (in wei) required bytes max_priority_fee = 4; // <=256 bit unsigned big endian (in wei)
required bytes gas_limit = 5; // <=256 bit unsigned big endian required bytes gas_limit = 5; // <=256 bit unsigned big endian
optional string to = 6 [default='']; // recipient address optional string to = 6 [default='']; // recipient address
required bytes value = 7; // <=256 bit unsigned big endian (in wei) required bytes value = 7; // <=256 bit unsigned big endian (in wei)
optional bytes data_initial_chunk = 8 [default='']; // The initial data chunk (<= 1024 bytes) optional bytes data_initial_chunk = 8 [default='']; // The initial data chunk (<= 1024 bytes)
required uint32 data_length = 9; // Length of transaction payload required uint32 data_length = 9; // Length of transaction payload
required uint32 chain_id = 10; // Chain Id for EIP 155 required uint64 chain_id = 10; // Chain Id for EIP 155
repeated EthereumAccessList access_list = 11; // Access List repeated EthereumAccessList access_list = 11; // Access List
message EthereumAccessList { message EthereumAccessList {
required string address = 1; required string address = 1;

@ -155,6 +155,82 @@
"sig_r": "f699de96e886995e460e760839d4f2c7b9f1c98f2d3c108d0add4e8663a679d8", "sig_r": "f699de96e886995e460e760839d4f2c7b9f1c98f2d3c108d0add4e8663a679d8",
"sig_s": "1447ba45be9fca42bcbf250389403245c8c1b0476e60b96dea320b0a596b5528" "sig_s": "1447ba45be9fca42bcbf250389403245c8c1b0476e60b96dea320b0a596b5528"
} }
},
{
"name": "Palm",
"parameters": {
"chain_id": 11297108109,
"path": "44'/60'/0'/0/0",
"nonce": 0,
"gas_price": 20000000000,
"gas_limit": 21000,
"value": 10000000000,
"to_address": "0x8eA7a3fccC211ED48b763b4164884DDbcF3b0A98",
"tx_type": null,
"data": ""
},
"result": {
"sig_v": 22594216254,
"sig_r": "9d05ca7cdcf971f3114c0ef8d636c5aae1353bb227e04ec1198c60d874e676c0",
"sig_s": "35414067209e27fb690d9387264c74e334e25a117705f3583fb24434a952c9ca"
}
},
{
"name": "max_chain_id",
"parameters": {
"chain_id": 2147483629,
"path": "44'/1'/0'/0/0",
"nonce": 0,
"gas_price": 20000000000,
"gas_limit": 21000,
"value": 10000000000,
"to_address": "0x8eA7a3fccC211ED48b763b4164884DDbcF3b0A98",
"tx_type": null,
"data": ""
},
"result": {
"sig_v": 4294967293,
"sig_r": "97f217d851c9f54013d7792d3b06492abbeda334191687323f08e03e979bd6c9",
"sig_s": "6a5f60d9abb1fa76be8ab76d3c879e1f0187e432692e3e9adce60642f06abe74"
}
},
{
"name": "max_chain_plus_one",
"parameters": {
"chain_id": 2147483630,
"path": "44'/1'/0'/0/0",
"nonce": 0,
"gas_price": 20000000000,
"gas_limit": 21000,
"value": 10000000000,
"to_address": "0x8eA7a3fccC211ED48b763b4164884DDbcF3b0A98",
"tx_type": null,
"data": ""
},
"result": {
"sig_v": 4294967296,
"sig_r": "f643499025c61025d27f7815ed1b1dcd92233548ebdd13bdd056e9cf3f84a853",
"sig_s": "33f363b014e5a404bec8479bb08649a6843f65c1f3166d3289211fb5361dab45"
}
},
{
"name": "max_uint64",
"parameters": {
"chain_id": 18446744073709551615,
"path": "44'/1'/0'/0/0",
"nonce": 0,
"gas_price": 20000000000,
"gas_limit": 21000,
"value": 10000000000,
"to_address": "0x8eA7a3fccC211ED48b763b4164884DDbcF3b0A98",
"tx_type": null,
"data": ""
},
"result": {
"sig_v": 36893488147419103266,
"sig_r": "7bf581e8c7ff7d0e94d25eaa476de928d444b180fe50a91374b8883ff5dee3a8",
"sig_s": "3a3efa7a3f97043a999b3183d958a03126ec2652608c376c4626850b9b6a33fa"
}
} }
] ]
} }

@ -0,0 +1 @@
Ethereum: support 64-bit chain IDs

@ -16,8 +16,10 @@ from .layout import (
require_confirm_unknown_token, require_confirm_unknown_token,
) )
# maximum supported chain id # Maximum chain_id which returns the full signature_v (which must fit into an uint32).
MAX_CHAIN_ID = 2147483629 # chain_ids larger than this will only return one bit and the caller must recalculate
# the full value: v = 2 * chain_id + 35 + v_bit
MAX_CHAIN_ID = (0xFFFF_FFFF - 36) // 2
@with_keychain_from_chain_id @with_keychain_from_chain_id

@ -58,7 +58,7 @@ bool address_check_prefix(const uint8_t *addr, uint32_t address_type) {
#include "sha3.h" #include "sha3.h"
void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60,
uint32_t chain_id) { uint64_t chain_id) {
const char *hex = "0123456789abcdef"; const char *hex = "0123456789abcdef";
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
address[i * 2] = hex[(addr[i] >> 4) & 0xF]; address[i * 2] = hex[(addr[i] >> 4) & 0xF];

@ -34,7 +34,7 @@ void address_write_prefix_bytes(uint32_t address_type, uint8_t *out);
bool address_check_prefix(const uint8_t *addr, uint32_t address_type); bool address_check_prefix(const uint8_t *addr, uint32_t address_type);
#if USE_ETHEREUM #if USE_ETHEREUM
void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60,
uint32_t chain_id); uint64_t chain_id);
#endif #endif
#endif #endif

@ -0,0 +1 @@
Ethereum: support 64-bit chain IDs

@ -37,14 +37,16 @@
#include "transaction.h" #include "transaction.h"
#include "util.h" #include "util.h"
/* maximum supported chain id. v must fit in an uint32_t. */ /* Maximum chain_id which returns the full signature_v (which must fit into an
#define MAX_CHAIN_ID 2147483629 uint32). chain_ids larger than this will only return one bit and the caller must
recalculate the full value: v = 2 * chain_id + 35 + v_bit */
#define MAX_CHAIN_ID ((0xFFFFFFFF - 36) >> 1)
static bool ethereum_signing = false; static bool ethereum_signing = false;
static uint32_t data_total, data_left; static uint32_t data_total, data_left;
static EthereumTxRequest msg_tx_request; static EthereumTxRequest msg_tx_request;
static CONFIDENTIAL uint8_t privkey[32]; static CONFIDENTIAL uint8_t privkey[32];
static uint32_t chain_id; static uint64_t chain_id;
static uint32_t tx_type; static uint32_t tx_type;
struct SHA3_CTX keccak_ctx = {0}; struct SHA3_CTX keccak_ctx = {0};
@ -118,20 +120,24 @@ static void hash_rlp_field(const uint8_t *buf, size_t size) {
* Push an RLP encoded number to the hash buffer. * Push an RLP encoded number to the hash buffer.
* Ethereum yellow paper says to convert to big endian and strip leading zeros. * Ethereum yellow paper says to convert to big endian and strip leading zeros.
*/ */
static void hash_rlp_number(uint32_t number) { static void hash_rlp_number(uint64_t number) {
if (!number) { if (!number) {
return; return;
} }
uint8_t data[4] = {0}; uint8_t data[8] = {0};
data[0] = (number >> 24) & 0xff; data[0] = (number >> 56) & 0xff;
data[1] = (number >> 16) & 0xff; data[1] = (number >> 48) & 0xff;
data[2] = (number >> 8) & 0xff; data[2] = (number >> 40) & 0xff;
data[3] = (number)&0xff; data[3] = (number >> 32) & 0xff;
data[4] = (number >> 24) & 0xff;
data[5] = (number >> 16) & 0xff;
data[6] = (number >> 8) & 0xff;
data[7] = (number)&0xff;
int offset = 0; int offset = 0;
while (!data[offset]) { while (!data[offset]) {
offset++; offset++;
} }
hash_rlp_field(data + offset, 4 - offset); hash_rlp_field(data + offset, 8 - offset);
} }
/* /*
@ -153,18 +159,18 @@ static int rlp_calculate_length(int length, uint8_t firstbyte) {
} }
} }
static int rlp_calculate_number_length(uint32_t number) { /* If number is less than 0x80 the RLP encoding is iteself (1 byte).
if (number <= 0x7f) { * If it is 0x80 or larger, RLP encoding is 1 + length in bytes.
return 1; */
} else if (number <= 0xff) { static int rlp_calculate_number_length(uint64_t number) {
return 2; int length = 1;
} else if (number <= 0xffff) { if (number >= 0x80) {
return 3; while (number) {
} else if (number <= 0xffffff) { length++;
return 4; number = number >> 8;
} else { }
return 5;
} }
return length;
} }
static void send_request_chunk(void) { static void send_request_chunk(void) {

@ -13,7 +13,7 @@ const TokenType tokens[TOKENS_COUNT] = {
static const TokenType _UnknownToken = { 0, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", " UNKN", 0 }; static const TokenType _UnknownToken = { 0, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", " UNKN", 0 };
const TokenType *UnknownToken = &_UnknownToken; const TokenType *UnknownToken = &_UnknownToken;
const TokenType *tokenByChainAddress(uint32_t chain_id, const uint8_t *address) const TokenType *tokenByChainAddress(uint64_t chain_id, const uint8_t *address)
{ {
if (!address) return 0; if (!address) return 0;
for (int i = 0; i < TOKENS_COUNT; i++) { for (int i = 0; i < TOKENS_COUNT; i++) {

@ -10,7 +10,7 @@
#define TOKENS_COUNT ${len(erc20_list)} #define TOKENS_COUNT ${len(erc20_list)}
typedef struct { typedef struct {
uint32_t chain_id; uint64_t chain_id;
const char * const address; const char * const address;
const char * const ticker; const char * const ticker;
int decimals; int decimals;
@ -20,6 +20,6 @@ extern const TokenType tokens[TOKENS_COUNT];
extern const TokenType *UnknownToken; extern const TokenType *UnknownToken;
const TokenType *tokenByChainAddress(uint32_t chain_id, const uint8_t *address); const TokenType *tokenByChainAddress(uint64_t chain_id, const uint8_t *address);
#endif #endif

@ -99,7 +99,7 @@ void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) {
uint32_t slip44 = uint32_t slip44 =
(msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0; (msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0;
bool rskip60 = false; bool rskip60 = false;
uint32_t chain_id = 0; uint64_t chain_id = 0;
// constants from trezor-common/defs/ethereum/networks.json // constants from trezor-common/defs/ethereum/networks.json
switch (slip44) { switch (slip44) {
case 137: case 137:

@ -0,0 +1 @@
Ethereum: support 64-bit chain IDs

@ -4264,7 +4264,7 @@ class EthereumSignTx(protobuf.MessageType):
6: protobuf.Field("value", "bytes", repeated=False, required=False), 6: protobuf.Field("value", "bytes", repeated=False, required=False),
7: protobuf.Field("data_initial_chunk", "bytes", repeated=False, required=False), 7: protobuf.Field("data_initial_chunk", "bytes", repeated=False, required=False),
8: protobuf.Field("data_length", "uint32", repeated=False, required=False), 8: protobuf.Field("data_length", "uint32", repeated=False, required=False),
9: protobuf.Field("chain_id", "uint32", repeated=False, required=False), 9: protobuf.Field("chain_id", "uint64", repeated=False, required=False),
10: protobuf.Field("tx_type", "uint32", repeated=False, required=False), 10: protobuf.Field("tx_type", "uint32", repeated=False, required=False),
} }
@ -4306,7 +4306,7 @@ class EthereumSignTxEIP1559(protobuf.MessageType):
7: protobuf.Field("value", "bytes", repeated=False, required=True), 7: protobuf.Field("value", "bytes", repeated=False, required=True),
8: protobuf.Field("data_initial_chunk", "bytes", repeated=False, required=False), 8: protobuf.Field("data_initial_chunk", "bytes", repeated=False, required=False),
9: protobuf.Field("data_length", "uint32", repeated=False, required=True), 9: protobuf.Field("data_length", "uint32", repeated=False, required=True),
10: protobuf.Field("chain_id", "uint32", repeated=False, required=True), 10: protobuf.Field("chain_id", "uint64", repeated=False, required=True),
11: protobuf.Field("access_list", "EthereumAccessList", repeated=True, required=False), 11: protobuf.Field("access_list", "EthereumAccessList", repeated=True, required=False),
} }

Loading…
Cancel
Save