From 6a73a7922b351eedd5435e398db141f8f5746807 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Thu, 1 Feb 2018 13:23:12 +0100 Subject: [PATCH] signing/multisig: get_address for change outputs, address_n check --- src/apps/wallet/sign_tx/addresses.py | 17 ++++++++++++++++- src/apps/wallet/sign_tx/multisig.py | 7 +++++++ src/apps/wallet/sign_tx/scripts.py | 6 +++--- src/apps/wallet/sign_tx/signing.py | 6 +++++- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/apps/wallet/sign_tx/addresses.py b/src/apps/wallet/sign_tx/addresses.py index 124d8a342..ac13d1090 100644 --- a/src/apps/wallet/sign_tx/addresses.py +++ b/src/apps/wallet/sign_tx/addresses.py @@ -19,7 +19,7 @@ class AddressError(Exception): pass -def get_address(script_type: InputScriptType, coin: CoinType, node) -> str: +def get_address(script_type: InputScriptType, coin: CoinType, node, multisig=None) -> str: if script_type == InputScriptType.SPENDADDRESS: # p2pkh return node.address(coin.address_type) @@ -36,6 +36,21 @@ def get_address(script_type: InputScriptType, coin: CoinType, node) -> str: 'Segwit not enabled on this coin') return address_p2wpkh_in_p2sh(node.public_key(), coin.address_type_p2sh) + elif script_type == InputScriptType.SPENDMULTISIG: # multisig + if multisig is None: + raise AddressError(FailureType.ProcessError, + 'Multisig details required') + pubkey = node.public_key() + index = multisig_pubkey_index(multisig, pubkey) + if index is None: + raise AddressError(FailureType.ProcessError, + 'Public key not found') + if coin.address_type_p2sh is None: + raise AddressError(FailureType.ProcessError, + 'Multisig not enabled on this coin') + + return address_multisig_p2sh(multisig_get_pubkeys(multisig), multisig.m, coin.address_type_p2sh) + else: raise AddressError(FailureType.ProcessError, 'Invalid script type') diff --git a/src/apps/wallet/sign_tx/multisig.py b/src/apps/wallet/sign_tx/multisig.py index 6ba5f7891..85f0ab897 100644 --- a/src/apps/wallet/sign_tx/multisig.py +++ b/src/apps/wallet/sign_tx/multisig.py @@ -29,3 +29,10 @@ def multisig_get_pubkey(hd: HDNodePathType) -> bytes: def multisig_get_pubkeys(multisig: MultisigRedeemScriptType): return [multisig_get_pubkey(hd) for hd in multisig.pubkeys] + + +def check_address_n_against_pubkeys(multisig: MultisigRedeemScriptType, address_n) -> bool: + for p in multisig.pubkeys: + if p.address_n == address_n: + return True + return False diff --git a/src/apps/wallet/sign_tx/scripts.py b/src/apps/wallet/sign_tx/scripts.py index cb3cb6a73..0034e11b7 100644 --- a/src/apps/wallet/sign_tx/scripts.py +++ b/src/apps/wallet/sign_tx/scripts.py @@ -122,14 +122,14 @@ def input_script_multisig(current_signature, other_signatures, pubkeys, m: int): # returns a ripedm(sha256()) hash of a multisig script used in P2SH -def output_script_multisig_p2sh(pubkeys, m) -> HashWriter: +def output_script_multisig_p2sh(pubkeys, m) -> bytes: script = script_multisig(pubkeys, m) h = sha256(script).digest() return ripemd160(h).digest() # returns a sha256() hash of a multisig script used in native P2WSH -def output_script_multisig_p2wsh(pubkeys, m) -> HashWriter: +def output_script_multisig_p2wsh(pubkeys, m) -> bytes: for pubkey in pubkeys: if len(pubkey) != 33: raise Exception # only compressed public keys are allowed for P2WSH @@ -137,7 +137,7 @@ def output_script_multisig_p2wsh(pubkeys, m) -> HashWriter: return sha256(script).digest() -def script_multisig(pubkeys, m) -> bytes: +def script_multisig(pubkeys, m) -> bytearray: n = len(pubkeys) if n < 1 or n > 15: raise Exception diff --git a/src/apps/wallet/sign_tx/signing.py b/src/apps/wallet/sign_tx/signing.py index 38ffd5161..cba238b5e 100644 --- a/src/apps/wallet/sign_tx/signing.py +++ b/src/apps/wallet/sign_tx/signing.py @@ -438,6 +438,10 @@ def output_derive_script(o: TxOutputType, coin: CoinType, root) -> bytes: if o.address_n: # change output if o.address: raise SigningError(FailureType.DataError, 'Address in change output') + if o.multisig: + if not check_address_n_against_pubkeys(o.multisig, o.address_n): + raise AddressError(FailureType.ProcessError, + 'address_n must match one of the address_n in the MultisigRedeemScriptType pubkeys') o.address = get_address_for_change(o, coin, root) else: if not o.address: @@ -471,7 +475,7 @@ def get_address_for_change(o: TxOutputType, coin: CoinType, root): input_script_type = InputScriptType.SPENDP2SHWITNESS else: raise SigningError(FailureType.DataError, 'Invalid script type') - return get_address(input_script_type, coin, node_derive(root, o.address_n)) + return get_address(input_script_type, coin, node_derive(root, o.address_n), o.multisig) def output_is_change(o: TxOutputType, wallet_path: list, segwit_in: int) -> bool: