diff --git a/CHANGELOG.md b/CHANGELOG.md index 8161952bd..6bd4f8ee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ customers cannot upgrade their bootloader, its changes are recorded separately. - Bitcoin: allow multisig accounts at arbitrary keypaths - Bitcoin: allow spendung UTXOs at very high BIP-44 address indices - Ethereum: allow signing EIP-712 messages containing multi-line strings +- Ethereum: display the addresses on device in the same case as the user input - Allow exiting the screen asking to insert the microSD card - HWW: add initialized status byte to _api_info response diff --git a/messages/eth.proto b/messages/eth.proto index c552e49c7..65c8f9016 100644 --- a/messages/eth.proto +++ b/messages/eth.proto @@ -27,6 +27,12 @@ enum ETHCoin { RinkebyETH = 2; } +enum ETHAddressCase { + ETH_ADDRESS_CASE_MIXED = 0; + ETH_ADDRESS_CASE_UPPER = 1; + ETH_ADDRESS_CASE_LOWER = 2; +} + message ETHPubRequest { repeated uint32 keypath = 1; // Deprecated: use chain_id instead. @@ -56,6 +62,7 @@ message ETHSignRequest { AntiKleptoHostNonceCommitment host_nonce_commitment = 9; // If non-zero, `coin` is ignored and `chain_id` is used to identify the network. uint64 chain_id = 10; + ETHAddressCase address_case = 11; } // TX payload for an EIP-1559 (type 2) transaction: https://eips.ethereum.org/EIPS/eip-1559 @@ -70,6 +77,7 @@ message ETHSignEIP1559Request { bytes value = 8; // smallest big endian serialization, max. 32 bytes bytes data = 9; AntiKleptoHostNonceCommitment host_nonce_commitment = 10; + ETHAddressCase address_case = 11; } message ETHSignMessageRequest { diff --git a/py/bitbox02/CHANGELOG.md b/py/bitbox02/CHANGELOG.md index 262571119..6b5ab21e4 100644 --- a/py/bitbox02/CHANGELOG.md +++ b/py/bitbox02/CHANGELOG.md @@ -4,6 +4,7 @@ # 7.0.0 - get_info: add optional device initialized boolean to returned tuple +- eth_sign: add address_case field, which should be initialized by the client # 6.3.0 - Allow infering product and version via API call instead of via USB descriptor diff --git a/py/bitbox02/bitbox02/bitbox02/bitbox02.py b/py/bitbox02/bitbox02/bitbox02/bitbox02.py index 35cad9b3c..96edafe2a 100644 --- a/py/bitbox02/bitbox02/bitbox02/bitbox02.py +++ b/py/bitbox02/bitbox02/bitbox02/bitbox02.py @@ -788,7 +788,13 @@ def eth_pub( ) return self._eth_msg_query(request, expected_response="pub").pub.pub - def eth_sign(self, transaction: bytes, keypath: Sequence[int], chain_id: int = 1) -> bytes: + def eth_sign( + self, + transaction: bytes, + keypath: Sequence[int], + address_case: eth.ETHAddressCase.ValueType = eth.ETH_ADDRESS_CASE_MIXED, + chain_id: int = 1, + ) -> bytes: """ transaction should be given as a full rlp encoded eth transaction. """ @@ -853,6 +859,7 @@ def handle_antiklepto(request: eth.ETHRequest) -> bytes: recipient=recipient, value=value, data=data, + address_case=address_case, ) ) return handle_antiklepto(request) @@ -871,6 +878,7 @@ def handle_antiklepto(request: eth.ETHRequest) -> bytes: recipient=recipient, value=value, data=data, + address_case=address_case, ) ) diff --git a/py/bitbox02/bitbox02/communication/generated/eth_pb2.py b/py/bitbox02/bitbox02/communication/generated/eth_pb2.py index c871b3589..ce8cd4012 100644 --- a/py/bitbox02/bitbox02/communication/generated/eth_pb2.py +++ b/py/bitbox02/bitbox02/communication/generated/eth_pb2.py @@ -15,45 +15,47 @@ from . import antiklepto_pb2 as antiklepto__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\teth.proto\x12\x14shiftcrypto.bitbox02\x1a\x0c\x63ommon.proto\x1a\x10\x61ntiklepto.proto\"\xf4\x01\n\rETHPubRequest\x12\x0f\n\x07keypath\x18\x01 \x03(\r\x12+\n\x04\x63oin\x18\x02 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.ETHCoin\x12\x43\n\x0boutput_type\x18\x03 \x01(\x0e\x32..shiftcrypto.bitbox02.ETHPubRequest.OutputType\x12\x0f\n\x07\x64isplay\x18\x04 \x01(\x08\x12\x18\n\x10\x63ontract_address\x18\x05 \x01(\x0c\x12\x10\n\x08\x63hain_id\x18\x06 \x01(\x04\"#\n\nOutputType\x12\x0b\n\x07\x41\x44\x44RESS\x10\x00\x12\x08\n\x04XPUB\x10\x01\"\x99\x02\n\x0e\x45THSignRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.ETHCoin\x12\x0f\n\x07keypath\x18\x02 \x03(\r\x12\r\n\x05nonce\x18\x03 \x01(\x0c\x12\x11\n\tgas_price\x18\x04 \x01(\x0c\x12\x11\n\tgas_limit\x18\x05 \x01(\x0c\x12\x11\n\trecipient\x18\x06 \x01(\x0c\x12\r\n\x05value\x18\x07 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x08 \x01(\x0c\x12R\n\x15host_nonce_commitment\x18\t \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\x12\x10\n\x08\x63hain_id\x18\n \x01(\x04\"\x9b\x02\n\x15\x45THSignEIP1559Request\x12\x10\n\x08\x63hain_id\x18\x01 \x01(\x04\x12\x0f\n\x07keypath\x18\x02 \x03(\r\x12\r\n\x05nonce\x18\x03 \x01(\x0c\x12 \n\x18max_priority_fee_per_gas\x18\x04 \x01(\x0c\x12\x17\n\x0fmax_fee_per_gas\x18\x05 \x01(\x0c\x12\x11\n\tgas_limit\x18\x06 \x01(\x0c\x12\x11\n\trecipient\x18\x07 \x01(\x0c\x12\r\n\x05value\x18\x08 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\t \x01(\x0c\x12R\n\x15host_nonce_commitment\x18\n \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\"\xc8\x01\n\x15\x45THSignMessageRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.ETHCoin\x12\x0f\n\x07keypath\x18\x02 \x03(\r\x12\x0b\n\x03msg\x18\x03 \x01(\x0c\x12R\n\x15host_nonce_commitment\x18\x04 \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\x12\x10\n\x08\x63hain_id\x18\x05 \x01(\x04\"$\n\x0f\x45THSignResponse\x12\x11\n\tsignature\x18\x01 \x01(\x0c\"\xfb\x05\n\x1a\x45THSignTypedMessageRequest\x12\x10\n\x08\x63hain_id\x18\x01 \x01(\x04\x12\x0f\n\x07keypath\x18\x02 \x03(\r\x12J\n\x05types\x18\x03 \x03(\x0b\x32;.shiftcrypto.bitbox02.ETHSignTypedMessageRequest.StructType\x12\x14\n\x0cprimary_type\x18\x04 \x01(\t\x12R\n\x15host_nonce_commitment\x18\x05 \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\x1a\xc9\x01\n\nMemberType\x12G\n\x04type\x18\x01 \x01(\x0e\x32\x39.shiftcrypto.bitbox02.ETHSignTypedMessageRequest.DataType\x12\x0c\n\x04size\x18\x02 \x01(\r\x12\x13\n\x0bstruct_name\x18\x03 \x01(\t\x12O\n\narray_type\x18\x04 \x01(\x0b\x32;.shiftcrypto.bitbox02.ETHSignTypedMessageRequest.MemberType\x1a\x61\n\x06Member\x12\x0c\n\x04name\x18\x01 \x01(\t\x12I\n\x04type\x18\x02 \x01(\x0b\x32;.shiftcrypto.bitbox02.ETHSignTypedMessageRequest.MemberType\x1a\x64\n\nStructType\x12\x0c\n\x04name\x18\x01 \x01(\t\x12H\n\x07members\x18\x02 \x03(\x0b\x32\x37.shiftcrypto.bitbox02.ETHSignTypedMessageRequest.Member\"o\n\x08\x44\x61taType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05\x42YTES\x10\x01\x12\x08\n\x04UINT\x10\x02\x12\x07\n\x03INT\x10\x03\x12\x08\n\x04\x42OOL\x10\x04\x12\x0b\n\x07\x41\x44\x44RESS\x10\x05\x12\n\n\x06STRING\x10\x06\x12\t\n\x05\x41RRAY\x10\x07\x12\n\n\x06STRUCT\x10\x08\"\xb4\x01\n\x1c\x45THTypedMessageValueResponse\x12R\n\x0broot_object\x18\x01 \x01(\x0e\x32=.shiftcrypto.bitbox02.ETHTypedMessageValueResponse.RootObject\x12\x0c\n\x04path\x18\x02 \x03(\r\"2\n\nRootObject\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x44OMAIN\x10\x01\x12\x0b\n\x07MESSAGE\x10\x02\",\n\x1b\x45THTypedMessageValueRequest\x12\r\n\x05value\x18\x01 \x01(\x0c\"\xf3\x03\n\nETHRequest\x12\x32\n\x03pub\x18\x01 \x01(\x0b\x32#.shiftcrypto.bitbox02.ETHPubRequestH\x00\x12\x34\n\x04sign\x18\x02 \x01(\x0b\x32$.shiftcrypto.bitbox02.ETHSignRequestH\x00\x12?\n\x08sign_msg\x18\x03 \x01(\x0b\x32+.shiftcrypto.bitbox02.ETHSignMessageRequestH\x00\x12P\n\x14\x61ntiklepto_signature\x18\x04 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.AntiKleptoSignatureRequestH\x00\x12J\n\x0esign_typed_msg\x18\x05 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.ETHSignTypedMessageRequestH\x00\x12L\n\x0ftyped_msg_value\x18\x06 \x01(\x0b\x32\x31.shiftcrypto.bitbox02.ETHTypedMessageValueRequestH\x00\x12\x43\n\x0csign_eip1559\x18\x07 \x01(\x0b\x32+.shiftcrypto.bitbox02.ETHSignEIP1559RequestH\x00\x42\t\n\x07request\"\xab\x02\n\x0b\x45THResponse\x12\x30\n\x03pub\x18\x01 \x01(\x0b\x32!.shiftcrypto.bitbox02.PubResponseH\x00\x12\x35\n\x04sign\x18\x02 \x01(\x0b\x32%.shiftcrypto.bitbox02.ETHSignResponseH\x00\x12X\n\x1c\x61ntiklepto_signer_commitment\x18\x03 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.AntiKleptoSignerCommitmentH\x00\x12M\n\x0ftyped_msg_value\x18\x04 \x01(\x0b\x32\x32.shiftcrypto.bitbox02.ETHTypedMessageValueResponseH\x00\x42\n\n\x08response*2\n\x07\x45THCoin\x12\x07\n\x03\x45TH\x10\x00\x12\x0e\n\nRopstenETH\x10\x01\x12\x0e\n\nRinkebyETH\x10\x02\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\teth.proto\x12\x14shiftcrypto.bitbox02\x1a\x0c\x63ommon.proto\x1a\x10\x61ntiklepto.proto\"\xf4\x01\n\rETHPubRequest\x12\x0f\n\x07keypath\x18\x01 \x03(\r\x12+\n\x04\x63oin\x18\x02 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.ETHCoin\x12\x43\n\x0boutput_type\x18\x03 \x01(\x0e\x32..shiftcrypto.bitbox02.ETHPubRequest.OutputType\x12\x0f\n\x07\x64isplay\x18\x04 \x01(\x08\x12\x18\n\x10\x63ontract_address\x18\x05 \x01(\x0c\x12\x10\n\x08\x63hain_id\x18\x06 \x01(\x04\"#\n\nOutputType\x12\x0b\n\x07\x41\x44\x44RESS\x10\x00\x12\x08\n\x04XPUB\x10\x01\"\xd5\x02\n\x0e\x45THSignRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.ETHCoin\x12\x0f\n\x07keypath\x18\x02 \x03(\r\x12\r\n\x05nonce\x18\x03 \x01(\x0c\x12\x11\n\tgas_price\x18\x04 \x01(\x0c\x12\x11\n\tgas_limit\x18\x05 \x01(\x0c\x12\x11\n\trecipient\x18\x06 \x01(\x0c\x12\r\n\x05value\x18\x07 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x08 \x01(\x0c\x12R\n\x15host_nonce_commitment\x18\t \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\x12\x10\n\x08\x63hain_id\x18\n \x01(\x04\x12:\n\x0c\x61\x64\x64ress_case\x18\x0b \x01(\x0e\x32$.shiftcrypto.bitbox02.ETHAddressCase\"\xd7\x02\n\x15\x45THSignEIP1559Request\x12\x10\n\x08\x63hain_id\x18\x01 \x01(\x04\x12\x0f\n\x07keypath\x18\x02 \x03(\r\x12\r\n\x05nonce\x18\x03 \x01(\x0c\x12 \n\x18max_priority_fee_per_gas\x18\x04 \x01(\x0c\x12\x17\n\x0fmax_fee_per_gas\x18\x05 \x01(\x0c\x12\x11\n\tgas_limit\x18\x06 \x01(\x0c\x12\x11\n\trecipient\x18\x07 \x01(\x0c\x12\r\n\x05value\x18\x08 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\t \x01(\x0c\x12R\n\x15host_nonce_commitment\x18\n \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\x12:\n\x0c\x61\x64\x64ress_case\x18\x0b \x01(\x0e\x32$.shiftcrypto.bitbox02.ETHAddressCase\"\xc8\x01\n\x15\x45THSignMessageRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.ETHCoin\x12\x0f\n\x07keypath\x18\x02 \x03(\r\x12\x0b\n\x03msg\x18\x03 \x01(\x0c\x12R\n\x15host_nonce_commitment\x18\x04 \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\x12\x10\n\x08\x63hain_id\x18\x05 \x01(\x04\"$\n\x0f\x45THSignResponse\x12\x11\n\tsignature\x18\x01 \x01(\x0c\"\xfb\x05\n\x1a\x45THSignTypedMessageRequest\x12\x10\n\x08\x63hain_id\x18\x01 \x01(\x04\x12\x0f\n\x07keypath\x18\x02 \x03(\r\x12J\n\x05types\x18\x03 \x03(\x0b\x32;.shiftcrypto.bitbox02.ETHSignTypedMessageRequest.StructType\x12\x14\n\x0cprimary_type\x18\x04 \x01(\t\x12R\n\x15host_nonce_commitment\x18\x05 \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\x1a\xc9\x01\n\nMemberType\x12G\n\x04type\x18\x01 \x01(\x0e\x32\x39.shiftcrypto.bitbox02.ETHSignTypedMessageRequest.DataType\x12\x0c\n\x04size\x18\x02 \x01(\r\x12\x13\n\x0bstruct_name\x18\x03 \x01(\t\x12O\n\narray_type\x18\x04 \x01(\x0b\x32;.shiftcrypto.bitbox02.ETHSignTypedMessageRequest.MemberType\x1a\x61\n\x06Member\x12\x0c\n\x04name\x18\x01 \x01(\t\x12I\n\x04type\x18\x02 \x01(\x0b\x32;.shiftcrypto.bitbox02.ETHSignTypedMessageRequest.MemberType\x1a\x64\n\nStructType\x12\x0c\n\x04name\x18\x01 \x01(\t\x12H\n\x07members\x18\x02 \x03(\x0b\x32\x37.shiftcrypto.bitbox02.ETHSignTypedMessageRequest.Member\"o\n\x08\x44\x61taType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05\x42YTES\x10\x01\x12\x08\n\x04UINT\x10\x02\x12\x07\n\x03INT\x10\x03\x12\x08\n\x04\x42OOL\x10\x04\x12\x0b\n\x07\x41\x44\x44RESS\x10\x05\x12\n\n\x06STRING\x10\x06\x12\t\n\x05\x41RRAY\x10\x07\x12\n\n\x06STRUCT\x10\x08\"\xb4\x01\n\x1c\x45THTypedMessageValueResponse\x12R\n\x0broot_object\x18\x01 \x01(\x0e\x32=.shiftcrypto.bitbox02.ETHTypedMessageValueResponse.RootObject\x12\x0c\n\x04path\x18\x02 \x03(\r\"2\n\nRootObject\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x44OMAIN\x10\x01\x12\x0b\n\x07MESSAGE\x10\x02\",\n\x1b\x45THTypedMessageValueRequest\x12\r\n\x05value\x18\x01 \x01(\x0c\"\xf3\x03\n\nETHRequest\x12\x32\n\x03pub\x18\x01 \x01(\x0b\x32#.shiftcrypto.bitbox02.ETHPubRequestH\x00\x12\x34\n\x04sign\x18\x02 \x01(\x0b\x32$.shiftcrypto.bitbox02.ETHSignRequestH\x00\x12?\n\x08sign_msg\x18\x03 \x01(\x0b\x32+.shiftcrypto.bitbox02.ETHSignMessageRequestH\x00\x12P\n\x14\x61ntiklepto_signature\x18\x04 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.AntiKleptoSignatureRequestH\x00\x12J\n\x0esign_typed_msg\x18\x05 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.ETHSignTypedMessageRequestH\x00\x12L\n\x0ftyped_msg_value\x18\x06 \x01(\x0b\x32\x31.shiftcrypto.bitbox02.ETHTypedMessageValueRequestH\x00\x12\x43\n\x0csign_eip1559\x18\x07 \x01(\x0b\x32+.shiftcrypto.bitbox02.ETHSignEIP1559RequestH\x00\x42\t\n\x07request\"\xab\x02\n\x0b\x45THResponse\x12\x30\n\x03pub\x18\x01 \x01(\x0b\x32!.shiftcrypto.bitbox02.PubResponseH\x00\x12\x35\n\x04sign\x18\x02 \x01(\x0b\x32%.shiftcrypto.bitbox02.ETHSignResponseH\x00\x12X\n\x1c\x61ntiklepto_signer_commitment\x18\x03 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.AntiKleptoSignerCommitmentH\x00\x12M\n\x0ftyped_msg_value\x18\x04 \x01(\x0b\x32\x32.shiftcrypto.bitbox02.ETHTypedMessageValueResponseH\x00\x42\n\n\x08response*2\n\x07\x45THCoin\x12\x07\n\x03\x45TH\x10\x00\x12\x0e\n\nRopstenETH\x10\x01\x12\x0e\n\nRinkebyETH\x10\x02*d\n\x0e\x45THAddressCase\x12\x1a\n\x16\x45TH_ADDRESS_CASE_MIXED\x10\x00\x12\x1a\n\x16\x45TH_ADDRESS_CASE_UPPER\x10\x01\x12\x1a\n\x16\x45TH_ADDRESS_CASE_LOWER\x10\x02\x62\x06proto3') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'eth_pb2', globals()) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _ETHCOIN._serialized_start=2924 - _ETHCOIN._serialized_end=2974 + _ETHCOIN._serialized_start=3044 + _ETHCOIN._serialized_end=3094 + _ETHADDRESSCASE._serialized_start=3096 + _ETHADDRESSCASE._serialized_end=3196 _ETHPUBREQUEST._serialized_start=68 _ETHPUBREQUEST._serialized_end=312 _ETHPUBREQUEST_OUTPUTTYPE._serialized_start=277 _ETHPUBREQUEST_OUTPUTTYPE._serialized_end=312 _ETHSIGNREQUEST._serialized_start=315 - _ETHSIGNREQUEST._serialized_end=596 - _ETHSIGNEIP1559REQUEST._serialized_start=599 - _ETHSIGNEIP1559REQUEST._serialized_end=882 - _ETHSIGNMESSAGEREQUEST._serialized_start=885 - _ETHSIGNMESSAGEREQUEST._serialized_end=1085 - _ETHSIGNRESPONSE._serialized_start=1087 - _ETHSIGNRESPONSE._serialized_end=1123 - _ETHSIGNTYPEDMESSAGEREQUEST._serialized_start=1126 - _ETHSIGNTYPEDMESSAGEREQUEST._serialized_end=1889 - _ETHSIGNTYPEDMESSAGEREQUEST_MEMBERTYPE._serialized_start=1374 - _ETHSIGNTYPEDMESSAGEREQUEST_MEMBERTYPE._serialized_end=1575 - _ETHSIGNTYPEDMESSAGEREQUEST_MEMBER._serialized_start=1577 - _ETHSIGNTYPEDMESSAGEREQUEST_MEMBER._serialized_end=1674 - _ETHSIGNTYPEDMESSAGEREQUEST_STRUCTTYPE._serialized_start=1676 - _ETHSIGNTYPEDMESSAGEREQUEST_STRUCTTYPE._serialized_end=1776 - _ETHSIGNTYPEDMESSAGEREQUEST_DATATYPE._serialized_start=1778 - _ETHSIGNTYPEDMESSAGEREQUEST_DATATYPE._serialized_end=1889 - _ETHTYPEDMESSAGEVALUERESPONSE._serialized_start=1892 - _ETHTYPEDMESSAGEVALUERESPONSE._serialized_end=2072 - _ETHTYPEDMESSAGEVALUERESPONSE_ROOTOBJECT._serialized_start=2022 - _ETHTYPEDMESSAGEVALUERESPONSE_ROOTOBJECT._serialized_end=2072 - _ETHTYPEDMESSAGEVALUEREQUEST._serialized_start=2074 - _ETHTYPEDMESSAGEVALUEREQUEST._serialized_end=2118 - _ETHREQUEST._serialized_start=2121 - _ETHREQUEST._serialized_end=2620 - _ETHRESPONSE._serialized_start=2623 - _ETHRESPONSE._serialized_end=2922 + _ETHSIGNREQUEST._serialized_end=656 + _ETHSIGNEIP1559REQUEST._serialized_start=659 + _ETHSIGNEIP1559REQUEST._serialized_end=1002 + _ETHSIGNMESSAGEREQUEST._serialized_start=1005 + _ETHSIGNMESSAGEREQUEST._serialized_end=1205 + _ETHSIGNRESPONSE._serialized_start=1207 + _ETHSIGNRESPONSE._serialized_end=1243 + _ETHSIGNTYPEDMESSAGEREQUEST._serialized_start=1246 + _ETHSIGNTYPEDMESSAGEREQUEST._serialized_end=2009 + _ETHSIGNTYPEDMESSAGEREQUEST_MEMBERTYPE._serialized_start=1494 + _ETHSIGNTYPEDMESSAGEREQUEST_MEMBERTYPE._serialized_end=1695 + _ETHSIGNTYPEDMESSAGEREQUEST_MEMBER._serialized_start=1697 + _ETHSIGNTYPEDMESSAGEREQUEST_MEMBER._serialized_end=1794 + _ETHSIGNTYPEDMESSAGEREQUEST_STRUCTTYPE._serialized_start=1796 + _ETHSIGNTYPEDMESSAGEREQUEST_STRUCTTYPE._serialized_end=1896 + _ETHSIGNTYPEDMESSAGEREQUEST_DATATYPE._serialized_start=1898 + _ETHSIGNTYPEDMESSAGEREQUEST_DATATYPE._serialized_end=2009 + _ETHTYPEDMESSAGEVALUERESPONSE._serialized_start=2012 + _ETHTYPEDMESSAGEVALUERESPONSE._serialized_end=2192 + _ETHTYPEDMESSAGEVALUERESPONSE_ROOTOBJECT._serialized_start=2142 + _ETHTYPEDMESSAGEVALUERESPONSE_ROOTOBJECT._serialized_end=2192 + _ETHTYPEDMESSAGEVALUEREQUEST._serialized_start=2194 + _ETHTYPEDMESSAGEVALUEREQUEST._serialized_end=2238 + _ETHREQUEST._serialized_start=2241 + _ETHREQUEST._serialized_end=2740 + _ETHRESPONSE._serialized_start=2743 + _ETHRESPONSE._serialized_end=3042 # @@protoc_insertion_point(module_scope) diff --git a/py/bitbox02/bitbox02/communication/generated/eth_pb2.pyi b/py/bitbox02/bitbox02/communication/generated/eth_pb2.pyi index e29bbbad7..1104b2528 100644 --- a/py/bitbox02/bitbox02/communication/generated/eth_pb2.pyi +++ b/py/bitbox02/bitbox02/communication/generated/eth_pb2.pyi @@ -40,6 +40,23 @@ RinkebyETH: ETHCoin.ValueType # 2 global___ETHCoin = ETHCoin +class _ETHAddressCase: + ValueType = typing.NewType('ValueType', builtins.int) + V: typing_extensions.TypeAlias = ValueType +class _ETHAddressCaseEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_ETHAddressCase.ValueType], builtins.type): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + ETH_ADDRESS_CASE_MIXED: _ETHAddressCase.ValueType # 0 + ETH_ADDRESS_CASE_UPPER: _ETHAddressCase.ValueType # 1 + ETH_ADDRESS_CASE_LOWER: _ETHAddressCase.ValueType # 2 +class ETHAddressCase(_ETHAddressCase, metaclass=_ETHAddressCaseEnumTypeWrapper): + pass + +ETH_ADDRESS_CASE_MIXED: ETHAddressCase.ValueType # 0 +ETH_ADDRESS_CASE_UPPER: ETHAddressCase.ValueType # 1 +ETH_ADDRESS_CASE_LOWER: ETHAddressCase.ValueType # 2 +global___ETHAddressCase = ETHAddressCase + + class ETHPubRequest(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor class _OutputType: @@ -97,6 +114,7 @@ class ETHSignRequest(google.protobuf.message.Message): DATA_FIELD_NUMBER: builtins.int HOST_NONCE_COMMITMENT_FIELD_NUMBER: builtins.int CHAIN_ID_FIELD_NUMBER: builtins.int + ADDRESS_CASE_FIELD_NUMBER: builtins.int coin: global___ETHCoin.ValueType """Deprecated: use chain_id instead.""" @@ -123,6 +141,7 @@ class ETHSignRequest(google.protobuf.message.Message): chain_id: builtins.int """If non-zero, `coin` is ignored and `chain_id` is used to identify the network.""" + address_case: global___ETHAddressCase.ValueType def __init__(self, *, coin: global___ETHCoin.ValueType = ..., @@ -135,9 +154,10 @@ class ETHSignRequest(google.protobuf.message.Message): data: builtins.bytes = ..., host_nonce_commitment: typing.Optional[antiklepto_pb2.AntiKleptoHostNonceCommitment] = ..., chain_id: builtins.int = ..., + address_case: global___ETHAddressCase.ValueType = ..., ) -> None: ... def HasField(self, field_name: typing_extensions.Literal["host_nonce_commitment",b"host_nonce_commitment"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["chain_id",b"chain_id","coin",b"coin","data",b"data","gas_limit",b"gas_limit","gas_price",b"gas_price","host_nonce_commitment",b"host_nonce_commitment","keypath",b"keypath","nonce",b"nonce","recipient",b"recipient","value",b"value"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["address_case",b"address_case","chain_id",b"chain_id","coin",b"coin","data",b"data","gas_limit",b"gas_limit","gas_price",b"gas_price","host_nonce_commitment",b"host_nonce_commitment","keypath",b"keypath","nonce",b"nonce","recipient",b"recipient","value",b"value"]) -> None: ... global___ETHSignRequest = ETHSignRequest class ETHSignEIP1559Request(google.protobuf.message.Message): @@ -153,6 +173,7 @@ class ETHSignEIP1559Request(google.protobuf.message.Message): VALUE_FIELD_NUMBER: builtins.int DATA_FIELD_NUMBER: builtins.int HOST_NONCE_COMMITMENT_FIELD_NUMBER: builtins.int + ADDRESS_CASE_FIELD_NUMBER: builtins.int chain_id: builtins.int @property def keypath(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: ... @@ -177,6 +198,7 @@ class ETHSignEIP1559Request(google.protobuf.message.Message): data: builtins.bytes @property def host_nonce_commitment(self) -> antiklepto_pb2.AntiKleptoHostNonceCommitment: ... + address_case: global___ETHAddressCase.ValueType def __init__(self, *, chain_id: builtins.int = ..., @@ -189,9 +211,10 @@ class ETHSignEIP1559Request(google.protobuf.message.Message): value: builtins.bytes = ..., data: builtins.bytes = ..., host_nonce_commitment: typing.Optional[antiklepto_pb2.AntiKleptoHostNonceCommitment] = ..., + address_case: global___ETHAddressCase.ValueType = ..., ) -> None: ... def HasField(self, field_name: typing_extensions.Literal["host_nonce_commitment",b"host_nonce_commitment"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["chain_id",b"chain_id","data",b"data","gas_limit",b"gas_limit","host_nonce_commitment",b"host_nonce_commitment","keypath",b"keypath","max_fee_per_gas",b"max_fee_per_gas","max_priority_fee_per_gas",b"max_priority_fee_per_gas","nonce",b"nonce","recipient",b"recipient","value",b"value"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["address_case",b"address_case","chain_id",b"chain_id","data",b"data","gas_limit",b"gas_limit","host_nonce_commitment",b"host_nonce_commitment","keypath",b"keypath","max_fee_per_gas",b"max_fee_per_gas","max_priority_fee_per_gas",b"max_priority_fee_per_gas","nonce",b"nonce","recipient",b"recipient","value",b"value"]) -> None: ... global___ETHSignEIP1559Request = ETHSignEIP1559Request class ETHSignMessageRequest(google.protobuf.message.Message): diff --git a/py/send_message.py b/py/send_message.py index 38a8fb9e1..bbc98f860 100755 --- a/py/send_message.py +++ b/py/send_message.py @@ -1023,6 +1023,7 @@ def _sign_eth_tx(self) -> None: sig = self._device.eth_sign( tx, keypath=[44 + HARDENED, 60 + HARDENED, 0 + HARDENED, 0, 0], + address_case=bitbox02.eth.ETHAddressCase.ETH_ADDRESS_CASE_MIXED, chain_id=chain_id, ) print("Signature: {}".format(sig.hex())) diff --git a/src/rust/bitbox02-rust/src/hww/api/ethereum/address.rs b/src/rust/bitbox02-rust/src/hww/api/ethereum/address.rs index 12027367f..36bec4a3b 100644 --- a/src/rust/bitbox02-rust/src/hww/api/ethereum/address.rs +++ b/src/rust/bitbox02-rust/src/hww/api/ethereum/address.rs @@ -17,36 +17,48 @@ use sha3::digest::Digest; use alloc::string::String; use core::convert::TryInto; +use super::pb; + /// Generates a checksummed ethereum hex address from a 20 byte recipient. /// `recipient` - 20 byte tail (last 20 bytes of the pubkeyhash). -pub fn from_pubkey_hash(recipient: &[u8; 20]) -> String { - let mut hex = [0u8; 40]; - hex::encode_to_slice(recipient, &mut hex).unwrap(); - let hash = sha3::Keccak256::digest(&hex[..]); - for (i, e) in hex.iter_mut().enumerate() { - let hash_byte = { - let b = hash[i / 2]; - if i % 2 == 0 { - b >> 4 - } else { - b & 0xf +pub fn from_pubkey_hash(recipient: &[u8; 20], address_case: pb::EthAddressCase) -> String { + match address_case { + pb::EthAddressCase::Mixed => { + let mut hex = [0u8; 40]; + hex::encode_to_slice(recipient, &mut hex).unwrap(); + let hash = sha3::Keccak256::digest(&hex[..]); + for (i, e) in hex.iter_mut().enumerate() { + let hash_byte = { + let b = hash[i / 2]; + if i % 2 == 0 { + b >> 4 + } else { + b & 0xf + } + }; + if *e > b'9' && hash_byte > 7 { + *e -= 32; // convert to uppercase + } } - }; - if *e > b'9' && hash_byte > 7 { - *e -= 32; // convert to uppercase + format!("0x{}", unsafe { + // valid utf8 because hex and the uppercasing above is correct. + core::str::from_utf8_unchecked(&hex[..]) + }) + }, + pb::EthAddressCase::Upper => { + format!("0x{}", hex::encode_upper(recipient)) + }, + pb::EthAddressCase::Lower => { + format!("0x{}", hex::encode(recipient)) } } - format!("0x{}", unsafe { - // valid utf8 because hex and the uppercasing above is correct. - core::str::from_utf8_unchecked(&hex[..]) - }) } /// Generates a checksummed ethereum hex address from a 65 byte pubkey. /// `recipient` - 20 byte tail (last 20 bytes of the pubkeyhash). pub fn from_pubkey(pubkey_uncompressed: &[u8; 65]) -> String { let hash = sha3::Keccak256::digest(&pubkey_uncompressed[1..]); - from_pubkey_hash(hash[hash.len() - 20..].try_into().unwrap()) + from_pubkey_hash(hash[hash.len() - 20..].try_into().unwrap(), pb::EthAddressCase::Mixed) } #[cfg(test)] @@ -58,9 +70,24 @@ mod tests { assert_eq!( from_pubkey_hash( b"\xf4\xc2\x17\x10\xef\x8b\x5a\x5e\xc4\xbd\x37\x80\xa6\x87\xfe\x08\x34\x46\xe6\x7b", + pb::EthAddressCase::Mixed, ), "0xF4C21710Ef8b5a5Ec4bd3780A687FE083446e67B" ); + assert_eq!( + from_pubkey_hash( + b"\xf4\xc2\x17\x10\xef\x8b\x5a\x5e\xc4\xbd\x37\x80\xa6\x87\xfe\x08\x34\x46\xe6\x7b", + pb::EthAddressCase::Upper, + ), + "0xF4C21710EF8B5A5EC4BD3780A687FE083446E67B" + ); + assert_eq!( + from_pubkey_hash( + b"\xf4\xc2\x17\x10\xef\x8b\x5a\x5e\xc4\xbd\x37\x80\xa6\x87\xfe\x08\x34\x46\xe6\x7b", + pb::EthAddressCase::Lower, + ), + "0xf4c21710ef8b5a5ec4bd3780a687fe083446e67b" + ); } #[test] diff --git a/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs b/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs index e379c12e5..825cbaad0 100644 --- a/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs +++ b/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs @@ -90,6 +90,12 @@ impl<'a> Transaction<'a> { Transaction::Eip1559(_) => Ok(None), } } + fn case(&self) -> Result { + match self { + Transaction::Legacy(legacy) => Ok(pb::EthAddressCase::try_from(legacy.address_case)?), + Transaction::Eip1559(eip1559) => Ok(pb::EthAddressCase::try_from(eip1559.address_case)?), + } + } } /// Converts `recipient` to an array of 20 chars. If `recipient` is @@ -203,7 +209,7 @@ async fn verify_erc20_transaction( ) -> Result<(), Error> { let erc20_params = erc20_params::get(params.chain_id, parse_recipient(request.recipient())?); let formatted_fee = parse_fee(request, params).format(); - let recipient_address = super::address::from_pubkey_hash(&erc20_recipient); + let recipient_address = super::address::from_pubkey_hash(&erc20_recipient, request.case()?); let (formatted_value, formatted_total) = match erc20_params { Some(erc20_params) => { let value = Amount { @@ -262,8 +268,8 @@ async fn verify_standard_transaction( }) .await?; } - - let address = super::address::from_pubkey_hash(&recipient); + + let address = super::address::from_pubkey_hash(&recipient, request.case()?); let amount = Amount { unit: params.unit, decimals: WEI_DECIMALS, @@ -490,6 +496,7 @@ mod tests { data: b"".to_vec(), host_nonce_commitment: None, chain_id: 0, + address_case: pb::EthAddressCase::Mixed as _, }))), Ok(Response::Sign(pb::EthSignResponse { signature: b"\xc3\xae\x24\xc1\x67\xe2\x16\xcf\xb7\x5c\x72\xb5\xe0\x3e\xf9\x7a\xcc\x2b\x60\x7f\x3a\xcf\x63\x86\x5f\x80\x96\x0f\x76\xf6\x56\x47\x0f\x8e\x23\xf1\xd2\x78\x8f\xb0\x07\x0e\x28\xc2\xa5\xc8\xaa\xf1\x5b\x5d\xbf\x30\xb4\x09\x07\xff\x6c\x50\x68\xfd\xcb\xc1\x1a\x2d\x00" @@ -508,6 +515,7 @@ mod tests { data: b"".to_vec(), host_nonce_commitment: None, chain_id: 1, + address_case: pb::EthAddressCase::Mixed as _, }))), Ok(Response::Sign(pb::EthSignResponse { signature: b"\x28\x91\x11\x77\x0d\xc0\x67\x89\x57\x80\xde\x3e\x9b\x30\x45\x4e\x33\x1b\xa6\x66\x1f\x04\x6e\x9e\x26\x43\x15\x76\xd7\xf0\x8a\x49\x6f\xfe\x6d\xef\xfb\x07\xdd\x8d\x47\x13\xd8\xc5\x23\xb6\xc3\x3b\x53\xdd\x6e\xf2\xdc\x9c\x39\x4d\x6e\x21\xf6\x43\x07\xd2\xbc\xf0\x01" @@ -562,6 +570,7 @@ mod tests { data: b"".to_vec(), host_nonce_commitment: None, chain_id: 0, + address_case: pb::EthAddressCase::Mixed as _, }))) .is_ok()); assert_eq!(unsafe { UI_COUNTER }, 1); @@ -613,6 +622,7 @@ mod tests { data: b"".to_vec(), host_nonce_commitment: None, chain_id: 1, + address_case: pb::EthAddressCase::Mixed as _, }))) .is_ok()); assert_eq!(unsafe { UI_COUNTER }, 1); @@ -666,6 +676,7 @@ mod tests { data: b"".to_vec(), host_nonce_commitment: None, chain_id: 5, + address_case: pb::EthAddressCase::Mixed as _, }))) .unwrap(); assert_eq!(unsafe { CONFIRM_COUNTER }, 1); @@ -718,6 +729,7 @@ mod tests { data: b"foo bar".to_vec(), host_nonce_commitment: None, chain_id: 0, + address_case: pb::EthAddressCase::Mixed as _, }))), Ok(Response::Sign(pb::EthSignResponse { signature: b"\x7d\x3f\x37\x13\xe3\xcf\x10\x82\x79\x1d\x5c\x0f\xc6\x8e\xc2\x9e\xaf\xf5\xe1\xee\x84\x67\xa8\xec\x54\x7d\xc7\x96\xe8\x5a\x79\x04\x2b\x7c\x01\x69\x2f\xb7\x2f\x55\x76\xab\x50\xdc\xaa\x62\x1a\xd1\xee\xab\xd9\x97\x59\x73\xb8\x62\x56\xf4\x0c\x6f\x85\x50\xef\x44\x00" @@ -773,6 +785,7 @@ mod tests { data: b"foo bar".to_vec(), host_nonce_commitment: None, chain_id: 1, + address_case: pb::EthAddressCase::Mixed as _, }))), Ok(Response::Sign(pb::EthSignResponse { signature: b"\xc5\xd9\x63\x9a\x77\x8a\x34\x15\xf6\x3a\x11\xc0\x3a\x58\xbe\xde\x6b\x3c\xaf\xff\x4f\x2c\xe6\xea\x16\x41\x1e\x76\xfb\xa9\x46\xf7\x21\x66\xf0\x9e\x31\x3c\x07\xe7\x8b\x7b\x1f\xff\x87\x45\x0c\x43\x21\x17\x0c\x02\xdf\x2d\x36\xc4\x4c\x3a\x02\x1a\xbf\x20\x54\x60\x01" @@ -814,6 +827,7 @@ mod tests { data: b"\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\xce\x0a\x09\x2a\x99\x70\x0c\xd4\xcc\xcc\xbb\x1f\xed\xc3\x9c\xf5\x3e\x63\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x65\xc0\x40".to_vec(), host_nonce_commitment: None, chain_id: 1, + address_case: pb::EthAddressCase::Mixed as _, }))), Ok(Response::Sign(pb::EthSignResponse { signature: b"\x67\x4e\x9a\x01\x70\xee\xe0\xca\x8c\x40\x6e\xc9\xa7\xdf\x2e\x3a\x6b\xdd\x17\x9c\xf6\x93\x85\x80\x0e\x1f\xd3\x78\xe7\xcf\xb1\x9c\x4d\x55\x16\x2c\x54\x7b\x04\xd1\x81\x8e\x43\x90\x16\x91\xae\xc9\x88\xef\x75\xcd\x67\xd9\xbb\x30\x1d\x14\x90\x2f\xd6\xe6\x92\x92\x01" @@ -832,6 +846,7 @@ mod tests { data: b"\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\xce\x0a\x09\x2a\x99\x70\x0c\xd4\xcc\xcc\xbb\x1f\xed\xc3\x9c\xf5\x3e\x63\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x65\xc0\x40".to_vec(), host_nonce_commitment: None, chain_id: 1, + address_case: pb::EthAddressCase::Mixed as _, }))), Ok(Response::Sign(pb::EthSignResponse { signature: b"\x31\x62\x48\x78\x80\xab\xde\xa1\xf3\x52\xd9\xa4\xe3\xd5\x60\x66\xf1\x22\xf0\x4f\xf1\x12\x11\x7c\x8c\xa3\xcd\x22\x0f\x16\x66\x30\x2d\xac\xd5\xe5\xe8\xda\x4c\xd3\x97\x04\xe3\x34\x43\xa9\xa7\xf3\x26\x02\xd3\x32\xbb\x52\x56\x7c\x2e\x34\xaa\xfe\x9e\xd4\x8f\xeb\x01" @@ -872,6 +887,7 @@ mod tests { data: b"\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\x7b\x3d\x96\x9e\xac\xb7\x75\xa9\xf7\x9c\xab\xc6\x2e\xc4\xbb\x1d\x1c\xd6\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98\xa6\x3c\xbe\xb8\x59\xd0\x27\xb0".to_vec(), host_nonce_commitment: None, chain_id: 0, + address_case: pb::EthAddressCase::Mixed as _, }))), Ok(Response::Sign(pb::EthSignResponse { signature: b"\xec\x6e\x53\x0c\x8e\xe2\x54\x34\xfc\x44\x0e\x9a\xc0\xf8\x88\xe9\xc6\x3c\xf0\x7e\xbc\xf1\xc2\xf8\xa8\x3e\x2e\x8c\x39\x83\x2c\x55\x15\x12\x71\x6f\x6e\x1a\x8b\x66\xce\x38\x11\xa7\x26\xbc\xb2\x44\x66\x4e\xf2\x6f\x98\xee\x35\xc0\xc9\xdb\x4c\xaa\xb0\x73\x98\x56\x00" @@ -890,6 +906,7 @@ mod tests { data: b"\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\x7b\x3d\x96\x9e\xac\xb7\x75\xa9\xf7\x9c\xab\xc6\x2e\xc4\xbb\x1d\x1c\xd6\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98\xa6\x3c\xbe\xb8\x59\xd0\x27\xb0".to_vec(), host_nonce_commitment: None, chain_id: 1, + address_case: pb::EthAddressCase::Mixed as _, }))), Ok(Response::Sign(pb::EthSignResponse { signature: b"\x82\x03\xd8\x0b\x60\x0d\xce\x8e\x77\xcd\xcb\x11\x9d\x45\xdb\x7f\x60\xd7\xca\x34\xe7\x36\x91\x40\xe9\x2d\x93\x91\x92\x21\xf8\x5a\x0a\x11\x9d\x24\x64\xdf\xab\x65\x83\x30\x95\xc1\x27\x63\xfe\xd3\x7c\x07\x2f\xeb\x29\x61\x0e\x14\x37\xf3\x88\x95\x8d\x77\x56\x28\x01" @@ -913,6 +930,7 @@ mod tests { data: b"".to_vec(), host_nonce_commitment: None, chain_id: 0, + address_case: pb::EthAddressCase::Mixed as _, }; { @@ -1051,6 +1069,7 @@ mod tests { data: b"".to_vec(), host_nonce_commitment: None, chain_id: 1, + address_case: pb::EthAddressCase::Mixed as _, }; { @@ -1146,6 +1165,7 @@ mod tests { data: b"".to_vec(), host_nonce_commitment: None, chain_id: 12345, + address_case: pb::EthAddressCase::Mixed as _, }))), Ok(Response::Sign(pb::EthSignResponse { signature: b"\xb1\xb6\xb3\x4e\x15\xa0\x30\x9d\xdc\x26\x03\xdf\x4c\x40\x38\xea\x86\x65\xed\x85\xd3\xf2\xc8\x1e\x7f\x1a\xa0\x25\x4b\x21\x38\x72\x0d\x60\x1f\x42\x19\xfb\x29\xab\x3d\x5f\xf7\x76\xea\xe1\xbe\x15\x26\xb4\x67\xe2\xb0\xe6\x30\xe8\xe6\x34\xa4\xda\x4a\x82\x2e\x39\x00".to_vec() diff --git a/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs b/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs index 6d50fee4e..d791586d0 100644 --- a/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs +++ b/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs @@ -1248,6 +1248,8 @@ pub struct EthSignRequest { /// If non-zero, `coin` is ignored and `chain_id` is used to identify the network. #[prost(uint64, tag = "10")] pub chain_id: u64, + #[prost(enumeration = "EthAddressCase", tag = "11")] + pub address_case: i32, } /// TX payload for an EIP-1559 (type 2) transaction: #[allow(clippy::derive_partial_eq_without_eq)] @@ -1279,6 +1281,8 @@ pub struct EthSignEip1559Request { pub data: ::prost::alloc::vec::Vec, #[prost(message, optional, tag = "10")] pub host_nonce_commitment: ::core::option::Option, + #[prost(enumeration = "EthAddressCase", tag = "11")] + pub address_case: i32, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1543,6 +1547,35 @@ impl EthCoin { } } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum EthAddressCase { + Mixed = 0, + Upper = 1, + Lower = 2, +} +impl EthAddressCase { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + EthAddressCase::Mixed => "ETH_ADDRESS_CASE_MIXED", + EthAddressCase::Upper => "ETH_ADDRESS_CASE_UPPER", + EthAddressCase::Lower => "ETH_ADDRESS_CASE_LOWER", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "ETH_ADDRESS_CASE_MIXED" => Some(Self::Mixed), + "ETH_ADDRESS_CASE_UPPER" => Some(Self::Upper), + "ETH_ADDRESS_CASE_LOWER" => Some(Self::Lower), + _ => None, + } + } +} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ElectrumEncryptionKeyRequest { diff --git a/src/rust/bitbox02/src/ui/ui_stub_c_unit_tests.rs b/src/rust/bitbox02/src/ui/ui_stub_c_unit_tests.rs index be43fe7ab..44ec9cf3f 100644 --- a/src/rust/bitbox02/src/ui/ui_stub_c_unit_tests.rs +++ b/src/rust/bitbox02/src/ui/ui_stub_c_unit_tests.rs @@ -130,6 +130,10 @@ pub fn confirm_transaction_address_create<'a, 'b>( _address: &'a str, mut callback: AcceptRejectCb<'b>, ) -> Component<'b> { + crate::print_stdout(&format!( + "CONFIRM TRANSACTION ADDRESS SCREEN START\nAMOUNT: {}\nADDRESS: {}\nCONFIRM TRANSACTION ADDRESS SCREEN END\n", + _amount, _address + )); callback(true); Component { is_pushed: false, @@ -143,6 +147,10 @@ pub fn confirm_transaction_fee_create<'a, 'b>( _longtouch: bool, mut callback: AcceptRejectCb<'b>, ) -> Component<'b> { + crate::print_stdout(&format!( + "CONFIRM TRANSACTION FEE SCREEN START\nAMOUNT: {}\nFEE: {}\nCONFIRM TRANSACTION FEE SCREEN END\n", + _amount, _fee + )); callback(true); Component { is_pushed: false,