diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54d899a1..ab1af1b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,7 +73,7 @@ jobs: pip install --upgrade pip pip install "protobuf>=3.20,<4" pip install -e . - pip install pytest semver rlp requests + pip install pytest semver rlp requests eth-keys pycryptodome - name: Wait for emulator run: | diff --git a/device-protocol b/device-protocol index 4337c452..8ef74da7 160000 --- a/device-protocol +++ b/device-protocol @@ -1 +1 @@ -Subproject commit 4337c452426c9e047afe0eb455f455604d0fec52 +Subproject commit 8ef74da7491ec1549f5d554202851fc4353290ed diff --git a/keepkeylib/client.py b/keepkeylib/client.py index 768ca968..77ea8563 100644 --- a/keepkeylib/client.py +++ b/keepkeylib/client.py @@ -1628,9 +1628,26 @@ def solana_sign_tx(self, address_n, raw_tx): ) @expect(solana_proto.SolanaMessageSignature) - def solana_sign_message(self, address_n, message): + def solana_sign_message(self, address_n, message, show_display=False): return self.call( - solana_proto.SolanaSignMessage(address_n=address_n, message=message) + solana_proto.SolanaSignMessage( + address_n=address_n, + message=message, + show_display=show_display, + ) + ) + + @expect(solana_proto.SolanaOffchainMessageSignature) + def solana_sign_offchain_message(self, address_n, message, message_format, + version=0, show_display=False): + return self.call( + solana_proto.SolanaSignOffchainMessage( + address_n=address_n, + version=version, + message_format=message_format, + message=message, + show_display=show_display, + ) ) # ── Tron ─────────────────────────────────────────────────── @@ -1646,6 +1663,37 @@ def tron_sign_tx(self, address_n, raw_tx): tron_proto.TronSignTx(address_n=address_n, raw_tx=raw_tx) ) + @expect(tron_proto.TronMessageSignature) + def tron_sign_message(self, address_n, message, show_display=False): + return self.call( + tron_proto.TronSignMessage( + address_n=address_n, + message=message, + show_display=show_display, + ) + ) + + @expect(proto.Success) + def tron_verify_message(self, address, signature, message): + return self.call( + tron_proto.TronVerifyMessage( + address=address, + signature=signature, + message=message, + ) + ) + + @expect(tron_proto.TronTypedDataSignature) + def tron_sign_typed_hash(self, address_n, domain_separator_hash, + message_hash=None): + kwargs = dict( + address_n=address_n, + domain_separator_hash=domain_separator_hash, + ) + if message_hash is not None: + kwargs['message_hash'] = message_hash + return self.call(tron_proto.TronSignTypedHash(**kwargs)) + # ── TON ──────────────────────────────────────────────────── @expect(ton_proto.TonAddress) def ton_get_address(self, address_n, show_display=False): @@ -1659,6 +1707,16 @@ def ton_sign_tx(self, address_n, raw_tx): ton_proto.TonSignTx(address_n=address_n, raw_tx=raw_tx) ) + @expect(ton_proto.TonMessageSignature) + def ton_sign_message(self, address_n, message, show_display=False): + return self.call( + ton_proto.TonSignMessage( + address_n=address_n, + message=message, + show_display=show_display, + ) + ) + # ── Zcash Address Display ───────────────────────────────── @expect(zcash_proto.ZcashAddress) def zcash_display_address(self, address_n, address, ak, nk, rivk, diff --git a/keepkeylib/messages_pb2.py b/keepkeylib/messages_pb2.py index fbada188..a79606fc 100644 --- a/keepkeylib/messages_pb2.py +++ b/keepkeylib/messages_pb2.py @@ -743,6 +743,42 @@ name='MessageType_TonSignedTx', index=177, number=1503, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SolanaSignOffchainMessage', index=178, number=756, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SolanaOffchainMessageSignature', index=179, number=757, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronSignMessage', index=180, number=1404, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronMessageSignature', index=181, number=1405, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronVerifyMessage', index=182, number=1406, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronSignTypedHash', index=183, number=1407, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronTypedDataSignature', index=184, number=1408, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TonSignMessage', index=185, number=1504, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TonMessageSignature', index=186, number=1505, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), ], containing_type=None, options=None, @@ -858,6 +894,8 @@ MessageType_SolanaSignedTx = 753 MessageType_SolanaSignMessage = 754 MessageType_SolanaMessageSignature = 755 +MessageType_SolanaSignOffchainMessage = 756 +MessageType_SolanaOffchainMessageSignature = 757 MessageType_BinanceGetAddress = 800 MessageType_BinanceAddress = 801 MessageType_BinanceGetPublicKey = 802 @@ -926,10 +964,17 @@ MessageType_TronAddress = 1401 MessageType_TronSignTx = 1402 MessageType_TronSignedTx = 1403 +MessageType_TronSignMessage = 1404 +MessageType_TronMessageSignature = 1405 +MessageType_TronVerifyMessage = 1406 +MessageType_TronSignTypedHash = 1407 +MessageType_TronTypedDataSignature = 1408 MessageType_TonGetAddress = 1500 MessageType_TonAddress = 1501 MessageType_TonSignTx = 1502 MessageType_TonSignedTx = 1503 +MessageType_TonSignMessage = 1504 +MessageType_TonMessageSignature = 1505 @@ -4609,6 +4654,10 @@ _MESSAGETYPE.values_by_name["MessageType_SolanaSignMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_SolanaMessageSignature"].has_options = True _MESSAGETYPE.values_by_name["MessageType_SolanaMessageSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SolanaSignOffchainMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SolanaSignOffchainMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SolanaOffchainMessageSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SolanaOffchainMessageSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_BinanceGetAddress"].has_options = True _MESSAGETYPE.values_by_name["MessageType_BinanceGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_BinanceAddress"].has_options = True @@ -4745,6 +4794,16 @@ _MESSAGETYPE.values_by_name["MessageType_TronSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_TronSignedTx"].has_options = True _MESSAGETYPE.values_by_name["MessageType_TronSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronSignMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronSignMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronMessageSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronMessageSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronVerifyMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronVerifyMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronSignTypedHash"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronSignTypedHash"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronTypedDataSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronTypedDataSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_TonGetAddress"].has_options = True _MESSAGETYPE.values_by_name["MessageType_TonGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_TonAddress"].has_options = True @@ -4753,4 +4812,8 @@ _MESSAGETYPE.values_by_name["MessageType_TonSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_TonSignedTx"].has_options = True _MESSAGETYPE.values_by_name["MessageType_TonSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TonSignMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TonSignMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TonMessageSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TonMessageSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) # @@protoc_insertion_point(module_scope) diff --git a/keepkeylib/messages_ripple_pb2.py b/keepkeylib/messages_ripple_pb2.py index 7ab35638..5d89223e 100644 --- a/keepkeylib/messages_ripple_pb2.py +++ b/keepkeylib/messages_ripple_pb2.py @@ -19,7 +19,7 @@ name='messages-ripple.proto', package='', syntax='proto2', - serialized_pb=_b('\n\x15messages-ripple.proto\";\n\x10RippleGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x14\n\x0cshow_display\x18\x02 \x01(\x08\" \n\rRippleAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\"\x8e\x01\n\x0cRippleSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0b\n\x03\x66\x65\x65\x18\x02 \x01(\x04\x12\r\n\x05\x66lags\x18\x03 \x01(\r\x12\x10\n\x08sequence\x18\x04 \x01(\r\x12\x1c\n\x14last_ledger_sequence\x18\x05 \x01(\r\x12\x1f\n\x07payment\x18\x06 \x01(\x0b\x32\x0e.RipplePayment\"M\n\rRipplePayment\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x13\n\x0b\x64\x65stination\x18\x02 \x01(\t\x12\x17\n\x0f\x64\x65stination_tag\x18\x03 \x01(\r\":\n\x0eRippleSignedTx\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\x15\n\rserialized_tx\x18\x02 \x01(\x0c\x42;\n#com.shapeshift.keepkey.lib.protobufB\x14KeepKeyMessageRipple') + serialized_pb=_b('\n\x15messages-ripple.proto\";\n\x10RippleGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x14\n\x0cshow_display\x18\x02 \x01(\x08\" \n\rRippleAddress\x12\x0f\n\x07address\x18\x01 \x01(\t\"\x9c\x01\n\x0cRippleSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0b\n\x03fee\x18\x02 \x01(\x04\x12\r\n\x05flags\x18\x03 \x01(\r\x12\x10\n\x08sequence\x18\x04 \x01(\r\x12\x1c\n\x14last_ledger_sequence\x18\x05 \x01(\r\x12\x1f\n\x07payment\x18\x06 \x01(\x0b2\x0e.RipplePayment\x12\x0c\n\x04memo\x18\x07 \x01(\t\"M\n\rRipplePayment\x12\x0e\n\x06amount\x18\x01 \x01(\x04\x12\x13\n\x0bdestination\x18\x02 \x01(\t\x12\x17\n\x0fdestination_tag\x18\x03 \x01(\r\":\n\x0eRippleSignedTx\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\x15\n\rserialized_tx\x18\x02 \x01(\x0cB;\n#com.shapeshift.keepkey.lib.protobufB\x14KeepKeyMessageRipple') ) @@ -143,6 +143,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='memo', full_name='RippleSignTx.memo', index=6, + number=7, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -156,7 +163,7 @@ oneofs=[ ], serialized_start=121, - serialized_end=263, + serialized_end=277, ) @@ -200,8 +207,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=265, - serialized_end=342, + serialized_start=279, + serialized_end=356, ) @@ -238,8 +245,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=344, - serialized_end=402, + serialized_start=358, + serialized_end=416, ) _RIPPLESIGNTX.fields_by_name['payment'].message_type = _RIPPLEPAYMENT diff --git a/keepkeylib/messages_solana_pb2.py b/keepkeylib/messages_solana_pb2.py index 48436d9f..cf8d5ed6 100644 --- a/keepkeylib/messages_solana_pb2.py +++ b/keepkeylib/messages_solana_pb2.py @@ -19,7 +19,7 @@ name='messages-solana.proto', package='', syntax='proto2', - serialized_pb=_b('\n\x15messages-solana.proto\"V\n\x10SolanaGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x19\n\tcoin_name\x18\x02 \x01(\t:\x06Solana\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\" \n\rSolanaAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\"A\n\x0fSolanaTokenInfo\x12\x0c\n\x04mint\x18\x01 \x01(\x0c\x12\x0e\n\x06symbol\x18\x02 \x01(\t\x12\x10\n\x08\x64\x65\x63imals\x18\x03 \x01(\r\"r\n\x0cSolanaSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x19\n\tcoin_name\x18\x02 \x01(\t:\x06Solana\x12\x0e\n\x06raw_tx\x18\x03 \x01(\x0c\x12$\n\ntoken_info\x18\x04 \x03(\x0b\x32\x10.SolanaTokenInfo\"#\n\x0eSolanaSignedTx\x12\x11\n\tsignature\x18\x01 \x01(\x0c\"h\n\x11SolanaSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x19\n\tcoin_name\x18\x02 \x01(\t:\x06Solana\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x14\n\x0cshow_display\x18\x04 \x01(\x08\"?\n\x16SolanaMessageSignature\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x42\x32\n\x1a\x63om.keepkey.deviceprotocolB\x14KeepKeyMessageSolana') + serialized_pb=_b('\n\x15messages-solana.proto\"V\n\x10SolanaGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x19\n\tcoin_name\x18\x02 \x01(\t:\x06Solana\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\" \n\rSolanaAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\"A\n\x0fSolanaTokenInfo\x12\x0c\n\x04mint\x18\x01 \x01(\x0c\x12\x0e\n\x06symbol\x18\x02 \x01(\t\x12\x10\n\x08\x64\x65\x63imals\x18\x03 \x01(\r\"r\n\x0cSolanaSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x19\n\tcoin_name\x18\x02 \x01(\t:\x06Solana\x12\x0e\n\x06raw_tx\x18\x03 \x01(\x0c\x12$\n\ntoken_info\x18\x04 \x03(\x0b\x32\x10.SolanaTokenInfo\"#\n\x0eSolanaSignedTx\x12\x11\n\tsignature\x18\x01 \x01(\x0c\"h\n\x11SolanaSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x19\n\tcoin_name\x18\x02 \x01(\t:\x06Solana\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x14\n\x0cshow_display\x18\x04 \x01(\x08\"?\n\x16SolanaMessageSignature\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"\x9c\x01\n\x19SolanaSignOffchainMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x19\n\tcoin_name\x18\x02 \x01(\t:\x06Solana\x12\x12\n\x07version\x18\x03 \x01(\r:\x01\x30\x12\x16\n\x0emessage_format\x18\x04 \x01(\r\x12\x0f\n\x07message\x18\x05 \x01(\x0c\x12\x14\n\x0cshow_display\x18\x06 \x01(\x08\"G\n\x1eSolanaOffchainMessageSignature\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x42\x32\n\x1a\x63om.keepkey.deviceprotocolB\x14KeepKeyMessageSolana') ) @@ -318,6 +318,110 @@ serialized_end=536, ) + +_SOLANASIGNOFFCHAINMESSAGE = _descriptor.Descriptor( + name='SolanaSignOffchainMessage', + full_name='SolanaSignOffchainMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='SolanaSignOffchainMessage.address_n', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='coin_name', full_name='SolanaSignOffchainMessage.coin_name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Solana").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='version', full_name='SolanaSignOffchainMessage.version', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=True, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='message_format', full_name='SolanaSignOffchainMessage.message_format', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='message', full_name='SolanaSignOffchainMessage.message', index=4, + number=5, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='show_display', full_name='SolanaSignOffchainMessage.show_display', index=5, + number=6, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=539, + serialized_end=695, +) + + +_SOLANAOFFCHAINMESSAGESIGNATURE = _descriptor.Descriptor( + name='SolanaOffchainMessageSignature', + full_name='SolanaOffchainMessageSignature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='public_key', full_name='SolanaOffchainMessageSignature.public_key', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='signature', full_name='SolanaOffchainMessageSignature.signature', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=697, + serialized_end=768, +) + _SOLANASIGNTX.fields_by_name['token_info'].message_type = _SOLANATOKENINFO DESCRIPTOR.message_types_by_name['SolanaGetAddress'] = _SOLANAGETADDRESS DESCRIPTOR.message_types_by_name['SolanaAddress'] = _SOLANAADDRESS @@ -326,6 +430,8 @@ DESCRIPTOR.message_types_by_name['SolanaSignedTx'] = _SOLANASIGNEDTX DESCRIPTOR.message_types_by_name['SolanaSignMessage'] = _SOLANASIGNMESSAGE DESCRIPTOR.message_types_by_name['SolanaMessageSignature'] = _SOLANAMESSAGESIGNATURE +DESCRIPTOR.message_types_by_name['SolanaSignOffchainMessage'] = _SOLANASIGNOFFCHAINMESSAGE +DESCRIPTOR.message_types_by_name['SolanaOffchainMessageSignature'] = _SOLANAOFFCHAINMESSAGESIGNATURE _sym_db.RegisterFileDescriptor(DESCRIPTOR) SolanaGetAddress = _reflection.GeneratedProtocolMessageType('SolanaGetAddress', (_message.Message,), dict( @@ -377,6 +483,20 @@ )) _sym_db.RegisterMessage(SolanaMessageSignature) +SolanaSignOffchainMessage = _reflection.GeneratedProtocolMessageType('SolanaSignOffchainMessage', (_message.Message,), dict( + DESCRIPTOR = _SOLANASIGNOFFCHAINMESSAGE, + __module__ = 'messages_solana_pb2' + # @@protoc_insertion_point(class_scope:SolanaSignOffchainMessage) + )) +_sym_db.RegisterMessage(SolanaSignOffchainMessage) + +SolanaOffchainMessageSignature = _reflection.GeneratedProtocolMessageType('SolanaOffchainMessageSignature', (_message.Message,), dict( + DESCRIPTOR = _SOLANAOFFCHAINMESSAGESIGNATURE, + __module__ = 'messages_solana_pb2' + # @@protoc_insertion_point(class_scope:SolanaOffchainMessageSignature) + )) +_sym_db.RegisterMessage(SolanaOffchainMessageSignature) + DESCRIPTOR.has_options = True DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\032com.keepkey.deviceprotocolB\024KeepKeyMessageSolana')) diff --git a/keepkeylib/messages_ton_pb2.py b/keepkeylib/messages_ton_pb2.py index 20ae0cd3..3b1de09c 100644 --- a/keepkeylib/messages_ton_pb2.py +++ b/keepkeylib/messages_ton_pb2.py @@ -19,7 +19,7 @@ name='messages-ton.proto', package='', syntax='proto2', - serialized_pb=_b('\n\x12messages-ton.proto\"\x98\x01\n\rTonGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x16\n\tcoin_name\x18\x02 \x01(\t:\x03Ton\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\x12\x18\n\nbounceable\x18\x04 \x01(\x08:\x04true\x12\x16\n\x07testnet\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x14\n\tworkchain\x18\x06 \x01(\x11:\x01\x30\"2\n\nTonAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x13\n\x0braw_address\x18\x02 \x01(\t\"\xd3\x01\n\tTonSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x16\n\tcoin_name\x18\x02 \x01(\t:\x03Ton\x12\x0e\n\x06raw_tx\x18\x03 \x01(\x0c\x12\x11\n\texpire_at\x18\x04 \x01(\r\x12\r\n\x05seqno\x18\x05 \x01(\r\x12\x14\n\tworkchain\x18\x06 \x01(\x11:\x01\x30\x12\x12\n\nto_address\x18\x07 \x01(\t\x12\x0e\n\x06\x61mount\x18\x08 \x01(\x04\x12\x0e\n\x06\x62ounce\x18\t \x01(\x08\x12\x0c\n\x04memo\x18\n \x01(\t\x12\x11\n\tis_deploy\x18\x0b \x01(\x08\" \n\x0bTonSignedTx\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x42/\n\x1a\x63om.keepkey.deviceprotocolB\x11KeepKeyMessageTon') + serialized_pb=_b('\n\x12messages-ton.proto\"\x98\x01\n\rTonGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x16\n\tcoin_name\x18\x02 \x01(\t:\x03Ton\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\x12\x18\n\nbounceable\x18\x04 \x01(\x08:\x04true\x12\x16\n\x07testnet\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x14\n\tworkchain\x18\x06 \x01(\x11:\x01\x30\"2\n\nTonAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x13\n\x0braw_address\x18\x02 \x01(\t\"\xd3\x01\n\tTonSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x16\n\tcoin_name\x18\x02 \x01(\t:\x03Ton\x12\x0e\n\x06raw_tx\x18\x03 \x01(\x0c\x12\x11\n\texpire_at\x18\x04 \x01(\r\x12\r\n\x05seqno\x18\x05 \x01(\r\x12\x14\n\tworkchain\x18\x06 \x01(\x11:\x01\x30\x12\x12\n\nto_address\x18\x07 \x01(\t\x12\x0e\n\x06\x61mount\x18\x08 \x01(\x04\x12\x0e\n\x06\x62ounce\x18\t \x01(\x08\x12\x0c\n\x04memo\x18\n \x01(\t\x12\x11\n\tis_deploy\x18\x0b \x01(\x08\" \n\x0bTonSignedTx\x12\x11\n\tsignature\x18\x01 \x01(\x0c\"b\n\x0eTonSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x16\n\tcoin_name\x18\x02 \x01(\t:\x03Ton\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x14\n\x0cshow_display\x18\x04 \x01(\x08\"<\n\x13TonMessageSignature\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x42/\n\x1a\x63om.keepkey.deviceprotocolB\x11KeepKeyMessageTon') ) @@ -260,10 +260,102 @@ serialized_end=475, ) + +_TONSIGNMESSAGE = _descriptor.Descriptor( + name='TonSignMessage', + full_name='TonSignMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='TonSignMessage.address_n', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='coin_name', full_name='TonSignMessage.coin_name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Ton").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='message', full_name='TonSignMessage.message', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='show_display', full_name='TonSignMessage.show_display', index=3, + number=4, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=477, + serialized_end=575, +) + + +_TONMESSAGESIGNATURE = _descriptor.Descriptor( + name='TonMessageSignature', + full_name='TonMessageSignature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='public_key', full_name='TonMessageSignature.public_key', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='signature', full_name='TonMessageSignature.signature', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=577, + serialized_end=637, +) + DESCRIPTOR.message_types_by_name['TonGetAddress'] = _TONGETADDRESS DESCRIPTOR.message_types_by_name['TonAddress'] = _TONADDRESS DESCRIPTOR.message_types_by_name['TonSignTx'] = _TONSIGNTX DESCRIPTOR.message_types_by_name['TonSignedTx'] = _TONSIGNEDTX +DESCRIPTOR.message_types_by_name['TonSignMessage'] = _TONSIGNMESSAGE +DESCRIPTOR.message_types_by_name['TonMessageSignature'] = _TONMESSAGESIGNATURE _sym_db.RegisterFileDescriptor(DESCRIPTOR) TonGetAddress = _reflection.GeneratedProtocolMessageType('TonGetAddress', (_message.Message,), dict( @@ -294,6 +386,20 @@ )) _sym_db.RegisterMessage(TonSignedTx) +TonSignMessage = _reflection.GeneratedProtocolMessageType('TonSignMessage', (_message.Message,), dict( + DESCRIPTOR = _TONSIGNMESSAGE, + __module__ = 'messages_ton_pb2' + # @@protoc_insertion_point(class_scope:TonSignMessage) + )) +_sym_db.RegisterMessage(TonSignMessage) + +TonMessageSignature = _reflection.GeneratedProtocolMessageType('TonMessageSignature', (_message.Message,), dict( + DESCRIPTOR = _TONMESSAGESIGNATURE, + __module__ = 'messages_ton_pb2' + # @@protoc_insertion_point(class_scope:TonMessageSignature) + )) +_sym_db.RegisterMessage(TonMessageSignature) + DESCRIPTOR.has_options = True DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\032com.keepkey.deviceprotocolB\021KeepKeyMessageTon')) diff --git a/keepkeylib/messages_tron_pb2.py b/keepkeylib/messages_tron_pb2.py index dc8f265c..09317e77 100644 --- a/keepkeylib/messages_tron_pb2.py +++ b/keepkeylib/messages_tron_pb2.py @@ -19,7 +19,7 @@ name='messages-tron.proto', package='', syntax='proto2', - serialized_pb=_b('\n\x13messages-tron.proto\"R\n\x0eTronGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x17\n\tcoin_name\x18\x02 \x01(\t:\x04Tron\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\"\x1e\n\x0bTronAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\":\n\x14TronTransferContract\x12\x12\n\nto_address\x18\x01 \x01(\t\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\"V\n\x18TronTriggerSmartContract\x12\x18\n\x10\x63ontract_address\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x12\n\ncall_value\x18\x03 \x01(\x04\"\xd9\x02\n\nTronSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x17\n\tcoin_name\x18\x02 \x01(\t:\x04Tron\x12\x10\n\x08raw_data\x18\x03 \x01(\x0c\x12\x17\n\x0fref_block_bytes\x18\x04 \x01(\x0c\x12\x16\n\x0eref_block_hash\x18\x05 \x01(\x0c\x12\x12\n\nexpiration\x18\x06 \x01(\x04\x12\x15\n\rcontract_type\x18\x07 \x01(\t\x12\x12\n\nto_address\x18\x08 \x01(\t\x12\x0e\n\x06\x61mount\x18\t \x01(\x04\x12\'\n\x08transfer\x18\n \x01(\x0b\x32\x15.TronTransferContract\x12\x30\n\rtrigger_smart\x18\x0b \x01(\x0b\x32\x19.TronTriggerSmartContract\x12\x11\n\tfee_limit\x18\x0c \x01(\x04\x12\x11\n\ttimestamp\x18\r \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x0e \x01(\x0c\"8\n\x0cTronSignedTx\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\x15\n\rserialized_tx\x18\x02 \x01(\x0c\x42\x30\n\x1a\x63om.keepkey.deviceprotocolB\x12KeepKeyMessageTron') + serialized_pb=_b('\n\x13messages-tron.proto\"R\n\x0eTronGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x17\n\tcoin_name\x18\x02 \x01(\t:\x04Tron\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\"\x1e\n\x0bTronAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\":\n\x14TronTransferContract\x12\x12\n\nto_address\x18\x01 \x01(\t\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\"V\n\x18TronTriggerSmartContract\x12\x18\n\x10\x63ontract_address\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x12\n\ncall_value\x18\x03 \x01(\x04\"\xd9\x02\n\nTronSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x17\n\tcoin_name\x18\x02 \x01(\t:\x04Tron\x12\x10\n\x08raw_data\x18\x03 \x01(\x0c\x12\x17\n\x0fref_block_bytes\x18\x04 \x01(\x0c\x12\x16\n\x0eref_block_hash\x18\x05 \x01(\x0c\x12\x12\n\nexpiration\x18\x06 \x01(\x04\x12\x15\n\rcontract_type\x18\x07 \x01(\t\x12\x12\n\nto_address\x18\x08 \x01(\t\x12\x0e\n\x06\x61mount\x18\t \x01(\x04\x12\'\n\x08transfer\x18\n \x01(\x0b\x32\x15.TronTransferContract\x12\x30\n\rtrigger_smart\x18\x0b \x01(\x0b\x32\x19.TronTriggerSmartContract\x12\x11\n\tfee_limit\x18\x0c \x01(\x04\x12\x11\n\ttimestamp\x18\r \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x0e \x01(\x0c\"8\n\x0cTronSignedTx\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\x15\n\rserialized_tx\x18\x02 \x01(\x0c\"d\n\x0fTronSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x17\n\tcoin_name\x18\x02 \x01(\t:\x04Tron\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x14\n\x0cshow_display\x18\x04 \x01(\x08\":\n\x14TronMessageSignature\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"H\n\x11TronVerifyMessage\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\"t\n\x11TronSignTypedHash\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x17\n\tcoin_name\x18\x02 \x01(\t:\x04Tron\x12\x1d\n\x15\x64omain_separator_hash\x18\x03 \x02(\x0c\x12\x14\n\x0cmessage_hash\x18\x04 \x01(\x0c\"<\n\x16TronTypedDataSignature\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x02(\t\x12\x11\n\tsignature\x18\x02 \x02(\x0c\x42\x30\n\x1a\x63om.keepkey.deviceprotocolB\x12KeepKeyMessageTron') ) @@ -343,6 +343,231 @@ serialized_end=691, ) + +_TRONSIGNMESSAGE = _descriptor.Descriptor( + name='TronSignMessage', + full_name='TronSignMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='TronSignMessage.address_n', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='coin_name', full_name='TronSignMessage.coin_name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Tron").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='message', full_name='TronSignMessage.message', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='show_display', full_name='TronSignMessage.show_display', index=3, + number=4, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=693, + serialized_end=793, +) + + +_TRONMESSAGESIGNATURE = _descriptor.Descriptor( + name='TronMessageSignature', + full_name='TronMessageSignature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='TronMessageSignature.address', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='signature', full_name='TronMessageSignature.signature', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=795, + serialized_end=853, +) + + +_TRONVERIFYMESSAGE = _descriptor.Descriptor( + name='TronVerifyMessage', + full_name='TronVerifyMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='TronVerifyMessage.address', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='signature', full_name='TronVerifyMessage.signature', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='message', full_name='TronVerifyMessage.message', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=855, + serialized_end=927, +) + + +_TRONSIGNTYPEDHASH = _descriptor.Descriptor( + name='TronSignTypedHash', + full_name='TronSignTypedHash', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='TronSignTypedHash.address_n', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='coin_name', full_name='TronSignTypedHash.coin_name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Tron").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='domain_separator_hash', full_name='TronSignTypedHash.domain_separator_hash', index=2, + number=3, type=12, cpp_type=9, label=2, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='message_hash', full_name='TronSignTypedHash.message_hash', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=929, + serialized_end=1045, +) + + +_TRONTYPEDDATASIGNATURE = _descriptor.Descriptor( + name='TronTypedDataSignature', + full_name='TronTypedDataSignature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='TronTypedDataSignature.address', index=0, + number=1, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='signature', full_name='TronTypedDataSignature.signature', index=1, + number=2, type=12, cpp_type=9, label=2, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1047, + serialized_end=1107, +) + _TRONSIGNTX.fields_by_name['transfer'].message_type = _TRONTRANSFERCONTRACT _TRONSIGNTX.fields_by_name['trigger_smart'].message_type = _TRONTRIGGERSMARTCONTRACT DESCRIPTOR.message_types_by_name['TronGetAddress'] = _TRONGETADDRESS @@ -351,6 +576,11 @@ DESCRIPTOR.message_types_by_name['TronTriggerSmartContract'] = _TRONTRIGGERSMARTCONTRACT DESCRIPTOR.message_types_by_name['TronSignTx'] = _TRONSIGNTX DESCRIPTOR.message_types_by_name['TronSignedTx'] = _TRONSIGNEDTX +DESCRIPTOR.message_types_by_name['TronSignMessage'] = _TRONSIGNMESSAGE +DESCRIPTOR.message_types_by_name['TronMessageSignature'] = _TRONMESSAGESIGNATURE +DESCRIPTOR.message_types_by_name['TronVerifyMessage'] = _TRONVERIFYMESSAGE +DESCRIPTOR.message_types_by_name['TronSignTypedHash'] = _TRONSIGNTYPEDHASH +DESCRIPTOR.message_types_by_name['TronTypedDataSignature'] = _TRONTYPEDDATASIGNATURE _sym_db.RegisterFileDescriptor(DESCRIPTOR) TronGetAddress = _reflection.GeneratedProtocolMessageType('TronGetAddress', (_message.Message,), dict( @@ -395,6 +625,41 @@ )) _sym_db.RegisterMessage(TronSignedTx) +TronSignMessage = _reflection.GeneratedProtocolMessageType('TronSignMessage', (_message.Message,), dict( + DESCRIPTOR = _TRONSIGNMESSAGE, + __module__ = 'messages_tron_pb2' + # @@protoc_insertion_point(class_scope:TronSignMessage) + )) +_sym_db.RegisterMessage(TronSignMessage) + +TronMessageSignature = _reflection.GeneratedProtocolMessageType('TronMessageSignature', (_message.Message,), dict( + DESCRIPTOR = _TRONMESSAGESIGNATURE, + __module__ = 'messages_tron_pb2' + # @@protoc_insertion_point(class_scope:TronMessageSignature) + )) +_sym_db.RegisterMessage(TronMessageSignature) + +TronVerifyMessage = _reflection.GeneratedProtocolMessageType('TronVerifyMessage', (_message.Message,), dict( + DESCRIPTOR = _TRONVERIFYMESSAGE, + __module__ = 'messages_tron_pb2' + # @@protoc_insertion_point(class_scope:TronVerifyMessage) + )) +_sym_db.RegisterMessage(TronVerifyMessage) + +TronSignTypedHash = _reflection.GeneratedProtocolMessageType('TronSignTypedHash', (_message.Message,), dict( + DESCRIPTOR = _TRONSIGNTYPEDHASH, + __module__ = 'messages_tron_pb2' + # @@protoc_insertion_point(class_scope:TronSignTypedHash) + )) +_sym_db.RegisterMessage(TronSignTypedHash) + +TronTypedDataSignature = _reflection.GeneratedProtocolMessageType('TronTypedDataSignature', (_message.Message,), dict( + DESCRIPTOR = _TRONTYPEDDATASIGNATURE, + __module__ = 'messages_tron_pb2' + # @@protoc_insertion_point(class_scope:TronTypedDataSignature) + )) +_sym_db.RegisterMessage(TronTypedDataSignature) + DESCRIPTOR.has_options = True DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\032com.keepkey.deviceprotocolB\022KeepKeyMessageTron')) diff --git a/scripts/generate-test-report.py b/scripts/generate-test-report.py index 37322705..df3b24a1 100644 --- a/scripts/generate-test-report.py +++ b/scripts/generate-test-report.py @@ -618,6 +618,15 @@ def parse_junit(path): 'Sign EIP-1559 transaction', 'Type 2 transaction with base fee + priority fee. Device shows both gas parameters.', ['EIP-1559 gas display']), + ('E5b', 'test_msg_ethereum_signtx_chunked_data_eip1559', + 'test_eip1559_chunked_data_signature_recovers_to_device_address', + 'Sign EIP-1559 with data > 1024 B (chunked transmission)', + 'Regression for an access-list ordering bug in firmware/ethereum.c — when data exceeded ' + 'the 1024-byte single-chunk threshold, the empty access-list byte (0xC0) was hashed ' + 'between data chunks instead of after them, producing a non-canonical pre-image. The ' + 'signature recovered to a wrong-but-deterministic address and the broadcast tx was ' + 'dropped from the mempool. Fixed in 7.14.1.', + []), ('E6', 'test_msg_ethereum_signtx', 'test_ethereum_signtx_knownerc20_eip_1559', 'Sign known ERC-20 (EIP-1559)', 'Known token (in firmware token list) via EIP-1559. Shows human-readable token name + amount.', diff --git a/setup.py b/setup.py index 813a2edf..c49f73e8 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='keepkey', - version='7.0.3', + version='7.14.1', author='TREZOR and KeepKey', author_email='support@keepkey.com', description='Python library for communicating with KeepKey Hardware Wallet', diff --git a/tests/test_message_signing_protocol_bindings.py b/tests/test_message_signing_protocol_bindings.py new file mode 100644 index 00000000..10cce3f7 --- /dev/null +++ b/tests/test_message_signing_protocol_bindings.py @@ -0,0 +1,65 @@ +import unittest + +from keepkeylib import mapping +from keepkeylib import messages_pb2 as proto +from keepkeylib import messages_solana_pb2 as solana_proto +from keepkeylib import messages_ton_pb2 as ton_proto +from keepkeylib import messages_tron_pb2 as tron_proto + + +class TestMessageSigningProtocolBindings(unittest.TestCase): + + def test_solana_offchain_messages_are_mapped(self): + self.assertEqual(proto.MessageType_SolanaSignOffchainMessage, 756) + self.assertEqual(proto.MessageType_SolanaOffchainMessageSignature, 757) + self.assertIs( + mapping.get_class(proto.MessageType_SolanaSignOffchainMessage), + solana_proto.SolanaSignOffchainMessage, + ) + self.assertIs( + mapping.get_class(proto.MessageType_SolanaOffchainMessageSignature), + solana_proto.SolanaOffchainMessageSignature, + ) + + def test_tron_message_signing_messages_are_mapped(self): + self.assertEqual(proto.MessageType_TronSignMessage, 1404) + self.assertEqual(proto.MessageType_TronMessageSignature, 1405) + self.assertEqual(proto.MessageType_TronVerifyMessage, 1406) + self.assertEqual(proto.MessageType_TronSignTypedHash, 1407) + self.assertEqual(proto.MessageType_TronTypedDataSignature, 1408) + self.assertIs( + mapping.get_class(proto.MessageType_TronSignMessage), + tron_proto.TronSignMessage, + ) + self.assertIs( + mapping.get_class(proto.MessageType_TronMessageSignature), + tron_proto.TronMessageSignature, + ) + self.assertIs( + mapping.get_class(proto.MessageType_TronVerifyMessage), + tron_proto.TronVerifyMessage, + ) + self.assertIs( + mapping.get_class(proto.MessageType_TronSignTypedHash), + tron_proto.TronSignTypedHash, + ) + self.assertIs( + mapping.get_class(proto.MessageType_TronTypedDataSignature), + tron_proto.TronTypedDataSignature, + ) + + def test_ton_message_signing_messages_are_mapped(self): + self.assertEqual(proto.MessageType_TonSignMessage, 1504) + self.assertEqual(proto.MessageType_TonMessageSignature, 1505) + self.assertIs( + mapping.get_class(proto.MessageType_TonSignMessage), + ton_proto.TonSignMessage, + ) + self.assertIs( + mapping.get_class(proto.MessageType_TonMessageSignature), + ton_proto.TonMessageSignature, + ) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_msg_ethereum_signtx_chunked_data_eip1559.py b/tests/test_msg_ethereum_signtx_chunked_data_eip1559.py new file mode 100644 index 00000000..b9b4112b --- /dev/null +++ b/tests/test_msg_ethereum_signtx_chunked_data_eip1559.py @@ -0,0 +1,178 @@ +# Regression — EIP-1559 sign-tx with data > 1024 bytes (chunked transmission). +# +# Background: +# The KeepKey USB transport carries the first up-to-1024 bytes of EVM +# tx-data inside the EthereumSignTx message; remaining bytes arrive in +# subsequent EthereumTxAck frames. For EIP-1559 transactions, the empty +# access-list byte (0xC0) closes the RLP body and MUST be the last byte +# fed to keccak before signing. +# +# Firmware versions 7.x.0 .. 7.14.0 hash 0xC0 inside ethereum_signing_init() +# immediately after data_initial_chunk — i.e. BEFORE the host has sent the +# remaining EthereumTxAck frames. For any tx with data <= 1024 bytes this +# accidentally lands at the end of the stream; for tx-data > 1024 bytes the +# 0xC0 is sandwiched between the first chunk and the rest of the data, +# producing a non-canonical pre-image: +# +# keccak( ...header... || data_len_prefix +# || data[0..1024] || 0xC0 || data[1024..end] ) +# +# The signature is mathematically valid for that mangled hash so RPCs +# accept the broadcast (signature checks pass), but the recovered signer +# is a wrong-but-deterministic address that does not match the device's +# own EOA. The transaction is dropped from the mempool because the +# recovered "from" has no balance / wrong nonce. +# +# Visible production symptom: every Uniswap Universal Router swap, Permit2 +# batch, and large multicall on this firmware hung at "Confirm in wallet" +# — broadcast accepted, never confirmed. +# +# Fix: hash 0xC0 immediately before send_signature() in BOTH the +# single-chunk path (ethereum_signing_init) and the multi-chunk path +# (ethereum_signing_txack). Released in firmware 7.14.1. +# +# This test pairs the device, signs a 1550-byte EIP-1559 transaction with +# the all-all-all test mnemonic, then verifies that ECDSA recovery against +# the canonical type-2 pre-image yields the device's own ETH address. +# It will FAIL on firmware 7.14.0 and earlier; PASS on 7.14.1+. + +import unittest +import common +import binascii + +import keepkeylib.messages_ethereum_pb2 as eth_proto + + +class TestMsgEthereumSigntxChunkedDataEip1559(common.KeepKeyTest): + + # m/44'/60'/0'/0/0 hardened path + ETH_PATH = [0x80000000 | 44, 0x80000000 | 60, 0x80000000, 0, 0] + + # Universal Router on Ethereum mainnet — `to` from the captured + # production failure (Uniswap LINK -> USDT swap). Address itself is + # immaterial; what matters is `data` is large enough to require + # multi-chunk transmission. + UNISWAP_UR = binascii.unhexlify("4c82d1fbfe28c977cbb58d8c7ff8fcf9f70a2cca") + + @staticmethod + def _rlp_int(n): + # Canonical RLP encoding of a non-negative integer is its big-endian + # representation with leading zeros stripped (zero -> empty bytes). + if n == 0: + return b"" + out = bytearray() + while n: + out.append(n & 0xff) + n >>= 8 + return bytes(reversed(out)) + + @classmethod + def _build_canonical_eip1559_pre_image(cls, chain_id, nonce, max_priority_fee_per_gas, + max_fee_per_gas, gas_limit, to, value, data): + """Build keccak(0x02 || rlp([fields..., access_list=[]])). + + Mirrors what ethers / @ethereumjs/tx / go-ethereum produce for the + unsigned type-2 envelope. + """ + import rlp # listed in CI install (`pip install ... rlp ...`) + from eth_utils import keccak # ships with eth-keys + body = rlp.encode([ + cls._rlp_int(chain_id), + cls._rlp_int(nonce), + cls._rlp_int(max_priority_fee_per_gas), + cls._rlp_int(max_fee_per_gas), + cls._rlp_int(gas_limit), + to, + cls._rlp_int(value), + data, + [], # empty access list + ]) + return keccak(b"\x02" + body) + + @staticmethod + def _recover_eth_address(msg_hash, v, r, s): + """Return the 20-byte ETH address that signed `msg_hash`.""" + from eth_keys import keys + # EIP-1559 returns v in {0, 1} (raw recovery id), which is what + # eth_keys.Signature expects for `vrs`. + sig = keys.Signature(vrs=(v, int.from_bytes(r, 'big'), int.from_bytes(s, 'big'))) + return sig.recover_public_key_from_msg_hash(msg_hash).to_canonical_address() + + def test_eip1559_chunked_data_signature_recovers_to_device_address(self): + self.requires_fullFeature() + # Gate on the fixed firmware. The bug this test asserts against shipped + # in 7.x.0 .. 7.14.0 (see header comment); 7.14.1 is the first release + # where the canonical pre-image is hashed correctly. Skip on older + # firmware so CI doesn't flag a known-broken build as a new regression. + self.requires_firmware("7.14.1") + self.setup_mnemonic_allallall() + self.client.apply_policy("AdvancedMode", 1) # blind-sign opt-in + + device_address = self.client.ethereum_get_address(self.ETH_PATH) + + # 1550 bytes -> first 1024 ride in EthereumSignTx, remaining 526 ride + # in one EthereumTxAck. Same size class as the captured production + # failure (Uniswap Universal Router calldata). + data = bytes((i & 0xff) for i in range(1550)) + chain_id = 1 + nonce = 0 + max_priority_fee_per_gas = 0x218711a00 + max_fee_per_gas = 0x291d5740f + gas_limit = 0x6c8b8 + value = 0 + + sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( + n=self.ETH_PATH, + nonce=nonce, + max_fee_per_gas=max_fee_per_gas, + max_priority_fee_per_gas=max_priority_fee_per_gas, + gas_limit=gas_limit, + to=self.UNISWAP_UR, + value=value, + chain_id=chain_id, + data=data, + ) + + canonical_hash = self._build_canonical_eip1559_pre_image( + chain_id=chain_id, + nonce=nonce, + max_priority_fee_per_gas=max_priority_fee_per_gas, + max_fee_per_gas=max_fee_per_gas, + gas_limit=gas_limit, + to=self.UNISWAP_UR, + value=value, + data=data, + ) + + recovered = self._recover_eth_address(canonical_hash, sig_v, sig_r, sig_s) + + recovered_hex = binascii.hexlify(recovered).decode() + expected_hex = binascii.hexlify(device_address).decode() + + # On broken firmware (<= 7.14.0) the device signs a different hash + # whose recovered signer is a wrong-but-deterministic address. Print + # the divergence before asserting so triage doesn't have to re-run. + if recovered_hex != expected_hex: + print( + "\n[REGRESSION] EIP-1559 chunked-data signature does not recover to " + "device address. This is the firmware/ethereum.c access-list " + "ordering bug fixed in 7.14.1.\n" + " expected (device): 0x%s\n" + " recovered: 0x%s\n" + " canonical hash: 0x%s\n" + " sig: v=%d r=%s s=%s" + % ( + expected_hex, + recovered_hex, + binascii.hexlify(canonical_hash).decode(), + sig_v, + binascii.hexlify(sig_r).decode(), + binascii.hexlify(sig_s).decode(), + ) + ) + + self.assertEqual(recovered_hex, expected_hex) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_msg_ethereum_thorchain_deposit.py b/tests/test_msg_ethereum_thorchain_deposit.py new file mode 100644 index 00000000..03fc88ef --- /dev/null +++ b/tests/test_msg_ethereum_thorchain_deposit.py @@ -0,0 +1,142 @@ +# This file is part of the KeepKey project. +# +# Copyright (C) 2026 KeepKey +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Test coverage for THORChain EVM depositWithExpiry() selector recognition. +# The legacy deposit() selector (0x1fece7b4) was already handled; firmware +# 7.14.2 adds recognition of the modern depositWithExpiry() selector (0x44bc937b). + +import unittest +import common +import binascii + +import keepkeylib.messages_pb2 as proto +from keepkeylib.tools import parse_path + + +THOR_ROUTER = "d37bbe5744d730a1d98d8dc97c42f0ca46ad7146" # ETH THORChain router +ETH_NATIVE = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" # sentinel for native ETH + + +def _build_deposit_calldata(memo): + """Build deposit(address,address,uint256,string) calldata (legacy selector).""" + selector = bytes.fromhex("1fece7b4") + vault = bytes(12) + bytes.fromhex(THOR_ROUTER) + asset = bytes(12) + bytes.fromhex(ETH_NATIVE) + amount = (500000000000000000).to_bytes(32, "big") # 0.5 ETH + memo_offset = (4 * 32).to_bytes(32, "big") # offset = 128 + memo_bytes = memo.encode("ascii") + memo_len = len(memo_bytes).to_bytes(32, "big") + pad = ((len(memo_bytes) + 31) // 32) * 32 + memo_data = memo_bytes + bytes(pad - len(memo_bytes)) + return selector + vault + asset + amount + memo_offset + memo_len + memo_data + + +def _build_deposit_with_expiry_calldata(memo, expiry=9999999999): + """Build depositWithExpiry(address,address,uint256,string,uint256) calldata.""" + selector = bytes.fromhex("44bc937b") + vault = bytes(12) + bytes.fromhex(THOR_ROUTER) + asset = bytes(12) + bytes.fromhex(ETH_NATIVE) + amount = (500000000000000000).to_bytes(32, "big") # 0.5 ETH + memo_offset = (5 * 32).to_bytes(32, "big") # offset = 160 (after expiry) + expiry_b = expiry.to_bytes(32, "big") + memo_bytes = memo.encode("ascii") + memo_len = len(memo_bytes).to_bytes(32, "big") + pad = ((len(memo_bytes) + 31) // 32) * 32 + memo_data = memo_bytes + bytes(pad - len(memo_bytes)) + return selector + vault + asset + amount + memo_offset + expiry_b + memo_len + memo_data + + +class TestMsgEthereumThorchainDeposit(common.KeepKeyTest): + + def test_deposit_legacy_selector(self): + """Existing deposit() selector (0x1fece7b4) is recognized without AdvancedMode.""" + self.requires_fullFeature() + self.requires_firmware("7.5.0") + self.setup_mnemonic_allallall() + + memo = "=:ETH.ETH:0xabcdef1234567890abcdef1234567890abcdef12:0:t:0" + data = _build_deposit_calldata(memo) + + sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( + n=parse_path("m/44'/60'/0'/0/0"), + nonce=1, + gas_price=50000000000, + gas_limit=300000, + to=binascii.unhexlify(THOR_ROUTER), + value=500000000000000000, + chain_id=1, + data=data, + ) + self.assertIn(sig_v, [27, 28]) + self.assertEqual(len(sig_r), 32) + self.assertEqual(len(sig_s), 32) + + def test_deposit_with_expiry_selector(self): + """Modern depositWithExpiry() selector (0x44bc937b) is recognized without AdvancedMode. + + Before 7.14.2 the firmware only matched the legacy 0x1fece7b4 selector. + All modern THORChain routers use depositWithExpiry. Without this fix the + device would fall through to the blind-sign gate and refuse to sign (or + require AdvancedMode), breaking every EVM->THORChain swap. + """ + self.requires_fullFeature() + self.requires_firmware("7.14.2") + self.setup_mnemonic_allallall() + + memo = "=:ETH.ETH:0xabcdef1234567890abcdef1234567890abcdef12:0:t:0" + data = _build_deposit_with_expiry_calldata(memo) + + # AdvancedMode is intentionally OFF — THORChain txs must sign without it. + sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( + n=parse_path("m/44'/60'/0'/0/0"), + nonce=2, + gas_price=50000000000, + gas_limit=300000, + to=binascii.unhexlify(THOR_ROUTER), + value=500000000000000000, + chain_id=1, + data=data, + ) + self.assertIn(sig_v, [27, 28]) + self.assertEqual(len(sig_r), 32) + self.assertEqual(len(sig_s), 32) + + def test_deposit_with_expiry_non_thor_address_blind_sign_blocked(self): + """depositWithExpiry to a non-THORChain address must not be auto-approved. + + The firmware only clears the blind-sign gate when msg->has_to && the + deposit selector matches. Sending to an arbitrary address must still + require AdvancedMode so unrelated contracts can't exploit the selector. + """ + self.requires_fullFeature() + self.requires_firmware("7.14.2") + self.setup_mnemonic_allallall() + + memo = "malicious memo" + data = _build_deposit_with_expiry_calldata(memo) + + from keepkeylib.client import CallException + import keepkeylib.types_pb2 as types + + # No AdvancedMode, random contract address — should be rejected + with self.assertRaises((CallException, Exception)): + self.client.ethereum_sign_tx( + n=parse_path("m/44'/60'/0'/0/0"), + nonce=3, + gas_price=50000000000, + gas_limit=300000, + to=binascii.unhexlify("1234567890123456789012345678901234567890"), + value=0, + chain_id=1, + data=data, + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_msg_ripple_sign_tx.py b/tests/test_msg_ripple_sign_tx.py index 891982d3..ed5d503e 100644 --- a/tests/test_msg_ripple_sign_tx.py +++ b/tests/test_msg_ripple_sign_tx.py @@ -100,6 +100,57 @@ def test_sign(self): ) + def test_sign_with_thorchain_memo(self): + self.requires_fullFeature() + self.requires_firmware("7.14.2") + + self.setup_mnemonic_allallall() + + memo = "=:ETH.ETH:0xabcdef1234567890abcdef1234567890abcdef12:0:t:0" + msg = messages.RippleSignTx( + address_n=parse_path("m/44'/144'/0'/0/0"), + payment=messages.RipplePayment( + amount=100000000, + destination="rBKz5MC2iXdoS3XgnNSYmF69K1Yo4NS3Ws" + ), + flags=0x80000000, + fee=100000, + sequence=25, + memo=memo + ) + resp = self.client.call(msg) + + # Verify the XRPL Memos array is appended to the serialized tx. + # Format: 0xF9 (STArray[9]) 0xEA (STObject[10]) 0x7D (MemoData VL[13]) + # 0xE1 (end object) 0xF1 (end array) + memo_bytes = memo.encode('ascii') + expected_tail = ( + bytes([0xF9, 0xEA, 0x7D, len(memo_bytes)]) + + memo_bytes + + bytes([0xE1, 0xF1]) + ) + self.assertTrue( + resp.serialized_tx.endswith(expected_tail), + "serialized_tx must end with XRPL Memos array containing THORChain routing memo" + ) + + # A plain send without memo must not contain the Memos marker + msg_no_memo = messages.RippleSignTx( + address_n=parse_path("m/44'/144'/0'/0/0"), + payment=messages.RipplePayment( + amount=100000000, + destination="rBKz5MC2iXdoS3XgnNSYmF69K1Yo4NS3Ws" + ), + flags=0x80000000, + fee=100000, + sequence=26 + ) + resp2 = self.client.call(msg_no_memo) + self.assertFalse( + b'\xf9' in resp2.serialized_tx, + "plain send must not contain Memos array (0xF9 marker)" + ) + def test_ripple_sign_invalid_fee(self): self.requires_fullFeature() self.requires_firmware("6.4.0")