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
- Architecture — the actors (employer, registrar, KYB attester, worker, verifier, mirrors) and what each is and isn’t trusted for.
- Objects — the
tn-*object catalogue, the domain-tagged BCS encoding rule, and the claim schemas. - Log & epochs — the per-employer append-only hash chain, epoch-scoped authority, delegations, signed heads, and checkpoints.
- Verification — the pure 5-check predicate and the one-time import verification of a full log.
- Claim families — how exact/band/threshold variants are minted and retired together.
- Privacy — derive-then-purge, per-employer keys, and the public/authorized/holder-held data split.
- 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-dalekv2,blake3,x25519+ age-style sealing (chacha20poly1305+ HKDF), andgetrandom. 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_logandrevocationsare append-only; theattestationstable 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
| Quantity | Encoding |
|---|---|
| IDs | ULIDs (strings) |
| Public keys | lowercase hex |
| Signatures | base64url, no padding |
| Hashes | lowercase hex (empty string = genesis / none-yet) |
| Money | integer cents (never floats) |
| Dates | unix 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.