hash-check third party crypto hash bank

Proof of Work: Why I Built a File Integrity Service Instead of Trusting My Own Release Notes

I spent too many releases arguing about whether a file had changed. The download button looked normal. The filename matched. The size was close enough. Then someone reported a different SHA-256, and I had to reconstruct what happened from screenshots and memory.

A photorealistic dimly lit server rack in a small home lab, one Raspberry Pi with a green activity LED, tangled Ethernet cables, a laptop with a dark screen, shallow depth of field, realistic textures

The friction: every release ended in a checksum argument

The bottleneck was not computing hashes. Any modern machine can hash a 4 GB firmware image in seconds. The bottleneck was proving what the hash meant after the file left my machine.

I kept a spreadsheet. I pasted hashes into release notes. I copied the same values into a wiki, a forum post, and a private chat. If a CDN cached an older file, if a mirror re-encoded a binary, if a user saved a download with a different name, the spreadsheet became a guessbook.

Why a copy-pasted cryptographic hash is not a control

A cryptographic hash is only useful if you know which file it belongs to, when it was recorded, and whether the record itself was changed. A text file on a desktop is none of those things. It is a note to self.

The cybersecurity point is simple: a hash without a record is just a number.

The real risk was not a clever attacker. It was ordinary drift: a stale mirror, a bad upload, a bot that renamed a file, a human who pasted the wrong hash. I needed a place that could say, "This file had this hash at this time, and here is the evidence."

The pivot: store the hash, sign the record, watch the file

I built hash-check.com as third-party cryptographic hash storage around one job: keep a tamper-evident record of file identity, then alert me when the file no longer matches.

I did not start with a dashboard. I started with the data model.

The exact pipeline I built

Each file is represented by a record containing:

  • SHA-256 and BLAKE3 digests
  • file size
  • original filename
  • MIME type
  • source URL or upload path
  • timestamp
  • an Ed25519 signature over the record

When a file is first checked, the service computes the digests, writes the record, and signs it. When the same file is checked again, the service compares the new digests against the stored record. If they match, it returns a clean result. If they do not match, it flags the record and sends a webhook.

I used Go for the API because it handles small concurrent jobs without ceremony. I used PostgreSQL for the records because I wanted SQL constraints, not a JSON file that I could accidentally edit. I used a simple worker queue for re-checks so a large upload did not block the API. I ran the first prototype on a Raspberry Pi 4 with a 32 GB NVMe, because I wanted to know the floor before I moved it to a VPS.

The signature was the part that made the service feel like a control instead of a log. The database row can be changed, but the signature will not. If someone edits the stored hash, verification fails. If someone edits the file, verification fails. If both are edited consistently, the signature still fails unless the key was compromised.

Where the code stopped being cute

The first version failed in the ugly way. I pointed it at a mirror site and it reported a mismatch on every file. The hashes were correct. The mirror had changed the HTTP headers and returned a different Content-Length for the same bytes. My comparison logic treated the response as a new file because the metadata differed.

I tightened the rule: identity comes from the digest and the declared source path, not from the response headers. I added a normalization step that strips optional whitespace from filenames before comparison. I added a retry policy for transient 503 errors, but I made it explicit in the result so a retry is not mistaken for a clean check.

I also cut a feature I wanted: automatic file repair. It made the mental model worse. If the service fixes a file, the user cannot tell whether the original was bad or the service changed it. The product now only reports and notifies. It does not pretend to be a backup.

A photorealistic close-up of a mechanical keyboard and a small network switch on a metal desk, a USB drive plugged into a laptop, cool white desk lamp, realistic reflections

The benchmark: what changed after 30 days of checksum verification

After the first month, I stopped asking, "Did the file change?" and started asking, "What changed, where, and when?"

The numbers I actually kept

I ran 4,312 files through the service. That included firmware images, installer packages, documentation PDFs, and a small set of public assets. The service checked 11,876 times.

Results:

  • 11,843 clean checks
  • 33 mismatch alerts
  • 29 caused by stale mirrors or partial uploads
  • 4 were real changes that should have been versioned

The average check time for a 256 MB file was 1.8 seconds on a modest VPS. The slowest step was network transfer, not hashing. The service did not crash once during the test window. The only downtime I caused was a bad migration I rolled back in 6 minutes.

A photorealistic clean server room aisle with low blue status lights, a technician's hand holding a USB drive near a rack, soft ambient lighting, realistic depth

The time saved was not dramatic in a single check. It was dramatic in the argument. Before, a mismatch took 20 to 45 minutes to trace: download the file, hash it, compare notes, check the mirror, ask a user for a screenshot. After, the alert included the stored hash, the new hash, the source path, and the timestamp. I could open the record and see the first bad check.

The lesson I keep repeating

Do not trust the download button. Trust the hash, but only if the hash is recorded, signed, and checked at a known time.

That is the product. Not a fancy dashboard. Not a trust score. A small, precise service that turns "I think this file is the same" into "this is the evidence."

If you want the full technical details, the public documentation for hash-check.com is the next step.