Verify a WORM ledger entry
fix(how-to): Records & storage group rewritten against real source (Group 4, Phase 1 continued)
@@ -1,85 +1,73 @@ --- schema: foundry-doc-v1 title: "How to verify a WORM ledger entry" title: "Verify a WORM ledger entry" slug: verify-worm-ledger short_description: "Verifies a WORM ledger entry by checking its hash chain against the tile files and, where present, a signed checkpoint — using only a standard SHA-256 toolchain." short_description: "Verifies WORM ledger entries against a fetched checkpoint over service-fs's real HTTP API, using a standard SHA-256 toolchain — no CLI or proprietary tooling exists or is required." category: how-to content_type: how-to type: how-to quality: complete status: active last_edited: 2026-06-14 audience: "Engineers (hands on keyboard); customer operators" last_edited: 2026-08-06 editor: pointsav-engineering paired_with: verify-worm-ledger.es.md research_trail: sources: [pointsav-monorepo service-fs/src/http.rs (GET /v1/entries, GET /v1/checkpoint), service-fs/src/ledger.rs (Checkpoint struct, C2SP signed-note signing), architecture/worm-ledger-architecture.md] verification_method: "grounded directly in the real service-fs HTTP API confirmed while rewriting read-the-command-ledger.md in the same session (2026-08-06); the guide's own prior Correction note already confirmed service-fs has no CLI at all and no verify subcommand — this rewrite replaces the fabricated tool commands with the real routes, and is deliberately conservative about the exact Merkle-tree verification math of the underlying C2SP tlog-tiles format, which isn't independently re-derived here" --- **Correction (2026-08-02, verified against canonical `origin/main`):** the `service-fs verify --from/--to` CLI subcommand doesn't exist — `service-fs` has no CLI at all, it's a pure HTTP daemon. `read_since(...)` is not a directly-callable operation either — the real routes are `/v1/append`, `/v1/entries`, `/v1/checkpoint`. The general concepts (C2SP tlog-tiles, Sigstore Rekor anchoring) are real, confirmed in `service-fs/ARCHITECTURE.md` and `ledger.rs`, but the concrete tool commands below are fabricated. **Flagged, not resolved** — needs rewriting around the real HTTP routes. The WORM ledger guarantees that records cannot be modified or deleted after they are written. Verification confirms that guarantee holds for a specific entry: that the hash chain is intact and that no post-write alteration occurred. This guide covers verification using the service-fs API and the standard SHA-256 toolchain — no proprietary tooling is required. For what the WORM guarantee covers and does not cover, see [[worm-ledger-architecture]]. For the storage format, see [[worm-ledger-storage-architecture]]. ## Prerequisites - Access to a Totebox ledger (local file access or service-fs API) - A SHA-256 utility (`sha256sum` on Linux, `shasum -a 256` on macOS, or equivalent) - The position (row index) or timestamp range of the entry you want to verify ## Step 1: Export the tile containing your entry - Network access to your `service-fs` instance - Your module identifier for the `X-Foundry-Module-ID` header - A SHA-256 utility (`sha256sum` on Linux, `shasum -a 256` on macOS) Using the service-fs API, call `read_since` with the checkpoint immediately preceding your target entry: ## Purpose ``` read_since(checkpoint_id: "<checkpoint-id>", limit: 1) ``` Confirm that a ledger entry hasn't been altered since it was written, using only `curl` and standard hashing tools — no CLI or proprietary verification tool exists for this, and none is needed. This returns the tile file for that segment of the ledger. On a local deployment you can also read the C2SP tlog-tiles files directly from the ledger directory. ## Procedure ## Step 2: Locate the entry in the tile 1. Fetch the entry (or range of entries) you want to verify, per [[read-the-command-ledger]]: The tile is plain text in C2SP tlog-tiles format. Each line is a base64-encoded log entry followed by its hash. Find the row matching your target entry by timestamp or sequence number. ```bash curl -s -H "X-Foundry-Module-ID: <your-module-id>" \ "http://<service-fs-host>/v1/entries?since=<cursor>" ``` ## Step 3: Verify the hash chain 2. Fetch the current checkpoint: For each row in the tile, the hash of that row is included in the hash computation for the next row. To verify entry N: ```bash curl -s -H "X-Foundry-Module-ID: <your-module-id>" \ "http://<service-fs-host>/v1/checkpoint" ``` 1. Take the hash from row N−1 (or the genesis hash for the first entry). 2. Concatenate it with the raw bytes of entry N. 3. Compute SHA-256 of the concatenation. 4. Compare the result to the hash recorded in row N. The checkpoint carries `tree_size` (total entry count at the time it was issued), `root_hash` (a hex-encoded SHA-256 commitment covering every entry up to `tree_size`), `algorithm` (`"sha256"`), a `timestamp`, and a `signature`. A match confirms the chain is intact from the genesis to that point. A mismatch at row N means either row N or some earlier row was altered — inspect each row backwards from N to isolate the point of tampering. 3. Confirm your fetched entries are covered by the checkpoint: their cursors must fall within `tree_size`. If your target entry's cursor is higher than the checkpoint's `tree_size`, fetch a newer checkpoint first. ## Step 4: Verify against a signed checkpoint 4. If the checkpoint carries a signature, verify it. `signature` holds an Ed25519 signature over the C2SP signed-note body (`origin`, `tree_size`, and the base64-encoded `root_hash`), using the platform's published verifying key. A valid signature means the chain state was attested at that point — independent of trusting the live service in the moment you read it. If a signed checkpoint covers the range containing your entry, you can verify that checkpoint's signature to extend the guarantee to the anchor point: > **Note:** `signature` is only present if the `service-fs` instance was started with a signing key configured. An unsigned deployment's checkpoint is still a real, honest snapshot of `tree_size`/`root_hash` — it just carries no independent third-party attestation. Don't treat a missing signature as an error. 1. Retrieve the C2SP signed-note for the relevant checkpoint. 2. Verify the note's Ed25519 signature using the public key published for the Sigstore Rekor anchor. 3. Confirm that the checkpoint covers a sequence number that includes your entry. ## Expected outcome A valid signature from Sigstore Rekor means the chain state was externally timestamped at that point, providing verifiability independent of the live service. A checkpoint whose `root_hash` and `tree_size` you can independently hold as a commitment to the ledger state at that point, and — where a signature is present — cryptographic proof that commitment was attested, not merely asserted by the running service. ## Automated verification ## Verification The `service-fs` CLI provides a `verify` subcommand that runs steps 2–4 automatically: Re-fetch the checkpoint later and confirm `tree_size` only ever increases and that the `root_hash` for any `tree_size` you've seen before never changes. A ledger entry that was covered by an earlier checkpoint's `root_hash` and is still present, unmodified, under a later checkpoint's larger `tree_size` has never been altered — that consistency across checkpoints over time is the practical, repeatable verification available with just these two endpoints. ``` service-fs verify --from <checkpoint-id> --to <entry-id> ``` ## Rollback Use the manual procedure above when you want to inspect the chain without trusting the CLI. Verification is read-only. Nothing to undo. ## Key takeaways ## Next steps - Verification requires only a SHA-256 utility and the raw tile files — no live service needed - A mismatch in the hash chain at row N means alteration at or before N; inspect backwards to isolate it - Signed checkpoints extend verification to a public timestamp anchor, enabling third-party audits - The C2SP tlog-tiles format ensures these steps remain executable with standard tools for decades - [[read-the-command-ledger]] — the entry-reading procedure this guide verifies against ## See also - [[worm-ledger-architecture]] — what the WORM guarantee covers and its structural properties - [[worm-ledger-storage-architecture]] — the tile format, atomic writes, and checkpoint structure - [[service-fs-architecture]] — the service that implements and serves the ledger - [[read-the-command-ledger]] — reading ledger entries from within os-console - [[worm-ledger-design]] — the design philosophy and regulatory compliance rationale - [[worm-ledger-architecture]] — what the WORM guarantee covers and what it does not - [[service-fs]] — the service that implements and serves the ledger