Provenance

Why every page here carries a fingerprint, and what is missing from it.

At the bottom of every post and note there is a line like this:

FIRST PUBLISHED  9 December 2025
LAST REVISED     16 August 2026
FINGERPRINT      4f2a8c1e9b3d7a05

Here is what it means, and, more usefully, what it does not.

What the fingerprint is

It is the first sixteen characters of a SHA-256 hash of the words on that page.

A hash is a function that turns any amount of text into a short fixed-length string. Change a single character anywhere in the page and the hash changes completely. Change nothing and it stays identical forever.

So the fingerprint is a compact answer to one question: is this the same text I read last time?

It is computed when the site is built. No JavaScript, no keys, no service, nothing to go down.

Why I bother

Because notes are not posts.

A post is dated and finished. I wrote it, it went out, it stays as it was. If you read it twice you read the same thing.

A note is alive. I revise them as I learn, which is the whole point of keeping them separate. That is good for me and slightly rude to you, because a page can change under your feet and nothing tells you.

The fingerprint tells you. If it differs from the last time you looked, the words changed.

That is a small thing. But I write about systems that should be able to say what they know and how they know it, and it would be a bit rich to argue that while running a site that cannot say whether its own pages have changed.

What it does not do

Be clear about this, because hashes get oversold.

It does not prove I wrote this. Anyone can hash anything. The fingerprint says the text is unchanged. It says nothing about who produced it.

It does not prove when. The dates come from the same files as everything else. If I changed them, the hash would happily agree.

It is not a signature. A signature is made with a private key that only I hold, and anyone can check it against a public key without trusting me. That is a different and much stronger claim: this specific person asserted this specific text. It is what non-repudiation actually means, and it is the thing a hash on its own cannot give you.

So what is here is the weakest of the three properties I care about. Integrity, not authenticity.

What comes next

Signing, and the reason it is not done yet is boring and honest: a private key cannot live in a public repository. The moment it does, it is not private and it signs nothing.

The version I want is roughly:

  • an Ed25519 keypair, with the public half published here and as a did:key
  • a manifest of every page and its hash
  • one signature over the manifest, made away from the repo, committed alongside it
  • enough instructions that you could verify it without any of my code

That is a small amount of work and a real amount of care, which is why it is a plan rather than a feature. When it exists this page will say so and will show you how to check it yourself.

There is also a longer-term problem worth naming. Signature algorithms in wide use today are the ones a sufficiently capable quantum computer would break. That barely matters for a blog. It matters a great deal for anything signed today that must still be verifiable in fifteen years, which is a lot of the world’s records. I write about that in five years.

Checking one yourself

The fingerprint is a hash of the page’s markdown source, not of what you see rendered. That distinction is the whole reason this is checkable: the source is published, so you can fetch the exact bytes I hashed.

curl -s https://denniseirorere.com/notes/what-entity-resolution-actually-is/source.txt | sha256sum

Compare the first sixteen characters with the fingerprint at the foot of that page. They will match, because they are hashes of the same bytes.

Every page’s source sits at <page-url>source.txt, and the full list with hashes is at fingerprints.json.

If you would rather not use a terminal, the verify page does the same thing in your browser for every page at once. It fetches each source, hashes it locally, and compares. Nothing is uploaded.

I would gently suggest the terminal version is better, because then you are trusting sha256sum rather than trusting my JavaScript.

An earlier version of this hashed the rendered text, which nobody could reproduce. That made it a claim rather than a proof, so it was changed.