示例#1
0
def sign_tx(private_key, tx, *, unspents):
    """Signs inputs in provided transaction object for which unspents
    are provided and can be signed by the private key.

    :param private_key: Private key
    :type private_key: ``PrivateKey`` or ``MultiSig``
    :param tx: Transaction object
    :type tx: ``TxObj``
    :param unspents: For inputs to be signed their corresponding Unspent objects
                     must be provided.
    :type unspents: ``list`` of :class:`~bit.network.meta.Unspent`
    :returns: The signed transaction as hex.
    :rtype: ``str``
    """

    # input_dict contains those unspents that can be signed by private_key,
    # providing additional information for segwit-inputs (the amount to spend)
    input_dict = {}
    try:
        for unspent in unspents:
            if not private_key.can_sign_unspent(unspent):
                continue
            tx_input = hex_to_bytes(
                unspent.txid)[::-1] + unspent.txindex.to_bytes(
                    4, byteorder='little')
            input_dict[tx_input] = unspent.to_dict()
    except TypeError:
        raise TypeError(
            'Please provide as unspents at least all inputs to be signed with the function call in a list.'
        )

    # Determine input indices to sign from input_dict (allows for transaction batching)
    sign_inputs = [
        j for j, i in enumerate(tx.TxIn) if i.txid + i.txindex in input_dict
    ]

    segwit_tx = TxObj.is_segwit(tx)
    public_key = private_key.public_key
    public_key_push = script_push(len(public_key))
    hash_type = HASH_TYPE

    # Make input parameters for preimage calculation
    inputs_parameters = []

    # The TxObj in `tx` will below be modified to contain the scriptCodes used
    # for the transaction structure to be signed

    # `input_script_field` copies the scriptSigs for partially signed
    # transactions to later extract signatures from it:
    input_script_field = [tx.TxIn[i].script_sig for i in range(len(tx.TxIn))]

    for i in sign_inputs:
        # Create transaction object for preimage calculation
        tx_input = tx.TxIn[i].txid + tx.TxIn[i].txindex
        segwit_input = input_dict[tx_input]['segwit']
        tx.TxIn[i].segwit_input = segwit_input

        script_code = private_key.scriptcode
        script_code_len = int_to_varint(len(script_code))

        # Use scriptCode for preimage calculation of transaction object:
        tx.TxIn[i].script_sig = script_code
        tx.TxIn[i].script_sig_len = script_code_len

        if segwit_input:
            try:
                tx.TxIn[i].script_sig += input_dict[tx_input][
                    'amount'].to_bytes(8, byteorder='little')

                # For partially signed Segwit transactions the signatures must
                # be extracted from the witnessScript field:
                input_script_field[i] = tx.TxIn[i].witness
            except AttributeError:
                raise ValueError(
                    'Cannot sign a segwit input when the input\'s amount is '
                    'unknown. Maybe no network connection or the input is '
                    'already spent? Then please provide all inputs to sign as '
                    '`Unspent` objects to the function call.')

        inputs_parameters.append([i, hash_type, segwit_input])
    preimages = calculate_preimages(tx, inputs_parameters)

    # Calculate signature scripts:
    for hash, (i, _, segwit_input) in zip(preimages, inputs_parameters):
        signature = private_key.sign(hash) + b'\x01'

        # ------------------------------------------------------------------
        if private_key.instance == 'MultiSig' or private_key.instance == 'MultiSigTestnet':
            # P2(W)SH input

            script_blob = b''
            sigs = {}
            # Initial number of witness items (OP_0 + one signature + redeemscript).
            witness_count = 3
            if input_script_field[i]:
                sig_list = get_signatures_from_script(input_script_field[i])
                # Bitcoin Core convention: Every missing signature is denoted
                # by 0x00. Only used for already partially-signed scriptSigs:
                script_blob += b'\x00' * (private_key.m - len(sig_list) - 1)
                # Total number of witness items when partially or fully signed:
                witness_count = private_key.m + 2
                # For a partially signed input make a dictionary containing
                # all the provided signatures with public-keys as keys:
                for sig in sig_list:
                    for pub in private_key.public_keys:
                        if verify_sig(sig[:-1], hash, pub):
                            # If we already found a valid signature for pubkey
                            # we just overwrite it and don't care.
                            sigs[pub] = sig
                if len(sigs) >= private_key.m:
                    raise ValueError(
                        'Transaction is already signed with sufficiently needed signatures.'
                    )

            sigs[public_key] = signature

            witness = b''
            # Sort ingthe signatures according to the public-key list:
            for pub in private_key.public_keys:
                if pub in sigs:
                    sig = sigs[pub]
                    length = int_to_varint(
                        len(sig)) if segwit_input else script_push(len(sig))
                    witness += length + sig

            script_sig = b'\x22' + private_key.segwit_scriptcode

            witness = (int_to_varint(witness_count) if segwit_input else
                       b'') + b'\x00' + witness + script_blob
            witness += (int_to_varint(len(
                private_key.redeemscript)) if segwit_input else script_push(
                    len(private_key.redeemscript))) + private_key.redeemscript

            script_sig = script_sig if segwit_input else witness
            witness = witness if segwit_input else b'\x00' if segwit_tx else b''

        # ------------------------------------------------------------------
        else:
            # P2(W)PKH input

            script_sig = b'\x16' + private_key.segwit_scriptcode

            witness = ((b'\x02' if segwit_input else b'') +
                       len(signature).to_bytes(
                           1, byteorder='little')  # witness counter
                       + signature + public_key_push + public_key)

            script_sig = script_sig if segwit_input else witness
            witness = witness if segwit_input else b'\x00' if segwit_tx else b''

        # Providing the signature(s) to the input
        tx.TxIn[i].script_sig = script_sig
        tx.TxIn[i].script_sig_len = int_to_varint(len(script_sig))
        tx.TxIn[i].witness = witness

    return tx.to_hex()
示例#2
0
 def test_invalid(self):
     assert not verify_sig(INVALID_SIGNATURE, DATA, PUBLIC_KEY_COMPRESSED)
示例#3
0
 def test_high_s(self):
     with pytest.raises(InvalidSignature):
         verify_sig(SIGNATURE_HIGH_S,
                    DATA,
                    PUBLIC_KEY_COMPRESSED,
                    strict=True)
示例#4
0
 def test_sign(self):
     base_key = BaseKey()
     data = os.urandom(200)
     signature = base_key.sign(data)
     assert verify_sig(signature, data, base_key.public_key)
示例#5
0
 def test_strict_valid(self):
     assert verify_sig(VALID_SIGNATURE,
                       DATA,
                       PUBLIC_KEY_COMPRESSED,
                       strict=True)
示例#6
0
 def test_invalid(self):
     with pytest.raises(InvalidSignature):
         verify_sig(b'invalid', DATA, PUBLIC_KEY_COMPRESSED)
示例#7
0
文件: transaction.py 项目: xacce/bit
def sign_tx(
    private_key,
    tx,
    j=-1
):  # Future-TODO: add sw_dict to allow override of segwit input dictionary?
    # j is the input to be signed and can be a single index, a list of indices, or denote all inputs (-1)

    if not isinstance(tx, TxObj):
        # Add sw_dict containing unspent segwit txid:txindex and amount to deserialize tx:
        sw_dict = {}
        unspents = private_key.unspents
        for u in unspents:
            if u.segwit:
                tx_input = u.txid + ':' + str(u.txindex)
                sw_dict[tx_input] = u.amount
        tx = deserialize(tx, sw_dict, private_key.sw_scriptcode)

    version = tx.version
    marker = b'\x00'
    flag = b'\x01'
    lock_time = tx.locktime
    hash_type = HASH_TYPE

    input_count = int_to_varint(tx.input_count)
    output_count = int_to_varint(tx.output_count)

    output_block = b''
    for i in range(tx.output_count):
        output_block += tx.TxOut[i].value
        output_block += tx.TxOut[i].script_len
        output_block += tx.TxOut[i].script

    hashPrevouts = double_sha256(b''.join(
        [i.txid + i.txindex for i in tx.TxIn]))
    hashSequence = double_sha256(b''.join([i.sequence for i in tx.TxIn]))
    hashOutputs = double_sha256(b''.join([bytes(o) for o in tx.TxOut]))

    if j < 0:  # Sign all inputs
        j = range(len(tx.TxIn))
    elif not isinstance(j, list):  # Sign a single input
        j = [j]

    segwit = False  # Global check if at least one input is segwit

    for i in j:
        # Check if input is segwit or non-segwit:
        sw = tx.TxIn[i].segwit
        segwit = segwit or sw  # Global check if at least one input is segwit => Transaction must be of segwit-format

        public_key = private_key.public_key
        public_key_len = script_push(len(public_key))

        scriptCode = private_key.scriptcode
        scriptCode_len = int_to_varint(len(scriptCode))

        if sw == False:
            hashed = sha256(version + input_count +
                            b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence
                                     for ti in islice(tx.TxIn, i)) +
                            tx.TxIn[i].txid + tx.TxIn[i].txindex +
                            scriptCode_len + scriptCode + tx.TxIn[i].sequence +
                            b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence
                                     for ti in islice(tx.TxIn, i + 1, None)) +
                            output_count + output_block + lock_time +
                            hash_type)

            input_script_field = tx.TxIn[i].script

        else:
            hashed = sha256(  # BIP-143: Used for Segwit
                version + hashPrevouts + hashSequence + tx.TxIn[i].txid +
                tx.TxIn[i].txindex + scriptCode_len + scriptCode +
                tx.TxIn[i].amount + tx.TxIn[i].sequence + hashOutputs +
                lock_time + hash_type)

            input_script_field = tx.TxIn[i].witness

        signature = private_key.sign(hashed) + b'\x01'

        # ------------------------------------------------------------------
        if private_key.instance == 'MultiSig' or private_key.instance == 'MultiSigTestnet':
            # P2(W)SH input

            script_blob = b''
            sigs = {}
            if input_script_field:  # If tx is already partially signed: Make a dictionary of the provided signatures with public-keys as key-values
                sig_list = get_signatures_from_script(input_script_field)
                if len(sig_list) > private_key.m:
                    raise TypeError(
                        'Transaction is already signed with {} of {} needed signatures.'
                    ).format(len(sig_list), private_key.m)
                for sig in sig_list:
                    for pub in private_key.public_keys:
                        if verify_sig(sig[:-1], hashed, hex_to_bytes(pub)):
                            sigs[pub] = sig
                script_blob += b'\x00' * (
                    private_key.m - len(sig_list) - 1
                )  # Bitcoin Core convention: Every missing signature is denoted by 0x00. Only used for already partially-signed scriptSigs.

            sigs[bytes_to_hex(public_key)] = signature

            witness = b''
            witness_count = 2  # count number of witness items (OP_0 + each signature + redeemscript).
            for pub in private_key.public_keys:  # Sort the signatures according to the public-key list:
                if pub in sigs:
                    sig = sigs[pub]
                    length = int_to_varint(
                        len(sig)) if sw == True else script_push(len(sig))
                    witness += length + sig
                    witness_count += 1

            script_sig = b'\x22' + private_key.sw_scriptcode

            witness = (witness_count.to_bytes(1, byteorder='little') if sw
                       == True else b'') + b'\x00' + witness + script_blob
            witness += (int_to_varint(len(
                private_key.redeemscript)) if sw == True else script_push(
                    len(private_key.redeemscript))) + private_key.redeemscript

            script_sig = witness if sw == False else script_sig
            witness = b'\x00' if sw == False else witness

        # ------------------------------------------------------------------
        else:
            # P2(W)PKH input

            script_sig = b'\x16' + private_key.sw_scriptcode

            witness = ((b'\x02' if sw == True else b'') +  # witness counter
                       len(signature).to_bytes(1, byteorder='little') +
                       signature + public_key_len + public_key)

            script_sig = witness if sw == False else script_sig
            witness = b'\x00' if sw == False else witness

        tx.TxIn[i].script = script_sig
        tx.TxIn[i].script_len = int_to_varint(len(script_sig))
        tx.TxIn[i].witness = witness

    return bytes_to_hex(
        version + (marker if segwit == True else b'') +
        (flag if segwit == True else b'') + input_count +
        construct_input_block(tx.TxIn) + output_count + output_block +
        (construct_witness_block(tx.TxIn) if segwit == True else b'') +
        lock_time)
示例#8
0
def sign_tx(private_key, tx, *, unspents):
    """Signs inputs in provided transaction object for which unspents
    are provided and can be signed by the private key.

    :param private_key: Private key
    :type private_key: ``PrivateKey`` or ``MultiSig``
    :param tx: Transaction object
    :type tx: ``TxObj``
    :param unspents: For inputs to be signed their corresponding Unspent objects
                     must be provided.
    :returns: The signed transaction as hex.
    :rtype: ``str``
    """

    # input_dict contains those unspents that can be signed by private_key,
    # providing additional information for segwit-inputs (the amount to spend)
    input_dict = {}
    try:
        for unspent in unspents:
            if not private_key.can_sign_unspent(unspent):
                continue
            tx_input = hex_to_bytes(unspent.txid)[::-1] + \
                unspent.txindex.to_bytes(4, byteorder='little')
            input_dict[tx_input] = unspent.to_dict()
    except TypeError:
        raise ValueError('Please provide as unspents at least all inputs to '
                         'be signed with the function call.')

    # Determine input indices to sign from input_dict (allows for transaction batching)
    sign_inputs = [j for j, i in enumerate(tx.TxIn) if i.txid+i.txindex in input_dict]

    segwit_tx = TxObj.is_segwit(tx)

    version = tx.version
    lock_time = tx.locktime
    hash_type = HASH_TYPE

    input_count = int_to_varint(len(tx.TxIn))
    output_count = int_to_varint(len(tx.TxOut))

    output_block = b''.join([bytes(o) for o in tx.TxOut])

    hashPrevouts = double_sha256(b''.join([i.txid+i.txindex for i in tx.TxIn]))
    hashSequence = double_sha256(b''.join([i.sequence for i in tx.TxIn]))
    hashOutputs = double_sha256(output_block)

    for i in sign_inputs:

        tx_input = tx.TxIn[i].txid + tx.TxIn[i].txindex
        segwit_input = input_dict[tx_input]['segwit']
        tx.TxIn[i].segwit_input = segwit_input

        public_key = private_key.public_key
        public_key_push = script_push(len(public_key))

        script_code = private_key.scriptcode
        script_code_len = int_to_varint(len(script_code))

        if not segwit_input:
            hashed = sha256(
                version +
                input_count +
                b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence
                         for ti in islice(tx.TxIn, i)) +
                tx.TxIn[i].txid +
                tx.TxIn[i].txindex +
                script_code_len +
                script_code +
                tx.TxIn[i].sequence +
                b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence
                         for ti in islice(tx.TxIn, i + 1, None)) +
                output_count +
                output_block +
                lock_time +
                hash_type
                )

            input_script_field = tx.TxIn[i].script_sig

        elif segwit_input:
            try:
                tx.TxIn[i].amount = input_dict[tx_input]['amount']\
                                    .to_bytes(8, byteorder='little')
            except Attributerror:
                raise ValueError(
                    'Cannot sign a segwit input when the input\'s amount is '
                    'unknown. Maybe no network connection or the input is '
                    'already spent? Then please provide all inputs to sign as '
                    '`Unspent` objects to the function call.')

            hashed = sha256(  # BIP-143: Used for Segwit
                version +
                hashPrevouts +
                hashSequence +
                tx.TxIn[i].txid +
                tx.TxIn[i].txindex +
                script_code_len +
                script_code +
                tx.TxIn[i].amount +
                tx.TxIn[i].sequence +
                hashOutputs +
                lock_time +
                hash_type
                )

            input_script_field = tx.TxIn[i].witness

        signature = private_key.sign(hashed) + b'\x01'

        # ------------------------------------------------------------------
        if (private_key.instance == 'MultiSig' or
                private_key.instance == 'MultiSigTestnet'):
            # P2(W)SH input

            script_blob = b''
            sigs = {}
            # Initial number of witness items (OP_0 + one signature + redeemscript).
            witness_count = 3
            if input_script_field:
                sig_list = get_signatures_from_script(input_script_field)
                # Bitcoin Core convention: Every missing signature is denoted
                # by 0x00. Only used for already partially-signed scriptSigs:
                script_blob += b'\x00' * (private_key.m - len(sig_list)-1)
                # Total number of witness items when partially or fully signed:
                witness_count = private_key.m + 2
                # For a partially signed input make a dictionary containing
                # all the provided signatures with public-keys as keys:
                for sig in sig_list:
                    for pub in private_key.public_keys:
                        if verify_sig(sig[:-1], hashed, hex_to_bytes(pub)):
                            # If we already found a valid signature for pubkey
                            # we just overwrite it and don't care.
                            sigs[pub] = sig
                if len(sigs) == private_key.m:
                    raise TypeError('Transaction is already signed with '
                                    'sufficiently needed signatures.')
                elif len(sigs) > private_key.m:
                    raise TypeError('Transaction already contains {} '
                                    'signatures, but only {} needed.').format(
                                        len(sigs), private_key.m)

            sigs[bytes_to_hex(public_key)] = signature

            witness = b''
            # Sort ingthe signatures according to the public-key list:
            for pub in private_key.public_keys:
                if pub in sigs:
                    sig = sigs[pub]
                    length = int_to_varint(len(sig)) if segwit_input else \
                        script_push(len(sig))
                    witness += length + sig

            script_sig = b'\x22' + private_key.segwit_scriptcode

            witness = (int_to_varint(witness_count) if segwit_input else b'') \
                + b'\x00' + witness + script_blob
            witness += (int_to_varint(len(private_key.redeemscript)) if
                segwit_input else script_push(len(private_key.redeemscript))) \
                + private_key.redeemscript

            script_sig = script_sig if segwit_input else witness
            witness = witness if segwit_input else b'\x00' if segwit_tx else b''

        # ------------------------------------------------------------------
        else:
            # P2(W)PKH input

            script_sig = b'\x16' + private_key.segwit_scriptcode

            witness = (
                      (b'\x02' if segwit_input else b'') +  # witness counter
                      len(signature).to_bytes(1, byteorder='little') +
                      signature +
                      public_key_push +
                      public_key
                     )

            script_sig = script_sig if segwit_input else witness
            witness = witness if segwit_input else b'\x00' if segwit_tx else b''

        # Providing the signature(s) to the input
        tx.TxIn[i].script_sig = script_sig
        tx.TxIn[i].script_sig_len = int_to_varint(len(script_sig))
        tx.TxIn[i].witness = witness

    return tx.to_hex()
示例#9
0
def sign_legacy_tx(private_key, tx, j=-1):
    # j is the input to be signed and can be a single index, a list of indices, or denote all inputs (-1)

    if not isinstance(tx, TxObj):
        tx = deserialize(tx)

    version = tx.version
    lock_time = tx.locktime
    hash_type = HASH_TYPE

    input_count = int_to_varint(tx.input_count)
    output_count = int_to_varint(tx.output_count)

    output_block = b''
    for i in range(tx.output_count):
        output_block += tx.TxOut[i].value
        output_block += tx.TxOut[i].script_len
        output_block += tx.TxOut[i].script

    inputs = tx.TxIn

    if j < 0:
        j = range(len(inputs))
    elif not isinstance(j, list):
        j = [j]

    for i in j:

        public_key = private_key.public_key
        public_key_len = script_push(len(public_key))

        scriptCode = private_key.scriptcode
        scriptCode_len = int_to_varint(len(scriptCode))

        hashed = sha256(version + input_count +
                        b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence
                                 for ti in islice(inputs, i)) +
                        inputs[i].txid + inputs[i].txindex + scriptCode_len +
                        scriptCode + inputs[i].sequence +
                        b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence
                                 for ti in islice(inputs, i + 1, None)) +
                        output_count + output_block + lock_time + hash_type)

        signature = private_key.sign(hashed) + b'\x01'

        # ------------------------------------------------------------------
        if private_key.instance == 'MultiSig' or private_key.instance == 'MultiSigTestnet':

            script_blob = b''
            sigs = {}
            if tx.TxIn[
                    i].script:  # If tx is already partially signed: Make a dictionary of the provided signatures with public-keys as key-values
                sig_list = get_signatures_from_script(tx.TxIn[i].script)
                if len(sig_list) > private_key.m:
                    raise TypeError(
                        'Transaction is already signed with {} of {} needed signatures.'
                    ).format(len(sig_list), private_key.m)
                for sig in sig_list:
                    for pub in private_key.public_keys:
                        if verify_sig(sig[:-1], hashed, hex_to_bytes(pub)):
                            sigs[pub] = sig
                script_blob += b'\x00' * (
                    private_key.m - len(sig_list) - 1
                )  # Bitcoin Core convention: Every missing signature is denoted by 0x00. Only used for already partially-signed scriptSigs.

            sigs[bytes_to_hex(public_key)] = signature

            script_sig = b''  # P2SH -  Multisig
            for pub in private_key.public_keys:  # Sort the signatures according to the public-key list:
                if pub in sigs:
                    sig = sigs[pub]
                    length = script_push(len(sig))
                    script_sig += length + sig

            script_sig = b'\x00' + script_sig + script_blob
            script_sig += script_push(len(
                private_key.redeemscript)) + private_key.redeemscript

        # ------------------------------------------------------------------
        else:
            script_sig = (  # P2PKH
                len(signature).to_bytes(1, byteorder='little') + signature +
                public_key_len + public_key)

        inputs[i].script = script_sig
        inputs[i].script_len = int_to_varint(len(script_sig))

    return bytes_to_hex(version + input_count + construct_input_block(inputs) +
                        output_count + output_block + lock_time)