mesh: cryptographic foundation, off by default

Phase 1 of the federation/gossip layer fox sketched as the natural
extension of v9.8 admissibility's content-addressed identity. Two
peers ingesting the same dump already compute identical document_roots
and identical 8-dim cache_keys; the mesh layer is the wire-and-trust
plumbing that lets them dedup answers, exchange Merkle proofs, and
cleanly distrust an evicted member without a hard fork.

Cryptography (cryptography lib, audited):
  Ed25519       — every membership mutation + (future) gossip envelope
                  is signed by the actor's pubkey.
  X25519 ECDH   — wraps each epoch's symmetric mesh secret to every
                  current member's DH pubkey via HKDF-derived AEAD key.
  ChaCha20-P1305— AEAD for envelope payloads + per-member secret wrap.

State machine:
  mesh_identity   — singleton; this peer's keys + group name
  mesh_roster     — per-epoch (member_id, sign_pub, dh_pub, role)
  mesh_epochs     — epoch_id -> {started_at, started_event_hash,
                                  secret_envelope JSON, reason}
  meta:mesh.enabled flag — off by default; gates everything

Eviction works by rotating to a new epoch whose envelope omits the
kicked member. Their prior signatures stay verifiable (the older
roster row is retained), but any gossip from epoch+1 onward is
opaque to them — the secret was never shared with their pubkey.

Authority gate: only roster members with role='admin' can add or
kick. Self-kick is rejected explicitly. The last admin can't be
kicked. Schedule-rotate (refresh secret, no roster change) is open
to any current member as a session-hygiene op.

Audit-chain integration: every mesh state mutation writes an audit
event (mesh_init, mesh_enable/disable, mesh_epoch_rotate). The
epoch's started_event_hash backfills into mesh_epochs after the
audit row commits, giving each epoch a tamper-evident pin into the
ledger.

CLI subcommands: mesh init, mesh status, mesh enable, mesh disable,
mesh members, mesh add, mesh kick, mesh rotate. All read-only or
local-state-only — no network code paths in this commit.

The HTTP gossip wire (`mesh sync`, `mesh serve`) is the next phase.
Schema, cryptography, and roster state machine are all in place to
support it without further migration.
This commit is contained in:
russell@unturf.com 2026-04-27 19:00:24 -04:00
parent 082143e158
commit aa8caeeece
No known key found for this signature in database
9 changed files with 1318 additions and 0 deletions

View file

@ -236,6 +236,31 @@ make falsify KEY=<cache_key> REASON="why it was wrong"
The original record stays in the database (history matters). A `falsifications` row + `falsify` audit event record the act. Future lookups skip records whose `falsification_state != 'live'`.
## Mesh / federation (off by default)
Two machines that ingest the same dump compute *bit-identical* `document_root`s — that's the v9.8 admissibility property. The mesh layer is the wire-and-trust scaffolding that lets peers gossip those identities (plus derivations, falsifications, cross-witnesses) and dedup-by-content across instances.
It ships **off by default**. No code path touches the network unless the `mesh.enabled` flag is set. Initialization flow:
```
aborist mesh init --group myteam # mint Ed25519 + X25519 keys; create epoch 0
aborist mesh status # always-safe inspection; shows enabled/false until you flip it
aborist mesh enable # flip the gating flag on
```
Membership is per-epoch. Adding a member, kicking a member, or rotating the secret each bumps the epoch and writes an audit event:
```
aborist mesh add --member-id bob --sign-pub <hex> --dh-pub <hex>
aborist mesh kick --member-id bob --reason "..." # admin-only; bumps epoch, omits bob from new envelope
aborist mesh rotate --reason "..." # refresh secret, same roster
aborist mesh members # list current epoch's roster
```
The kicked member's prior signatures stay verifiable forever (their roster row at older epochs is preserved on disk). They have no entry in the new epoch's secret envelope, so any AEAD-protected gossip from epoch+1 onward is opaque to them — that is the eviction guarantee.
The HTTP gossip wire (`mesh sync`, `mesh serve`) is on the roadmap; this commit ships the cryptographic foundation, state machine, and CLI. The crypto is `cryptography`-backed Ed25519 + X25519 + ChaCha20-Poly1305.
## Inspecting
```