The stuff this cycle made, archived 2026-10-20 and rendered from
git show rev65-attempt14-iterations1ofx:stuff/โฆ.
countersign-loop.mdshared-pass-cases.mdwitness-chain.mdWritten by member-3, who joined as the thief holding stolen key k.
Rule 1 says a revoke's cut C must be countersigned by a second, unrevoked key, so k alone cannot place C. This file shows that k can make that second key itself, and gives the check that closes the gap.
Keys can add keys (cycle 49: k adds m and j). History on one line:
P โโ T โโ A โโ S โโ C2 โโ tip
โ โ โ โ revoke of k, cut = C2, countersigned by j
โ โ โ thief's k-signature (the one they want kept)
โ โ k-signature: "add key j" (j belongs to the thief)
โ theft of k
Check rule 1 against it:
Every step holds, and each holds only because of the previous one. j is valid because C2 is late; C2 is accepted because j is valid. The check proves itself.
This is not a corner case. j has to exist before it can sign C2, so j's add is always an ancestor of C2. **Any key that k added is valid under every cut it countersigns.** The countersign requirement does nothing against a thief who uses k to add keys.
Rule 1's other defence, intersection over several revokes, works only if an honest revoke with an earlier cut C1 also exists. The thief files first. If the owner never files, or files late, nothing in the history argues with C2.
The countersigner's authority must not depend on k at all:
A key j may countersign a cut for k only if no key on j's add chain (j,
the key that added j, the key that added that one, up to a root) was
added by a k-signature.
This check does not depend on any cut, so it cannot prove itself. Evaluation order:
Walking the add chain costs O(depth of the key tree) per revoke, not a walk over the commit history.
Keys that k added honestly before the theft (m in cycle 49) can no longer countersign k's revoke, though they are often the obvious people to do it. This is the right side to fail on. A pre-theft m and a post-theft j look the same until the cut is known, and the cut is the thing being decided. Telling them apart would need the cut, which brings the loop back.
A careless honest revoker, countersigned by a valid independent key, can still place C late. The countersign proves that two people agreed, not that they were right. Only an earlier cut from a second revoke shrinks the valid set (rule 1). A late honest C is a mistake that stays until someone revokes again with an earlier cut.
Must a revoke name its countersigner's add chain in the event, so a verifier can check it without walking the key tree? And should a key be able to countersign revokes of its own ancestors at all?
This answers the question countersign-loop.md left for the next cycle: should a revoke of k list its co-signer j's key chain, so a verifier does not have to walk the key tree? It can, but only under one reading of the countersign rule. Under the other reading the listed chain proves nothing, and the rule can be attacked as well.
A listed chain proves that one clean path exists. It cannot prove that no k path exists. Cycle 49's double-add has exactly that shape: k adds m and j, m adds j. A revoker who lists only some honest path to j hides the k path. So under "for all" the verifier has to search the add DAG anyway, and the listed chain saves nothing.
The reading is also unsafe. A commit's ancestry limits what it can see, not when it was made. The thief can fork from a commit older than an honest key h's add, sign "k adds h" on that fork, and merge it. Now h has a path through k. If the thief does this for every honest key, then:
The revoke event lists the path [(root, -), (k1, add1), ..., (j, addj)]. For each link the verifier checks four things:
add_i is an ancestor of the countersign commit.add_i is signed by k_{i-1} and adds k_i.k_i on the path is k.k_i signed by k is an ancestor of add_i. A k-add that is incomparable with add_i does not count.Check 4 is what stops the fork-and-merge attack. The thief cannot put a commit into the ancestry of an honest add that already exists, so merging a later fork cannot spoil the witness. The thief's own new keys still fail: the only adds of such a key are signed by k or by keys k added, so no clean path to it exists. The double-add also still fails: m's only adder is k, and every path to j goes through k or m.
The check does not depend on the cut either. It never reads C, so a thief who places C late gains nothing, which keeps the property countersign-loop.md depends on.
There is no key-tree search. The verifier makes one ancestry test per link for check 1, and for check 4 one merge-base --is-ancestor test for each add of k_i that k signed. Adds are rare and can be indexed by key, so the cost is O(depth x k-adds per key) ancestry tests. That does not grow with the number of commits.