Skip to content

SHA-256

SHA-256 ("Secure Hash Algorithm 256-bit") is the specific hash function Bitcoin uses for mining, transaction IDs, block hashes, and Merkle trees. This chapter goes inside the algorithm itself (not just how to call it, but what it actually does to the bits you feed it) because Bitcoin's mining process (covered in Proof of Work) is, mechanically, nothing more than calling this specific function billions of times per second.

Origin

SHA-256 is part of the SHA-2 family, designed by the US National Security Agency and published by NIST (the National Institute of Standards and Technology) in 2001 as FIPS 180-2, superseding the earlier SHA-1, which had begun showing theoretical weaknesses. SHA-2 has withstood over two decades of public cryptanalysis without a practical collision attack being found, which is part of why it remains trusted for Bitcoin's security despite its NSA origin. Its design and full specification are public, and it has been the subject of sustained, adversarial academic scrutiny, unlike a function whose internals are kept secret.

How it works, step by step

SHA-256 processes input in 512-bit (64-byte) blocks, running each through 64 rounds of mixing operations, and produces a 256-bit (32-byte) output. Here is the process broken into its actual stages:

1. Padding

The message is padded so its length is a multiple of 512 bits. Padding always appends a single 1 bit, followed by enough 0 bits, followed by a 64-bit big-endian integer encoding the original message's length in bits. This padding scheme (called Merkle–Damgård strengthening) ensures no two different-length messages pad to the identical padded form, which matters for the function's security proofs.

2. Breaking into blocks

The padded message is split into 512-bit chunks. Each chunk is processed sequentially, with the output of processing one chunk feeding into the processing of the next. This chaining is why SHA-256 belongs to the family of Merkle–Damgård construction hash functions.

3. Message schedule expansion

Each 512-bit chunk is broken into sixteen 32-bit words, then expanded to sixty-four 32-bit words using a recurrence formula involving bitwise rotations, shifts, and XOR operations on earlier words in the schedule. This expansion is what makes each of the 64 compression rounds operate on different derived data rather than repeating the same 16 words.

4. The compression function

SHA-256 maintains eight 32-bit working variables (conventionally named a through h), initialized for the first block from eight fixed constants derived from the fractional parts of the square roots of the first eight prime numbers (2, 3, 5, 7, 11, 13, 17, 19). For each of the 64 rounds, the algorithm combines the current working variables with one word from the message schedule and one of 64 round constants (derived similarly, from the fractional parts of the cube roots of the first 64 primes) using bitwise AND, XOR, NOT, modular addition, and fixed rotations, collectively designed so that each output bit depends, after enough rounds, on every input bit in a way that is fast to compute forward but has no known efficient way to compute backward.

The specific choice of constants derived from prime-number roots (sometimes called "nothing-up-my-sleeve numbers") is a deliberate design choice: it demonstrates the constants weren't secretly chosen to create a hidden weakness (a backdoor), since they were derived through an obvious, publicly reproducible mathematical procedure rather than picked arbitrarily.

5. Chaining and output

After processing all 64 rounds for a chunk, the resulting working variables are added (modulo 2^32) to the state carried in from before that chunk, producing the new state passed to the next chunk. After the final chunk, the eight 32-bit working variables are concatenated to form the 256-bit output.

Message ──► Pad to multiple of 512 bits ──► Split into 512-bit blocks
                                                     │
                        ┌────────────────────────────┘
                        ▼
              Block 1 ──► Compression function ──► intermediate state
                                                     │
                        ┌────────────────────────────┘
                        ▼
              Block 2 ──► Compression function ──► intermediate state
                                                     │
                                                    ...
                                                     │
                                                     ▼
                                          Final 256-bit hash output

SHA-256d: Bitcoin's actual choice

Bitcoin does not use a single SHA-256 pass for most of its hashing. It uses SHA-256 applied twice, written SHA-256d(x) = SHA-256(SHA-256(x)). This choice was made to mitigate a specific theoretical concern called a length-extension attack, which affects Merkle–Damgård hash functions including plain SHA-256: given H(x) and the length of x (but not x itself), an attacker can compute H(x || y) for a chosen suffix y, without knowing x, because the Merkle–Damgård construction's final internal state is the output, and that state alone is enough to keep processing additional blocks. Applying SHA-256 a second time to the first hash's output means an attacker would need to reverse the second hash to mount this attack, which preimage resistance (see Preimage Resistance) prevents. This is why every reference in this book to "Bitcoin's hash function" without further qualification generally means SHA-256d specifically, not a single SHA-256 pass. See Proof of Work and Block Headers for where this exact function is applied.

Example

import { createHash } from "node:crypto";

function sha256(buf: Buffer): Buffer {
  return createHash("sha256").update(buf).digest();
}

function sha256d(buf: Buffer): Buffer {
  return sha256(sha256(buf));
}

const message = Buffer.from("hello");
console.log("SHA-256:  ", sha256(message).toString("hex"));
console.log("SHA-256d: ", sha256d(message).toString("hex"));
SHA-256:   2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
SHA-256d:  9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50

The two outputs are completely different from each other, as expected. SHA-256d is not "SHA-256 but stronger against every attack," it is specifically SHA-256 composed with itself to close the length-extension gap.

Tradeoffs

SHA-256 is fast on general-purpose CPUs, which was fine for Bitcoin's earliest years, but this same speed became a liability once mining became competitive: because SHA-256d can be computed extremely quickly and in parallel by specialized hardware, Bitcoin mining rapidly moved from CPUs to GPUs to FPGAs to purpose-built ASICs (Application-Specific Integrated Circuits, see ASICs) over its first several years, concentrating mining capability among those who can afford and deploy specialized hardware at scale. This is a direct, documented consequence of choosing a fast, hardware-friendly hash function for a proof-of-work system, and it is a real centralization pressure discussed further in Mining Pools. A design tradeoff other proof-of-work systems (such as some that chose deliberately memory-hard functions to resist ASIC specialization) made differently.

Common misconceptions

SHA-256 is not "encryption," and Bitcoin addresses are not "encrypted" data. Hashing is one-way; nothing is being kept confidential and later decrypted. See Hash Functions.

No practical collision has ever been found in SHA-256. This is distinct from SHA-1, which had a practical collision demonstrated publicly in 2017 (the "SHAttered" attack by Google and CWI Amsterdam researchers). SHA-1 and SHA-256 are different algorithms with different security margins, and conflating a SHA-1 weakness with SHA-256 is a common but incorrect generalization.

Further reading


← Previous: Hash Functions · Back to Cryptography · Next: Hash Collisions →