Expand description
SYNC.md’s checks over a served log page.
SYNC.md’s three checks over one served page, as a function (D17).
Pure and node-free on purpose. The verification logic is the part worth being certain about, and a check that can only be exercised against a live node can only ever be exercised against a correct one — so the cases that matter, a flipped hash and a broken parent link, would never run. Mutations proved exactly that: removing the recomputation and removing the continuity check both left the end-to-end test green, because nothing ever handed it a bad page.
§What each check establishes
-
Continuity — the page is a contiguous run and each entry’s
parentis the previous entry’shash. Catches a page that begins in the wrong place or has an entry dropped from the middle. -
Recomputation — the
hashthe node claims is the hash of the entry it was attached to. Needs nothing but the page. -
Authorship — the actor named actually signed it, and was still trusted at that position (D44). For an ed25519 entry this is the only check that needs things the page does not carry: the public key, and the revocation positions. An entry whose key the caller does not hold is reported unverified, never verified; an entry signed at or after its key’s revocation is a failure, because that is a claim the log itself contradicts rather than one this client cannot check.
A passkey entry carries its own credential key (D45) and so needs nothing external — but for the same reason it establishes only half of what the ed25519 path does. See
crate::verify::Report::integrity_only.
§What still cannot be verified forever
For an ed25519 entry the log records a key id — hash(pubkey) —
never the public key itself. So those signatures are checkable only
while somebody still holds the key material, and an operator who
deletes a revoked key’s line from the trusted-keys file makes that
key’s history permanently unverified. Revocation no longer causes
that decay; deletion still does. Retaining revoked keys’ public
material is an operator responsibility nothing in the code can
enforce.
D45 fixed that for passkeys by a route not open to ed25519 keys: a WebAuthn signature is useless without the authenticator data anyway, so the entry already carried scheme-specific material and the credential key joined it. An ed25519 signature carries nothing, and adding the public key to every one of them would grow every entry to re-state what a one-line file already says.
What no passkey entry can establish, before or after D45, is that the credential belonged to the channel. That binding lives in the accounts store, which is server state, is not in the backup set, and is deliberately erasable. An entry admitted on a credential now withdrawn looks exactly like one admitted on a credential still enrolled, and neither this client nor any other can tell them apart.
D46 widens that split to every scheme, and it is a property given up on purpose. The channel an entry names is an opaque handle, so verification still needs nothing but the page and a key, while attribution — which person that handle was — needs the accounts store and gets no answer once the account is revoked. “These bytes are genuine” is permanent; “this was alice” is deletable. A handle this client cannot resolve is the expected state for a deleted account, not a fault in the log.
Structs§
- Report
- What one page’s verification found.
Functions§
- page
- Runs the three checks over
entries, in order. - rebuild
- Rebuilds the hashed form from the fields
/api/logserves.
Type Aliases§
- Revocations
- Actor id (hex, as
author_keycarries it) → the log position its binding was revoked at, from/api/view’sbindings[].revoked.at.