Witness co-signed key-log heads (relay#23) #97

Merged
paulhitt merged 1 commits from feat/witness-cosigned-heads into main 2026-09-04 20:40:40 +00:00
paulhitt commented 2026-09-04 13:36:53 +00:00 (Migrated from gitlab.com)

The relay signs its own head, which is why a fork can hide. A
relay that splits its log — showing one set of keys to one person and a
different set to another — signs both halves with the same key. Every
client sees a head that verifies, and nothing any single client can
fetch says the two exist. Only gossip between clients catches it, and
that needs two clients who happen to compare.

A witness is an independent party that remembers what it has already
signed. Ask it to co-sign size 100 with root A and it will; ask it later
for size 100 with root B and an honest witness refuses, because it has
already made a statement about size 100. A relay wanting an undetected
fork now needs the witness's cooperation as well as its own key.

A stateless witness is decoration. The whole value is the memory:
one that signs whatever it is shown produces signatures proving only
that it was asked. Witness.decide is that memory, and the fork refusal
is the reason the type exists.

The witness KEYS never travel in the relay's response — only the
names.
A client taking keys from this response would be letting the
relay nominate its own auditors, and the second signature would be the
first one wearing a hat.

Co-signatures are keyed by the exact (size, root) statement, not by
size. Serving a size-100-root-A signature beside size-100-root-B would
be this relay manufacturing the very evidence a witness exists to make
impossible.

What this does not do. It does not prevent a fork, and it does
not detect one on its own — a client still has to check the
co-signatures are present and from witnesses it trusts. A witness that
colludes adds nothing, so more than one, run by different people, is the
only configuration worth having.

A LARGER head is co-signed without proving it extends what came
before. Proving extension needs a consistency proof, which is a heavier
protocol and a separate decision; this buys the property that matters
most and costs least.

The store is in memory on purpose. A co-signature is meaningful for
one exact head, and the head moves on every registration — persisting
them would mean serving yesterday's witness statement beside today's
head, which looks like corroboration and is not.

The response field is additive and optional: a relay with no
witnesses omits it, and older clients ignore it.

581 relay tests in 51 suites, green — including all seven core paths.

**The relay signs its own head, which is why a fork can hide.** A relay that splits its log — showing one set of keys to one person and a different set to another — signs both halves with the same key. Every client sees a head that verifies, and nothing any single client can fetch says the two exist. Only gossip between clients catches it, and that needs two clients who happen to compare. A witness is an independent party that remembers what it has already signed. Ask it to co-sign size 100 with root A and it will; ask it later for size 100 with root B and an honest witness refuses, because it has already made a statement about size 100. A relay wanting an undetected fork now needs the witness's cooperation as well as its own key. **A stateless witness is decoration.** The whole value is the memory: one that signs whatever it is shown produces signatures proving only that it was asked. `Witness.decide` is that memory, and the fork refusal is the reason the type exists. **The witness KEYS never travel in the relay's response — only the names.** A client taking keys from this response would be letting the relay nominate its own auditors, and the second signature would be the first one wearing a hat. Co-signatures are keyed by the exact `(size, root)` statement, not by size. Serving a size-100-root-A signature beside size-100-root-B would be this relay manufacturing the very evidence a witness exists to make impossible. **What this does not do.** It does not prevent a fork, and it does not detect one on its own — a client still has to check the co-signatures are present and from witnesses it trusts. A witness that colludes adds nothing, so more than one, run by different people, is the only configuration worth having. A LARGER head is co-signed without proving it extends what came before. Proving extension needs a consistency proof, which is a heavier protocol and a separate decision; this buys the property that matters most and costs least. The store is in memory on purpose. A co-signature is meaningful for one exact head, and the head moves on every registration — persisting them would mean serving yesterday's witness statement beside today's head, which looks like corroboration and is not. The response field is additive and optional: a relay with no witnesses omits it, and older clients ignore it. 581 relay tests in 51 suites, green — including all seven core paths.
paulhitt commented 2026-09-04 13:36:54 +00:00 (Migrated from gitlab.com)

assigned to @paulhitt

assigned to @paulhitt
paulhitt commented 2026-09-04 20:40:39 +00:00 (Migrated from gitlab.com)

deleted the feat/drain-connections-on-deploy branch. This merge request now targets the main branch

deleted the `feat/drain-connections-on-deploy` branch. This merge request now targets the `main` branch
paulhitt commented 2026-09-04 20:40:41 +00:00 (Migrated from gitlab.com)

mentioned in commit 149c3518bb

mentioned in commit 149c3518bb06633a1b715eafcc0ae89eb1950777
paulhitt (Migrated from gitlab.com) merged commit 149c3518bb into main 2026-09-04 20:40:41 +00:00
paulhitt commented 2026-09-09 18:59:12 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
Sign in to join this conversation.