Cryptography

SHA-256 (Merkle-Damgard)

One-way, one fixed size, no matter how big the input

SHA-256 hashes any message to a fixed 256-bit digest by padding it, splitting it into 512-bit blocks, and chaining them through a one-way compression function in the Merkle-Damgard construction.

  • Digest size256 bits (64 hex chars)
  • Block size512 bits
  • Rounds per block64
  • Collision resistance≈ 2¹²⁸ work
  • Preimage resistance≈ 2²⁵⁶ work

Interactive visualization

Press play, or step through manually. The visualization is yours to drive — try it before reading on.

Open visualization fullscreen ↗

Watch the 60-second explainer

A condensed visual walkthrough — narrated, captioned, under a minute.

How SHA-256 turns any input into 256 bits

A hash function has an awkward job: accept an input of any length — a single byte or a 10 GB disk image — and return a fixed 256-bit fingerprint that is one-way (you can't run it backwards) and collision-resistant (you can't find two inputs that map to the same output). The trick that makes this possible is the Merkle-Damgard construction, and SHA-256 is its most-deployed example: it backs TLS certificates, Git commit IDs, Bitcoin's proof-of-work, file checksums, and HMAC tokens.

SHA-256 keeps a 256-bit state: eight 32-bit words named a through h, initialized to fixed constants (the first 32 bits of the fractional parts of the square roots of the first eight primes). It processes the message in three phases:

  1. Pad. Append a single 1 bit, then zeros, then the 64-bit message length, so the total is an exact multiple of 512 bits.
  2. Chain. Split the padded message into 512-bit blocks and fold each one into the state: state = compress(state, block). Each block depends on the result of the previous one — this serial chaining is the heart of Merkle-Damgard.
  3. Finalize. After the last block, the 256-bit state is the digest. Concatenate the eight words and you have your 64-hex-character hash.

The compression function itself does the cryptographic heavy lifting. For each block it builds a 64-entry message schedule W (the 16 input words expanded to 64 via rotation and XOR mixing), then runs 64 rounds. Each round stirs in one schedule word W[t] and one round constant K[t] through the nonlinear functions Ch, Maj, Σ0, and Σ1, diffusing every input bit across the whole state. After 64 rounds the round output is added word-wise (mod 2³²) back to the block's starting state — this feed-forward addition is what makes a single round block hard to invert.

Why the chaining matters

The reason cryptographers reach for Merkle-Damgard is a security reduction: Merkle and Damgard proved independently in 1989 that if the underlying compression function f is collision-resistant, then the full chained hash is collision-resistant too. You only have to design and analyze a small fixed-input primitive; the construction promises the any-length wrapper inherits its strength.

The proof leans entirely on the padding. The final block always encodes the original message length (this is the Merkle-Damgard strengthening or "MD-strengthening"). Without that length field, an attacker could find two messages of different lengths that collide by exploiting the chain's serial structure. With it, the padding is injective: distinct messages always produce distinct padded bit strings, so a collision in the hash forces a collision somewhere inside f.

The same serial chaining has one famous downside, covered below: the digest exposes the full internal state, which enables length-extension attacks. Newer designs (the sponge construction in SHA-3, or the truncated SHA-512/256) drop Merkle-Damgard precisely to close that gap.

When to use SHA-256 — and when not to

  • Integrity checks and content addressing. Git names every object by its hash; package managers verify downloads; deduplicating backups use the digest as a key. SHA-256 is ideal here — fast, deterministic, collision-resistant.
  • Digital signatures and certificates. You sign the 256-bit hash of a document, not the document. TLS certificate fingerprints are SHA-256.
  • Proof-of-work. Bitcoin mining is a brute-force search for an input whose double-SHA-256 starts with enough zero bits.
  • Message authentication — but wrapped in HMAC. Never authenticate with raw SHA256(key || message); the length-extension flaw breaks it. Use HMAC-SHA-256.

Do not use SHA-256 directly for password storage. It is too fast — a GPU computes billions per second, so a leaked database of unsalted SHA-256 password hashes is crackable in hours. Passwords need a deliberately slow, salted, memory-hard KDF: bcrypt, scrypt, or Argon2. And don't use it for a random unique ID where you only need uniqueness, not security — a UUID or Snowflake ID is cheaper.

SHA-256 vs other hash functions

SHA-256SHA-1MD5SHA-512SHA-3-256BLAKE3
Digest size256 bits160 bits128 bits512 bits256 bits256 bits (extendable)
ConstructionMerkle-DamgardMerkle-DamgardMerkle-DamgardMerkle-DamgardSponge (Keccak)Merkle tree
Block / word size512 b / 32 b512 b / 32 b512 b / 32 b1024 b / 64 b1088 b rate64-byte chunks
Collision statusnone knownbroken (2017)trivially brokennone knownnone knownnone known
Length-extensionvulnerablevulnerablevulnerablevulnerableimmuneimmune
Parallelizableno (serial chain)nonononoyes (tree)
Throughput (1 core)~0.5–2 GB/s*faster than SHA-256fastest, insecureoften faster on 64-bit CPUsslower than SHA-256multi-GB/s
Use it forcertificates, Git, PoWlegacy onlynon-security checksums only64-bit servers, KDF basenew protocolsfast file hashing

*With the Intel/ARM SHA hardware extensions enabled; pure software SHA-256 is several times slower. The headline lesson: MD5 and SHA-1 share SHA-256's Merkle-Damgard skeleton but have weaker compression functions and shorter digests, so both have practical collisions. SHA-512 is the same design with 64-bit words and a 512-bit state — counterintuitively often faster than SHA-256 on 64-bit CPUs because it does fewer rounds per byte. SHA-3 abandons Merkle-Damgard entirely for a sponge, which is why it's immune to length extension.

What the numbers actually say

  • Collision resistance ≈ 2¹²⁸ (the birthday bound). That's about 3.4 × 10³⁸ hashes. The Bitcoin network in mid-2024 ran near 6 × 10²⁰ SHA-256 hashes per second — the largest sustained hash effort in history. At that rate a birthday collision search would still take roughly the current age of the universe.
  • Preimage resistance ≈ 2²⁵⁶. Reversing a digest to find any input is squared-harder than finding a collision — out of reach for any conceivable classical computer. Grover's algorithm on a hypothetical large quantum computer would cut this to ~2¹²⁸, still astronomically safe, which is why SHA-256 is considered quantum-resistant for preimages.
  • One block ≈ 64 rounds. Each 512-bit block costs a fixed 64 rounds of work, so SHA-256 is exactly linear in input length: hashing a 2× larger file takes 2× longer, with no surprises.
  • Throughput. Software SHA-256 runs around 0.2–0.5 GB/s per core; with the SHA-NI / ARMv8 crypto extensions it jumps to 1–2 GB/s. That gap — roughly 4–8× — is why "is the SHA extension available?" matters for any high-volume hashing service.
  • Empty-string digest. SHA256("") = e3b0c442…b855, a fixed 64-hex value worth memorizing as a sanity check that your implementation pads correctly.

JavaScript implementation

Modern browsers and Node ship SHA-256 in the Web Crypto API — use it in production, never hand-rolled crypto. The async one-liner:

async function sha256(message) {
  const data = new TextEncoder().encode(message);     // UTF-8 bytes
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  return [...new Uint8Array(hashBuffer)]
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');                                          // 64 hex chars
}

await sha256('');         // e3b0c442...b855
await sha256('abc');      // ba7816bf...ad15

To see the Merkle-Damgard chain, here is the padding and block loop spelled out (the inner compress is the standard 64-round core, omitted for length):

function padMessage(bytes) {
  const bitLen = bytes.length * 8;
  const out = [...bytes, 0x80];                 // append the mandatory 1 bit
  while ((out.length % 64) !== 56) out.push(0); // zero-fill to 56 mod 64
  // append 64-bit big-endian length
  for (let i = 7; i >= 0; i--) out.push((bitLen / 2 ** (8 * i)) & 0xff);
  return out;
}

function sha256Bytes(bytes) {
  let state = [...H0];                           // eight 32-bit init constants
  const padded = padMessage(bytes);
  for (let i = 0; i < padded.length; i += 64) {  // one 512-bit block at a time
    state = compress(state, padded.slice(i, i + 64));   // chain: depends on previous
  }
  return state.map(w => (w >>> 0).toString(16).padStart(8, '0')).join('');
}

Python implementation

The standard library wraps OpenSSL's optimized SHA-256:

import hashlib

def sha256(message: str) -> str:
    return hashlib.sha256(message.encode('utf-8')).hexdigest()

sha256('')      # 'e3b0c442...b855'
sha256('abc')   # 'ba7816bf...ad15'

# Streaming a large file without loading it into memory —
# this IS the Merkle-Damgard chain, one block-batch at a time:
def sha256_file(path: str) -> str:
    h = hashlib.sha256()
    with open(path, 'rb') as f:
        for chunk in iter(lambda: f.read(65536), b''):
            h.update(chunk)        # folds each chunk into the running state
    return h.hexdigest()

The update() / hexdigest() split is the construction laid bare: update advances the chain, hexdigest reads out the final state. For authentication, reach for the keyed wrapper instead of concatenating a secret:

import hmac, hashlib

def tag(key: bytes, message: bytes) -> str:
    # HMAC defeats length extension: SHA256(key || msg) does NOT.
    return hmac.new(key, message, hashlib.sha256).hexdigest()

Variants worth knowing

SHA-224. Same engine as SHA-256 with different initial constants, truncated to 224 bits. The truncation alone blunts length extension because the attacker can't see the full 256-bit state.

SHA-512 and SHA-384. The SHA-2 family member built on 64-bit words, a 1024-bit block, and 80 rounds. On 64-bit CPUs it often beats SHA-256 on throughput. SHA-384 is SHA-512 truncated to 384 bits.

SHA-512/256. SHA-512 truncated to 256 bits with distinct initial constants. Same 256-bit output as SHA-256, but the truncation makes it immune to length extension — a drop-in upgrade when that attack is a concern and you're on a 64-bit machine.

HMAC-SHA-256. Not a hash but a keyed MAC: H((key ⊕ opad) || H((key ⊕ ipad) || msg)). The nested structure is specifically engineered to neutralize Merkle-Damgard's length-extension weakness; it's the right tool for tokens and API signatures.

SHA-3 (Keccak). A different beast entirely — a sponge construction, not Merkle-Damgard. Standardized in 2015 as a structural backup in case a flaw were ever found in SHA-2. It's immune to length extension by design but generally slower in software than SHA-256.

Common bugs and edge cases

  • Using SHA256(secret || msg) for authentication. The single most common SHA-256 security bug. The digest leaks the internal state, so an attacker can append data and forge a valid hash. Always use HMAC-SHA-256.
  • Hashing passwords with raw SHA-256. It's far too fast. A leaked unsalted table falls to GPU brute force and rainbow tables in hours. Use bcrypt, scrypt, or Argon2.
  • Encoding ambiguity. SHA-256 hashes bytes, not strings. SHA256("café") differs between UTF-8 and Latin-1. Pin the encoding explicitly or two systems will disagree on the "same" input.
  • 32-bit overflow in hand-rolled code. JavaScript's bitwise ops are signed 32-bit; forgetting the final >>> 0 to coerce back to unsigned yields negative words and a wrong digest. This is why the empty-string test vector exists.
  • Forgetting the length field on the last block. Drop the 64-bit length and you've broken MD-strengthening — collisions become findable and your hash is no longer SHA-256.
  • Confusing hex, base64, and raw-byte digests. A SHA-256 digest is 32 bytes, 64 hex characters, or 44 base64 characters. Comparing a hex digest to a base64 one always fails; normalize the representation before comparing.

Frequently asked questions

Why is SHA-256 called a Merkle-Damgard construction?

Merkle-Damgard is the design pattern that turns a fixed-input compression function into a hash that accepts any-length input. You pad the message to a whole number of blocks, then fold each block into a running state: state = compress(state, block). SHA-256, SHA-1, and MD5 all follow it; Ralph Merkle and Ivan Damgard proved independently in 1989 that if the compression function is collision-resistant, the whole chained hash is too.

What is the length-extension attack and does SHA-256 have it?

Yes, SHA-256 is vulnerable. Because the final digest is just the internal state after the last block, an attacker who knows hash(secret || message) and the length of the secret can resume the chain and compute hash(secret || message || padding || extra) without ever seeing the secret. The fix is to never use raw SHA-256 for authentication — use HMAC-SHA-256, which wraps the message in two keyed hashes, or SHA-512/256 / SHA-3, which are not extendable.

How many SHA-256 hashes would it take to find a collision?

By the birthday bound, about 2^128 hashes — roughly 3.4 × 10^38. Even at the entire Bitcoin network's mid-2024 rate of ~6 × 10^20 hashes per second, a collision search would take on the order of the age of the universe. No SHA-256 collision has ever been found; SHA-1, with a 160-bit digest and 2^80 birthday bound, was broken in practice in 2017.

What is the padding rule in SHA-256?

Append a single 1 bit, then enough 0 bits so the length is 64 bits short of a multiple of 512, then append the original message length as a 64-bit big-endian integer. The length field and the mandatory 1 bit are what make the padding injective — two different messages can never pad to the same bit string, which is required for collision resistance.

Why does SHA-256 produce exactly 256 bits no matter the input size?

The internal state is eight 32-bit words = 256 bits, and each compression step maps a 256-bit state plus a 512-bit block back to a 256-bit state. After the last block the state is the digest. A one-gigabyte file and an empty string both leave the chain in a 256-bit state, so both digests are 64 hex characters long.

Is SHA-256 reversible, and can it ever fail to be one-way?

It is designed to be one-way: given a digest there is no known method faster than brute force (2^256 work) to recover an input. But short or low-entropy inputs like passwords are recoverable by precomputed rainbow tables or GPU brute force — modern GPUs do billions of SHA-256 per second. That is why password storage uses a slow, salted KDF such as bcrypt, scrypt, or Argon2 instead of raw SHA-256.