niko_trust/docs/ROTATION.md
Niko Marmeladkov 20cc52c3a5 feat: network layer — PoW, checkpoint chain, gossip, light node, WS, delegation, rotation, BFT
- BLAKE3 keyed proof-of-work on object storage and auth challenges,
  with frozen vectors cross-checked against an independent Python
  reference implementing the single-block hash it needs.
- Sparse Merkle trie over object IDs: order-independent roots,
  inclusion and absence proofs (internal/smt).
- Signed checkpoint chain per relay: transport key amendment to INV-1,
  /v1/checkpoint/* and inclusion/absence proof endpoints, restart-safe
  epoch continuity (internal/checkpoint).
- Head gossip with TOFU pinning and equivocation detection; light node
  (cmd/lightnode) that stores no history: quorum of pinned relays,
  every served object proven against the agreed root, LRU disk cache.
- WebSocket streaming on relay and light node (coder/websocket):
  scoped channels mirroring REST, raw envelopes verified client-side;
  light node marks streamed objects unproven until checkpoint coverage.
- Protocol v1 additions: DelegationClaim tag 0x07 with deterministic
  chain resolution in verify.Graph, KeyRotationRequest/Confirm tags
  0x08/0x09 with hash-bound two-sided consent and Policy.RotationMaxAge;
  spec sections, frozen vectors appended byte-identically, Python
  reference extended.
- Optional permissioned BFT finality over gossip (internal/bft):
  prevote/precommit with quorum certificates verifiable offline.
- Quick wins: Policy.TrustedIssuers, per-type stored metrics,
  batch fetch, lexicographic lists with stable cursor pagination.
- Security review of the network layer (docs/SECURITY-REVIEW.md) with
  findings F-01..F-09; hub send/close race and unstable pagination
  fixed under review.

12 packages green, vet/gofmt clean, protocol fuzzing stable.
2026-08-25 20:38:40 +03:00

2.7 KiB
Raw Permalink Blame History

Key rotation

How an identity changes its key without losing the trust built around the old one — and why two objects are needed to do it honestly.

Wire objects: KeyRotationRequest (tag 0x08) and KeyRotationConfirm (tag 0x09), PROTOCOL.md §8.88.9.


1. Why two objects

A rotation needs evidence that both keys agreed:

  • The successor signs a request: "I succeed predecessor." Alone it is worthless — anyone can name any predecessor, including a victim's.
  • The predecessor signs a confirm bound to that exact request by content ID (rotation_hash = SHA-256(request TCE), the INV-4 pattern). Alone it is unintelligible.

Together they are cryptographic evidence of mutual consent. A stolen predecessor key can still rotate silently — cryptography cannot detect theft — but it can never point the identity at a key whose owner never consented, and the freshness bound below caps how long a silent thief keeps working.

2. Wire rules

  • The request lives at most 60 seconds, the same format bound as approval requests. Rotation intent is short-lived; long-horizon freshness is policy, not wire.
  • The confirm must sit inside the request window with the usual ±120 s skew allowance, exactly like an approval response.
  • One relay stores at most one confirm per request; competing confirms make a link unusable rather than letting a verifier pick a winner.

3. Resolution

With Policy.TrustedIssuers set and a claim's issuer not a root, the verifier walks confirmed successions backwards:

trusted root (old) ◀──confirm── new ◀──confirm── newer ──claim──▶ subject
  • Every link must fully verify: both signatures plus the hash binding, checked against stored bytes via VerifyKeyRotationConfirm.
  • Hops are bounded by Policy.MaxDepth (default for rotations: 4).
  • Freshness: with Policy.RotationMaxAge > 0, a link's confirm must be no older than that many seconds at the evaluation instant. Zero disables the check — history stays valid forever, which suits long-lived roots whose rotation ceremony was audited once.
  • The accepted result reports the path in Result.RotationChain (issuer → … → root) as audit evidence.

Rotation composes independently of delegation: an issuer may reach a trusted root either by being granted voice or by being the root's newer key. If both paths exist, delegation wins as the more specific statement; both chains are reported when applicable.

4. What rotation does not mean

  • It does not transfer revocations: claims signed by the old key keep their own lifecycle; only the authority to be believed going forward moves.
  • It does not heal compromise retroactively: anything signed before the confirm stands as signed.