diff --git a/common/protob/messages-ethereum.proto b/common/protob/messages-ethereum.proto index 2f6ff12e565..21dd426d0c8 100644 --- a/common/protob/messages-ethereum.proto +++ b/common/protob/messages-ethereum.proto @@ -65,7 +65,7 @@ message EthereumSignTx { optional bytes value = 6; // <=256 bit unsigned big endian (in wei) optional bytes data_initial_chunk = 7; // The initial data chunk (<= 1024 bytes) 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 } @@ -86,7 +86,7 @@ message EthereumSignTxEIP1559 { required bytes value = 7; // <=256 bit unsigned big endian (in wei) optional bytes data_initial_chunk = 8 [default='']; // The initial data chunk (<= 1024 bytes) 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 message EthereumAccessList { @@ -104,7 +104,7 @@ message EthereumSignTxEIP1559 { */ message EthereumTxRequest { optional uint32 data_length = 1; // Number of bytes being requested (<= 1024) - optional uint32 signature_v = 2; // Computed signature (recovery parameter, limited to 27 or 28) + optional uint64 signature_v = 2; // Computed signature (recovery parameter, limited to 27 or 28) optional bytes signature_r = 3; // Computed signature R component (256 bit) optional bytes signature_s = 4; // Computed signature S component (256 bit) } diff --git a/core/.changelog.d/1771.added b/core/.changelog.d/1771.added new file mode 100644 index 00000000000..fe5e9ab41aa --- /dev/null +++ b/core/.changelog.d/1771.added @@ -0,0 +1 @@ +Ethereum: support 64-bit chain IDs diff --git a/crypto/address.c b/crypto/address.c index 8f3aa9734ab..6379489b097 100644 --- a/crypto/address.c +++ b/crypto/address.c @@ -58,7 +58,7 @@ bool address_check_prefix(const uint8_t *addr, uint32_t address_type) { #include "sha3.h" void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, - uint32_t chain_id) { + uint64_t chain_id) { const char *hex = "0123456789abcdef"; for (int i = 0; i < 20; i++) { address[i * 2] = hex[(addr[i] >> 4) & 0xF]; diff --git a/crypto/address.h b/crypto/address.h index 8147f2c35a8..e799484ee9a 100644 --- a/crypto/address.h +++ b/crypto/address.h @@ -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); #if USE_ETHEREUM void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, - uint32_t chain_id); + uint64_t chain_id); #endif #endif diff --git a/legacy/firmware/.changelog.d/1771.added b/legacy/firmware/.changelog.d/1771.added new file mode 100644 index 00000000000..fe5e9ab41aa --- /dev/null +++ b/legacy/firmware/.changelog.d/1771.added @@ -0,0 +1 @@ +Ethereum: support 64-bit chain IDs diff --git a/legacy/firmware/ethereum.c b/legacy/firmware/ethereum.c index edb51f299db..7da5a188193 100644 --- a/legacy/firmware/ethereum.c +++ b/legacy/firmware/ethereum.c @@ -37,14 +37,16 @@ #include "transaction.h" #include "util.h" -/* maximum supported chain id. v must fit in an uint32_t. */ -#define MAX_CHAIN_ID 2147483629 +/* maximum supported chain id. + * signature_v must also fit in an uint64_t. + */ +#define MAX_CHAIN_ID ((0xFFFFFFFFFFFFFFFF - 35) >> 1) static bool ethereum_signing = false; static uint32_t data_total, data_left; static EthereumTxRequest msg_tx_request; static CONFIDENTIAL uint8_t privkey[32]; -static uint32_t chain_id; +static uint64_t chain_id; static uint32_t tx_type; 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. * 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) { return; } - uint8_t data[4] = {0}; - data[0] = (number >> 24) & 0xff; - data[1] = (number >> 16) & 0xff; - data[2] = (number >> 8) & 0xff; - data[3] = (number)&0xff; + uint8_t data[8] = {0}; + data[0] = (number >> 56) & 0xff; + data[1] = (number >> 48) & 0xff; + data[2] = (number >> 40) & 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; while (!data[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 <= 0x7f) { - return 1; - } else if (number <= 0xff) { - return 2; - } else if (number <= 0xffff) { - return 3; - } else if (number <= 0xffffff) { - return 4; - } else { - return 5; +/* If number is less than 0x80 the RLP encoding is iteself (1 byte). + * If it is 0x80 or larger, RLP encoding is 1 + length in bytes. + */ +static int rlp_calculate_number_length(uint64_t number) { + int length = 1; + if (number >= 0x80) { + while (number) { + length++; + number = number >> 8; + } } + return length; } static void send_request_chunk(void) { diff --git a/legacy/firmware/ethereum_tokens.c.mako b/legacy/firmware/ethereum_tokens.c.mako index a16d60da934..19737f84db8 100644 --- a/legacy/firmware/ethereum_tokens.c.mako +++ b/legacy/firmware/ethereum_tokens.c.mako @@ -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 }; 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; for (int i = 0; i < TOKENS_COUNT; i++) { diff --git a/legacy/firmware/ethereum_tokens.h.mako b/legacy/firmware/ethereum_tokens.h.mako index 12008d7efdb..160506c3d33 100644 --- a/legacy/firmware/ethereum_tokens.h.mako +++ b/legacy/firmware/ethereum_tokens.h.mako @@ -10,7 +10,7 @@ #define TOKENS_COUNT ${len(erc20_list)} typedef struct { - uint32_t chain_id; + uint64_t chain_id; const char * const address; const char * const ticker; int decimals; @@ -20,6 +20,6 @@ extern const TokenType tokens[TOKENS_COUNT]; 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 diff --git a/legacy/firmware/fsm_msg_ethereum.h b/legacy/firmware/fsm_msg_ethereum.h index 20115bb6847..82d4fa4d503 100644 --- a/legacy/firmware/fsm_msg_ethereum.h +++ b/legacy/firmware/fsm_msg_ethereum.h @@ -99,7 +99,7 @@ void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) { uint32_t slip44 = (msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0; bool rskip60 = false; - uint32_t chain_id = 0; + uint64_t chain_id = 0; // constants from trezor-common/defs/ethereum/networks.json switch (slip44) { case 137: diff --git a/python/.changelog.d/1771.added b/python/.changelog.d/1771.added new file mode 100644 index 00000000000..fe5e9ab41aa --- /dev/null +++ b/python/.changelog.d/1771.added @@ -0,0 +1 @@ +Ethereum: support 64-bit chain IDs diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index 4acc24239d5..dd0b5bccabc 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -3942,7 +3942,7 @@ class EthereumSignTx(protobuf.MessageType): 6: protobuf.Field("value", "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), - 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), } @@ -3984,7 +3984,7 @@ class EthereumSignTxEIP1559(protobuf.MessageType): 7: protobuf.Field("value", "bytes", repeated=False, required=True), 8: protobuf.Field("data_initial_chunk", "bytes", repeated=False, required=False), 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), } @@ -4020,7 +4020,7 @@ class EthereumTxRequest(protobuf.MessageType): MESSAGE_WIRE_TYPE = 59 FIELDS = { 1: protobuf.Field("data_length", "uint32", repeated=False, required=False), - 2: protobuf.Field("signature_v", "uint32", repeated=False, required=False), + 2: protobuf.Field("signature_v", "uint64", repeated=False, required=False), 3: protobuf.Field("signature_r", "bytes", repeated=False, required=False), 4: protobuf.Field("signature_s", "bytes", repeated=False, required=False), } diff --git a/tests/device_tests/test_msg_ethereum_signtx_eip155.py b/tests/device_tests/test_msg_ethereum_signtx_eip155.py index 43260dd5539..0dfcfc931d7 100644 --- a/tests/device_tests/test_msg_ethereum_signtx_eip155.py +++ b/tests/device_tests/test_msg_ethereum_signtx_eip155.py @@ -20,6 +20,8 @@ from trezorlib import ethereum from trezorlib.tools import parse_path +MAX_CHAIN_ID = 2147483629 + VECTORS_CHAIN_IDS = ( # chain_id, slip44, sig_v, sig_r, sig_s # Ethereum ( @@ -101,6 +103,66 @@ "1447ba45be9fca42bcbf250389403245c8c1b0476e60b96dea320b0a596b5528", ), ), + # Previous max chain id + ( + 2147483639, + 1, + ( + 4294967314, + "f06ba56a3d3602a3d39a614375b2867f8a867354ba17fde98a5cb5f1806320d1", + "7bc197e0f656e52183805abada49c7d41f5d2b929f1ae0ebe99618286dfed116", + ), + ), + # PALM + ( + 11297108109, + 60, + ( + 22594216254, + "9d05ca7cdcf971f3114c0ef8d636c5aae1353bb227e04ec1198c60d874e676c0", + "35414067209e27fb690d9387264c74e334e25a117705f3583fb24434a952c9ca", + ), + ), + # PALM + ( + 11297108109, + 1, + ( + 22594216253, + "cccccef8f6636f316e69a1239436f9d61021501ba20ed72b6528c84b2f727980", + "614cb533a5d73cbf92ba4683c87c9238d0547572ee8f0f821ab1decdfc9639b8", + ), + ), + # MAX_CHAIN_ID + ( + MAX_CHAIN_ID, + 1, + ( + 4294967293, + "97f217d851c9f54013d7792d3b06492abbeda334191687323f08e03e979bd6c9", + "6a5f60d9abb1fa76be8ab76d3c879e1f0187e432692e3e9adce60642f06abe74", + ), + ), + # MAX_CHAIN_ID+1 + ( + MAX_CHAIN_ID + 1, + 1, + ( + 4294967296, + "f643499025c61025d27f7815ed1b1dcd92233548ebdd13bdd056e9cf3f84a853", + "33f363b014e5a404bec8479bb08649a6843f65c1f3166d3289211fb5361dab45", + ), + ), + # Max uint64 + ( + 0xFFFF_FFFF_FFFF_FFFF, + 1, + ( + 36893488147419103266, + "7bf581e8c7ff7d0e94d25eaa476de928d444b180fe50a91374b8883ff5dee3a8", + "3a3efa7a3f97043a999b3183d958a03126ec2652608c376c4626850b9b6a33fa", + ), + ), )