Insert a scriptsig for an input that will later be spent by a p2pkh, p2pk, or p2sh scriptPubkey.

    @private_key_info is either a single private key, or a dict with 'redeem_script' and 'private_keys' defined.

    @redeem_script, if given, must NOT start with the varint encoding its length.
    However, it must otherwise be a hex string

    Return the transaction with the @idx'th scriptSig filled in.

def btc_tx_sign(tx_hex, idx, prevout_script, prevout_amount, private_key_info, scriptsig_type, hashcode=SIGHASH_ALL, hashcodes=None, redeem_script=None, witness_script=None):
    """
    Insert a scriptsig for an input that will later be spent by a p2pkh, p2pk, or p2sh scriptPubkey.

    @private_key_info is either a single private key, or a dict with 'redeem_script' and 'private_keys' defined.

    @redeem_script, if given, must NOT start with the varint encoding its length.
    However, it must otherwise be a hex string

    Return the transaction with the @idx'th scriptSig filled in.
    """
    new_tx = None
    
    # print 'sign input {} as {}'.format(idx, scriptsig_type)

    if scriptsig_type in ['p2pkh', 'p2pk']:
        if not btc_is_singlesig(private_key_info):
            raise ValueError('Need only one private key for {}'.format(scriptsig_type))

        pk = ecdsalib.ecdsa_private_key(str(private_key_info))
        pubk = pk.public_key()
        pub = pubk.to_hex()

        sig = btc_tx_make_input_signature(tx_hex, idx, prevout_script, private_key_info, hashcode)

        # print 'non-segwit sig: {}'.format(sig)
        # print 'non-segwit pubk: {}'.format(pub)

        # NOTE: sig and pub need to be hex-encoded
        txobj = btc_tx_deserialize(str(tx_hex))

        if scriptsig_type == 'p2pkh':
            # scriptSig + scriptPubkey is <signature> <pubkey> OP_DUP OP_HASH160 <pubkeyhash> OP_EQUALVERIFY OP_CHECKSIG
            txobj['ins'][idx]['script'] = btc_script_serialize([sig, pub])

        else:
            # p2pk
            # scriptSig + scriptPubkey is <signature> <pubkey> OP_CHECKSIG
            txobj['ins'][idx]['script'] = btc_script_serialize([sig])

        new_tx = btc_tx_serialize(txobj)

    elif scriptsig_type == 'p2wpkh' or scriptsig_type == 'p2sh-p2wpkh':
        # must be a segwit singlesig bundle
        if not btc_is_singlesig_segwit(private_key_info):
            raise ValueError('Keys are not for p2wpkh or p2sh-p2wpkh')

        privkey_str = str(btc_get_singlesig_privkey(private_key_info))
        pk = ecdsalib.ecdsa_private_key(privkey_str)
        pubk = pk.public_key()
        pub = keylib.key_formatting.compress(pubk.to_hex())

        # special bip141 rule: this is always 0x1976a914{20-byte-pubkey-hash}88ac
        prevout_script_sighash = '76a914' + hashing.bin_hash160(pub.decode('hex')).encode('hex') + '88ac'

        sig = btc_tx_make_input_signature_segwit(tx_hex, idx, prevout_amount, prevout_script_sighash, privkey_str, hashcode)

        txobj = btc_tx_deserialize(str(tx_hex))
        txobj['ins'][idx]['witness_script'] = btc_witness_script_serialize([sig, pub])

        if scriptsig_type == 'p2wpkh':
            # native
            # NOTE: sig and pub need to be hex-encoded
            txobj['ins'][idx]['script'] = ''

            if redeem_script:
                # goes in scriptSig 
                txobj['ins'][idx]['script'] = btc_script_serialize([redeem_script])

        else:
            # p2sh-p2wpkh
            redeem_script = btc_make_p2sh_p2wpkh_redeem_script(pub)
            txobj['ins'][idx]['script'] = redeem_script

            # print 'scriptsig {} from {} is {}'.format(pub, privkey_str, txobj['ins'][idx]['script'])

        new_tx = btc_tx_serialize(txobj)

        # print 'scriptsig type: {}'.format(scriptsig_type)
        # print 'segwit scriptsig: {}'.format(txobj['ins'][idx]['script'])
        # print 'segwit witness script: {}'.format(txobj['ins'][idx]['witness_script'])

    elif scriptsig_type == 'p2wsh' or scriptsig_type == 'p2sh-p2wsh':
        # only support p2wsh for multisig purposes at this time
        if not btc_is_multisig_segwit(private_key_info):
            raise ValueError('p2wsh requires a multisig key bundle')

        native = None
        if scriptsig_type == 'p2wsh':
            native = True
        else:
            native = False

        new_tx = btc_tx_sign_multisig_segwit(tx_hex, idx, prevout_amount, private_key_info['redeem_script'], private_key_info['private_keys'], hashcode=hashcode, hashcodes=hashcodes, native=native)
       
        txobj = btc_tx_deserialize(new_tx)

        # print 'segwit scriptsig: {}'.format(txobj['ins'][idx]['script'])
        # print 'segwit witness script: {}'.format(txobj['ins'][idx]['witness_script'])

    elif scriptsig_type == 'p2sh':
    
        if not redeem_script:
            # p2sh multisig
            if not btc_is_multisig(private_key_info):
                raise ValueError('No redeem script given, and not a multisig key bundle')

            new_tx = btc_tx_sign_multisig(tx_hex, idx, private_key_info['redeem_script'], private_key_info['private_keys'], hashcode=hashcode)

        else:
            # NOTE: sig and pub need to be hex-encoded
            txobj = btc_tx_deserialize(str(tx_hex))

            # scriptSig + scriptPubkey is <redeem script> OP_HASH160 <script hash> OP_EQUAL
            txobj['ins'][idx]['script'] = btc_script_serialize([redeem_script]) 
            new_tx = btc_tx_serialize(txobj)

    else:
        raise ValueError("Unknown script type {}".format(scriptsig_type))

    return new_tx