Skip to content
About
Main content

A checksum that proves identity

Break it on purposeNeeds Python

Problem

A stored next to the data it covers proves that the bytes have not been corrupted since they were written. It does not prove they are the right bytes. If the storage writes a correct block to the wrong address (a ), the block and its checksum move together and still match. If a write is silently dropped (a ), the old block and its old checksum still match. Catching these needs a checksum that also covers the block's identity, stored somewhere the faulty write did not touch: in a separate index keyed by block number, covering the pair (block number, content), as and some databases do.

Write a toy block store in Python with two designs: (a) each block stores crc(content) next to its content; (b) each block's checksum is stored in a separate index keyed by block number and covers (block_number, content). Then simulate a misdirected write: copy the bytes of block 7 (with its stored checksum) into the place of block 3. Then simulate a lost write (skip the write).

The question. Which design notices a misdirected write, and which notices a lost write?


Predict

With the checksum stored beside the block, what happens when a write lands on the wrong block?

Run it

  1. 1Install uv once. It fetches Python and the lab's packages for you.

    Terminal
    curl -LsSf https://astral.sh/uv/install.sh | sh
  2. 2Get the script. It is the whole lab: read it, then download it.

    a-checksum-that-proves-identity.py57 linesDownload
    View the code
    a-checksum-that-proves-identity.py
    # /// script
    # requires-python = ">=3.10"
    # ///
    # Copyright (c) 2026 Aayush Sharma · SPDX-License-Identifier: MIT
    # https://thedataengineering.com/lab-code/LICENSE.txt
    """A checksum that proves identity, not just integrity.
    
    A toy block store, two designs: (a) each block stores crc(content) next to
    its content; (b) a separate index stores, per block number, a checksum over
    (block number, content). Then a misdirected write (block 7's bytes and
    checksum land in block 3's place) and a lost write (a write that never
    happened): which design notices?
    """
    import argparse, json, zlib
    
    p = argparse.ArgumentParser(description=__doc__.splitlines()[0])
    p.add_argument("--blocks", type=int, default=16, help="Blocks in the store.")
    p.add_argument("--json", help="Also write the results to this JSON file.")
    args = p.parse_args()
    crc = lambda b: zlib.crc32(b)
    
    class InlineStore:                       # (a) checksum next to the data
        def __init__(self, n): self.disk = {i: (f"block {i} v1".encode(), crc(f"block {i} v1".encode())) for i in range(n)}
        def write(self, i, data, lose=False):
            if not lose: self.disk[i] = (data, crc(data))
        def read(self, i):
            data, c = self.disk[i]
            return data, crc(data) == c
    
    class IndexedStore:                      # (b) checksum of (block number, content) kept elsewhere
        def __init__(self, n):
            self.disk = {i: f"block {i} v1".encode() for i in range(n)}
            self.index = {i: crc(i.to_bytes(8, "big") + self.disk[i]) for i in range(n)}
        def write(self, i, data, lose=False):
            if not lose: self.disk[i] = data
            self.index[i] = crc(i.to_bytes(8, "big") + data)        # the index is updated even if the data write is lost
        def read(self, i):
            data = self.disk[i]
            return data, crc(i.to_bytes(8, "big") + data) == self.index[i]
    
    rows = []
    for name, cls in (("(a) checksum stored with the block", InlineStore), ("(b) checksum of (block no., content) in an index", IndexedStore)):
        s = cls(args.blocks)
        s.disk[3] = s.disk[7]                                        # misdirected write: block 7's bytes (and inline checksum) land at 3
        data, ok = s.read(3)
        mis = "returned block 7's data as valid" if ok else "reported a mismatch"
        s = cls(args.blocks)
        s.write(5, b"block 5 v2", lose=True)                         # lost write: the new version never reaches the disk
        data, ok = s.read(5)
        lost = "returned the stale version as valid" if ok else "reported a mismatch"
        rows.append({"design": name, "misdirected_write": mis, "lost_write": lost})
        print(f"{name:<50} misdirected write: {mis:<34} lost write: {lost}")
    
    if args.json:
        with open(args.json, "w") as f:
            json.dump({"tables": {"designs": rows}}, f)
    
  3. 3Run it in the folder you saved it to, with the defaults first. Then change a knob from the table below and run it again.

    Terminal
    uv run a-checksum-that-proves-identity.py
    uv run a-checksum-that-proves-identity.py --help     # every knob
Knobs
Knob · defaultWhat it changes
--blocks16 Blocks in the store.

Our run

Two checksum designs, two silent faults

Two checksum designs, two silent faults
DesignMisdirected writeLost write
(a) checksum stored with the blockreturned block 7's data as validreturned the stale version as valid
(b) checksum of (block no., content) in an indexreported a mismatchreported a mismatch
Reference runApple M2 · 8 cores · 8 GB
Output · uv run a-checksum-that-proves-identity.py
(a) checksum stored with the block                 misdirected write: returned block 7's data as valid   lost write: returned the stale version as valid
(b) checksum of (block no., content) in an index   misdirected write: reported a mismatch                lost write: reported a mismatch
macOS 26.6.2 · Python 3.13.3 · run 2026-10-20

What we found

With the checksum stored beside the block, the misdirected write returned block 7's data as valid, and the lost write returned the stale version as valid. With the checksum of (block number, content) in a separate index, both were caught: the misdirected write reported a mismatch, and the lost write reported a mismatch.


Read it

A checksum answers the question it covers. Stored with the data, it covers content; to cover identity and freshness it must include the address and be stored apart from the data, so that one faulty write cannot update both. The lost write is caught by (b) only because the index was updated when the write was issued: the index records what should be there, the block holds what is there.

This is why end-to-end checks in a pipeline compare against something recorded elsewhere (a manifest, a control total) rather than a checksum carried with the file.