TeachMeBitcoin

Single SHA256 vulnerable to length extension:

From TeachMeBitcoin, the free encyclopedia Reading time: 2 min

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])
☕ Help support TeachMeBitcoin

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:

Ethereum: 0x578417C51783663D8A6A811B3544E1f779D39A85
Bitcoin: bc1q77k9e95rn669kpzyjr8ke9w95zhk7pa5s63qzz
Solana: 4ycT2ayqeMucixj3wS8Ay8Tq9NRDYRPKYbj3UGESyQ4J
Address copied to clipboard!