Friday, February 13, 2026
Homeบิทคอยน์python - Why Double SHA-256 Would not Work for Pizza Transaction Enter...

python – Why Double SHA-256 Would not Work for Pizza Transaction Enter Validation and Tips on how to Assemble Appropriate Signing Information in bitcoin


Bitcoin transaction signature validation issues

To validate every enter of a Bitcoin transaction utilizing ECDSA on the secp256k1 curve, we’d like three parameters:

  1. Public key (Uncompressed instance: 042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb)
  2. Signature (Thought-about in DER format: 30450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e, final byte 01 SIGHASH_ALL eliminated)
  3. Double hash of uncooked transaction information that the sender initially signed (Discovered hash: 083867478cb0d1d8bb864175bbc49728cffcc114bc2e762c6df64f2c965a9a66)

Right here’s the documentation on tips on how to create transaction information for signing https://en.bitcoin.it/wiki/OP_CHECKSIG

All over the place in documentation and books, it’s said tips on how to assemble this information after which compute its double SHA-256 hash

I tried to assemble all of the transaction information from this pizza transaction (https://blockstream.data/api/tx/cca7507897abc89628f450e8b1e0c6fca4ec3f7b34cccf55f3f531c659ff4d79) and adopted the step-by-step supplied on this Bitcoin StackExchange reply

  1. However the writer bought: 692678553d1b85ccf87d4d4443095f276cdf600f2bb7dd44f6effbd7458fd4c2 after double hashing
  2. And I attempted hash it ones, bought this: 083867478cb0d1d8bb864175bbc49728cffcc114bc2e762c6df64f2c965a9a66

Used on-line EDCDSA verification instrument https://emn178.github.io/online-tools/ecdsa/confirm/

Then look, my enter was appropriate and initially signed message was like this 083867478cb0d1d8bb864175bbc49728cffcc114bc2e762c6df64f2c965a9a66

DOUBLE SHA256:
enter image description here

ONE SHA256:
enter image description here

I wrote a script that takes a transaction ID and validates its inputs, however my script at the moment returns a completely incorrect enter (public key and signature appropriate)

Questions:

Right here is my code:

import requests
import hashlib
from bitcoin.core import CTransaction, CTxIn, CTxOut, COutPoint, x, b2x, lx
from bitcoin.core.script import CScript
from cryptography.hazmat.primitives.uneven import ec
from cryptography.hazmat.primitives.hashes import SHA256
from cryptography.exceptions import InvalidSignature
import logging


def fetch_raw_transaction(transaction_id):
    """
    Fetch the uncooked transaction hex from Blockstream API.

    :param transaction_id: Transaction ID (txid)
    :return: Uncooked transaction hex
    """
    url = f"https://blockstream.data/api/tx/{transaction_id}/hex"
    response = requests.get(url)
    if response.status_code == 200:
        logging.debug(f"Uncooked transaction fetched: {response.textual content.strip()}")
        return bytes.fromhex(response.textual content.strip())  # Return as bytes
    else:
        elevate Exception(f"Did not fetch transaction. Standing code: {response.status_code}")

def fetch_utxo_script_pubkey(txid, vout):
    """
    Fetch the ScriptPubKey for a given UTXO utilizing Blockstream API.

    :param txid: Transaction ID of the UTXO
    :param vout: Output index of the UTXO
    :return: ScriptPubKey as bytes
    """
    url = f"https://blockstream.data/api/tx/{txid}"
    response = requests.get(url)
    if response.status_code == 200:
        outputs = response.json().get('vout', [])

        if 0 <= vout < len(outputs):
            script_pubkey = outputs[vout].get('scriptpubkey', None)
            if script_pubkey:
                return bytes.fromhex(script_pubkey)
            else:
                elevate Exception(f"ScriptPubKey not discovered for vout {vout} in transaction {txid}")
        else:
            elevate Exception(f"Invalid vout index: {vout} for transaction {txid}")
    else:
        elevate Exception(f"Did not fetch transaction particulars. Standing code: {response.status_code}")

def compute_sighash(transaction_id, input_index, script_pubkey):
    """
    Compute the sighash for a particular enter in a Bitcoin transaction.

    :param transaction_id: Transaction ID (txid)
    :param input_index: Index of the enter being signed
    :param script_pubkey: ScriptPubKey for the enter
    :return: SIGHASH (message for signature)
    """
    attempt:
        # Fetch the uncooked transaction bytes
        raw_tx_bytes = fetch_raw_transaction(transaction_id)
        logging.debug(f"Uncooked transaction bytes: {raw_tx_bytes.hex()}")

        # Deserialize the transaction
        tx = CTransaction.deserialize(raw_tx_bytes)
        logging.debug(f"Deserialized transaction: {tx}")

        # Create a brand new transaction with up to date scriptSig
        modified_tx_ins = []
        for i, tx_in in enumerate(tx.vin):
            if i == input_index:
                # Substitute scriptSig for the desired enter
                modified_tx_ins.append(CTxIn(tx_in.prevout, CScript(script_pubkey), tx_in.nSequence))
            else:
                # Maintain different inputs unchanged
                modified_tx_ins.append(tx_in)

        modified_tx = CTransaction(modified_tx_ins, tx.vout, tx.nLockTime)
        logging.debug(f"Modified transaction: {modified_tx}")

        # Serialize transaction with SIGHASH_ALL (0x01)
        tx_raw_with_sighash = modified_tx.serialize() + bytes([1])  # 0x01 = SIGHASH_ALL
        logging.debug(f"Serialized transaction with SIGHASH_ALL: {tx_raw_with_sighash.hex()}")

        # Compute double SHA-256
        sighash = hashlib.sha256(hashlib.sha256(tx_raw_with_sighash).digest()).digest()
        logging.debug(f"Computed SIGHASH: {sighash.hex()}")

        return sighash
    besides Exception as e:
        logging.error("Error throughout SIGHASH computation", exc_info=True)
        elevate

def verify_signature(public_key_hex, signature_hex, message):
    """
    Confirm the signature utilizing ECDSA.

    :param public_key_hex: Hex-encoded public key
    :param signature_hex: Hex-encoded signature
    :param message: Message (hash) to confirm
    :return: True if legitimate, raises exception in any other case
    """
    attempt:
        public_key_bytes = bytes.fromhex(public_key_hex)
        signature_bytes = bytes.fromhex(signature_hex[:-2])  # Take away the final byte (SIGHASH flag)

        # Load the general public key
        public_key = ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256K1(), public_key_bytes)

        # Confirm the signature
        public_key.confirm(signature_bytes, message, ec.ECDSA(SHA256()))
        print("Signature is legitimate.")
    besides InvalidSignature:
        print("Signature is invalid.")
    besides Exception as e:
        logging.error("Error throughout signature verification", exc_info=True)
        elevate

if __name__ == "__main__":
    transaction_id = "cca7507897abc89628f450e8b1e0c6fca4ec3f7b34cccf55f3f531c659ff4d79"

    attempt:
        # Fetch the uncooked transaction bytes
        raw_tx_bytes = fetch_raw_transaction(transaction_id)
        tx = CTransaction.deserialize(raw_tx_bytes)

        # Iterate over every enter to validate signatures
        for i, tx_in in enumerate(tx.vin):
            print(f"nValidating enter {i}:")

            # Extract public key and signature from scriptSig
            script_sig = tx_in.scriptSig
            signature_hex = b2x(script_sig[1:1 + script_sig[0]])
            public_key_hex = b2x(script_sig[1 + script_sig[0] + 1:])

            print(f"Public Key: {public_key_hex}")
            print(f"Signature: {signature_hex}")

            # Fetch ScriptPubKey for this enter
            prev_txid = b2x(tx_in.prevout.hash[::-1])  # Convert to little-endian
            script_pubkey = fetch_utxo_script_pubkey(prev_txid, tx_in.prevout.n)
            print(f"ScriptPubKey: {script_pubkey.hex()}")

            # Compute sighash
            sighash = compute_sighash(transaction_id, i, script_pubkey)
            print(f"Computed SIGHASH (message): {sighash.hex()}")

            # Confirm signature
            verify_signature(public_key_hex, signature_hex, sighash)
    besides Exception as e:
        print("Error:", str(e))

Output:

Validating enter 0:
Public Key: 042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb
Signature: 30450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e01
ScriptPubKey: 76a91446af3fb481837fadbb421727f9959c2d32a3682988ac
Computed SIGHASH (message): 48fd60a2aeb4247255d2c1929c28ab47bdaaa49b12ff17e50b742789a3604602
Signature is invalid.

Anticipated Computed SIGHASH (message) is 083867478cb0d1d8bb864175bbc49728cffcc114bc2e762c6df64f2c965a9a66

Earlier than providing recommendation, please check the code and confirm the correctness of the answer.
I’ve already reviewed many solutions on tips on how to appropriately assemble the message for transaction signing, however none of them work

If there’s any API that return signed hash of transaction, so I can validate it, please inform me

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

ความเห็นล่าสุด