From 6e8eebfc9c3122c799b6f9518eddce41d81e7969 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Tue, 26 Jan 2021 18:51:35 +0100 Subject: [PATCH] chore(core/bitcoin): Separate Decred-specific scripts from Bitcoin scripts. --- core/src/apps/bitcoin/scripts.py | 13 ++--- core/src/apps/bitcoin/scripts_decred.py | 75 +++++++++++++++++++++++++ core/src/apps/bitcoin/sign_tx/decred.py | 18 +++++- 3 files changed, 95 insertions(+), 11 deletions(-) diff --git a/core/src/apps/bitcoin/scripts.py b/core/src/apps/bitcoin/scripts.py index f2cb0ef03..2bce70120 100644 --- a/core/src/apps/bitcoin/scripts.py +++ b/core/src/apps/bitcoin/scripts.py @@ -396,20 +396,17 @@ def input_script_multisig( redeem_script_length = output_script_multisig_length(pubkeys, multisig.m) # length of the result - total_length = 0 - if utils.BITCOIN_ONLY or not coin.decred: - total_length += 1 # OP_FALSE + total_length = 1 # OP_FALSE for s in signatures: total_length += 1 + len(s) + 1 # length, signature, hash_type total_length += 1 + redeem_script_length # length, script w = empty_bytearray(total_length) - if utils.BITCOIN_ONLY or not coin.decred: - # Starts with OP_FALSE because of an old OP_CHECKMULTISIG bug, which - # consumes one additional item on the stack: - # https://bitcoin.org/en/developer-guide#standard-transactions - w.append(0x00) + # Starts with OP_FALSE because of an old OP_CHECKMULTISIG bug, which + # consumes one additional item on the stack: + # https://bitcoin.org/en/developer-guide#standard-transactions + w.append(0x00) for s in signatures: if len(s): diff --git a/core/src/apps/bitcoin/scripts_decred.py b/core/src/apps/bitcoin/scripts_decred.py index 3e27f1e94..a160071d4 100644 --- a/core/src/apps/bitcoin/scripts_decred.py +++ b/core/src/apps/bitcoin/scripts_decred.py @@ -1,9 +1,84 @@ from trezor import utils, wire from trezor.crypto import base58 from trezor.crypto.base58 import blake256d_32 +from trezor.messages import InputScriptType from apps.common.writers import empty_bytearray, write_bytes_fixed, write_uint64_le +from . import scripts +from .multisig import multisig_get_pubkeys, multisig_pubkey_index +from .scripts import ( # noqa: F401 + output_script_multisig, + output_script_p2pkh, + output_script_paytoopreturn, +) +from .writers import write_op_push + +if False: + from typing import Optional + + from trezor.messages.MultisigRedeemScriptType import MultisigRedeemScriptType + from trezor.messages.TxInput import EnumTypeInputScriptType + + from apps.common.coininfo import CoinInfo + + +def input_derive_script( + script_type: EnumTypeInputScriptType, + multisig: Optional[MultisigRedeemScriptType], + coin: CoinInfo, + hash_type: int, + pubkey: bytes, + signature: bytes, +) -> bytes: + if script_type == InputScriptType.SPENDADDRESS: + # p2pkh or p2sh + return scripts.input_script_p2pkh_or_p2sh(pubkey, signature, hash_type) + elif script_type == InputScriptType.SPENDMULTISIG: + # p2sh multisig + assert multisig is not None # checked in sanitize_tx_input + signature_index = multisig_pubkey_index(multisig, pubkey) + return input_script_multisig( + multisig, signature, signature_index, hash_type, coin + ) + else: + raise wire.ProcessError("Invalid script type") + + +def input_script_multisig( + multisig: MultisigRedeemScriptType, + signature: bytes, + signature_index: int, + hash_type: int, + coin: CoinInfo, +) -> bytearray: + signatures = multisig.signatures # other signatures + if len(signatures[signature_index]) > 0: + raise wire.DataError("Invalid multisig parameters") + signatures[signature_index] = signature # our signature + + # length of the redeem script + pubkeys = multisig_get_pubkeys(multisig) + redeem_script_length = scripts.output_script_multisig_length(pubkeys, multisig.m) + + # length of the result + total_length = 0 + for s in signatures: + total_length += 1 + len(s) + 1 # length, signature, hash_type + total_length += 1 + redeem_script_length # length, script + + w = empty_bytearray(total_length) + + for s in signatures: + if len(s): + scripts.append_signature(w, s, hash_type) + + # redeem script + write_op_push(w, redeem_script_length) + scripts.write_output_script_multisig(w, pubkeys, multisig.m) + + return w + # A ticket purchase submission for an address hash. def output_script_sstxsubmissionpkh(addr: str) -> bytearray: diff --git a/core/src/apps/bitcoin/sign_tx/decred.py b/core/src/apps/bitcoin/sign_tx/decred.py index 346e8797f..6a607b1e6 100644 --- a/core/src/apps/bitcoin/sign_tx/decred.py +++ b/core/src/apps/bitcoin/sign_tx/decred.py @@ -8,7 +8,7 @@ from trezor.utils import HashWriter, ensure from apps.common.writers import write_bitcoin_varint -from .. import multisig, scripts, scripts_decred, writers +from .. import multisig, scripts_decred, writers from ..common import ecdsa_hash_pubkey, ecdsa_sign from . import approvers, helpers, progress from .bitcoin import Bitcoin @@ -144,12 +144,12 @@ class Decred(Bitcoin): ) elif txi_sign.script_type == InputScriptType.SPENDMULTISIG: assert txi_sign.multisig is not None - prev_pkscript = scripts.output_script_multisig( + prev_pkscript = scripts_decred.output_script_multisig( multisig.multisig_get_pubkeys(txi_sign.multisig), txi_sign.multisig.m, ) elif txi_sign.script_type == InputScriptType.SPENDADDRESS: - prev_pkscript = scripts.output_script_p2pkh( + prev_pkscript = scripts_decred.output_script_p2pkh( ecdsa_hash_pubkey(key_sign_pub, self.coin) ) else: @@ -297,3 +297,15 @@ class Decred(Bitcoin): writers.write_uint32(w, 0) # block height fraud proof writers.write_uint32(w, 0xFFFF_FFFF) # block index fraud proof writers.write_bytes_prefixed(w, script_sig) + + def input_derive_script( + self, txi: TxInput, pubkey: bytes, signature: bytes + ) -> bytes: + return scripts_decred.input_derive_script( + txi.script_type, + txi.multisig, + self.coin, + self.get_hash_type(txi), + pubkey, + signature, + )