This is the part that does not require trusting us. A result's provenance block is a claim,
and everything needed to check it is published.
Read as a sentence: at fetchedAt, this URL was fetched, and running the procedure named by
(protocol, protocolVersion) over the bytes received produced contentHash. The attestation
is that claim, written to Base, timestamped and signed.
A procedure is identified by (schema UID, protocolVersion), never by the version alone.
The protocol name is not an attestation field, because repeating a constant onchain cost 17% of
every attestation's gas. The API still reports it in provenance; onchain, the schema UID
plays that role.
contentHash.The procedure, version 1, given the bytes and the URL they came from:
<body>
innerHTML, so a page is never reduced to nothing. Markdown sources skip straight to step 4.headingStyle: 'atx', codeBlockStyle: 'fenced',
bulletListMarker: '-', emDelimiter: '*'.\r\n and lone \r to \n; strip trailing spaces
and tabs from every line; collapse three or more newlines to exactly two; trim the whole
document; append exactly one trailing \n.contentHash is the hex sha256 of that markdown, encoded UTF-8.Order is part of the protocol. NFC runs before the whitespace passes because composition can change which characters sit at the end of a line.
The full specification, with conformance vectors you can run against your own implementation, is VERIFY.md. The vectors are the spec in executable form; the input files are authored by hand and the outputs are frozen.
A mismatch means one of three things, and separating them matters:
fetchedAt. Expected on a live web, and the reason the timestamp
is in the record.(protocol, protocolVersion) pair names.attestationUrl opens the attestation on easscan. To read it programmatically you need no EAS
SDK: the payload is plain ABI encoding.
Check revocationTime before trusting one. A non-zero value means it was withdrawn, and
getAttestation returns revoked attestations rather than erroring.
The schema, its UID, and the full decoding notes are in SCHEMA.md.
contentHash covers the canonical markdown. rawHash, which is in the attestation, is sha256
over the exact bytes the origin served with no normalization at all.
They answer different questions. rawHash changes if a single byte does. contentHash is
stable across changes that do not alter the readable content, such as line endings or trailing
whitespace. A page whose rawHash moved but whose contentHash did not was re-served, not
rewritten.
Never content. The index is public, the corpus is other people's writing, and an attestation is a commitment to what was fetched rather than a copy of it. The attestation schema carries no content field, and it carries nothing about which index paid for the crawl either: provenance is a property of the fetch.