From a1686b2377c7ee0c32a26087a6e60cdf8bf14247 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 17 Apr 2025 15:59:09 +0200 Subject: [PATCH] feat(core): Set mac field in altcoin Address response messages. --- core/src/apps/cardano/get_address.py | 8 +++++++- core/src/apps/cardano/helpers/paths.py | 20 ++++++++++---------- core/src/apps/common/keychain.py | 13 ++++++++++--- core/src/apps/ripple/get_address.py | 9 ++++++--- core/src/apps/solana/get_address.py | 8 ++++++-- core/src/apps/stellar/get_address.py | 10 ++++++---- core/src/apps/tezos/get_address.py | 12 ++++++++---- python/src/trezorlib/cardano.py | 10 +++++++--- python/src/trezorlib/ripple.py | 12 ++++++++---- python/src/trezorlib/solana.py | 12 ++++++++---- python/src/trezorlib/stellar.py | 12 ++++++++---- python/src/trezorlib/tezos.py | 12 ++++++++---- 12 files changed, 92 insertions(+), 46 deletions(-) diff --git a/core/src/apps/cardano/get_address.py b/core/src/apps/cardano/get_address.py index 3661c4945b..d34b1c57ed 100644 --- a/core/src/apps/cardano/get_address.py +++ b/core/src/apps/cardano/get_address.py @@ -15,8 +15,11 @@ async def get_address( from trezor import log, wire from trezor.messages import CardanoAddress + from apps.common.address_mac import get_address_mac + from . import addresses from .helpers.credential import Credential, should_show_credentials + from .helpers.paths import SLIP44_ID from .helpers.utils import validate_network_info from .layout import show_cardano_address, show_credentials @@ -34,6 +37,9 @@ async def get_address( log.exception(__name__, e) raise wire.ProcessError("Deriving address failed") + mac = get_address_mac( + address, SLIP44_ID, address_parameters.address_n, slip21_keychain + ) if msg.show_display: # _display_address if should_show_credentials(address_parameters): @@ -45,4 +51,4 @@ async def get_address( address_parameters, address, msg.protocol_magic, chunkify=bool(msg.chunkify) ) - return CardanoAddress(address=address) + return CardanoAddress(address=address, mac=mac) diff --git a/core/src/apps/cardano/helpers/paths.py b/core/src/apps/cardano/helpers/paths.py index 9fade5b70d..099aae9603 100644 --- a/core/src/apps/cardano/helpers/paths.py +++ b/core/src/apps/cardano/helpers/paths.py @@ -2,21 +2,21 @@ from micropython import const from apps.common.paths import HARDENED, PathSchema, unharden # noqa: F401 -_SLIP44_ID = const(1815) +SLIP44_ID = const(1815) -BYRON_ROOT = [44 | HARDENED, _SLIP44_ID | HARDENED] -SHELLEY_ROOT = [1852 | HARDENED, _SLIP44_ID | HARDENED] -MULTISIG_ROOT = [1854 | HARDENED, _SLIP44_ID | HARDENED] -MINTING_ROOT = [1855 | HARDENED, _SLIP44_ID | HARDENED] +BYRON_ROOT = [44 | HARDENED, SLIP44_ID | HARDENED] +SHELLEY_ROOT = [1852 | HARDENED, SLIP44_ID | HARDENED] +MULTISIG_ROOT = [1854 | HARDENED, SLIP44_ID | HARDENED] +MINTING_ROOT = [1855 | HARDENED, SLIP44_ID | HARDENED] # fmt: off -SCHEMA_PUBKEY = PathSchema.parse("m/[44,1852,1854]'/coin_type'/account'/*", _SLIP44_ID) +SCHEMA_PUBKEY = PathSchema.parse("m/[44,1852,1854]'/coin_type'/account'/*", SLIP44_ID) # minting has a specific schema for key derivation - see CIP-1855 -SCHEMA_MINT = PathSchema.parse(f"m/1855'/coin_type'/[0-{HARDENED - 1}]'", _SLIP44_ID) -SCHEMA_PAYMENT = PathSchema.parse("m/[44,1852]'/coin_type'/account'/[0,1]/address_index", _SLIP44_ID) +SCHEMA_MINT = PathSchema.parse(f"m/1855'/coin_type'/[0-{HARDENED - 1}]'", SLIP44_ID) +SCHEMA_PAYMENT = PathSchema.parse("m/[44,1852]'/coin_type'/account'/[0,1]/address_index", SLIP44_ID) # staking is only allowed on Shelley paths with suffix /2/0 -SCHEMA_STAKING = PathSchema.parse("m/1852'/coin_type'/account'/2/address_index", _SLIP44_ID) -SCHEMA_STAKING_ANY_ACCOUNT = PathSchema.parse(f"m/1852'/coin_type'/[0-{HARDENED - 1}]'/2/address_index", _SLIP44_ID) +SCHEMA_STAKING = PathSchema.parse("m/1852'/coin_type'/account'/2/address_index", SLIP44_ID) +SCHEMA_STAKING_ANY_ACCOUNT = PathSchema.parse(f"m/1852'/coin_type'/[0-{HARDENED - 1}]'/2/address_index", SLIP44_ID) # fmt: on ACCOUNT_PATH_INDEX = const(2) diff --git a/core/src/apps/common/keychain.py b/core/src/apps/common/keychain.py index 16913d1529..5120f6947d 100644 --- a/core/src/apps/common/keychain.py +++ b/core/src/apps/common/keychain.py @@ -182,6 +182,7 @@ def with_slip44_keychain( slip44_id: int, curve: str = "secp256k1", allow_testnet: bool = True, + slip21_namespaces: Iterable[paths.Slip21Path] = (), ) -> Callable[[HandlerWithKeychain[MsgIn, MsgOut]], Handler[MsgIn, MsgOut]]: if not patterns: raise ValueError # specify a pattern @@ -195,7 +196,7 @@ def with_slip44_keychain( def decorator(func: HandlerWithKeychain[MsgIn, MsgOut]) -> Handler[MsgIn, MsgOut]: async def wrapper(msg: MsgIn) -> MsgOut: - keychain = await get_keychain(curve, schemas) + keychain = await get_keychain(curve, schemas, slip21_namespaces) with keychain: return await func(msg, keychain) @@ -205,7 +206,9 @@ def with_slip44_keychain( def auto_keychain( - modname: str, allow_testnet: bool = True + modname: str, + allow_testnet: bool = True, + slip21_namespaces: Iterable[paths.Slip21Path] = (), ) -> Callable[[HandlerWithKeychain[MsgIn, MsgOut]], Handler[MsgIn, MsgOut]]: import sys @@ -217,5 +220,9 @@ def auto_keychain( curve = getattr(parent_module, "CURVE") slip44_id = getattr(parent_module, "SLIP44_ID") return with_slip44_keychain( - pattern, slip44_id=slip44_id, curve=curve, allow_testnet=allow_testnet + pattern, + slip44_id=slip44_id, + curve=curve, + allow_testnet=allow_testnet, + slip21_namespaces=slip21_namespaces, ) diff --git a/core/src/apps/ripple/get_address.py b/core/src/apps/ripple/get_address.py index 1450669817..9815252f72 100644 --- a/core/src/apps/ripple/get_address.py +++ b/core/src/apps/ripple/get_address.py @@ -8,14 +8,16 @@ if TYPE_CHECKING: from apps.common.keychain import Keychain -@auto_keychain(__name__) +@auto_keychain(__name__, slip21_namespaces=[[b"SLIP-0024"]]) async def get_address(msg: RippleGetAddress, keychain: Keychain) -> RippleAddress: # NOTE: local imports here saves 20 bytes from trezor.messages import RippleAddress from trezor.ui.layouts import show_address from apps.common import paths + from apps.common.address_mac import get_address_mac + from . import SLIP44_ID from .helpers import address_from_public_key address_n = msg.address_n # local_cache_attribute @@ -25,9 +27,10 @@ async def get_address(msg: RippleGetAddress, keychain: Keychain) -> RippleAddres node = keychain.derive(address_n) pubkey = node.public_key() address = address_from_public_key(pubkey) + mac = get_address_mac(address, SLIP44_ID, address_n, keychain) if msg.show_display: - from . import PATTERN, SLIP44_ID + from . import PATTERN await show_address( address, @@ -36,4 +39,4 @@ async def get_address(msg: RippleGetAddress, keychain: Keychain) -> RippleAddres chunkify=bool(msg.chunkify), ) - return RippleAddress(address=address) + return RippleAddress(address=address, mac=mac) diff --git a/core/src/apps/solana/get_address.py b/core/src/apps/solana/get_address.py index b543b8245d..7884a364e1 100644 --- a/core/src/apps/solana/get_address.py +++ b/core/src/apps/solana/get_address.py @@ -12,7 +12,9 @@ if TYPE_CHECKING: from apps.common.keychain import Keychain -@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE) +@with_slip44_keychain( + *PATTERNS, slip44_id=SLIP44_ID, curve=CURVE, slip21_namespaces=[[b"SLIP-0024"]] +) async def get_address( msg: SolanaGetAddress, keychain: Keychain, @@ -21,11 +23,13 @@ async def get_address( from trezor.ui.layouts import show_address from apps.common import paths + from apps.common.address_mac import get_address_mac from .get_public_key import derive_public_key public_key = derive_public_key(keychain, msg.address_n) address = base58.encode(public_key) + mac = get_address_mac(address, SLIP44_ID, msg.address_n, keychain) if msg.show_display: await show_address( @@ -34,4 +38,4 @@ async def get_address( chunkify=bool(msg.chunkify), ) - return SolanaAddress(address=address) + return SolanaAddress(address=address, mac=mac) diff --git a/core/src/apps/stellar/get_address.py b/core/src/apps/stellar/get_address.py index 65b323bbf8..d52881a0d7 100644 --- a/core/src/apps/stellar/get_address.py +++ b/core/src/apps/stellar/get_address.py @@ -8,14 +8,15 @@ if TYPE_CHECKING: from apps.common.keychain import Keychain -@auto_keychain(__name__) +@auto_keychain(__name__, slip21_namespaces=[[b"SLIP-0024"]]) async def get_address(msg: StellarGetAddress, keychain: Keychain) -> StellarAddress: from trezor.messages import StellarAddress from trezor.ui.layouts import show_address from apps.common import paths, seed + from apps.common.address_mac import get_address_mac - from . import helpers + from . import SLIP44_ID, helpers address_n = msg.address_n # local_cache_attribute @@ -24,9 +25,10 @@ async def get_address(msg: StellarGetAddress, keychain: Keychain) -> StellarAddr node = keychain.derive(address_n) pubkey = seed.remove_ed25519_prefix(node.public_key()) address = helpers.address_from_public_key(pubkey) + mac = get_address_mac(address, SLIP44_ID, address_n, keychain) if msg.show_display: - from . import PATTERN, SLIP44_ID + from . import PATTERN await show_address( address, @@ -36,4 +38,4 @@ async def get_address(msg: StellarGetAddress, keychain: Keychain) -> StellarAddr chunkify=bool(msg.chunkify), ) - return StellarAddress(address=address) + return StellarAddress(address=address, mac=mac) diff --git a/core/src/apps/tezos/get_address.py b/core/src/apps/tezos/get_address.py index 8269fce154..673771dbd9 100644 --- a/core/src/apps/tezos/get_address.py +++ b/core/src/apps/tezos/get_address.py @@ -10,15 +10,18 @@ if TYPE_CHECKING: from apps.common.keychain import Keychain -@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE) +@with_slip44_keychain( + *PATTERNS, slip44_id=SLIP44_ID, curve=CURVE, slip21_namespaces=[[b"SLIP-0024"]] +) async def get_address(msg: TezosGetAddress, keychain: Keychain) -> TezosAddress: from trezor.crypto import hashlib from trezor.messages import TezosAddress from trezor.ui.layouts import show_address from apps.common import paths, seed + from apps.common.address_mac import get_address_mac - from . import helpers + from . import SLIP44_ID, helpers address_n = msg.address_n # local_cache_attribute @@ -29,9 +32,10 @@ async def get_address(msg: TezosGetAddress, keychain: Keychain) -> TezosAddress: pk = seed.remove_ed25519_prefix(node.public_key()) pkh = hashlib.blake2b(pk, outlen=helpers.PUBLIC_KEY_HASH_SIZE).digest() address = helpers.base58_encode_check(pkh, helpers.TEZOS_ED25519_ADDRESS_PREFIX) + mac = get_address_mac(address, SLIP44_ID, address_n, keychain) if msg.show_display: - from . import PATTERNS, SLIP44_ID + from . import PATTERNS await show_address( address, @@ -40,4 +44,4 @@ async def get_address(msg: TezosGetAddress, keychain: Keychain) -> TezosAddress: chunkify=bool(msg.chunkify), ) - return TezosAddress(address=address) + return TezosAddress(address=address, mac=mac) diff --git a/python/src/trezorlib/cardano.py b/python/src/trezorlib/cardano.py index 4cbc635f1f..dd35c7cf1c 100644 --- a/python/src/trezorlib/cardano.py +++ b/python/src/trezorlib/cardano.py @@ -817,7 +817,11 @@ def _get_collateral_inputs_items( # ====== Client functions ====== # -def get_address( +def get_address(*args: Any, **kwargs: Any) -> str: + return get_authenticated_address(*args, **kwargs).address + + +def get_authenticated_address( client: "TrezorClient", address_parameters: m.CardanoAddressParametersType, protocol_magic: int = PROTOCOL_MAGICS["mainnet"], @@ -825,7 +829,7 @@ def get_address( show_display: bool = False, derivation_type: m.CardanoDerivationType = m.CardanoDerivationType.ICARUS, chunkify: bool = False, -) -> str: +) -> m.CardanoAddress: return client.call( m.CardanoGetAddress( address_parameters=address_parameters, @@ -836,7 +840,7 @@ def get_address( chunkify=chunkify, ), expect=m.CardanoAddress, - ).address + ) def get_public_key( diff --git a/python/src/trezorlib/ripple.py b/python/src/trezorlib/ripple.py index 00a027c6d9..7b0d988ca7 100644 --- a/python/src/trezorlib/ripple.py +++ b/python/src/trezorlib/ripple.py @@ -14,7 +14,7 @@ # You should have received a copy of the License along with this library. # If not, see . -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from . import messages from .protobuf import dict_to_proto @@ -28,18 +28,22 @@ REQUIRED_FIELDS = ("Fee", "Sequence", "TransactionType", "Payment") REQUIRED_PAYMENT_FIELDS = ("Amount", "Destination") -def get_address( +def get_address(*args: Any, **kwargs: Any) -> str: + return get_authenticated_address(*args, **kwargs).address + + +def get_authenticated_address( client: "TrezorClient", address_n: "Address", show_display: bool = False, chunkify: bool = False, -) -> str: +) -> messages.RippleAddress: return client.call( messages.RippleGetAddress( address_n=address_n, show_display=show_display, chunkify=chunkify ), expect=messages.RippleAddress, - ).address + ) def sign_tx( diff --git a/python/src/trezorlib/solana.py b/python/src/trezorlib/solana.py index 0054e0fd92..db9d07ca8a 100644 --- a/python/src/trezorlib/solana.py +++ b/python/src/trezorlib/solana.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, List, Optional +from typing import TYPE_CHECKING, Any, List, Optional from . import messages @@ -17,12 +17,16 @@ def get_public_key( ).public_key -def get_address( +def get_address(*args: Any, **kwargs: Any) -> str: + return get_authenticated_address(*args, **kwargs).address + + +def get_authenticated_address( client: "TrezorClient", address_n: List[int], show_display: bool, chunkify: bool = False, -) -> str: +) -> messages.SolanaAddress: return client.call( messages.SolanaGetAddress( address_n=address_n, @@ -30,7 +34,7 @@ def get_address( chunkify=chunkify, ), expect=messages.SolanaAddress, - ).address + ) def sign_tx( diff --git a/python/src/trezorlib/stellar.py b/python/src/trezorlib/stellar.py index 5bd0a749e4..202ef69e71 100644 --- a/python/src/trezorlib/stellar.py +++ b/python/src/trezorlib/stellar.py @@ -15,7 +15,7 @@ # If not, see . from decimal import Decimal -from typing import TYPE_CHECKING, List, Tuple, Union +from typing import TYPE_CHECKING, Any, List, Tuple, Union from . import exceptions, messages @@ -321,18 +321,22 @@ def _read_asset(asset: "Asset") -> messages.StellarAsset: # ====== Client functions ====== # -def get_address( +def get_address(*args: Any, **kwargs: Any) -> str: + return get_authenticated_address(*args, **kwargs).address + + +def get_authenticated_address( client: "TrezorClient", address_n: "Address", show_display: bool = False, chunkify: bool = False, -) -> str: +) -> messages.StellarAddress: return client.call( messages.StellarGetAddress( address_n=address_n, show_display=show_display, chunkify=chunkify ), expect=messages.StellarAddress, - ).address + ) def sign_tx( diff --git a/python/src/trezorlib/tezos.py b/python/src/trezorlib/tezos.py index 9319aa1eaa..b1cdcd2804 100644 --- a/python/src/trezorlib/tezos.py +++ b/python/src/trezorlib/tezos.py @@ -14,7 +14,7 @@ # You should have received a copy of the License along with this library. # If not, see . -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from . import messages @@ -23,18 +23,22 @@ if TYPE_CHECKING: from .tools import Address -def get_address( +def get_address(*args: Any, **kwargs: Any) -> str: + return get_authenticated_address(*args, **kwargs).address + + +def get_authenticated_address( client: "TrezorClient", address_n: "Address", show_display: bool = False, chunkify: bool = False, -) -> str: +) -> messages.TezosAddress: return client.call( messages.TezosGetAddress( address_n=address_n, show_display=show_display, chunkify=chunkify ), expect=messages.TezosAddress, - ).address + ) def get_public_key(