Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
6 changes: 3 additions & 3 deletions common/protob/messages-ethereum.proto
Expand Up @@ -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
}

Expand All @@ -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 {
Expand All @@ -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)
}
Expand Down
1 change: 1 addition & 0 deletions core/.changelog.d/1771.added
@@ -0,0 +1 @@
Ethereum: support 64-bit chain IDs
2 changes: 1 addition & 1 deletion crypto/address.c
Expand Up @@ -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];
Expand Down
2 changes: 1 addition & 1 deletion crypto/address.h
Expand Up @@ -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
1 change: 1 addition & 0 deletions legacy/firmware/.changelog.d/1771.added
@@ -0,0 +1 @@
Ethereum: support 64-bit chain IDs
48 changes: 27 additions & 21 deletions legacy/firmware/ethereum.c
Expand Up @@ -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};

Expand Down Expand Up @@ -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);
}

/*
Expand All @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion legacy/firmware/ethereum_tokens.c.mako
Expand Up @@ -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++) {
Expand Down
4 changes: 2 additions & 2 deletions legacy/firmware/ethereum_tokens.h.mako
Expand Up @@ -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;
Expand All @@ -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
2 changes: 1 addition & 1 deletion legacy/firmware/fsm_msg_ethereum.h
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions python/.changelog.d/1771.added
@@ -0,0 +1 @@
Ethereum: support 64-bit chain IDs
6 changes: 3 additions & 3 deletions python/src/trezorlib/messages.py
Expand Up @@ -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),
}

Expand Down Expand Up @@ -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),
}

Expand Down Expand Up @@ -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),
}
Expand Down
62 changes: 62 additions & 0 deletions tests/device_tests/test_msg_ethereum_signtx_eip155.py
Expand Up @@ -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
(
Expand Down Expand Up @@ -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
arbitrarylink marked this conversation as resolved.
Show resolved Hide resolved
(
0xFFFF_FFFF_FFFF_FFFF,
1,
(
36893488147419103266,
"7bf581e8c7ff7d0e94d25eaa476de928d444b180fe50a91374b8883ff5dee3a8",
"3a3efa7a3f97043a999b3183d958a03126ec2652608c376c4626850b9b6a33fa",
),
),
)


Expand Down