示例#1
0
    def sign_input(self, input_index, hash_type, private_key, sub_script):
        """ Signs an input.

        Args:
            input_index (int): The index of the input to sign.
            hash_type (int): What kind of signature hash to do.
            private_key (crypto.PrivateKey): private key with which
                to sign the transaction.
            sub_script (Script): the scriptPubKey of the corresponding
                utxo being spent if the outpoint is P2PKH or the redeem
                script if the outpoint is P2SH.
        """
        if input_index < 0 or input_index >= len(self.inputs):
            raise ValueError("Invalid input index.")

        inp = self.inputs[input_index]

        multisig = False
        if sub_script.is_multisig_redeem():
            multisig = True
        elif not sub_script.is_p2pkh():
            raise TypeError(
                "Signing arbitrary redeem scripts is not currently supported.")

        tmp_script = sub_script.remove_op("OP_CODESEPARATOR")

        # Before signing we should verify that the address in the
        # sub_script corresponds to that of the private key
        m = self._match_public_key(private_key, tmp_script)
        if not m['match']:
            if multisig:
                msg = "Public key derived from private key does not match any of the public keys in redeem script."
            else:
                msg = "Address derived from private key does not match sub_script!"
            raise ValueError(msg)

        sig, signed_message = self.get_signature_for_input(
            input_index, hash_type, private_key, sub_script)

        if multisig:
            # For multisig, we need to determine if there are already
            # signatures and if so, where we insert this signature
            inp.script = self._do_multisig_script(
                [dict(index=m['info']['multisig_key_index'], signature=sig)],
                signed_message, inp.script, tmp_script, hash_type)
        else:
            pub_key_bytes = self._get_public_key_bytes(private_key,
                                                       m['info']['compressed'])
            inp.script = Script(
                [sig.to_der() + pack_compact_int(hash_type), pub_key_bytes])

        return True
示例#2
0
    def _copy_for_sig(self, input_index, hash_type, sub_script):
        """ Returns a copy of this txn appropriate for signing, based
            on hash_type.
        """
        new_txn = copy.deepcopy(self)

        # First deal w/the inputs

        # For the SIG_HASH_ANY case, we only care about
        # self.inputs[input_index]
        if hash_type == self.SIG_HASH_ANY:
            ti = new_txn.inputs[input_index]
            new_txn.inputs = [ti]
        else:
            for i, inp in enumerate(new_txn.inputs):
                inp.script = sub_script if i == input_index else Script("")

                if hash_type & 0x1f in [
                        self.SIG_HASH_NONE, self.SIG_HASH_SINGLE
                ] and input_index != i:
                    # Sequence numbers (nSequence) must be set to 0 for all but
                    # the input we care about.
                    inp.sequence_num = 0

        # Now deal with outputs

        if hash_type & 0x1f == self.SIG_HASH_NONE:
            new_txn.outputs = []
        elif hash_type & 0x1f == self.SIG_HASH_SINGLE:
            # Resize output vector to input_index + 1
            new_txn.outputs = new_txn.outputs[:input_index + 1]
            # All outputs except outputs[i] have a value of -1 (0xffffffff)
            # and a blank script
            for i, out in enumerate(new_txn.outputs):
                if i != input_index:
                    out.script = Script("")
                    out.value = 0xffffffff

        return new_txn
示例#3
0
    def from_bytes(b):
        """ Deserializes a byte stream into a TransactionOutput object.

        Args:
            b (bytes): byte-stream beginning with the value.

        Returns:
            tuple: First element of the tuple is a TransactionOutput,
                   the second is the remainder of the byte stream.
        """
        value, b0 = unpack_u64(b)
        script_len, b0 = unpack_compact_int(b0)

        return (TransactionOutput(value,
                                  Script(b0[:script_len])), b0[script_len:])
示例#4
0
    def _verify_input(self, input_index, sub_script, partial_multisig=False):
        p2sh = sub_script.is_p2sh()

        sig_script = self.inputs[input_index].script

        si = ScriptInterpreter(txn=self,
                               input_index=input_index,
                               sub_script=sub_script)
        try:
            si.run_script(sig_script)
        except ScriptInterpreterError:
            return False

        # This copy_stack and the restore_stack emulate the behavior
        # found in bitcoin core for evaluating P2SH scripts. See:
        # https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L1170
        if p2sh:
            si.copy_stack()

        try:
            si.run_script(sub_script)
        except ScriptInterpreterError:
            return False
        rv = si.valid

        if p2sh:
            si.restore_stack()
            redeem_script = Script(si.stack.pop())
            si._sub_script = redeem_script

            try:
                if sig_script.is_multisig_sig() and partial_multisig:
                    # This is a hack for partial verification
                    partial_script = copy.deepcopy(redeem_script)
                    partial_script.ast[-1] = 'OP_CHECKPARTIALMULTISIG'

                    sig_info = sig_script.extract_multisig_sig_info()
                    si.run_script(partial_script)
                    rv &= si.match_count > 0 and si.match_count <= len(
                        sig_info['signatures'])
                else:
                    si.run_script(redeem_script)
                    rv &= si.valid
            except:
                rv = False

        return rv