Single SHA256 vulnerable to length extension:
4. OP_HASH256 — Double SHA256 Explained
Overview
OP_HASH256 applies SHA-256 twice in sequence to the top stack element, producing a 32-byte hash. This is the same hash function Bitcoin uses for block headers and transaction IDs.
Opcode value: 0xaa (decimal 170)
Output size: 32 bytes (256 bits)
Formula: HASH256(x) = SHA256(SHA256(x))
Rationale for Double SHA-256
Satoshi's choice to use double SHA-256 was partly motivated by protection against length-extension attacks. In a standard Merkle-Damgård construction (which SHA-256 uses), an attacker who knows SHA256(M) and the length of M can compute SHA256(M || padding || extra) without knowing M. Double hashing defeats this:
# Single SHA256 vulnerable to length extension:
SHA256(M) known → attacker can compute SHA256(M || padding || X)
# Double SHA256 is immune:
SHA256(SHA256(M)) → inner hash result is unknown to attacker
Comparison with OP_SHA256
OP_SHA256(x) = SHA256(x) # single hash, 32 bytes
OP_HASH256(x) = SHA256(SHA256(x)) # double hash, 32 bytes
# Example values:
data = b"hello"
sha256_once = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash256_data = 9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50
Use in Transaction Hashing
Every Bitcoin transaction has a TXID computed using OP_HASH256 semantics:
txid = SHA256(SHA256(serialized_transaction))
In little-endian form as stored in block explorers:
import hashlib
def txid(raw_tx_bytes: bytes) -> str:
first = hashlib.sha256(raw_tx_bytes).digest()
second = hashlib.sha256(first).digest()
return second[::-1].hex() # reverse for display convention
Use in Block Header Hashing
# Block header fields (80 bytes total):
version (4 bytes)
prev_block_hash (32 bytes)
merkle_root (32 bytes)
timestamp (4 bytes)
bits (4 bytes)
nonce (4 bytes)
block_hash = SHA256(SHA256(block_header_80_bytes))
Mining is the process of finding a nonce such that block_hash < target.
Script Usage
As a script opcode, OP_HASH256 functions identically to OP_SHA256 from a stack perspective, but outputs the double hash:
scriptPubKey: OP_HASH256 <expected_hash256> OP_EQUAL
scriptSig: <preimage>
# Stack trace:
[ <preimage> ]
→ [ SHA256(SHA256(<preimage>)) ]
→ [ SHA256(SHA256(<preimage>)) | <expected_hash256> ]
→ [ 0x01 ]
Merkle Tree Construction
Bitcoin's Merkle tree for blocks uses OP_HASH256 semantics:
def merkle_hash(a: bytes, b: bytes) -> bytes:
return hashlib.sha256(hashlib.sha256(a + b).digest()).digest()
# Merkle root computation
def compute_merkle_root(txids: list) -> bytes:
if len(txids) == 1:
return txids[0]
if len(txids) % 2 == 1:
txids.append(txids[-1]) # duplicate last tx if odd count
pairs = [(txids[i], txids[i+1]) for i in range(0, len(txids), 2)]
return compute_merkle_root([merkle_hash(a, b) for a, b in pairs])
TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation: