From 68ad1b07d28a726549450bad755b7d3ceb6d80d4 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Wed, 27 Oct 2021 16:50:59 +0200 Subject: [PATCH] feat(core): Recognize Taproot inputs. --- core/src/apps/bitcoin/common.py | 19 +++++++++++++++---- core/src/apps/bitcoin/sign_tx/bitcoin.py | 7 +++---- core/src/apps/bitcoin/sign_tx/bitcoinlike.py | 4 ++-- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/core/src/apps/bitcoin/common.py b/core/src/apps/bitcoin/common.py index a682c65f0..955878b10 100644 --- a/core/src/apps/bitcoin/common.py +++ b/core/src/apps/bitcoin/common.py @@ -20,6 +20,10 @@ SIGHASH_ALL = const(0x01) # The number of bip32 levels used in a wallet (chain and address) BIP32_WALLET_DEPTH = const(2) +# Bitcoin opcodes +OP_0 = const(0x00) +OP_1 = const(0x51) + # supported witness versions for bech32 addresses _BECH32_WITVERS = (0, 1) @@ -48,6 +52,7 @@ CHANGE_OUTPUT_SCRIPT_TYPES = tuple(CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES.keys()) SEGWIT_INPUT_SCRIPT_TYPES = ( InputScriptType.SPENDP2SHWITNESS, InputScriptType.SPENDWITNESS, + InputScriptType.SPENDTAPROOT, ) SEGWIT_OUTPUT_SCRIPT_TYPES = ( @@ -101,10 +106,16 @@ def input_is_segwit(txi: TxInput) -> bool: ) -def input_is_nonsegwit(txi: TxInput) -> bool: - return txi.script_type in NONSEGWIT_INPUT_SCRIPT_TYPES or ( - txi.script_type == InputScriptType.EXTERNAL and txi.witness is None - ) +def input_is_taproot(txi: TxInput) -> bool: + if txi.script_type == InputScriptType.SPENDTAPROOT: + return True + + if txi.script_type == InputScriptType.EXTERNAL: + assert txi.script_pubkey is not None + if txi.script_pubkey[0] == OP_1: + return True + + return False def input_is_external(txi: TxInput) -> bool: diff --git a/core/src/apps/bitcoin/sign_tx/bitcoin.py b/core/src/apps/bitcoin/sign_tx/bitcoin.py index 6ee26c44e..9f4cc1098 100644 --- a/core/src/apps/bitcoin/sign_tx/bitcoin.py +++ b/core/src/apps/bitcoin/sign_tx/bitcoin.py @@ -223,7 +223,7 @@ class Bitcoin: if i in self.segwit: if i in self.external: txi = await helpers.request_tx_input(self.tx_req, i, self.coin) - self.serialized_tx.extend(txi.witness or b"") + self.serialized_tx.extend(txi.witness or b"\0") else: await self.sign_segwit_input(i) else: @@ -455,7 +455,7 @@ class Bitcoin: # STAGE_REQUEST_SEGWIT_INPUT in legacy txi = await helpers.request_tx_input(self.tx_req, i, self.coin) - if not input_is_segwit(txi): + if txi.script_type not in common.SEGWIT_INPUT_SCRIPT_TYPES: raise wire.ProcessError("Transaction has changed during signing") self.tx_info.check_input(txi) @@ -491,8 +491,7 @@ class Bitcoin: async def sign_segwit_input(self, i: int) -> None: # STAGE_REQUEST_SEGWIT_WITNESS in legacy txi = await helpers.request_tx_input(self.tx_req, i, self.coin) - - if not input_is_segwit(txi): + if txi.script_type not in common.SEGWIT_INPUT_SCRIPT_TYPES: raise wire.ProcessError("Transaction has changed during signing") public_key, signature = self.sign_bip143_input(txi) diff --git a/core/src/apps/bitcoin/sign_tx/bitcoinlike.py b/core/src/apps/bitcoin/sign_tx/bitcoinlike.py index 0d716bf95..e1247a8b7 100644 --- a/core/src/apps/bitcoin/sign_tx/bitcoinlike.py +++ b/core/src/apps/bitcoin/sign_tx/bitcoinlike.py @@ -6,7 +6,7 @@ from trezor.messages import PrevTx, SignTx, TxInput from apps.common.writers import write_bitcoin_varint from .. import multisig, writers -from ..common import input_is_nonsegwit +from ..common import NONSEGWIT_INPUT_SCRIPT_TYPES from . import helpers from .bitcoin import Bitcoin @@ -21,7 +21,7 @@ class Bitcoinlike(Bitcoin): async def sign_nonsegwit_bip143_input(self, i_sign: int) -> None: txi = await helpers.request_tx_input(self.tx_req, i_sign, self.coin) - if not input_is_nonsegwit(txi): + if txi.script_type not in NONSEGWIT_INPUT_SCRIPT_TYPES: raise wire.ProcessError("Transaction has changed during signing") public_key, signature = self.sign_bip143_input(txi)