From 83697b775876d8dfd2fbaeef35c8fdaf8ad8fc08 Mon Sep 17 00:00:00 2001 From: obrusvit Date: Tue, 17 Jun 2025 22:21:41 +0200 Subject: [PATCH] feat(core): generate SLIP-21 node for Evolu --- common/protob/messages-evolu.proto | 24 ++ common/protob/messages.proto | 4 + core/.changelog.d/5220.added | 1 + core/embed/upymod/qstrdefsport.h | 2 + core/src/apps/misc/get_evolu_node.py | 31 ++ core/src/apps/workflow_handlers.py | 2 + core/src/trezor/enums/MessageType.py | 2 + core/src/trezor/enums/__init__.py | 2 + core/src/trezor/messages.py | 20 ++ legacy/firmware/protob/Makefile | 2 +- python/src/trezorlib/cli/evolu.py | 47 +++ python/src/trezorlib/cli/trezorctl.py | 2 + python/src/trezorlib/evolu.py | 30 ++ python/src/trezorlib/messages.py | 20 ++ rust/trezor-client/scripts/build_messages | 1 + rust/trezor-client/src/messages/generated.rs | 6 + .../src/protos/generated/messages.rs | 24 +- .../src/protos/generated/messages_evolu.rs | 325 ++++++++++++++++++ rust/trezor-client/src/protos/mod.rs | 1 + .../misc/test_msg_getevolunode.py | 31 ++ 20 files changed, 571 insertions(+), 6 deletions(-) create mode 100644 common/protob/messages-evolu.proto create mode 100644 core/.changelog.d/5220.added create mode 100644 core/src/apps/misc/get_evolu_node.py create mode 100644 python/src/trezorlib/cli/evolu.py create mode 100644 python/src/trezorlib/evolu.py create mode 100644 rust/trezor-client/src/protos/generated/messages_evolu.rs create mode 100644 tests/device_tests/misc/test_msg_getevolunode.py diff --git a/common/protob/messages-evolu.proto b/common/protob/messages-evolu.proto new file mode 100644 index 00000000000..457b7a0a0ef --- /dev/null +++ b/common/protob/messages-evolu.proto @@ -0,0 +1,24 @@ + +syntax = "proto2"; +package hw.trezor.messages.evolu; + +// Sugar for easier handling in Java +option java_package = "com.satoshilabs.trezor.lib.protobuf"; +option java_outer_classname = "TrezorMessageEvolu"; + +/** + * Request: Ask the device for the SLIP-21 node for Evolu, a local first storage + * framework. See https://github.com/evoluhq/evolu + * @start + * @next EvoluNode + */ +message EvoluGetNode { +} + +/** + * Response: Evolu SLIP-21 node + * @end + */ +message EvoluNode { + required bytes data = 1; +} diff --git a/common/protob/messages.proto b/common/protob/messages.proto index ab81366b34e..9eac404a36e 100644 --- a/common/protob/messages.proto +++ b/common/protob/messages.proto @@ -333,6 +333,10 @@ enum MessageType { MessageType_NostrSignEvent = 2003 [(wire_in) = true]; MessageType_NostrEventSignature = 2004 [(wire_out) = true]; + // Evolu + MessageType_EvoluGetNode = 2100 [(wire_in) = true]; + MessageType_EvoluNode = 2101 [(wire_out) = true]; + // Benchmark MessageType_BenchmarkListNames = 9100 [(bitcoin_only) = true]; MessageType_BenchmarkNames = 9101 [(bitcoin_only) = true]; diff --git a/core/.changelog.d/5220.added b/core/.changelog.d/5220.added new file mode 100644 index 00000000000..adb39cbc8e9 --- /dev/null +++ b/core/.changelog.d/5220.added @@ -0,0 +1 @@ +Generation of SLIP-21 node for a new way of storing labels (using Evolu). diff --git a/core/embed/upymod/qstrdefsport.h b/core/embed/upymod/qstrdefsport.h index 6e879e5cd4d..453833d73da 100644 --- a/core/embed/upymod/qstrdefsport.h +++ b/core/embed/upymod/qstrdefsport.h @@ -153,6 +153,7 @@ Q(apps.misc) Q(apps.misc.cipher_key_value) Q(apps.misc.get_ecdh_session_key) Q(apps.misc.get_entropy) +Q(apps.misc.get_evolu_node) Q(apps.misc.get_firmware_hash) Q(apps.misc.payment_notification) Q(apps.misc.sign_identity) @@ -218,6 +219,7 @@ Q(fido2) Q(get_address) Q(get_ecdh_session_key) Q(get_entropy) +Q(get_evolu_node) Q(get_firmware_hash) Q(get_next_u2f_counter) Q(get_nonce) diff --git a/core/src/apps/misc/get_evolu_node.py b/core/src/apps/misc/get_evolu_node.py new file mode 100644 index 00000000000..7a9acc9f367 --- /dev/null +++ b/core/src/apps/misc/get_evolu_node.py @@ -0,0 +1,31 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from trezor.messages import EvoluGetNode, EvoluNode + +_EVOLU_KEY_PATH_PREFIX = [b"TREZOR", b"Evolu"] + + +async def get_evolu_node(_msg: EvoluGetNode) -> EvoluNode: + from storage.device import is_initialized + from trezor.messages import EvoluNode + from trezor.ui.layouts import confirm_action + from trezor.wire import NotInitialized + + from apps.common.seed import Slip21Node, get_seed + + if not is_initialized(): + raise NotInitialized("Device is not initialized") + + # TODO: use translated strings when exposing this to production + await confirm_action( + "get_evolu_keys", + "Evolu node", + action="Derive SLIP-21 node for Evolu?", + prompt_screen=True, + ) + seed = await get_seed() + node = Slip21Node(seed) + node.derive_path(_EVOLU_KEY_PATH_PREFIX) + + return EvoluNode(data=node.data) diff --git a/core/src/apps/workflow_handlers.py b/core/src/apps/workflow_handlers.py index bd1df49364d..d3eb5e79559 100644 --- a/core/src/apps/workflow_handlers.py +++ b/core/src/apps/workflow_handlers.py @@ -104,6 +104,8 @@ def _find_message_handler_module(msg_type: int) -> str: return "apps.misc.cipher_key_value" if msg_type == MessageType.GetFirmwareHash: return "apps.misc.get_firmware_hash" + if msg_type == MessageType.EvoluGetNode: + return "apps.misc.get_evolu_node" if not utils.BITCOIN_ONLY: # When promoting the Nostr app to production-level diff --git a/core/src/trezor/enums/MessageType.py b/core/src/trezor/enums/MessageType.py index 30489f272fe..cf8e8686cbb 100644 --- a/core/src/trezor/enums/MessageType.py +++ b/core/src/trezor/enums/MessageType.py @@ -255,3 +255,5 @@ NostrPubkey = 2002 NostrSignEvent = 2003 NostrEventSignature = 2004 + EvoluGetNode = 2100 + EvoluNode = 2101 diff --git a/core/src/trezor/enums/__init__.py b/core/src/trezor/enums/__init__.py index 01c9b7c93f0..7add057fd33 100644 --- a/core/src/trezor/enums/__init__.py +++ b/core/src/trezor/enums/__init__.py @@ -617,6 +617,8 @@ class MessageType(IntEnum): NostrPubkey = 2002 NostrSignEvent = 2003 NostrEventSignature = 2004 + EvoluGetNode = 2100 + EvoluNode = 2101 BenchmarkListNames = 9100 BenchmarkNames = 9101 BenchmarkRun = 9102 diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index 61bd3959203..22f96e7d886 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -3988,6 +3988,26 @@ def __init__( def is_type_of(cls, msg: Any) -> TypeGuard["EthereumFieldType"]: return isinstance(msg, cls) + class EvoluGetNode(protobuf.MessageType): + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["EvoluGetNode"]: + return isinstance(msg, cls) + + class EvoluNode(protobuf.MessageType): + data: "bytes" + + def __init__( + self, + *, + data: "bytes", + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["EvoluNode"]: + return isinstance(msg, cls) + class MoneroTransactionSourceEntry(protobuf.MessageType): outputs: "list[MoneroOutputEntry]" real_output: "int | None" diff --git a/legacy/firmware/protob/Makefile b/legacy/firmware/protob/Makefile index 5f5a94008c6..081cbccae02 100644 --- a/legacy/firmware/protob/Makefile +++ b/legacy/firmware/protob/Makefile @@ -15,7 +15,7 @@ SKIPPED_MESSAGES := Cardano DebugMonero Eos Monero Ontology Ripple SdProtect Tez SetBrightness DebugLinkOptigaSetSecMax \ BenchmarkListNames BenchmarkRun BenchmarkNames BenchmarkResult \ NostrGetPubkey NostrPubkey NostrSignEvent NostrEventSignature \ - BleUnpair PaymentNotification + BleUnpair PaymentNotification EvoluGetNode EvoluNode ifeq ($(BITCOIN_ONLY), 1) SKIPPED_MESSAGES += Ethereum NEM Stellar diff --git a/python/src/trezorlib/cli/evolu.py b/python/src/trezorlib/cli/evolu.py new file mode 100644 index 00000000000..092ca7026c3 --- /dev/null +++ b/python/src/trezorlib/cli/evolu.py @@ -0,0 +1,47 @@ +# This file is part of the Trezor project. +# +# Copyright (C) 2012-2025 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 . + +from __future__ import annotations + +import typing as t + +import click + +from .. import evolu, messages +from . import with_session + +if t.TYPE_CHECKING: + from ..transport.session import Session + + +@click.group(name="evolu") +def cli() -> None: + """Evolu commands. Evolu is a local first storage framework. See https://github.com/evoluhq/evolu""" + + +@cli.command() +@with_session +def get_node( + session: "Session", +) -> dict[str, str]: + """Return the SLIP-21 node for Evolu.""" + + node: messages.EvoluNode = evolu.get_evolu_node( + session, + ) + return { + "data": node.data.hex(), + } diff --git a/python/src/trezorlib/cli/trezorctl.py b/python/src/trezorlib/cli/trezorctl.py index 024ccd0b6f0..2fd52bf643e 100755 --- a/python/src/trezorlib/cli/trezorctl.py +++ b/python/src/trezorlib/cli/trezorctl.py @@ -40,6 +40,7 @@ device, eos, ethereum, + evolu, fido, firmware, monero, @@ -410,6 +411,7 @@ def wait_for_emulator(obj: TrezorConnection, timeout: float) -> None: cli.add_command(device.cli) cli.add_command(eos.cli) cli.add_command(ethereum.cli) +cli.add_command(evolu.cli) cli.add_command(fido.cli) cli.add_command(monero.cli) cli.add_command(nem.cli) diff --git a/python/src/trezorlib/evolu.py b/python/src/trezorlib/evolu.py new file mode 100644 index 00000000000..e139c12ec1f --- /dev/null +++ b/python/src/trezorlib/evolu.py @@ -0,0 +1,30 @@ +# This file is part of the Trezor project. +# +# Copyright (C) 2012-2025 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 . + + +from typing import TYPE_CHECKING + +from . import messages + +if TYPE_CHECKING: + from .transport.session import Session + + +def get_evolu_node(session: "Session") -> messages.EvoluNode: + return session.call( + messages.EvoluGetNode(), + expect=messages.EvoluNode, + ) diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index a261ecffdb4..1aeeaf424fd 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -670,6 +670,8 @@ class MessageType(IntEnum): NostrPubkey = 2002 NostrSignEvent = 2003 NostrEventSignature = 2004 + EvoluGetNode = 2100 + EvoluNode = 2101 BenchmarkListNames = 9100 BenchmarkNames = 9101 BenchmarkRun = 9102 @@ -5412,6 +5414,24 @@ def __init__( self.struct_name = struct_name +class EvoluGetNode(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 2100 + + +class EvoluNode(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 2101 + FIELDS = { + 1: protobuf.Field("data", "bytes", repeated=False, required=True), + } + + def __init__( + self, + *, + data: "bytes", + ) -> None: + self.data = data + + class MoneroTransactionSourceEntry(protobuf.MessageType): MESSAGE_WIRE_TYPE = None FIELDS = { diff --git a/rust/trezor-client/scripts/build_messages b/rust/trezor-client/scripts/build_messages index d1c25d0d7ee..707830e8a91 100755 --- a/rust/trezor-client/scripts/build_messages +++ b/rust/trezor-client/scripts/build_messages @@ -21,6 +21,7 @@ FEATURES = { # "Cardano": "cardano", "EOS": "eos", + "Evolu": "evolu", "Monero": "monero", "NEM": "nem", "Nostr": "nostr", diff --git a/rust/trezor-client/src/messages/generated.rs b/rust/trezor-client/src/messages/generated.rs index 7da533d89f0..1f2ae1308d2 100644 --- a/rust/trezor-client/src/messages/generated.rs +++ b/rust/trezor-client/src/messages/generated.rs @@ -182,6 +182,12 @@ trezor_message_impl! { EthereumSignTypedHash => MessageType_EthereumSignTypedHash, } +#[cfg(feature = "evolu")] +trezor_message_impl! { + EvoluGetNode => MessageType_EvoluGetNode, + EvoluNode => MessageType_EvoluNode, +} + #[cfg(feature = "monero")] trezor_message_impl! { MoneroTransactionInitRequest => MessageType_MoneroTransactionInitRequest, diff --git a/rust/trezor-client/src/protos/generated/messages.rs b/rust/trezor-client/src/protos/generated/messages.rs index fe2d6546642..ca6d1fe0380 100644 --- a/rust/trezor-client/src/protos/generated/messages.rs +++ b/rust/trezor-client/src/protos/generated/messages.rs @@ -519,6 +519,10 @@ pub enum MessageType { MessageType_NostrSignEvent = 2003, // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_NostrEventSignature) MessageType_NostrEventSignature = 2004, + // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_EvoluGetNode) + MessageType_EvoluGetNode = 2100, + // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_EvoluNode) + MessageType_EvoluNode = 2101, // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_BenchmarkListNames) MessageType_BenchmarkListNames = 9100, // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_BenchmarkNames) @@ -784,6 +788,8 @@ impl ::protobuf::Enum for MessageType { 2002 => ::std::option::Option::Some(MessageType::MessageType_NostrPubkey), 2003 => ::std::option::Option::Some(MessageType::MessageType_NostrSignEvent), 2004 => ::std::option::Option::Some(MessageType::MessageType_NostrEventSignature), + 2100 => ::std::option::Option::Some(MessageType::MessageType_EvoluGetNode), + 2101 => ::std::option::Option::Some(MessageType::MessageType_EvoluNode), 9100 => ::std::option::Option::Some(MessageType::MessageType_BenchmarkListNames), 9101 => ::std::option::Option::Some(MessageType::MessageType_BenchmarkNames), 9102 => ::std::option::Option::Some(MessageType::MessageType_BenchmarkRun), @@ -1040,6 +1046,8 @@ impl ::protobuf::Enum for MessageType { "MessageType_NostrPubkey" => ::std::option::Option::Some(MessageType::MessageType_NostrPubkey), "MessageType_NostrSignEvent" => ::std::option::Option::Some(MessageType::MessageType_NostrSignEvent), "MessageType_NostrEventSignature" => ::std::option::Option::Some(MessageType::MessageType_NostrEventSignature), + "MessageType_EvoluGetNode" => ::std::option::Option::Some(MessageType::MessageType_EvoluGetNode), + "MessageType_EvoluNode" => ::std::option::Option::Some(MessageType::MessageType_EvoluNode), "MessageType_BenchmarkListNames" => ::std::option::Option::Some(MessageType::MessageType_BenchmarkListNames), "MessageType_BenchmarkNames" => ::std::option::Option::Some(MessageType::MessageType_BenchmarkNames), "MessageType_BenchmarkRun" => ::std::option::Option::Some(MessageType::MessageType_BenchmarkRun), @@ -1295,6 +1303,8 @@ impl ::protobuf::Enum for MessageType { MessageType::MessageType_NostrPubkey, MessageType::MessageType_NostrSignEvent, MessageType::MessageType_NostrEventSignature, + MessageType::MessageType_EvoluGetNode, + MessageType::MessageType_EvoluNode, MessageType::MessageType_BenchmarkListNames, MessageType::MessageType_BenchmarkNames, MessageType::MessageType_BenchmarkRun, @@ -1556,10 +1566,12 @@ impl ::protobuf::EnumFull for MessageType { MessageType::MessageType_NostrPubkey => 243, MessageType::MessageType_NostrSignEvent => 244, MessageType::MessageType_NostrEventSignature => 245, - MessageType::MessageType_BenchmarkListNames => 246, - MessageType::MessageType_BenchmarkNames => 247, - MessageType::MessageType_BenchmarkRun => 248, - MessageType::MessageType_BenchmarkResult => 249, + MessageType::MessageType_EvoluGetNode => 246, + MessageType::MessageType_EvoluNode => 247, + MessageType::MessageType_BenchmarkListNames => 248, + MessageType::MessageType_BenchmarkNames => 249, + MessageType::MessageType_BenchmarkRun => 250, + MessageType::MessageType_BenchmarkResult => 251, }; Self::enum_descriptor().value_by_index(index) } @@ -1578,7 +1590,7 @@ impl MessageType { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0emessages.proto\x12\x12hw.trezor.messages\x1a\roptions.proto*\x90W\ + \n\x0emessages.proto\x12\x12hw.trezor.messages\x1a\roptions.proto*\xd7W\ \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_S\ @@ -1859,6 +1871,8 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \xb5\x18\x01\x12\"\n\x17MessageType_NostrPubkey\x10\xd2\x0f\x1a\x04\x98\ \xb5\x18\x01\x12%\n\x1aMessageType_NostrSignEvent\x10\xd3\x0f\x1a\x04\ \x90\xb5\x18\x01\x12*\n\x1fMessageType_NostrEventSignature\x10\xd4\x0f\ + \x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_EvoluGetNode\x10\xb4\x10\ + \x1a\x04\x90\xb5\x18\x01\x12\x20\n\x15MessageType_EvoluNode\x10\xb5\x10\ \x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_BenchmarkListNames\x10\ \x8cG\x1a\x04\x80\xa6\x1d\x01\x12%\n\x1aMessageType_BenchmarkNames\x10\ \x8dG\x1a\x04\x80\xa6\x1d\x01\x12#\n\x18MessageType_BenchmarkRun\x10\x8e\ diff --git a/rust/trezor-client/src/protos/generated/messages_evolu.rs b/rust/trezor-client/src/protos/generated/messages_evolu.rs new file mode 100644 index 00000000000..ffeefbb3013 --- /dev/null +++ b/rust/trezor-client/src/protos/generated/messages_evolu.rs @@ -0,0 +1,325 @@ +// This file is generated by rust-protobuf 3.7.2. 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(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-evolu.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_7_2; + +// @@protoc_insertion_point(message:hw.trezor.messages.evolu.EvoluGetNode) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct EvoluGetNode { + // special fields + // @@protoc_insertion_point(special_field:hw.trezor.messages.evolu.EvoluGetNode.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a EvoluGetNode { + fn default() -> &'a EvoluGetNode { + ::default_instance() + } +} + +impl EvoluGetNode { + pub fn new() -> EvoluGetNode { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(0); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "EvoluGetNode", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for EvoluGetNode { + const NAME: &'static str = "EvoluGetNode"; + + 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 { + 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; + 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<()> { + 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() -> EvoluGetNode { + EvoluGetNode::new() + } + + fn clear(&mut self) { + self.special_fields.clear(); + } + + fn default_instance() -> &'static EvoluGetNode { + static instance: EvoluGetNode = EvoluGetNode { + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for EvoluGetNode { + 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("EvoluGetNode").unwrap()).clone() + } +} + +impl ::std::fmt::Display for EvoluGetNode { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for EvoluGetNode { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:hw.trezor.messages.evolu.EvoluNode) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct EvoluNode { + // message fields + // @@protoc_insertion_point(field:hw.trezor.messages.evolu.EvoluNode.data) + pub data: ::std::option::Option<::std::vec::Vec>, + // special fields + // @@protoc_insertion_point(special_field:hw.trezor.messages.evolu.EvoluNode.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a EvoluNode { + fn default() -> &'a EvoluNode { + ::default_instance() + } +} + +impl EvoluNode { + pub fn new() -> EvoluNode { + ::std::default::Default::default() + } + + // required bytes data = 1; + + pub fn data(&self) -> &[u8] { + match self.data.as_ref() { + Some(v) => v, + None => &[], + } + } + + pub fn clear_data(&mut self) { + self.data = ::std::option::Option::None; + } + + pub fn has_data(&self) -> bool { + self.data.is_some() + } + + // Param is passed by value, moved + pub fn set_data(&mut self, v: ::std::vec::Vec) { + self.data = ::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_data(&mut self) -> &mut ::std::vec::Vec { + if self.data.is_none() { + self.data = ::std::option::Option::Some(::std::vec::Vec::new()); + } + self.data.as_mut().unwrap() + } + + // Take field + pub fn take_data(&mut self) -> ::std::vec::Vec { + self.data.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::<_, _>( + "data", + |m: &EvoluNode| { &m.data }, + |m: &mut EvoluNode| { &mut m.data }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "EvoluNode", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for EvoluNode { + const NAME: &'static str = "EvoluNode"; + + fn is_initialized(&self) -> bool { + if self.data.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.data = ::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.data.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.data.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() -> EvoluNode { + EvoluNode::new() + } + + fn clear(&mut self) { + self.data = ::std::option::Option::None; + self.special_fields.clear(); + } + + fn default_instance() -> &'static EvoluNode { + static instance: EvoluNode = EvoluNode { + data: ::std::option::Option::None, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for EvoluNode { + 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("EvoluNode").unwrap()).clone() + } +} + +impl ::std::fmt::Display for EvoluNode { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for EvoluNode { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x14messages-evolu.proto\x12\x18hw.trezor.messages.evolu\"\x0e\n\x0cEv\ + oluGetNode\"\x1f\n\tEvoluNode\x12\x12\n\x04data\x18\x01\x20\x02(\x0cR\ + \x04dataB9\n#com.satoshilabs.trezor.lib.protobufB\x12TrezorMessageEvolu\ +"; + +/// `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(0); + let mut messages = ::std::vec::Vec::with_capacity(2); + messages.push(EvoluGetNode::generated_message_descriptor_data()); + messages.push(EvoluNode::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/rust/trezor-client/src/protos/mod.rs b/rust/trezor-client/src/protos/mod.rs index 4c029c36dd6..70d1b5fef24 100644 --- a/rust/trezor-client/src/protos/mod.rs +++ b/rust/trezor-client/src/protos/mod.rs @@ -32,6 +32,7 @@ mod generated { "ethereum" => messages_ethereum_eip712 "cardano" => messages_cardano "eos" => messages_eos + "evolu" => messages_evolu "monero" => messages_monero "nem" => messages_nem "nostr" => messages_nostr diff --git a/tests/device_tests/misc/test_msg_getevolunode.py b/tests/device_tests/misc/test_msg_getevolunode.py new file mode 100644 index 00000000000..e2dc6fba153 --- /dev/null +++ b/tests/device_tests/misc/test_msg_getevolunode.py @@ -0,0 +1,31 @@ +# This file is part of the Trezor project. +# +# Copyright (C) 2012-2025 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 import evolu +from trezorlib.debuglink import SessionDebugWrapper as Session + +pytestmark = [pytest.mark.altcoin, pytest.mark.models("core")] + +EXPECTED_SLIP21_NODE_DATA = "a81aaf51997b6ddfa33d11c038d6aba5f711754a2c823823ff8b777825cdbb32b0e71c301fa381c75081bd3bcc134b63306aa6fc9a9f52d835ad4df8cd507be6" + + +def test_get_evolu_node(session: Session): + """Test Evolu key derivation against known test vectors.""" + res = evolu.get_evolu_node(session) + + assert res.data.hex() == EXPECTED_SLIP21_NODE_DATA