Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Protocol specification

This section specifies the Tenure protocol: the objects that travel on the wire, how they are encoded and signed, how authority is delegated and revoked, and how a credential is verified. It is the conceptual companion to the full product & engineering spec — where the two disagree, the spec wins.

Reading order

  1. Architecture — the actors (employer, registrar, KYB attester, worker, verifier, mirrors) and what each is and isn’t trusted for.
  2. Objects — the tn-* object catalogue, the domain-tagged BCS encoding rule, and the claim schemas.
  3. Log & epochs — the per-employer append-only hash chain, epoch-scoped authority, delegations, signed heads, and checkpoints.
  4. Verification — the pure 5-check predicate and the one-time import verification of a full log.
  5. Claim families — how exact/band/threshold variants are minted and retired together.
  6. Privacy — derive-then-purge, per-employer keys, and the public/authorized/holder-held data split.
  7. Misbehavior & switching — conflicting-head proofs and the epoch transition that lets an employer fire its registrar.

Foundational invariants

These hold everywhere in the protocol; the rest of this section builds on them.

  • Canonical bytes are BCS with a domain-separation tag. The only bytes ever signed or hashed are bcs(("tn-xxx-v1", body)). The tag rides inside the signed bytes, so a signature over one object kind can never be replayed as another. JSON is a display projection — never signed, never hashed.
  • One signature scheme. All signatures are Ed25519. The permitted cryptography is exactly: ed25519-dalek v2, blake3, x25519 + age-style sealing (chacha20poly1305 + HKDF), and getrandom. Nothing else. No JWT.
  • The employer key is the root of trust. Every valid attestation chains back to an employer-signed epoch chain. The registrar signs under delegations the employer issued; a mint outside its delegation is invalid even though it is signed.
  • The log is truth. event_log and revocations are append-only; the attestations table is a projection materialized from the log. Hash chaining (entry_hash = BLAKE3(payload_bcs || prev_hash)) plus externally witnessed signed heads make rewriting previously seen history detectable.
  • The verify predicate is pure. Chain, KYB, grant, revocation set, and the current time all arrive as arguments. The same function runs in the portal, the wallet, and the static verify page, and is mirrored byte-for-byte in TypeScript.

Encoding conventions

QuantityEncoding
IDsULIDs (strings)
Public keyslowercase hex
Signaturesbase64url, no padding
Hasheslowercase hex (empty string = genesis / none-yet)
Moneyinteger cents (never floats)
Datesunix seconds
Enums (canonical)BCS variant indices; string forms exist only for storage/display

The shared implementation of these conventions lives in crates/confed-core; the Tenure-specific objects and predicate live in crates/tenure-core, with a TypeScript twin in packages/tenure-core-ts.