From 179670b8aa6da03de5b758a24cd8b0b7b0a56f83 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Tue, 8 Apr 2025 12:43:27 +0200 Subject: [PATCH] feat(core): Add mac to EthereumAddress. --- common/protob/messages-ethereum.proto | 3 +- core/src/apps/ethereum/get_address.py | 7 +- core/src/trezor/messages.py | 2 + python/src/trezorlib/ethereum.py | 13 +- python/src/trezorlib/messages.py | 3 + .../src/protos/generated/messages_ethereum.rs | 153 ++++++++++++------ 6 files changed, 125 insertions(+), 56 deletions(-) diff --git a/common/protob/messages-ethereum.proto b/common/protob/messages-ethereum.proto index ee4010bd08..6aff81ea4a 100644 --- a/common/protob/messages-ethereum.proto +++ b/common/protob/messages-ethereum.proto @@ -47,7 +47,8 @@ message EthereumGetAddress { */ message EthereumAddress { optional bytes _old_address = 1 [deprecated=true]; // trezor <1.8.0, <2.1.0 - raw bytes of Ethereum address - optional string address = 2; // Ethereum address as hex-encoded string + optional string address = 2; // Ethereum address as hex-encoded string + optional bytes mac = 3; // Address authentication code } /** diff --git a/core/src/apps/ethereum/get_address.py b/core/src/apps/ethereum/get_address.py index 92ab88bd08..75eac57102 100644 --- a/core/src/apps/ethereum/get_address.py +++ b/core/src/apps/ethereum/get_address.py @@ -20,6 +20,7 @@ async def get_address( from trezor.ui.layouts import show_address from apps.common import paths + from apps.common.address_mac import get_address_mac from .helpers import address_from_bytes @@ -31,8 +32,10 @@ async def get_address( address = address_from_bytes(node.ethereum_pubkeyhash(), defs.network) + slip44_id = address_n[1] # it depends on the network (ETH vs ETC...) + mac = get_address_mac(address, paths.unharden(slip44_id), keychain) + if msg.show_display: - slip44_id = address_n[1] # it depends on the network (ETH vs ETC...) await show_address( address, path=paths.address_n_to_str(address_n), @@ -42,4 +45,4 @@ async def get_address( chunkify=bool(msg.chunkify), ) - return EthereumAddress(address=address) + return EthereumAddress(address=address, mac=mac) diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index c35cc70092..34dcc0c9de 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -3822,11 +3822,13 @@ if TYPE_CHECKING: class EthereumAddress(protobuf.MessageType): address: "str | None" + mac: "bytes | None" def __init__( self, *, address: "str | None" = None, + mac: "bytes | None" = None, ) -> None: pass diff --git a/python/src/trezorlib/ethereum.py b/python/src/trezorlib/ethereum.py index 96ce4d1066..9fd892f3c1 100644 --- a/python/src/trezorlib/ethereum.py +++ b/python/src/trezorlib/ethereum.py @@ -160,13 +160,19 @@ def network_from_address_n( # ====== Client functions ====== # -def get_address( +def get_address(*args: Any, **kwargs: Any) -> str: + resp = get_authenticated_address(*args, **kwargs) + assert resp.address is not None + return resp.address + + +def get_authenticated_address( client: "TrezorClient", n: "Address", show_display: bool = False, encoded_network: Optional[bytes] = None, chunkify: bool = False, -) -> str: +) -> messages.EthereumAddress: resp = client.call( messages.EthereumGetAddress( address_n=n, @@ -176,8 +182,7 @@ def get_address( ), expect=messages.EthereumAddress, ) - assert resp.address is not None - return resp.address + return resp def get_public_node( diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index 13d9b42fd8..51d30707bc 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -5190,6 +5190,7 @@ class EthereumAddress(protobuf.MessageType): FIELDS = { 1: protobuf.Field("_old_address", "bytes", repeated=False, required=False, default=None), 2: protobuf.Field("address", "string", repeated=False, required=False, default=None), + 3: protobuf.Field("mac", "bytes", repeated=False, required=False, default=None), } def __init__( @@ -5197,9 +5198,11 @@ class EthereumAddress(protobuf.MessageType): *, _old_address: Optional["bytes"] = None, address: Optional["str"] = None, + mac: Optional["bytes"] = None, ) -> None: self._old_address = _old_address self.address = address + self.mac = mac class EthereumSignTx(protobuf.MessageType): diff --git a/rust/trezor-client/src/protos/generated/messages_ethereum.rs b/rust/trezor-client/src/protos/generated/messages_ethereum.rs index 98650c8319..79ebcde4c4 100644 --- a/rust/trezor-client/src/protos/generated/messages_ethereum.rs +++ b/rust/trezor-client/src/protos/generated/messages_ethereum.rs @@ -636,6 +636,8 @@ pub struct EthereumAddress { pub _old_address: ::std::option::Option<::std::vec::Vec>, // @@protoc_insertion_point(field:hw.trezor.messages.ethereum.EthereumAddress.address) pub address: ::std::option::Option<::std::string::String>, + // @@protoc_insertion_point(field:hw.trezor.messages.ethereum.EthereumAddress.mac) + pub mac: ::std::option::Option<::std::vec::Vec>, // special fields // @@protoc_insertion_point(special_field:hw.trezor.messages.ethereum.EthereumAddress.special_fields) pub special_fields: ::protobuf::SpecialFields, @@ -724,8 +726,44 @@ impl EthereumAddress { self.address.take().unwrap_or_else(|| ::std::string::String::new()) } + // optional bytes mac = 3; + + pub fn mac(&self) -> &[u8] { + match self.mac.as_ref() { + Some(v) => v, + None => &[], + } + } + + pub fn clear_mac(&mut self) { + self.mac = ::std::option::Option::None; + } + + pub fn has_mac(&self) -> bool { + self.mac.is_some() + } + + // Param is passed by value, moved + pub fn set_mac(&mut self, v: ::std::vec::Vec) { + self.mac = ::std::option::Option::Some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_mac(&mut self) -> &mut ::std::vec::Vec { + if self.mac.is_none() { + self.mac = ::std::option::Option::Some(::std::vec::Vec::new()); + } + self.mac.as_mut().unwrap() + } + + // Take field + pub fn take_mac(&mut self) -> ::std::vec::Vec { + self.mac.take().unwrap_or_else(|| ::std::vec::Vec::new()) + } + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { - let mut fields = ::std::vec::Vec::with_capacity(2); + let mut fields = ::std::vec::Vec::with_capacity(3); let mut oneofs = ::std::vec::Vec::with_capacity(0); fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( "_old_address", @@ -737,6 +775,11 @@ impl EthereumAddress { |m: &EthereumAddress| { &m.address }, |m: &mut EthereumAddress| { &mut m.address }, )); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "mac", + |m: &EthereumAddress| { &m.mac }, + |m: &mut EthereumAddress| { &mut m.mac }, + )); ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( "EthereumAddress", fields, @@ -761,6 +804,9 @@ impl ::protobuf::Message for EthereumAddress { 18 => { self.address = ::std::option::Option::Some(is.read_string()?); }, + 26 => { + self.mac = ::std::option::Option::Some(is.read_bytes()?); + }, tag => { ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; }, @@ -779,6 +825,9 @@ impl ::protobuf::Message for EthereumAddress { if let Some(v) = self.address.as_ref() { my_size += ::protobuf::rt::string_size(2, &v); } + if let Some(v) = self.mac.as_ref() { + my_size += ::protobuf::rt::bytes_size(3, &v); + } my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); self.special_fields.cached_size().set(my_size as u32); my_size @@ -791,6 +840,9 @@ impl ::protobuf::Message for EthereumAddress { if let Some(v) = self.address.as_ref() { os.write_string(2, v)?; } + if let Some(v) = self.mac.as_ref() { + os.write_bytes(3, v)?; + } os.write_unknown_fields(self.special_fields.unknown_fields())?; ::std::result::Result::Ok(()) } @@ -810,6 +862,7 @@ impl ::protobuf::Message for EthereumAddress { fn clear(&mut self) { self._old_address = ::std::option::Option::None; self.address = ::std::option::Option::None; + self.mac = ::std::option::Option::None; self.special_fields.clear(); } @@ -817,6 +870,7 @@ impl ::protobuf::Message for EthereumAddress { static instance: EthereumAddress = EthereumAddress { _old_address: ::std::option::Option::None, address: ::std::option::Option::None, + mac: ::std::option::Option::None, special_fields: ::protobuf::SpecialFields::new(), }; &instance @@ -4103,55 +4157,56 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \"\x99\x01\n\x12EthereumGetAddress\x12\x1b\n\taddress_n\x18\x01\x20\x03(\ \rR\x08addressN\x12!\n\x0cshow_display\x18\x02\x20\x01(\x08R\x0bshowDisp\ lay\x12'\n\x0fencoded_network\x18\x03\x20\x01(\x0cR\x0eencodedNetwork\ - \x12\x1a\n\x08chunkify\x18\x04\x20\x01(\x08R\x08chunkify\"Q\n\x0fEthereu\ + \x12\x1a\n\x08chunkify\x18\x04\x20\x01(\x08R\x08chunkify\"c\n\x0fEthereu\ mAddress\x12$\n\x0c_old_address\x18\x01\x20\x01(\x0cR\nOldAddressB\x02\ - \x18\x01\x12\x18\n\x07address\x18\x02\x20\x01(\tR\x07address\"\xad\x03\n\ - \x0eEthereumSignTx\x12\x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\ - \x12\x16\n\x05nonce\x18\x02\x20\x01(\x0c:\0R\x05nonce\x12\x1b\n\tgas_pri\ - ce\x18\x03\x20\x02(\x0cR\x08gasPrice\x12\x1b\n\tgas_limit\x18\x04\x20\ - \x02(\x0cR\x08gasLimit\x12\x10\n\x02to\x18\x0b\x20\x01(\t:\0R\x02to\x12\ - \x16\n\x05value\x18\x06\x20\x01(\x0c:\0R\x05value\x12.\n\x12data_initial\ - _chunk\x18\x07\x20\x01(\x0c:\0R\x10dataInitialChunk\x12\"\n\x0bdata_leng\ - th\x18\x08\x20\x01(\r:\x010R\ndataLength\x12\x19\n\x08chain_id\x18\t\x20\ - \x02(\x04R\x07chainId\x12\x17\n\x07tx_type\x18\n\x20\x01(\rR\x06txType\ - \x12^\n\x0bdefinitions\x18\x0c\x20\x01(\x0b2<.hw.trezor.messages.ethereu\ - m_definitions.EthereumDefinitionsR\x0bdefinitions\x12\x1a\n\x08chunkify\ - \x18\r\x20\x01(\x08R\x08chunkify\"\xfc\x04\n\x15EthereumSignTxEIP1559\ - \x12\x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\x12\x14\n\x05nonce\ - \x18\x02\x20\x02(\x0cR\x05nonce\x12\x1e\n\x0bmax_gas_fee\x18\x03\x20\x02\ - (\x0cR\tmaxGasFee\x12(\n\x10max_priority_fee\x18\x04\x20\x02(\x0cR\x0ema\ - xPriorityFee\x12\x1b\n\tgas_limit\x18\x05\x20\x02(\x0cR\x08gasLimit\x12\ - \x10\n\x02to\x18\x06\x20\x01(\t:\0R\x02to\x12\x14\n\x05value\x18\x07\x20\ - \x02(\x0cR\x05value\x12.\n\x12data_initial_chunk\x18\x08\x20\x01(\x0c:\0\ - R\x10dataInitialChunk\x12\x1f\n\x0bdata_length\x18\t\x20\x02(\rR\ndataLe\ - ngth\x12\x19\n\x08chain_id\x18\n\x20\x02(\x04R\x07chainId\x12f\n\x0bacce\ - ss_list\x18\x0b\x20\x03(\x0b2E.hw.trezor.messages.ethereum.EthereumSignT\ - xEIP1559.EthereumAccessListR\naccessList\x12^\n\x0bdefinitions\x18\x0c\ - \x20\x01(\x0b2<.hw.trezor.messages.ethereum_definitions.EthereumDefiniti\ - onsR\x0bdefinitions\x12\x1a\n\x08chunkify\x18\r\x20\x01(\x08R\x08chunkif\ - y\x1aQ\n\x12EthereumAccessList\x12\x18\n\x07address\x18\x01\x20\x02(\tR\ - \x07address\x12!\n\x0cstorage_keys\x18\x02\x20\x03(\x0cR\x0bstorageKeys\ - \"\x97\x01\n\x11EthereumTxRequest\x12\x1f\n\x0bdata_length\x18\x01\x20\ - \x01(\rR\ndataLength\x12\x1f\n\x0bsignature_v\x18\x02\x20\x01(\rR\nsigna\ - tureV\x12\x1f\n\x0bsignature_r\x18\x03\x20\x01(\x0cR\nsignatureR\x12\x1f\ - \n\x0bsignature_s\x18\x04\x20\x01(\x0cR\nsignatureS\".\n\rEthereumTxAck\ - \x12\x1d\n\ndata_chunk\x18\x01\x20\x02(\x0cR\tdataChunk\"\x91\x01\n\x13E\ - thereumSignMessage\x12\x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\ - \x12\x18\n\x07message\x18\x02\x20\x02(\x0cR\x07message\x12'\n\x0fencoded\ - _network\x18\x03\x20\x01(\x0cR\x0eencodedNetwork\x12\x1a\n\x08chunkify\ - \x18\x04\x20\x01(\x08R\x08chunkify\"R\n\x18EthereumMessageSignature\x12\ - \x1c\n\tsignature\x18\x02\x20\x02(\x0cR\tsignature\x12\x18\n\x07address\ - \x18\x03\x20\x02(\tR\x07address\"\x85\x01\n\x15EthereumVerifyMessage\x12\ - \x1c\n\tsignature\x18\x02\x20\x02(\x0cR\tsignature\x12\x18\n\x07message\ - \x18\x03\x20\x02(\x0cR\x07message\x12\x18\n\x07address\x18\x04\x20\x02(\ - \tR\x07address\x12\x1a\n\x08chunkify\x18\x05\x20\x01(\x08R\x08chunkify\"\ - \xb4\x01\n\x15EthereumSignTypedHash\x12\x1b\n\taddress_n\x18\x01\x20\x03\ - (\rR\x08addressN\x122\n\x15domain_separator_hash\x18\x02\x20\x02(\x0cR\ - \x13domainSeparatorHash\x12!\n\x0cmessage_hash\x18\x03\x20\x01(\x0cR\x0b\ - messageHash\x12'\n\x0fencoded_network\x18\x04\x20\x01(\x0cR\x0eencodedNe\ - twork\"T\n\x1aEthereumTypedDataSignature\x12\x1c\n\tsignature\x18\x01\ - \x20\x02(\x0cR\tsignature\x12\x18\n\x07address\x18\x02\x20\x02(\tR\x07ad\ - dressB<\n#com.satoshilabs.trezor.lib.protobufB\x15TrezorMessageEthereum\ + \x18\x01\x12\x18\n\x07address\x18\x02\x20\x01(\tR\x07address\x12\x10\n\ + \x03mac\x18\x03\x20\x01(\x0cR\x03mac\"\xad\x03\n\x0eEthereumSignTx\x12\ + \x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\x12\x16\n\x05nonce\x18\ + \x02\x20\x01(\x0c:\0R\x05nonce\x12\x1b\n\tgas_price\x18\x03\x20\x02(\x0c\ + R\x08gasPrice\x12\x1b\n\tgas_limit\x18\x04\x20\x02(\x0cR\x08gasLimit\x12\ + \x10\n\x02to\x18\x0b\x20\x01(\t:\0R\x02to\x12\x16\n\x05value\x18\x06\x20\ + \x01(\x0c:\0R\x05value\x12.\n\x12data_initial_chunk\x18\x07\x20\x01(\x0c\ + :\0R\x10dataInitialChunk\x12\"\n\x0bdata_length\x18\x08\x20\x01(\r:\x010\ + R\ndataLength\x12\x19\n\x08chain_id\x18\t\x20\x02(\x04R\x07chainId\x12\ + \x17\n\x07tx_type\x18\n\x20\x01(\rR\x06txType\x12^\n\x0bdefinitions\x18\ + \x0c\x20\x01(\x0b2<.hw.trezor.messages.ethereum_definitions.EthereumDefi\ + nitionsR\x0bdefinitions\x12\x1a\n\x08chunkify\x18\r\x20\x01(\x08R\x08chu\ + nkify\"\xfc\x04\n\x15EthereumSignTxEIP1559\x12\x1b\n\taddress_n\x18\x01\ + \x20\x03(\rR\x08addressN\x12\x14\n\x05nonce\x18\x02\x20\x02(\x0cR\x05non\ + ce\x12\x1e\n\x0bmax_gas_fee\x18\x03\x20\x02(\x0cR\tmaxGasFee\x12(\n\x10m\ + ax_priority_fee\x18\x04\x20\x02(\x0cR\x0emaxPriorityFee\x12\x1b\n\tgas_l\ + imit\x18\x05\x20\x02(\x0cR\x08gasLimit\x12\x10\n\x02to\x18\x06\x20\x01(\ + \t:\0R\x02to\x12\x14\n\x05value\x18\x07\x20\x02(\x0cR\x05value\x12.\n\ + \x12data_initial_chunk\x18\x08\x20\x01(\x0c:\0R\x10dataInitialChunk\x12\ + \x1f\n\x0bdata_length\x18\t\x20\x02(\rR\ndataLength\x12\x19\n\x08chain_i\ + d\x18\n\x20\x02(\x04R\x07chainId\x12f\n\x0baccess_list\x18\x0b\x20\x03(\ + \x0b2E.hw.trezor.messages.ethereum.EthereumSignTxEIP1559.EthereumAccessL\ + istR\naccessList\x12^\n\x0bdefinitions\x18\x0c\x20\x01(\x0b2<.hw.trezor.\ + messages.ethereum_definitions.EthereumDefinitionsR\x0bdefinitions\x12\ + \x1a\n\x08chunkify\x18\r\x20\x01(\x08R\x08chunkify\x1aQ\n\x12EthereumAcc\ + essList\x12\x18\n\x07address\x18\x01\x20\x02(\tR\x07address\x12!\n\x0cst\ + orage_keys\x18\x02\x20\x03(\x0cR\x0bstorageKeys\"\x97\x01\n\x11EthereumT\ + xRequest\x12\x1f\n\x0bdata_length\x18\x01\x20\x01(\rR\ndataLength\x12\ + \x1f\n\x0bsignature_v\x18\x02\x20\x01(\rR\nsignatureV\x12\x1f\n\x0bsigna\ + ture_r\x18\x03\x20\x01(\x0cR\nsignatureR\x12\x1f\n\x0bsignature_s\x18\ + \x04\x20\x01(\x0cR\nsignatureS\".\n\rEthereumTxAck\x12\x1d\n\ndata_chunk\ + \x18\x01\x20\x02(\x0cR\tdataChunk\"\x91\x01\n\x13EthereumSignMessage\x12\ + \x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\x12\x18\n\x07message\ + \x18\x02\x20\x02(\x0cR\x07message\x12'\n\x0fencoded_network\x18\x03\x20\ + \x01(\x0cR\x0eencodedNetwork\x12\x1a\n\x08chunkify\x18\x04\x20\x01(\x08R\ + \x08chunkify\"R\n\x18EthereumMessageSignature\x12\x1c\n\tsignature\x18\ + \x02\x20\x02(\x0cR\tsignature\x12\x18\n\x07address\x18\x03\x20\x02(\tR\ + \x07address\"\x85\x01\n\x15EthereumVerifyMessage\x12\x1c\n\tsignature\ + \x18\x02\x20\x02(\x0cR\tsignature\x12\x18\n\x07message\x18\x03\x20\x02(\ + \x0cR\x07message\x12\x18\n\x07address\x18\x04\x20\x02(\tR\x07address\x12\ + \x1a\n\x08chunkify\x18\x05\x20\x01(\x08R\x08chunkify\"\xb4\x01\n\x15Ethe\ + reumSignTypedHash\x12\x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08addressN\ + \x122\n\x15domain_separator_hash\x18\x02\x20\x02(\x0cR\x13domainSeparato\ + rHash\x12!\n\x0cmessage_hash\x18\x03\x20\x01(\x0cR\x0bmessageHash\x12'\n\ + \x0fencoded_network\x18\x04\x20\x01(\x0cR\x0eencodedNetwork\"T\n\x1aEthe\ + reumTypedDataSignature\x12\x1c\n\tsignature\x18\x01\x20\x02(\x0cR\tsigna\ + ture\x12\x18\n\x07address\x18\x02\x20\x02(\tR\x07addressB<\n#com.satoshi\ + labs.trezor.lib.protobufB\x15TrezorMessageEthereum\ "; /// `FileDescriptorProto` object which was a source for this generated file