How we verify
The reader does not trust a badge, a gateway, or a curator override. It hashes bytes, then it renders — or it does not.
- 1
Canonical bytes
Markdown is treated as UTF-8. CRLF and CR become a single LF. That is the only normalization. We do not pretty-print, retitle, or strip punctuation before hashing.
- 2
SHA-256 of those bytes
The digest is the seal. It is stored on the catalog and, when a curator has sealed on-chain, in
RootRecord.content_sha256. Book bytes themselves never go on-chain. - 3
Fetch is untrusted
Storage returns bytes. A local fixture adapter, a CDN, or a later Arweave gateway could all lie. The URI is an address, not a proof.
- 4
verifyAndWrap, then VerifiedMarkdown
The load path calls
verifyAndWrap(bytes, expectedSha256). On mismatch the result has no markdown field.VerifiedMarkdownhashes again on render. There is no skip flag. - 5
Fail closed
Hash mismatch shows the expected and actual digests and withholds the body. Try it from any work’s reader with “Simulate tampered gateway.”
Full note: open a work and read. Program tests attempt a non-curator seal and a post-seal mutation; both must fail.