1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-12 09:28:10 +00:00

feat(contacts): sign receive address with

- bitcoin receiving address is signed with private key of the first
testnet bitcoin address
- signature is passed in `Address` response
This commit is contained in:
obrusvit 2024-12-10 13:21:46 +01:00
parent 3e9eb074e3
commit beb220054d
2 changed files with 48 additions and 3 deletions

View File

@ -3,6 +3,8 @@ from typing import TYPE_CHECKING
from trezor.enums import MultisigPubkeysOrder
from apps.common import safety_checks
from apps.common.coininfo import by_name as coin_by_name
from .keychain import get_keychain_for_coin
from .common import multisig_uses_single_path
from .keychain import with_keychain
@ -34,6 +36,43 @@ def _get_xpubs(
return result
def sign_from_testnet_priv_key(
address_to_sign: str, keychain: Keychain, coin: CoinInfo
) -> bytes:
"""Sign address with the first Bitcoin testnet private key derived from standard path"""
from trezor.crypto.curve import secp256k1
from apps.common.signverify import message_digest
# Derivation path for first testnet bitcoin address: m/44'/1'/0'/0/0
# 44' : BIP44
# 1' : Bitcoin testnet coin type
# 0' : Account 0
# 0 : External chain
# 0 : First address index
FIRST_TESTNET_ADDRESS_PATH = [2147483692, 2147483649, 2147483648, 0, 0]
# Below is basically trimmed version of sign_message.py
message = address_to_sign
address_n = FIRST_TESTNET_ADDRESS_PATH
node = keychain.derive(address_n)
# address = get_address(script_type, coin, node)
# path = address_n_to_str(address_n)
# account = address_n_to_name_or_unknown(coin, address_n, script_type)
seckey = node.private_key()
digest = message_digest(coin, message.encode())
signature = secp256k1.sign(seckey, digest)
# script_type == InputScriptType.SPENDWITNESS:
script_type_info = 8
# Add script type information to the recovery byte.
signature = bytes([signature[0] + script_type_info]) + signature[1:]
return signature
@with_keychain
async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Address:
from trezor.enums import InputScriptType
@ -103,6 +142,7 @@ async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Ad
):
mac = get_address_mac(address, coin.slip44, keychain)
signature = None
if msg.show_display:
path = address_n_to_str(address_n)
if multisig:
@ -147,6 +187,11 @@ async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Ad
)
else:
account = address_n_to_name_or_unknown(coin, address_n, script_type)
coin_testnet = coin_by_name("Testnet")
keychain_testnet = await get_keychain_for_coin(coin_testnet)
signature = sign_from_testnet_priv_key(
address, keychain_testnet, coin_testnet
)
await show_address(
address_short,
address_qr=address,
@ -156,4 +201,4 @@ async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Ad
chunkify=bool(msg.chunkify),
)
return Address(address=address, mac=mac)
return Address(address=address, mac=mac, signature=signature)

View File

@ -263,7 +263,7 @@ def _get_coin_by_name(coin_name: str | None) -> coininfo.CoinInfo:
raise wire.DataError("Unsupported coin type")
async def _get_keychain_for_coin(
async def get_keychain_for_coin(
coin: coininfo.CoinInfo,
unlock_schemas: Iterable[PathSchema] = (),
) -> Keychain:
@ -321,7 +321,7 @@ def with_keychain(func: HandlerWithCoinInfo[MsgOut]) -> Handler[MsgIn, MsgOut]:
) -> MsgOut:
coin = _get_coin_by_name(msg.coin_name)
unlock_schemas = _get_unlock_schemas(msg, auth_msg, coin)
keychain = await _get_keychain_for_coin(coin, unlock_schemas)
keychain = await get_keychain_for_coin(coin, unlock_schemas)
if AuthorizeCoinJoin.is_type_of(auth_msg):
auth_obj = authorization.from_cached_message(auth_msg)
return await func(msg, keychain, coin, auth_obj)