- 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.
2.8 KiB
2.8 KiB
Delegation
How one identity lends its voice to another, and how a verifier decides whether a claim made by someone it does not know is backed by someone it does.
The wire object is DelegationClaim (PROTOCOL.md §8.7, tag 0x07). This
document is about what it means and how chains are resolved.
1. The statement
granter says: grantee may issue claims covering these exact predicates,
re-delegating at most max_depth further times.
- Exact predicates only.
{minecraft.op: true}covers the keyminecraft.opand nothing else. There are no prefixes and no wildcards: a grant ofuser.that silently coveredusers.adminwould turn an administrative convenience into an escalation primitive. - Every predicate value is the boolean
true, enforced at decode time. Coverage is membership, not interpretation (INV-5). max_depthcounts hops below the grant.0means the grantee speaks for itself only;2allows the grantee to delegate onward once, and that sub-grantee once more.- Revocation mirrors claims: the granter signs a
Revocationtargeting the delegation's object ID. Expired grants die on their own; supersession (serial) replaces terms without revoking history.
2. Chain resolution
A consumer anchors trust in roots — issuers it already decided to believe
(Policy.TrustedIssuers). When a claim's issuer is not a root, the verifier
searches for a path:
trusted root ──grant──▶ … ──grant──▶ claim issuer ──claim──▶ subject
Rules, implemented deterministically in verify.Graph:
- Every link must be signature-valid, current at the evaluation instant, unrevoked by its granter, and cover the claim's exact predicate.
- Where several grants could serve, the highest
serialwins, ties broken by lowest content ID — map order never leaks into a decision. - Total hops are bounded by
Policy.MaxDepth(default 3), and each link's ownmax_depthmust fit the hops below it: link i of k needsmax_depth ≥ k−1−i. - Cycles cannot loop: depth bounds terminate every walk.
- The accepted result reports the full path in
Result.Chain(issuer → … → root) as audit evidence.
An empty TrustedIssuers keeps the original model exactly: any issuer the
consumer fed into the graph may satisfy the policy directly. Delegation only
activates when roots are named.
3. What delegation does not mean
- It is not identity merging: the claim still names its real issuer, and the chain names everyone who lent authority.
- It is not transitive by default: a root that grants with
max_depth: 0creates exactly one hop and nothing more. - A hostile link can stop forwarding, but cannot forge: every hop is signed by its own granter, and the root sees only grants it signed itself.