← Back to VerifyIndependent Verification

Verify an AcreSeal record yourself — without our cooperation

Anyone can independently verify this photo by downloading it and running exiftool (to read its metadata) or shasum -a 256 (to confirm the bytes are unchanged). AcreSeal's participation is not required for verification.

Who this is for

This page is written for someone with a reason to doubt the evidence: opposing counsel, a claims adjuster, a regulatory auditor, or a court-appointed expert. Nothing here requires an account, an API key, or any cooperation from AcreSeal. If a step cannot be completed exactly as written, treat that as a finding.

You will need

A terminal with shasum (or sha256sum) and openssl, both preinstalled on macOS and Linux. exiftool is optional and only needed to read photo metadata.

Part 1 — Verifying a record

A record is a single field report: a photo, its capture context, and an append-only audit chain. Verifying one establishes that the photo and its context have not changed since sealing.

1

Fetch the record

Replace <record-id> with the UUID you were given.

curl -s "https://acreseal.com/api/verify-chain?id=<record-id>&verify_env=true" -o record.json
jq '.valid, .authoritative, .broken_at' record.json

Expect valid: true, authoritative: true, and broken_at: null. An ID beginning demo- returns authoritative: false — those are illustrations, not evidence, and the response says so.

2

Reproduce the photo hash

Download the stored evidence photo and hash it. This is the load-bearing check.

curl -s "$(jq -r '.photo.url' record.json)" -o evidence.jpg
shasum -a 256 evidence.jpg
jq -r '.photo.serverSha256' record.json

The two values must be identical.

Two hashes exist — compare against the right one

photo.serverSha256 is the digest of the bytes as stored, and is what a downloaded file reproduces. photo.sha256 is a capture-time digest computed in the browser before AcreSeal embedded its provenance EXIF, and a downloaded file will not reproduce it. If a record publishes only photo.sha256, it predates server-side re-hashing and no downloaded file can match it — that is a limitation of that record, disclosed rather than hidden. For the same reason, a camera original never matches: the stored file is not byte-identical to what left the camera.

3

Recompute the environmental hash

The record's forensic_hash binds the capture time, coordinates, weather at that place and hour, and the photo hash into one digest. The raw inputs are published so you can recompute it rather than trust our answer.

jq -r '[.env_context.timestamp, .env_context.lat, .env_context.lng,
        .env_context.temp, .env_context.wind, .env_context.cloud,
        .env_context.photoHash] | join("|")' record.json | tr -d '\n' | shasum -a 256

jq -r '.env_verification.stored' record.json

The fields are joined with | in exactly that order, with no spaces, and SHA-256'd. Absent values appear as the literal string null. Numeric fields are fixed-precision strings as published — do not re-round them.

4

Walk the hash chain

Each audit entry embeds the previous entry's hash, so any edit to history breaks every link after it.

jq '.entries[] | {action, forensic_hash, previous_hash, chain_valid}' record.json

Every entry should report chain_valid: true, and broken_at at the top level should be null. Immutability is enforced by database triggers, not by application code.

5

Optionally, read the photo metadata

Corroborating only — never treat EXIF as the integrity anchor.

exiftool evidence.jpg

You will see Software: AcreSeal Forensic Pipeline v1.0 and an AcreSeal provenance block. Original camera tags are carried forward when the file had them, but many will not: mobile operating systems strip metadata from photos captured through a browser, and files above 2 MB are re-encoded during compression. A record with no camera EXIF is normal and does not weaken the hash evidence.

Part 2 — Verifying a job seal

A job seal covers a set of records sealed together. It is the only artifact that carries third-party attested time.

You need a job ID, and a record ID will not give you one. The public record endpoint deliberately does not return job_id; that linkage is only exposed to authenticated tenant users. A job ID normally reaches you inside a litigation defense package or forensic affidavit. If you do not have one, request it from the party producing the evidence.

1

Fetch the seal

curl -s "https://acreseal.com/api/verify-seal?job_id=<job-id>" -o seal.json
jq '{root_matches, signature_valid, trusted_timestamp_present, leaf_count: .seal.leaf_count}' seal.json

root_matches and signature_valid are our computations. The remaining steps let you reproduce them yourself, which is the point.

2

Recompute the Merkle root

The response returns leaves — the ordered per-record hashes. Rebuild the root from them using RFC 6962 rules:

  • leaf hash = SHA256(0x00 || leaf_bytes)
  • internal node = SHA256(0x01 || left || right)
  • an odd node at any level is promoted unchanged to the next level
  • leaves are the 64-character hex strings decoded to raw bytes, in the order given

Note the odd-node rule: AcreSeal promotes, it does not duplicate the last leaf. A Bitcoin-style implementation will produce a different root on any set with an odd count at some level. The result must equal seal.merkle_root_hash.

3

Verify the Ed25519 signature

The signed message is four fields joined with pipes:

<job_id>|<merkle_root_hash>|<combined_sha256>|<timestamp_sealed_self_asserted>

Verify seal.cryptographic_signature (base64) over that message using seal.public_key (SPKI PEM). Cross-check that key against the copy published independently at /.well-known/acreseal-seal-key.pem — if they differ, stop and ask why.

signature_valid: null means the seal carries no signature at all, which is different from false. Some early seals are unsigned.

4

Verify the trusted timestamp

This is the step that establishes time independently of AcreSeal. The token is a complete RFC 3161 response, verifiable with OpenSSL alone.

jq -r '.trusted_timestamps[0].token_base64' seal.json | base64 -d > token.tsr
ROOT=$(jq -r '.seal.merkle_root_hash' seal.json)

# Publicly-trusted authority (e.g. Sectigo, DigiCert) — nothing to download:
openssl ts -verify -digest "$ROOT" -in token.tsr -CAfile /etc/ssl/cert.pem

# Read the attested time:
openssl ts -reply -in token.tsr -text | grep "Time stamp:"

Expect Verification: OK. On Debian or Ubuntu the trust store is /etc/ssl/certs/ca-certificates.crt. Check trusted_timestamps[0].tsa_url to see which authority issued the token; if it is a self-signed service such as freetsa.org, fetch that authority's CA first and pass it instead of the system store.

timestamp_sealed_self_asserted is AcreSeal's own server clock and is not evidence of time. Only the RFC 3161 token constitutes third-party attested time. If trusted_timestamp_present is false, that seal has no independent time attestation and should not be described as though it does.

What this does and does not prove

EstablishedNot established
The stored photo is byte-for-byte unchanged since sealing.That the photograph depicts what its description claims. No cryptography can establish that.
The capture context — time, coordinates, weather — is bound into a digest that has not changed.That the device reported its position honestly. GPS can be spoofed at the device.
The audit history is append-only and unbroken, enforced by database triggers.That a record was created when its own timestamp says, unless a job seal with an RFC 3161 token covers it.
For a sealed job: that the root existed at a time attested by an independent authority.Anything about records not included in that seal's leaves.

Per-record integrity is proven by a linear SHA-256 hash chain, not a Merkle tree; no per-record Merkle inclusion proof is asserted. Job-level seals do use an RFC 6962 Merkle tree, verifiable separately as described above.

Frequently asked

Do I need an account, an API key, or AcreSeal's permission?

No. Every endpoint and file referenced on this page is public and unauthenticated. The verification steps use shasum, exiftool and openssl — standard utilities, none of them ours. If AcreSeal ceased to operate, a record you have already downloaded together with its published hashes remains verifiable.

shasum gives a different value than the hash I was shown. Is the evidence bad?

Check which hash you are comparing against. A record publishes up to two digests: the stored-bytes hash (server_photo_hash), which a downloaded file reproduces, and a capture-time hash computed in the browser before AcreSeal embedded its provenance EXIF, which it will not. Compare against the stored-bytes value. Records created before server-side re-hashing publish only the capture-time hash, and for those no downloaded file will reproduce it — the record says so explicitly rather than implying otherwise.

Why does the record's timestamp not prove when the photo was taken?

Because AcreSeal asserted it. A record's timestamps come from the submitting device and our servers, which is evidence of our records but not independent proof of time. Third-party attested time exists only at the job-seal level, via an RFC 3161 token issued by a Time Stamp Authority we do not control. If a seal reports trusted_timestamp_present: false, it has no independent time attestation and should not be described as though it does.

I have a record ID. How do I get to its job seal?

You cannot, from the public endpoint. /api/verify-chain deliberately does not return job_id. The record-to-seal linkage is only exposed to authenticated tenant users. A job ID normally reaches you in a litigation defense package or forensic affidavit; if you need one and do not have it, request it from the party producing the evidence.

signature_valid came back null. Is that a failure?

No — null means the seal was written without an Ed25519 signature, so there is nothing to verify. It is distinct from false, which would mean a signature exists and does not check out. Some early seals carry no signature. Treat null as an absent attestation, not a failed one.

The EXIF says the software is AcreSeal. Where is the camera's metadata?

AcreSeal writes a provenance block into the stored file, and in doing so sets Software, ImageDescription, UserComment and GPS from the capture context. Original camera EXIF is carried forward where present, but two common cases leave none to carry: photos captured through a mobile browser's camera are stripped of metadata by the operating system before the page receives them, and files above 2 MB are re-encoded during compression. EXIF is corroborating evidence here, never the integrity anchor.

If any step on this page fails against a record you were given, that is a finding worth raising with whoever produced the evidence — not a quirk to work around.