arborist/aborist/mesh/__init__.py
russell@unturf.com aa8caeeece
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.
2026-04-27 19:00:24 -04:00

65 lines
1.8 KiB
Python

"""Mesh — gossip / membership layer for federated aborist trees.
Off by default. Loaded only when the user explicitly opts in via
`aborist mesh init` (creates this peer's identity) and
`aborist mesh enable` (flips the gating flag in the meta table).
The cryptographic substrate:
- Ed25519 (signing) — every gossip message and every membership
mutation event is signed by the sender's pubkey.
- X25519 (ECDH) — used to wrap each epoch's symmetric mesh
secret to every current member's DH pubkey, so the new secret
is reconstructible only by the post-rotation roster.
Membership state is per-epoch:
epoch 0 = group genesis (just the founder)
epoch N = the N-th roster mutation (add member, kick, scheduled rotate)
Eviction is a rotate where the kicked member's pubkey isn't in the
new envelope. Their previously-signed events stay verifiable forever
(historical roster preserved in mesh_roster), but they no longer have
the new secret, so any AEAD-protected gossip for epoch N+1 is opaque
to them.
This module deliberately avoids networking. The wire layer (HTTP/TLS
gossip server + sync client) lives in `aborist.mesh.wire` and is also
opt-in.
"""
from aborist.mesh.crypto import (
aead_decrypt,
aead_encrypt,
ecdh_shared_secret,
generate_dh_keypair,
generate_signing_keypair,
sign,
verify,
)
from aborist.mesh.state import (
MESH_ENABLED_KEY,
MeshIdentity,
MeshRosterEntry,
current_epoch,
init_identity,
is_enabled,
load_identity,
set_enabled,
)
__all__ = [
"MESH_ENABLED_KEY",
"MeshIdentity",
"MeshRosterEntry",
"aead_decrypt",
"aead_encrypt",
"current_epoch",
"ecdh_shared_secret",
"generate_dh_keypair",
"generate_signing_keypair",
"init_identity",
"is_enabled",
"load_identity",
"set_enabled",
"sign",
"verify",
]