Check a FenceChat export

A FenceChat export is a PDF of someone’s message history. This page tells you two things about it: whether it really came from FenceChat, and whether anything has been left out. It takes a few seconds, and you do not need to know anything technical.

1. Find the check file

Every FenceChat PDF export has a check file that goes with it. The PDF is what you read. The check file is small, and its name ends in -manifest.json. The check file is what you need here.

That file holds a fingerprint of each message, and our signature. It has no message text in it.

Only got the PDF? Ask the person who gave it to you for the check file. If the export is your own, make it again: when the PDF has downloaded, use the “Download check file” link in your Archive.

2. Put that file here

Choose the file, or drag it here The one ending in -manifest.json. It stays on your computer.

Nothing is sent to us. Your own browser does the checking. The file never leaves your computer, and we do not know that you came here or what you looked at.

What a green answer means

What it cannot tell you

If you were sent the text instead of the file

Sometimes people copy the contents into an email rather than sending the file. Paste them here instead.

Notes for an IT expert (you can ignore this)

Our signing key is an Ed25519 key pair. The public half is published, so an export can be verified by anyone, offline, with ordinary tools, and still verified if FenceChat no longer exists. The key is at https://fencechat.com/.well-known/fencechat-archive-key.json. Opening that address in a browser shows a page of raw text rather than a designed page. That is expected: it is a data file meant for software, not a broken page.

The key that signs exports now is fc-archive-2026-10. The SHA-256 hash of its 32-byte public key is 074b01913824a41436b68844e80b12175b85088e8c02cf0d3bf09a210a89d0c9. A FenceChat custodian’s certificate prints the same hash, so you can confirm you have the right key. To work it out yourself, decode public_key_base64url from the key file to its 32 bytes and hash those bytes (not the text of the key).

Each message carries a SHA-256 content hash over a versioned, separator-delimited form of its evidentiary fields. Chain hashes are SHA-256(version + U+001F + previous chain hash + U+001F + content hash) -- note the U+001F unit separator between each part; it is invisible in a terminal or editor, so a reimplementation that quietly drops it will compute a different hash for what looks like an identical string. The first message in an account chains from sixty-four zeros. The manifest is signed over its canonical form: JSON with keys sorted at every level and no whitespace.

# 1. Fetch the public key
curl -s https://fencechat.com/.well-known/fencechat-archive-key.json

# 2. Canonicalise the manifest: keys sorted at every level, no whitespace.
#    Those are the exact bytes that were signed.

# 3. Verify the Ed25519 signature over those bytes with the published key.
#    Any Ed25519 implementation will do, including openssl pkeyutl -verify.

Each message’s content hash is SHA-256 of the version (fcav3) followed by these fields, each joined by U+001F: id, fence_address, channel, direction, received_at, from_email, from_name, subject, filtered_subject, original_body, filtered_body, then filter_applied, threat_detected and held as 1 or 0. Text is NFC-normalised, and NUL and U+001F characters are removed from inside each field. Exports made since 21 October 2026 contain fingerprints only. Earlier export files also carried a records list of these fields, so each hash could be recomputed from the message itself.

This page checks four things and reports a pass only if all of them hold: the signature over the canonical manifest, the recomputed chain across every entry, the chain head recorded in the manifest, and (when the file includes the messages) each message’s text against its content hash.