Cryptographic hashing and integrity
Compute SHA-256 digests and see why a one-character change produces a completely different hash.
import hashlib
print(hashlib.sha256(b"abc").hexdigest())
first = hashlib.sha256(b"transfer 100 to alice").hexdigest()
second = hashlib.sha256(b"transfer 900 to alice").hexdigest()
differing = sum(x != y for x, y in zip(first, second))
print(len(first), first == second)
print(differing > 40)ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad 64 False True
Explanation
A cryptographic hash function maps data of any length to a fixed-size digest. SHA-256, part of the SHA-2 family, always produces 256 bits, shown as 64 hexadecimal characters. A good hash has three properties: preimage resistance (given a digest, you cannot find an input that produces it), second-preimage resistance (given an input, you cannot find a different one with the same digest), and collision resistance (you cannot find any two inputs with the same digest).
Hashes also show the avalanche effect: changing a single character of the input changes about half of the output bits, so the digests look unrelated. That makes a hash useful for detecting accidental corruption and for verifying a download against a published digest. Hashing is not encryption: it has no key and cannot be reversed to recover the data.
Choose the algorithm carefully. MD5 and SHA-1 have practical collision attacks and must not be used where security matters. SHA-256 and SHA-3 are current choices. A plain hash proves integrity only against accidental changes: an attacker who can modify a message can simply recompute the hash. Protection against tampering needs a keyed construction, which the HMAC lesson covers.
Explore the dry run
import hashlib print(hashlib.sha256(b"abc").hexdigest())first = hashlib.sha256(b"transfer 100 to alice").hexdigest()second = hashlib.sha256(b"transfer 900 to alice").hexdigest()differing = sum(x != y for x, y in zip(first, second))print(len(first), first == second)print(differing > 40)Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| The SHA-256 digest of 'abc' is the standard test vector published by NIST. | ba7816bf…15ad | ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad | |
| Hash one message. | ba7816bf…15ad | ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad | |
| Changing one digit of the input is enough to produce a completely different digest. | ba7816bf…15ad | ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad | |
| Every SHA-256 digest is 64 hex characters, and these two are different. | ba7816bf…15ad | ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad 64 False | |
| Avalanche effect: far more than half of the 64 hex digits differ. | ba7816bf…15ad | ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad 64 False True |
Cost and common mistakes
Hashing is O(n) time in the input length and O(1) memory when the data is processed in blocks.
- A hash is not encryption. It cannot be reversed, but short or guessable inputs can be found by trying candidates.
- Do not use MD5 or SHA-1 for security purposes. Practical collision attacks exist for both.
- A plain hash does not authenticate a message. Anyone who can change the data can recompute the hash.
Try it yourself
Why can't you recover the original message from its SHA-256 digest?
Reveal answer and reasoning
The digest is only 256 bits, so many different inputs share the same digest in principle. The function is designed so that finding any input for a given digest is computationally infeasible.