banner
def BIP_143_raw_transaction(prev_tx_id: str, amount_to_be_sent: int | float, signatureScript: str | None, pubKeyScript: str | None):
    # Version
    version = bytes.fromhex("02000000")
    # HashPrevOuts = prev_tx + vout
    HashPrev_out = bytes.fromhex(double_sha256(
        "0"*72))
    # HashSequence
    HashSequence = bytes.fromhex(double_sha256("f"*8))
    # HashOutputs for ALL signHash
    HashOutputs = bytes.fromhex(double_sha256(
        "a08601000000000017a914043f512301b66ffa8d73e71907e2b0b80989521587"))
    # Hash preimage for all
    raw_hash_pre_images = bytearray()
    raw_hash_pre_images.extend(version)
    raw_hash_pre_images.extend(HashPrev_out)
    raw_hash_pre_images.extend(HashSequence)
    raw_hash_pre_images.extend(bytes.fromhex(
        "000000000000000000000000000000000000000000000000000000000000000000000000"))
    # CORRECTION 2 scriptcode
    #ONLY ERROR IF THIS
    raw_hash_pre_images.extend(bytes.fromhex(
        "475221032ff8c5df0bc00fe1ac2319c3b8070d6d1e04cfbf4fedda499ae7b775185ad53b21039bbc8d24f89e5bc44c5b0d1980d6658316a6b2440023117c3c03a4975b04dd5652ae"))
    raw_hash_pre_images.extend(bytes.fromhex("a086010000000000"))
    raw_hash_pre_images.extend(bytes.fromhex("ffffffff"))
    raw_hash_pre_images.extend(HashOutputs)
    raw_hash_pre_images.extend(bytes.fromhex("00000000"))
    raw_hash_pre_images.extend(bytes.fromhex("01000000"))

    return raw_hash_pre_images.hex()

def double_sha256(hex_string):
    binary_data = binascii.unhexlify(hex_string)
    # return hashlib.sha256(hashlib.sha256(binary_data).digest()).digest()[::-1].hex()
    return hashlib.sha256(hashlib.sha256(binary_data).digest()).hexdigest()

def finalize_signed_transaction(raw_tx, signatures, redeem_script, signatureScript: str, prev_tx_id: str, amount_to_be_sent: int, pubKeyScript: str):
    try:
        witness_stack = bytearray()
        # WITNESS STACK SIZE
        witness_stack.extend(bytes.fromhex("04"))
        witness_stack.extend(bytes.fromhex("00"))
        for sig in signatures:
            witness_stack.extend(struct.pack("<B", len(bytes.fromhex(sig))))
            witness_stack.extend(bytes.fromhex(sig))
        witness_stack.extend(struct.pack(
            "<B", len(bytes.fromhex(redeem_script))))
        witness_stack.extend(bytes.fromhex(redeem_script))
        version = bytes.fromhex("02000000")
        marker = bytes.fromhex("00")
        flag = bytes.fromhex("01")
        inputs = bytes.fromhex("01")
        # txid
        inputTx = bytes.fromhex(prev_tx_id)
        vout_index = bytes.fromhex("00000000")

        # signatureScript length <OP><256HashofRedeemScript/witnessScript>
        sigScriptlen = struct.pack('<B', len(bytes.fromhex(signatureScript)))
        # print(sigScriptlen.hex(),"LENGTH")
        sequence = bytes.fromhex("ffffffff")
        # Outputs
        numOutputs = bytes.fromhex("01")
        # satoshis
        satoshi_to_be_transferred = bytes.fromhex(
            struct.pack('<Q', amount_to_be_sent).hex())
        locktime = bytes.fromhex("00000000")

        raw_final_tx = bytearray()
        raw_final_tx.extend(version)
        raw_final_tx.extend(marker)
        raw_final_tx.extend(flag)
        raw_final_tx.extend(inputs)
        raw_final_tx.extend(inputTx)
        raw_final_tx.extend(vout_index)
        raw_final_tx.extend(sigScriptlen)
        raw_final_tx.extend(bytes.fromhex(signatureScript))
        raw_final_tx.extend(sequence)
        raw_final_tx.extend(numOutputs)
        raw_final_tx.extend(satoshi_to_be_transferred)
        raw_final_tx.extend(struct.pack(
            '<B', len(bytes.fromhex(pubKeyScript))))
        raw_final_tx.extend(bytes.fromhex(pubKeyScript))
        raw_final_tx.extend(witness_stack)
        raw_final_tx.extend(locktime)

        return raw_final_tx.hex()

    except Exception as e:
        print("Error finalizing transaction:", e)
        return None

def signScript_P2SH_P2WSH(witness_script_hash: str):
    # CHANGE NUMBER 1
    signScript = bytearray()
    signScript.extend(bytes.fromhex("22"))
    signScript.extend(bytes.fromhex("00"))
    signScript.extend(struct.pack(
        "<B", len(bytes.fromhex(witness_script_hash))))
    signScript.extend(bytes.fromhex(witness_script_hash))
    # SOMEHOW CSCRIPT IS NOT TAKING THE LENGTH ITSELF CAUSING AN ERROR WAY TOO MUCH TIME TO DEBUG THIS
    # sigScript = CScript([
    #     OP_0,
    #     bytes.fromhex(witness_script_hash)
    # ])
    return signScript.hex()

def signRawtransaction_P2SH_P2WSH(transaction_hash: str, private_key_arr: list[str]):
    signatures_arr = []
    public_key_arr = []


    for private_key in private_key_arr:
        sk = ecdsa.SigningKey.from_string(
            bytes.fromhex(private_key), curve=ecdsa.SECP256k1)
        x = deterministic_nonce_generator(custom_nonce)
        sig_der = sk.sign_digest_deterministic(
            bytes.fromhex(transaction_hash),
            sigencode=ecdsa.util.sigencode_der,
        )
        sig_der_with_sighash = sig_der + b'\x01'
        signatures_arr.append(sig_der_with_sighash.hex())
    
    return (signatures_arr, public_key_arr)
# It will generate the PubkeyScript for the P2SH-P2WSH Output following the corresponding format
# <OP><Script_hash><OP>


def P2SH_P2WSH_PubKeyScript(redeem_script_hash: str):
    try:
        pubKeyScript = CScript([
            OP_HASH160,
            bytes.fromhex(redeem_script_hash),
            OP_EQUAL
        ])
        return pubKeyScript.hex()

    except Exception as error:
        print("An error ocurred while generating the PubKey Script for P2SH-P2WSH Multi-sig transaction - :", error)

def util_main():
    # IT WORKS
    private_key_arr = ["39dc0a9f0b185a2ee56349691f34716e6e0cda06a7f9707742ac113c4e2317bf",
                       "5077ccd9c558b7d04a81920d38aa11b4a9f9de3b23fab45c3ef28039920fdd6d"]
    # SHA 256 on redeem Script
    hash_redeem_P2WSH = hashlib.sha256(bytes.fromhex(
        "5221032ff8c5df0bc00fe1ac2319c3b8070d6d1e04cfbf4fedda499ae7b775185ad53b21039bbc8d24f89e5bc44c5b0d1980d6658316a6b2440023117c3c03a4975b04dd5652ae")).hexdigest()
    print(hash_redeem_P2WSH, " HASHING THE REDEEM SCRIPT")
    # Witness Program
    scr = CScript([
        OP_0,
        bytes.fromhex(hash_redeem_P2WSH)
    ])
    # Hashing the Witness program
    scr_hash = hash_redeem_script(bytes.fromhex(scr.hex()))
    print(scr_hash, " HASHING THE WITNESS PROGRAM")
    # Recepient Address from the Script Hash
    scr_add = generate_token_address(scr_hash)
    print(scr_add, " Address after checksum and base58 decode")
    # Generating the output lock script or the pubKeyScript
    pub_key_P2SH_P2WSH = P2SH_P2WSH_PubKeyScript(scr_hash)
    print(pub_key_P2SH_P2WSH, " PubKeyScript Hex for P2SH P2WSH transaction")
    # Generating raw unsigned transaction for P2SH_P2WSH as The signScript will remain empty in case of witness program
    raw_tx_P2SH_P2WSH = createRawTransaction(
        "0000000000000000000000000000000000000000000000000000000000000000", 100000, "", pub_key_P2SH_P2WSH)
    print(raw_tx_P2SH_P2WSH, " Raw unsigned transaction for P2SH P2WSH")
    # breakpoint()
    bip_143_raw = BIP_143_raw_transaction("", 1, "", P2SH_P2WSH_PubKeyScript)
    print(bip_143_raw, " Raw BIP 143 raw transaction for ALL SigHash")
    # CORRECTION 3
    # s256 = hashlib.sha256(hashlib.sha256(
    #     bytes.fromhex(bip_143_raw)).digest()).digest()
    # s256 = hashlib.sha256(bytes.fromhex(bip_143_raw)).hexdigest()
    s256 = double_sha256(bip_143_raw)
    print(s256, " Hex for BIP - 143")
    signatures = signRawtransaction_P2SH_P2WSH(s256, private_key_arr)
    print(signatures[0], " Signatures from raw BIP-143")
    sigScript = signScript_P2SH_P2WSH(hash_redeem_P2WSH)
    print(sigScript, " Signature Script for P2SH_P2WSH")
    signed_transaction = finalize_signed_transaction(
        raw_tx_P2SH_P2WSH, signatures[0], "5221032ff8c5df0bc00fe1ac2319c3b8070d6d1e04cfbf4fedda499ae7b775185ad53b21039bbc8d24f89e5bc44c5b0d1980d6658316a6b2440023117c3c03a4975b04dd5652ae", sigScript, "0000000000000000000000000000000000000000000000000000000000000000", 100000, pub_key_P2SH_P2WSH)
    print(signed_transaction)
    # signature script is 256sha hash of witness script
    return signed_transaction


I don’t understand but the signatures are somehow coming out same each time ? I have checked multiple times at different sources but nothing answers it

I am trying to construct a P2SH-P2WSH transaction from scratch can someone help me debug the above implementation and what is wrong with it?

banner

Converter

Source: CurrencyRate
Top Selling Multipurpose WP Theme

Newsletter

Subscribe my Newsletter for new blog posts, tips & new photos. Let's stay updated!

banner

Leave a Comment

Layer 1
Your Crypto & Blockchain Beacon

CryptoInsightful

Welcome to CryptoInsightful.com, your trusted source for in-depth analysis, news, and insights into the world of cryptocurrencies, blockchain technology, NFTs (Non-Fungible Tokens), and cybersecurity. Our mission is to empower you with the knowledge and understanding you need to navigate the rapidly evolving landscape of digital assets and emerging technologies.