From ec4a607dbefe2d2ff8ea342a205b798dbad6a8c7 Mon Sep 17 00:00:00 2001 From: gabrielkerekes Date: Wed, 18 Oct 2023 11:40:19 +0200 Subject: [PATCH] feat(solana): add `get_public_key` --- common/protob/messages-solana.proto | 24 ++ common/protob/messages.proto | 4 + .../tests/fixtures/solana/get_public_key.json | 32 ++ core/src/all_modules.py | 4 + core/src/all_modules.py.mako | 1 + core/src/apps/solana/__init__.py | 7 + core/src/apps/solana/get_public_key.py | 36 ++ core/src/apps/workflow_handlers.py | 4 + core/src/trezor/enums/MessageType.py | 2 + core/src/trezor/enums/__init__.py | 2 + core/src/trezor/messages.py | 30 ++ python/src/trezorlib/cli/solana.py | 31 ++ python/src/trezorlib/cli/trezorctl.py | 3 + python/src/trezorlib/messages.py | 33 ++ python/src/trezorlib/solana.py | 19 + rust/trezor-client/src/messages/generated.rs | 2 + .../src/protos/generated/messages.rs | 62 +-- .../src/protos/generated/messages_solana.rs | 388 ++++++++++++++++++ tests/REGISTERED_MARKERS | 1 + tests/device_tests/solana/__init__.py | 0 tests/device_tests/solana/test_public_key.py | 40 ++ 21 files changed, 701 insertions(+), 24 deletions(-) create mode 100644 common/protob/messages-solana.proto create mode 100644 common/tests/fixtures/solana/get_public_key.json create mode 100644 core/src/apps/solana/__init__.py create mode 100644 core/src/apps/solana/get_public_key.py create mode 100644 python/src/trezorlib/cli/solana.py create mode 100644 python/src/trezorlib/solana.py create mode 100644 rust/trezor-client/src/protos/generated/messages_solana.rs create mode 100644 tests/device_tests/solana/__init__.py create mode 100644 tests/device_tests/solana/test_public_key.py diff --git a/common/protob/messages-solana.proto b/common/protob/messages-solana.proto new file mode 100644 index 0000000000..c6e99b226d --- /dev/null +++ b/common/protob/messages-solana.proto @@ -0,0 +1,24 @@ +syntax = "proto2"; +package hw.trezor.messages.solana; + +import "messages-common.proto"; + +/** + * Request: Ask device for public key corresponding to address_n path + * @start + * @next SolanaPublicKey + * @next Failure + */ +message SolanaGetPublicKey { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional bool show_display = 2; // optionally show on display before sending the result +} + +/** + * Response: Contains public key derived from device private seed + * @end + */ +message SolanaPublicKey { + required bytes public_key = 1; +} + diff --git a/common/protob/messages.proto b/common/protob/messages.proto index ae9637e060..6f1f247740 100644 --- a/common/protob/messages.proto +++ b/common/protob/messages.proto @@ -362,4 +362,8 @@ enum MessageType { MessageType_WebAuthnCredentials = 801 [(wire_out) = true]; MessageType_WebAuthnAddResidentCredential = 802 [(wire_in) = true]; MessageType_WebAuthnRemoveResidentCredential = 803 [(wire_in) = true]; + + // Solana + MessageType_SolanaGetPublicKey = 900 [(wire_in) = true]; + MessageType_SolanaPublicKey = 901 [(wire_out) = true]; } diff --git a/common/tests/fixtures/solana/get_public_key.json b/common/tests/fixtures/solana/get_public_key.json new file mode 100644 index 0000000000..25135df2c4 --- /dev/null +++ b/common/tests/fixtures/solana/get_public_key.json @@ -0,0 +1,32 @@ +{ + "setup": { + "mnemonic": "all all all all all all all all all all all all", + "passphrase": "" + }, + "tests": [ + { + "parameters": { + "path": "m/44'/501'" + }, + "result": { + "expected_public_key": "0ebf3b4a5e8efc65c508f1c813377a650f655814db3b23472bdcde5f2aeaa7a3" + } + }, + { + "parameters": { + "path": "m/44'/501'/0'" + }, + "result": { + "expected_public_key": "3398f0abc4f8ec2f62435a78d8f4f3219b47b04f268798d2ed2260da0b4de45f" + } + }, + { + "parameters": { + "path": "m/44'/501'/0'/0'" + }, + "result": { + "expected_public_key": "00d1699dcb1811b50bb0055f13044463128242e37a463b52f6c97a1f6eef88ad" + } + } + ] +} diff --git a/core/src/all_modules.py b/core/src/all_modules.py index 6883d01604..6789ca9d1d 100644 --- a/core/src/all_modules.py +++ b/core/src/all_modules.py @@ -681,6 +681,10 @@ if not utils.BITCOIN_ONLY: import apps.ripple.serialize apps.ripple.sign_tx import apps.ripple.sign_tx + apps.solana + import apps.solana + apps.solana.get_public_key + import apps.solana.get_public_key apps.stellar import apps.stellar apps.stellar.consts diff --git a/core/src/all_modules.py.mako b/core/src/all_modules.py.mako index 371dcf2887..c1ef0a14bb 100644 --- a/core/src/all_modules.py.mako +++ b/core/src/all_modules.py.mako @@ -26,6 +26,7 @@ ALTCOINS = ( "monero", "nem", "ripple", + "solana", "stellar", "tezos", "webauthn", diff --git a/core/src/apps/solana/__init__.py b/core/src/apps/solana/__init__.py new file mode 100644 index 0000000000..ba6d2630f5 --- /dev/null +++ b/core/src/apps/solana/__init__.py @@ -0,0 +1,7 @@ +CURVE = "ed25519" +SLIP44_ID = 501 +PATTERNS = ( + "m/44'/coin_type'", # Ledger compatibility + "m/44'/coin_type'/account'", # Ledger compatibility + "m/44'/coin_type'/account'/address_index'", +) diff --git a/core/src/apps/solana/get_public_key.py b/core/src/apps/solana/get_public_key.py new file mode 100644 index 0000000000..787ff1beff --- /dev/null +++ b/core/src/apps/solana/get_public_key.py @@ -0,0 +1,36 @@ +from typing import TYPE_CHECKING + +from trezor.crypto import base58 + +from apps.common import seed +from apps.common.keychain import with_slip44_keychain + +from . import CURVE, PATTERNS, SLIP44_ID + +if TYPE_CHECKING: + from trezor.messages import SolanaGetPublicKey, SolanaPublicKey + + from apps.common.keychain import Keychain + + +@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE) +async def get_public_key( + msg: SolanaGetPublicKey, keychain: Keychain +) -> SolanaPublicKey: + from trezor.messages import SolanaPublicKey + from trezor.ui.layouts import show_pubkey + + public_key = derive_public_key(keychain, msg.address_n) + + if msg.show_display: + from apps.common.paths import address_n_to_str + + path = address_n_to_str(msg.address_n) + await show_pubkey(base58.encode(public_key), path=path) + + return SolanaPublicKey(public_key=public_key) + + +def derive_public_key(keychain: Keychain, address_n: list[int]) -> bytes: + node = keychain.derive(address_n) + return seed.remove_ed25519_prefix(node.public_key()) diff --git a/core/src/apps/workflow_handlers.py b/core/src/apps/workflow_handlers.py index fd184be6e3..3cc4c996a2 100644 --- a/core/src/apps/workflow_handlers.py +++ b/core/src/apps/workflow_handlers.py @@ -190,6 +190,10 @@ def _find_message_handler_module(msg_type: int) -> str: if msg_type == MessageType.BinanceSignTx: return "apps.binance.sign_tx" + # solana + if msg_type == MessageType.SolanaGetPublicKey: + return "apps.solana.get_public_key" + raise ValueError diff --git a/core/src/trezor/enums/MessageType.py b/core/src/trezor/enums/MessageType.py index e010a34b12..59266e80bf 100644 --- a/core/src/trezor/enums/MessageType.py +++ b/core/src/trezor/enums/MessageType.py @@ -236,3 +236,5 @@ if not utils.BITCOIN_ONLY: WebAuthnCredentials = 801 WebAuthnAddResidentCredential = 802 WebAuthnRemoveResidentCredential = 803 + SolanaGetPublicKey = 900 + SolanaPublicKey = 901 diff --git a/core/src/trezor/enums/__init__.py b/core/src/trezor/enums/__init__.py index 346f8b9129..039e37a072 100644 --- a/core/src/trezor/enums/__init__.py +++ b/core/src/trezor/enums/__init__.py @@ -254,6 +254,8 @@ if TYPE_CHECKING: WebAuthnCredentials = 801 WebAuthnAddResidentCredential = 802 WebAuthnRemoveResidentCredential = 803 + SolanaGetPublicKey = 900 + SolanaPublicKey = 901 class FailureType(IntEnum): UnexpectedMessage = 1 diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index e901e92f7e..1ec0226ead 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -5195,6 +5195,36 @@ if TYPE_CHECKING: def is_type_of(cls, msg: Any) -> TypeGuard["RipplePayment"]: return isinstance(msg, cls) + class SolanaGetPublicKey(protobuf.MessageType): + address_n: "list[int]" + show_display: "bool | None" + + def __init__( + self, + *, + address_n: "list[int] | None" = None, + show_display: "bool | None" = None, + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["SolanaGetPublicKey"]: + return isinstance(msg, cls) + + class SolanaPublicKey(protobuf.MessageType): + public_key: "bytes" + + def __init__( + self, + *, + public_key: "bytes", + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["SolanaPublicKey"]: + return isinstance(msg, cls) + class StellarAsset(protobuf.MessageType): type: "StellarAssetType" code: "str | None" diff --git a/python/src/trezorlib/cli/solana.py b/python/src/trezorlib/cli/solana.py new file mode 100644 index 0000000000..9c70ec9224 --- /dev/null +++ b/python/src/trezorlib/cli/solana.py @@ -0,0 +1,31 @@ +from typing import TYPE_CHECKING + +import click + +from .. import messages, solana, tools +from . import with_client + +if TYPE_CHECKING: + from ..client import TrezorClient + +PATH_HELP = "BIP-32 path to key, e.g. m/44h/501h/0h/0h" +DEFAULT_PATH = "m/44h/501h/0h/0h" + + +@click.group(name="solana") +def cli() -> None: + """Solana commands.""" + + +@cli.command() +@click.option("-n", "--address", default=DEFAULT_PATH, help=PATH_HELP) +@click.option("-d", "--show-display", is_flag=True) +@with_client +def get_public_key( + client: "TrezorClient", + address: str, + show_display: bool, +) -> messages.SolanaPublicKey: + """Get Solana public key.""" + address_n = tools.parse_path(address) + return solana.get_public_key(client, address_n, show_display) diff --git a/python/src/trezorlib/cli/trezorctl.py b/python/src/trezorlib/cli/trezorctl.py index b820f28d96..e00c965aea 100755 --- a/python/src/trezorlib/cli/trezorctl.py +++ b/python/src/trezorlib/cli/trezorctl.py @@ -46,6 +46,7 @@ from . import ( nem, ripple, settings, + solana, stellar, tezos, with_client, @@ -76,6 +77,7 @@ COMMAND_ALIASES = { "bnb": binance.cli, "eth": ethereum.cli, "ada": cardano.cli, + "sol": solana.cli, "xmr": monero.cli, "xrp": ripple.cli, "xlm": stellar.cli, @@ -410,6 +412,7 @@ cli.add_command(monero.cli) cli.add_command(nem.cli) cli.add_command(ripple.cli) cli.add_command(settings.cli) +cli.add_command(solana.cli) cli.add_command(stellar.cli) cli.add_command(tezos.cli) diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index 49b68442d7..859abf98d6 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -262,6 +262,8 @@ class MessageType(IntEnum): WebAuthnCredentials = 801 WebAuthnAddResidentCredential = 802 WebAuthnRemoveResidentCredential = 803 + SolanaGetPublicKey = 900 + SolanaPublicKey = 901 class FailureType(IntEnum): @@ -6645,6 +6647,37 @@ class RipplePayment(protobuf.MessageType): self.destination_tag = destination_tag +class SolanaGetPublicKey(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 900 + FIELDS = { + 1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None), + 2: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), + } + + def __init__( + self, + *, + address_n: Optional[Sequence["int"]] = None, + show_display: Optional["bool"] = None, + ) -> None: + self.address_n: Sequence["int"] = address_n if address_n is not None else [] + self.show_display = show_display + + +class SolanaPublicKey(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 901 + FIELDS = { + 1: protobuf.Field("public_key", "bytes", repeated=False, required=True), + } + + def __init__( + self, + *, + public_key: "bytes", + ) -> None: + self.public_key = public_key + + class StellarAsset(protobuf.MessageType): MESSAGE_WIRE_TYPE = None FIELDS = { diff --git a/python/src/trezorlib/solana.py b/python/src/trezorlib/solana.py new file mode 100644 index 0000000000..2f9b090b7f --- /dev/null +++ b/python/src/trezorlib/solana.py @@ -0,0 +1,19 @@ +from typing import TYPE_CHECKING, List + +from . import messages +from .tools import expect + +if TYPE_CHECKING: + from .client import TrezorClient + from .protobuf import MessageType + + +@expect(messages.SolanaPublicKey) +def get_public_key( + client: "TrezorClient", + address_n: List[int], + show_display: bool, +) -> "MessageType": + return client.call( + messages.SolanaGetPublicKey(address_n=address_n, show_display=show_display) + ) diff --git a/rust/trezor-client/src/messages/generated.rs b/rust/trezor-client/src/messages/generated.rs index 1f46cd4d0c..e69648653b 100644 --- a/rust/trezor-client/src/messages/generated.rs +++ b/rust/trezor-client/src/messages/generated.rs @@ -79,6 +79,8 @@ trezor_message_impl! { DebugLinkEraseSdCard => MessageType_DebugLinkEraseSdCard, DebugLinkWatchLayout => MessageType_DebugLinkWatchLayout, DebugLinkResetDebugEvents => MessageType_DebugLinkResetDebugEvents, + SolanaGetPublicKey => MessageType_SolanaGetPublicKey, + SolanaPublicKey => MessageType_SolanaPublicKey, } #[cfg(feature = "binance")] diff --git a/rust/trezor-client/src/protos/generated/messages.rs b/rust/trezor-client/src/protos/generated/messages.rs index fccf39f933..dad0705328 100644 --- a/rust/trezor-client/src/protos/generated/messages.rs +++ b/rust/trezor-client/src/protos/generated/messages.rs @@ -494,6 +494,10 @@ pub enum MessageType { MessageType_WebAuthnAddResidentCredential = 802, // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_WebAuthnRemoveResidentCredential) MessageType_WebAuthnRemoveResidentCredential = 803, + // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_SolanaGetPublicKey) + MessageType_SolanaGetPublicKey = 900, + // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_SolanaPublicKey) + MessageType_SolanaPublicKey = 901, } impl ::protobuf::Enum for MessageType { @@ -738,6 +742,8 @@ impl ::protobuf::Enum for MessageType { 801 => ::std::option::Option::Some(MessageType::MessageType_WebAuthnCredentials), 802 => ::std::option::Option::Some(MessageType::MessageType_WebAuthnAddResidentCredential), 803 => ::std::option::Option::Some(MessageType::MessageType_WebAuthnRemoveResidentCredential), + 900 => ::std::option::Option::Some(MessageType::MessageType_SolanaGetPublicKey), + 901 => ::std::option::Option::Some(MessageType::MessageType_SolanaPublicKey), _ => ::std::option::Option::None } } @@ -977,6 +983,8 @@ impl ::protobuf::Enum for MessageType { "MessageType_WebAuthnCredentials" => ::std::option::Option::Some(MessageType::MessageType_WebAuthnCredentials), "MessageType_WebAuthnAddResidentCredential" => ::std::option::Option::Some(MessageType::MessageType_WebAuthnAddResidentCredential), "MessageType_WebAuthnRemoveResidentCredential" => ::std::option::Option::Some(MessageType::MessageType_WebAuthnRemoveResidentCredential), + "MessageType_SolanaGetPublicKey" => ::std::option::Option::Some(MessageType::MessageType_SolanaGetPublicKey), + "MessageType_SolanaPublicKey" => ::std::option::Option::Some(MessageType::MessageType_SolanaPublicKey), _ => ::std::option::Option::None } } @@ -1215,6 +1223,8 @@ impl ::protobuf::Enum for MessageType { MessageType::MessageType_WebAuthnCredentials, MessageType::MessageType_WebAuthnAddResidentCredential, MessageType::MessageType_WebAuthnRemoveResidentCredential, + MessageType::MessageType_SolanaGetPublicKey, + MessageType::MessageType_SolanaPublicKey, ]; } @@ -1459,6 +1469,8 @@ impl ::protobuf::EnumFull for MessageType { MessageType::MessageType_WebAuthnCredentials => 230, MessageType::MessageType_WebAuthnAddResidentCredential => 231, MessageType::MessageType_WebAuthnRemoveResidentCredential => 232, + MessageType::MessageType_SolanaGetPublicKey => 233, + MessageType::MessageType_SolanaPublicKey => 234, }; Self::enum_descriptor().value_by_index(index) } @@ -1508,7 +1520,7 @@ pub mod exts { static file_descriptor_proto_data: &'static [u8] = b"\ \n\x0emessages.proto\x12\x12hw.trezor.messages\x1a\x20google/protobuf/de\ - scriptor.proto*\xd3P\n\x0bMessageType\x12(\n\x16MessageType_Initialize\ + scriptor.proto*\xa6Q\n\x0bMessageType\x12(\n\x16MessageType_Initialize\ \x10\0\x1a\x0c\x80\xa6\x1d\x01\xb0\xb5\x18\x01\x90\xb5\x18\x01\x12\x1e\n\ \x10MessageType_Ping\x10\x01\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x12\ %\n\x13MessageType_Success\x10\x02\x1a\x0c\x80\xa6\x1d\x01\xa8\xb5\x18\ @@ -1771,29 +1783,31 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_WebAuthnCredentials\x10\xa1\ \x06\x1a\x04\x98\xb5\x18\x01\x124\n)MessageType_WebAuthnAddResidentCrede\ ntial\x10\xa2\x06\x1a\x04\x90\xb5\x18\x01\x127\n,MessageType_WebAuthnRem\ - oveResidentCredential\x10\xa3\x06\x1a\x04\x90\xb5\x18\x01\x1a\x04\xc8\ - \xf3\x18\x01\"\x04\x08Z\x10\\\"\x04\x08r\x10z\"\x06\x08\xac\x02\x10\xb0\ - \x02\"\x06\x08\xb5\x02\x10\xb8\x02:<\n\x07wire_in\x18\xd2\x86\x03\x20\ - \x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x06wireIn:>\n\x08wire_o\ - ut\x18\xd3\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\ - \x07wireOut:G\n\rwire_debug_in\x18\xd4\x86\x03\x20\x01(\x08\x12!.google.\ - protobuf.EnumValueOptionsR\x0bwireDebugIn:I\n\x0ewire_debug_out\x18\xd5\ - \x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0cwireDebu\ - gOut:@\n\twire_tiny\x18\xd6\x86\x03\x20\x01(\x08\x12!.google.protobuf.En\ - umValueOptionsR\x08wireTiny:L\n\x0fwire_bootloader\x18\xd7\x86\x03\x20\ - \x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0ewireBootloader:C\n\ - \x0bwire_no_fsm\x18\xd8\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumVa\ - lueOptionsR\twireNoFsm:F\n\x0cbitcoin_only\x18\xe0\xd4\x03\x20\x01(\x08\ - \x12!.google.protobuf.EnumValueOptionsR\x0bbitcoinOnly:U\n\x17has_bitcoi\ - n_only_values\x18\xb9\x8e\x03\x20\x01(\x08\x12\x1c.google.protobuf.EnumO\ - ptionsR\x14hasBitcoinOnlyValues:T\n\x14experimental_message\x18\xa1\x96\ - \x03\x20\x01(\x08\x12\x1f.google.protobuf.MessageOptionsR\x13experimenta\ - lMessage:>\n\twire_type\x18\xa2\x96\x03\x20\x01(\r\x12\x1f.google.protob\ - uf.MessageOptionsR\x08wireType:N\n\x12experimental_field\x18\x89\x9e\x03\ - \x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x11experimentalField\ - :U\n\x17include_in_bitcoin_only\x18\xe0\xd4\x03\x20\x01(\x08\x12\x1c.goo\ - gle.protobuf.FileOptionsR\x14includeInBitcoinOnlyB8\n#com.satoshilabs.tr\ - ezor.lib.protobufB\rTrezorMessage\x80\xa6\x1d\x01\ + oveResidentCredential\x10\xa3\x06\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMess\ + ageType_SolanaGetPublicKey\x10\x84\x07\x1a\x04\x90\xb5\x18\x01\x12&\n\ + \x1bMessageType_SolanaPublicKey\x10\x85\x07\x1a\x04\x98\xb5\x18\x01\x1a\ + \x04\xc8\xf3\x18\x01\"\x04\x08Z\x10\\\"\x04\x08r\x10z\"\x06\x08\xac\x02\ + \x10\xb0\x02\"\x06\x08\xb5\x02\x10\xb8\x02:<\n\x07wire_in\x18\xd2\x86\ + \x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x06wireIn:>\n\ + \x08wire_out\x18\xd3\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValue\ + OptionsR\x07wireOut:G\n\rwire_debug_in\x18\xd4\x86\x03\x20\x01(\x08\x12!\ + .google.protobuf.EnumValueOptionsR\x0bwireDebugIn:I\n\x0ewire_debug_out\ + \x18\xd5\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0c\ + wireDebugOut:@\n\twire_tiny\x18\xd6\x86\x03\x20\x01(\x08\x12!.google.pro\ + tobuf.EnumValueOptionsR\x08wireTiny:L\n\x0fwire_bootloader\x18\xd7\x86\ + \x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0ewireBootload\ + er:C\n\x0bwire_no_fsm\x18\xd8\x86\x03\x20\x01(\x08\x12!.google.protobuf.\ + EnumValueOptionsR\twireNoFsm:F\n\x0cbitcoin_only\x18\xe0\xd4\x03\x20\x01\ + (\x08\x12!.google.protobuf.EnumValueOptionsR\x0bbitcoinOnly:U\n\x17has_b\ + itcoin_only_values\x18\xb9\x8e\x03\x20\x01(\x08\x12\x1c.google.protobuf.\ + EnumOptionsR\x14hasBitcoinOnlyValues:T\n\x14experimental_message\x18\xa1\ + \x96\x03\x20\x01(\x08\x12\x1f.google.protobuf.MessageOptionsR\x13experim\ + entalMessage:>\n\twire_type\x18\xa2\x96\x03\x20\x01(\r\x12\x1f.google.pr\ + otobuf.MessageOptionsR\x08wireType:N\n\x12experimental_field\x18\x89\x9e\ + \x03\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x11experimentalF\ + ield:U\n\x17include_in_bitcoin_only\x18\xe0\xd4\x03\x20\x01(\x08\x12\x1c\ + .google.protobuf.FileOptionsR\x14includeInBitcoinOnlyB8\n#com.satoshilab\ + s.trezor.lib.protobufB\rTrezorMessage\x80\xa6\x1d\x01\ "; /// `FileDescriptorProto` object which was a source for this generated file diff --git a/rust/trezor-client/src/protos/generated/messages_solana.rs b/rust/trezor-client/src/protos/generated/messages_solana.rs new file mode 100644 index 0000000000..87b2398d11 --- /dev/null +++ b/rust/trezor-client/src/protos/generated/messages_solana.rs @@ -0,0 +1,388 @@ +// This file is generated by rust-protobuf 3.3.0. Do not edit +// .proto file is parsed by protoc 3.19.6 +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_results)] +#![allow(unused_mut)] + +//! Generated file from `messages-solana.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_3_0; + +// @@protoc_insertion_point(message:hw.trezor.messages.solana.SolanaGetPublicKey) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct SolanaGetPublicKey { + // message fields + // @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaGetPublicKey.address_n) + pub address_n: ::std::vec::Vec, + // @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaGetPublicKey.show_display) + pub show_display: ::std::option::Option, + // special fields + // @@protoc_insertion_point(special_field:hw.trezor.messages.solana.SolanaGetPublicKey.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a SolanaGetPublicKey { + fn default() -> &'a SolanaGetPublicKey { + ::default_instance() + } +} + +impl SolanaGetPublicKey { + pub fn new() -> SolanaGetPublicKey { + ::std::default::Default::default() + } + + // optional bool show_display = 2; + + pub fn show_display(&self) -> bool { + self.show_display.unwrap_or(false) + } + + pub fn clear_show_display(&mut self) { + self.show_display = ::std::option::Option::None; + } + + pub fn has_show_display(&self) -> bool { + self.show_display.is_some() + } + + // Param is passed by value, moved + pub fn set_show_display(&mut self, v: bool) { + self.show_display = ::std::option::Option::Some(v); + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(2); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>( + "address_n", + |m: &SolanaGetPublicKey| { &m.address_n }, + |m: &mut SolanaGetPublicKey| { &mut m.address_n }, + )); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "show_display", + |m: &SolanaGetPublicKey| { &m.show_display }, + |m: &mut SolanaGetPublicKey| { &mut m.show_display }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "SolanaGetPublicKey", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for SolanaGetPublicKey { + const NAME: &'static str = "SolanaGetPublicKey"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + is.read_repeated_packed_uint32_into(&mut self.address_n)?; + }, + 8 => { + self.address_n.push(is.read_uint32()?); + }, + 16 => { + self.show_display = ::std::option::Option::Some(is.read_bool()?); + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + for value in &self.address_n { + my_size += ::protobuf::rt::uint32_size(1, *value); + }; + if let Some(v) = self.show_display { + my_size += 1 + 1; + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + for v in &self.address_n { + os.write_uint32(1, *v)?; + }; + if let Some(v) = self.show_display { + os.write_bool(2, v)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> SolanaGetPublicKey { + SolanaGetPublicKey::new() + } + + fn clear(&mut self) { + self.address_n.clear(); + self.show_display = ::std::option::Option::None; + self.special_fields.clear(); + } + + fn default_instance() -> &'static SolanaGetPublicKey { + static instance: SolanaGetPublicKey = SolanaGetPublicKey { + address_n: ::std::vec::Vec::new(), + show_display: ::std::option::Option::None, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for SolanaGetPublicKey { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("SolanaGetPublicKey").unwrap()).clone() + } +} + +impl ::std::fmt::Display for SolanaGetPublicKey { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SolanaGetPublicKey { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:hw.trezor.messages.solana.SolanaPublicKey) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct SolanaPublicKey { + // message fields + // @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaPublicKey.public_key) + pub public_key: ::std::option::Option<::std::vec::Vec>, + // special fields + // @@protoc_insertion_point(special_field:hw.trezor.messages.solana.SolanaPublicKey.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a SolanaPublicKey { + fn default() -> &'a SolanaPublicKey { + ::default_instance() + } +} + +impl SolanaPublicKey { + pub fn new() -> SolanaPublicKey { + ::std::default::Default::default() + } + + // required bytes public_key = 1; + + pub fn public_key(&self) -> &[u8] { + match self.public_key.as_ref() { + Some(v) => v, + None => &[], + } + } + + pub fn clear_public_key(&mut self) { + self.public_key = ::std::option::Option::None; + } + + pub fn has_public_key(&self) -> bool { + self.public_key.is_some() + } + + // Param is passed by value, moved + pub fn set_public_key(&mut self, v: ::std::vec::Vec) { + self.public_key = ::std::option::Option::Some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_public_key(&mut self) -> &mut ::std::vec::Vec { + if self.public_key.is_none() { + self.public_key = ::std::option::Option::Some(::std::vec::Vec::new()); + } + self.public_key.as_mut().unwrap() + } + + // Take field + pub fn take_public_key(&mut self) -> ::std::vec::Vec { + self.public_key.take().unwrap_or_else(|| ::std::vec::Vec::new()) + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "public_key", + |m: &SolanaPublicKey| { &m.public_key }, + |m: &mut SolanaPublicKey| { &mut m.public_key }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "SolanaPublicKey", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for SolanaPublicKey { + const NAME: &'static str = "SolanaPublicKey"; + + fn is_initialized(&self) -> bool { + if self.public_key.is_none() { + return false; + } + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + self.public_key = ::std::option::Option::Some(is.read_bytes()?); + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if let Some(v) = self.public_key.as_ref() { + my_size += ::protobuf::rt::bytes_size(1, &v); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if let Some(v) = self.public_key.as_ref() { + os.write_bytes(1, v)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> SolanaPublicKey { + SolanaPublicKey::new() + } + + fn clear(&mut self) { + self.public_key = ::std::option::Option::None; + self.special_fields.clear(); + } + + fn default_instance() -> &'static SolanaPublicKey { + static instance: SolanaPublicKey = SolanaPublicKey { + public_key: ::std::option::Option::None, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for SolanaPublicKey { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("SolanaPublicKey").unwrap()).clone() + } +} + +impl ::std::fmt::Display for SolanaPublicKey { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SolanaPublicKey { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x15messages-solana.proto\x12\x19hw.trezor.messages.solana\x1a\x15mess\ + ages-common.proto\"T\n\x12SolanaGetPublicKey\x12\x1b\n\taddress_n\x18\ + \x01\x20\x03(\rR\x08addressN\x12!\n\x0cshow_display\x18\x02\x20\x01(\x08\ + R\x0bshowDisplay\"0\n\x0fSolanaPublicKey\x12\x1d\n\npublic_key\x18\x01\ + \x20\x02(\x0cR\tpublicKey\ +"; + +/// `FileDescriptorProto` object which was a source for this generated file +fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + static file_descriptor_proto_lazy: ::protobuf::rt::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::Lazy::new(); + file_descriptor_proto_lazy.get(|| { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() + }) +} + +/// `FileDescriptor` object which allows dynamic access to files +pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { + static generated_file_descriptor_lazy: ::protobuf::rt::Lazy<::protobuf::reflect::GeneratedFileDescriptor> = ::protobuf::rt::Lazy::new(); + static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new(); + file_descriptor.get(|| { + let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { + let mut deps = ::std::vec::Vec::with_capacity(1); + deps.push(super::messages_common::file_descriptor().clone()); + let mut messages = ::std::vec::Vec::with_capacity(2); + messages.push(SolanaGetPublicKey::generated_message_descriptor_data()); + messages.push(SolanaPublicKey::generated_message_descriptor_data()); + let mut enums = ::std::vec::Vec::with_capacity(0); + ::protobuf::reflect::GeneratedFileDescriptor::new_generated( + file_descriptor_proto(), + deps, + messages, + enums, + ) + }); + ::protobuf::reflect::FileDescriptor::new_generated_2(generated_file_descriptor) + }) +} diff --git a/tests/REGISTERED_MARKERS b/tests/REGISTERED_MARKERS index dcda43ed00..fab4ec8b3a 100644 --- a/tests/REGISTERED_MARKERS +++ b/tests/REGISTERED_MARKERS @@ -13,6 +13,7 @@ ontology peercoin ripple sd_card +solana stellar tezos zcash diff --git a/tests/device_tests/solana/__init__.py b/tests/device_tests/solana/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/device_tests/solana/test_public_key.py b/tests/device_tests/solana/test_public_key.py new file mode 100644 index 0000000000..90cc17e31b --- /dev/null +++ b/tests/device_tests/solana/test_public_key.py @@ -0,0 +1,40 @@ +# This file is part of the Trezor project. +# +# Copyright (C) 2012-2023 SatoshiLabs and contributors +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the License along with this library. +# If not, see . + +import pytest + +from trezorlib.debuglink import TrezorClientDebugLink as Client +from trezorlib.solana import get_public_key +from trezorlib.tools import parse_path + +from ...common import parametrize_using_common_fixtures + +pytestmark = [ + pytest.mark.altcoin, + pytest.mark.solana, + pytest.mark.skip_t1, +] + + +@parametrize_using_common_fixtures( + "solana/get_public_key.json", +) +def test_solana_get_public_key(client: Client, parameters, result): + actual_result = get_public_key( + client, address_n=parse_path(parameters["path"]), show_display=True + ) + + assert actual_result.public_key.hex() == result["expected_public_key"]