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

66 lines
2.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.