1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-17 01:52:02 +00:00

feat(core): Support multisig_xpub_magic in GetPublicKey.

This commit is contained in:
Andrew Kozlik 2024-11-03 10:59:30 +01:00
parent 4287d2b377
commit 6568c36a83
4 changed files with 44 additions and 47 deletions

View File

@ -0,0 +1 @@
Add multisig_xpub_magic option to GetPublicKey.

View File

@ -271,3 +271,30 @@ def descriptor_checksum(desc: str) -> str:
for j in range(0, 8): for j in range(0, 8):
ret[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31] ret[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31]
return "".join(ret) return "".join(ret)
def get_xpub_magic(
coin: CoinInfo,
script_type: InputScriptType,
ignore_xpub_magic: bool | None,
is_multisig: bool | None,
) -> int:
from trezor.enums import InputScriptType
xpub_magic = None
if not ignore_xpub_magic:
# Handle SegWit v0 script types.
# When coin.segwit is true, cointool.py guarantees that the corresponding xpub_magic_* attributes not None.
if not is_multisig:
if script_type == InputScriptType.SPENDP2SHWITNESS:
xpub_magic = coin.xpub_magic_segwit_p2sh
elif script_type == InputScriptType.SPENDWITNESS:
xpub_magic = coin.xpub_magic_segwit_native
else:
if script_type == InputScriptType.SPENDWITNESS:
xpub_magic = coin.xpub_magic_multisig_segwit_native
elif script_type == InputScriptType.SPENDP2SHWITNESS:
xpub_magic = coin.xpub_magic_multisig_segwit_p2sh
# SPENDADDRESS, SPENDMULTISIG, SPENDTAPROOT, ignore_xpub_magic or fallback.
return xpub_magic or coin.xpub_magic

View File

@ -39,6 +39,7 @@ async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Ad
from apps.common.paths import address_n_to_str, validate_path from apps.common.paths import address_n_to_str, validate_path
from . import addresses from . import addresses
from .common import get_xpub_magic
from .keychain import ( from .keychain import (
address_n_to_name_or_unknown, address_n_to_name_or_unknown,
validate_path_against_script_type, validate_path_against_script_type,
@ -72,20 +73,7 @@ async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Ad
address_case_sensitive = False # cashaddr address address_case_sensitive = False # cashaddr address
mac: bytes | None = None mac: bytes | None = None
multisig_xpub_magic = coin.xpub_magic if not multisig:
if multisig:
if coin.segwit and not msg.ignore_xpub_magic:
if (
script_type == InputScriptType.SPENDWITNESS
and coin.xpub_magic_multisig_segwit_native is not None
):
multisig_xpub_magic = coin.xpub_magic_multisig_segwit_native
elif (
script_type == InputScriptType.SPENDP2SHWITNESS
and coin.xpub_magic_multisig_segwit_p2sh is not None
):
multisig_xpub_magic = coin.xpub_magic_multisig_segwit_p2sh
else:
# Attach a MAC for single-sig addresses, but only if the path is standard # Attach a MAC for single-sig addresses, but only if the path is standard
# or if the user explicitly confirms a non-standard path. # or if the user explicitly confirms a non-standard path.
if msg.show_display or ( if msg.show_display or (
@ -97,6 +85,10 @@ async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Ad
if msg.show_display: if msg.show_display:
path = address_n_to_str(address_n) path = address_n_to_str(address_n)
if multisig: if multisig:
multisig_xpub_magic = get_xpub_magic(
coin, script_type, msg.ignore_xpub_magic, is_multisig=True
)
if multisig.nodes: if multisig.nodes:
pubnodes = multisig.nodes pubnodes = multisig.nodes
else: else:

View File

@ -10,20 +10,20 @@ if TYPE_CHECKING:
async def get_public_key( async def get_public_key(
msg: GetPublicKey, auth_msg: MessageType | None = None msg: GetPublicKey, auth_msg: MessageType | None = None
) -> PublicKey: ) -> PublicKey:
from trezor import TR, wire from trezor import TR
from trezor.enums import InputScriptType from trezor.enums import InputScriptType
from trezor.messages import HDNodeType, PublicKey, UnlockPath from trezor.messages import HDNodeType, PublicKey, UnlockPath
from apps.common import coininfo, paths from apps.common import coininfo, paths
from apps.common.keychain import FORBIDDEN_KEY_PATH, get_keychain from apps.common.keychain import FORBIDDEN_KEY_PATH, get_keychain
from .common import get_xpub_magic, sanitize_input_script_type
coin_name = msg.coin_name or "Bitcoin" coin_name = msg.coin_name or "Bitcoin"
script_type = msg.script_type or InputScriptType.SPENDADDRESS script_type = msg.script_type or InputScriptType.SPENDADDRESS
coin = coininfo.by_name(coin_name) coin = coininfo.by_name(coin_name)
curve_name = msg.ecdsa_curve_name or coin.curve_name curve_name = msg.ecdsa_curve_name or coin.curve_name
address_n = msg.address_n # local_cache_attribute address_n = msg.address_n # local_cache_attribute
ignore_xpub_magic = msg.ignore_xpub_magic # local_cache_attribute
xpub_magic = coin.xpub_magic # local_cache_attribute
if address_n and address_n[0] == paths.SLIP25_PURPOSE: if address_n and address_n[0] == paths.SLIP25_PURPOSE:
# UnlockPath is required to access SLIP25 paths. # UnlockPath is required to access SLIP25 paths.
@ -38,36 +38,13 @@ async def get_public_key(
node = keychain.derive(address_n) node = keychain.derive(address_n)
if ( sanitize_input_script_type(coin, script_type)
script_type
in (
InputScriptType.SPENDADDRESS,
InputScriptType.SPENDMULTISIG,
InputScriptType.SPENDTAPROOT,
)
and xpub_magic is not None
):
node_xpub = node.serialize_public(xpub_magic)
elif (
coin.segwit
and script_type == InputScriptType.SPENDP2SHWITNESS
and (ignore_xpub_magic or coin.xpub_magic_segwit_p2sh is not None)
):
assert coin.xpub_magic_segwit_p2sh is not None
node_xpub = node.serialize_public( node_xpub = node.serialize_public(
xpub_magic if ignore_xpub_magic else coin.xpub_magic_segwit_p2sh get_xpub_magic(
coin, script_type, msg.ignore_xpub_magic, msg.multisig_xpub_magic
) )
elif (
coin.segwit
and script_type == InputScriptType.SPENDWITNESS
and (ignore_xpub_magic or coin.xpub_magic_segwit_native is not None)
):
assert coin.xpub_magic_segwit_native is not None
node_xpub = node.serialize_public(
xpub_magic if ignore_xpub_magic else coin.xpub_magic_segwit_native
) )
else:
raise wire.DataError("Invalid combination of coin and script_type")
pubkey = node.public_key() pubkey = node.public_key()
# For curve25519 and ed25519, the public key has the prefix 0x00, as specified by SLIP-10. However, since this prefix is non-standard, it may be removed in the future. # For curve25519 and ed25519, the public key has the prefix 0x00, as specified by SLIP-10. However, since this prefix is non-standard, it may be removed in the future.
@ -79,7 +56,7 @@ async def get_public_key(
public_key=pubkey, public_key=pubkey,
) )
descriptor = _xpub_descriptor( descriptor = _xpub_descriptor(
node, xpub_magic, address_n, script_type, keychain.root_fingerprint() node, coin.xpub_magic, address_n, script_type, keychain.root_fingerprint()
) )
if msg.show_display: if msg.show_display: