Directory integration
Tenure is confederal: each employer’s data lives only with the registrar that employer hired, and verification is offline-capable from a self-contained bundle. The directory adds one optional, additive capability on top of that model — trustless discovery and a survivable freshness anchor — without changing the pure five-check predicate or adding a global chain.
The directory is an external transparency service: a sparse-Merkle-tree key/value store with a signed-header log, run by no one Tenure controls. Tenure treats it as a reference design, reached through a single thin adapter that is the only part of the system aware a directory exists. That adapter speaks a small request/response protocol over the protocol’s existing primitives — Ed25519 signatures and BLAKE3 hashing — and depends on no third-party directory library. Nothing else in the system handles directory data structures.
Writes are best-effort and off the critical path. A failed write is recorded and swallowed, so a slow or dead directory can never block onboarding, issuance, or an epoch transition.
Reads are on the critical path of the offline-verify and discovery paths — so they are trustless, not taken on faith. A read returns a Merkle proof under a signed tree-root header, and the client verifies it (below). “The directory told me X” becomes “X is part of the one committed state the anchor signed.” Trust still terminates in the anchor key; pushing that to an external ledger is the remaining step (see Non-equivocation).
What gets published
Section titled “What gets published”Three Tenure-native records, each written in the protocol’s canonical domain-tagged encoding (see Wire format) and stored by the directory as opaque bytes. Only Tenure code interprets them.
| Record | Written by | Contents |
|---|---|---|
| Employer Record | the registrar, at onboarding | The employer public key, the current epoch number, the current registrar’s public key and service address, any mirror addresses, a BLAKE3 digest of the KYB Entity Attestation, and a BLAKE3 digest of the Employer Descriptor. |
| Head Checkpoint | the registrar, as the log advances | The employer identifier, the sequence number, the head hash, the epoch number, and the registrar’s Signed Head signature over exactly those four fields. |
| Attester Record | the KYB attester | The attester public key, the attesting organisation’s name, the verification methods it performs, its jurisdiction, and its status — active, suspended, or revoked. |
An Attester Record is filed under an attester fingerprint: a truncated BLAKE3 hash of the attester’s public key, computed identically by writers (registrars and attesters) and readers (verifiers), so a record written under one is found under the other.
The integrity of the underlying employer-signed objects rides in the hashes, not in who owns the directory entry. The signature carried in a Head Checkpoint is exactly the Signed Head signature that wallets and verifiers already check, so a directory head is verifiable on its own.
The key-state model
Section titled “The key-state model”The directory’s data model follows nullspace — the reference confederal implementation — because Tenure’s directory is a stepping stone to the same destination: Mel, a light-client-first blockchain whose Global Namespace provides these exact semantics natively, with offchain name-equivocation detection. Building to the nullspace shape now means the eventual swap is a backend change, not a protocol migration. See Mel integration.
The directory is deliberately untyped: it stores keys and opaque values and does not know what any key “means” — higher layers define the namespace conventions. What the directory does commit to, per key, is a three-part key state:
- A highest-accepted nonce. Every update must strictly exceed the highest nonce ever accepted for that key, which kills the name-rollback attack: a replayed old signed update — say, re-pointing an employer’s record at the registrar that employer just fired — is dead on arrival because its nonce is spent. This is the offchain half of name-equivocation defence; the header chain (below) is the other.
- An owner set — a canonical, sorted, deduplicated set of Ed25519 public keys, not a single key. User sovereignty in practice: the registrar and the employer can co-own the employer’s head-checkpoint key, so the employer can evict a dead registrar from its own head key without the registrar’s cooperation.
- A value — opaque bytes, which at the Tenure layer are one of the three records above in canonical domain-tagged form.
Because the sparse Merkle tree’s leaf commits to the whole key state, ownership and replay protection are Merkle-provable under the anchor-signed root — not server bookkeeping a directory could lie about. A served response that misstates the owner set or the nonce fails proof verification client-side.
Updates and authorisation
Section titled “Updates and authorisation”An update replaces the key’s entire state and is signed over a canonical tuple of the key, the nonce, the signing key, the new owner set, and the new value. The directory enforces:
- for an existing key, the signer must be a member of the current owner set, and the nonce must exceed the highest accepted so far;
- for an unclaimed key, first writer claims it — but the claimer must include itself in the new owner set, since a key nobody can update is a key nobody should be able to create;
- the owner set must arrive in canonical form: sorted, deduplicated, non-empty.
Ownership transfer is therefore just an update that rewrites the owner set, signed by a current owner.
Writes may additionally be gated by proof of work when the directory advertises a nonzero difficulty, so that squatting on unclaimed keys and update spam both cost compute. The reference implementation uses BLAKE3-based hashcash; nullspace production uses EquiX with an effort parameter. The seed/solution shape is identical, so the algorithm swap does not change the protocol.
Merkle proofs travel compressed, in the nullspace bitmap form: a 256-bit bitmap marks the siblings that equal the canonical empty-subtree hash at their depth, and those are elided; only the real siblings ship. A sparse tree’s proof drops from roughly 16 KB to well under 100 bytes; the client expands the proof and verifies it against the full 256-level path.
The Tenure namespace, and where Mel fits
Section titled “The Tenure namespace, and where Mel fits”Tenure’s three record types are conventions inside an untyped global key space — the same layering nullspace uses for human-readable usernames. When the directory is replaced by Mel’s Global Namespace, the key-state semantics — ownership sets, nonces, Merkle-committed state — carry over unchanged. What improves is the root of trust: “is this root canonical?” stops being “trust the anchor key” and becomes a light-client check against a public chain, turning equivocation detection into prevention.
The sparse-Merkle hashing is nullspace’s exactly — keyed BLAKE3 with distinct domain keys for data blocks and interior nodes, and zero-collapsed empty subtrees — so the cutover needs no re-hashing migration. This alignment was done while no production directory existed; changing a live directory’s hashing would mean a new genesis and a client resync, which is why it was settled early rather than at cutover.
Trustless reads
Section titled “Trustless reads”The directory commits to its entire state with a sparse Merkle tree keyed by the BLAKE3 hash of the key, and signs a hash-chained header with its anchor key on every update, genesis included. Each header carries a directory identifier, a height, the tree root, the previous header’s hash, and a timestamp.
A read returns the value, a Merkle inclusion or non-membership proof, and the signed head header. The client then:
- verifies the head header is signed by the trusted anchor key;
- syncs the anchor’s header chain into its local light-client store, checking that each header links to the previous one by hash and is anchor-signed — so the served root is provably part of the one append-only sequence, not an invented side state;
- verifies the Merkle proof against that header’s root.
Only then is the value trusted. A wrong anchor, a tampered value, a forged root, or a broken chain link all fail the read.
Non-equivocation of the root
Section titled “Non-equivocation of the root”A signing directory can still sign two different roots at the same height and show them to different clients. Because a directory header has the same stream/sequence/head-hash shape the protocol already uses for signed heads — the directory being the stream, the height the sequence, the root the head hash — two such headers form a portable misbehavior proof that convicts the directory. This is the same machinery that convicts an equivocating registrar, reused rather than reimplemented. The client’s header store detects a conflict at sync time and surfaces the proof.
Witnesses that retain and gossip headers turn this into network-wide detection. Anchoring the root to an external ledger turns “is this root canonical?” into a light-client check, and turns detection into prevention. That anchor is the one remaining place where trust terminates in a provider’s key rather than in canonical state — and the header chain is the seam it plugs into.
Quorum freshness — the suppression gap
Section titled “Quorum freshness — the suppression gap”A non-equivocating signer can still suppress: serve a stale-but-valid root and hide a recent revocation. The proof checks out; the head is just old. The defence is to never take “this is the latest head” on one party’s word. The registrar or employer pushes each new head to several independent witnesses, and a verifier accepts a head only when at least some minimum number of distinct trusted witnesses corroborate it — the accepted head being the highest height-and-root pair that clears that threshold.
No single party — the directory or any one witness — can unilaterally assert the current head: a lone “newer” claim never reaches quorum, and a directory that suppresses by serving an older root is overridden whenever a quorum holds a newer one.
This is input sourcing, not part of the predicate. The quorum decides which head is fed to the pure verifier, so verification stays pure. A witness’s signed head has the same stream/sequence/head-hash shape, so a witness that signs two roots at one height is convictable by the same misbehavior proof as a directory or a registrar. An externally anchored root is the prevention form of the same guarantee: a root that cannot be suppressed because it is on a public ledger.
Scope. Both client implementations verify reads. One performs full header-chain light-client sync plus proof verification; the other verifies the anchor signature on the served header and the compressed Merkle proof against its root for each read. The reference directory server is in-memory with a single anchor, and witnesses are modelled as independent keys that receive pushes — sufficient for rehearsals. A live witness-gossip network and external ledger anchoring are the production forms.
Verifying when the registrar is offline
Section titled “Verifying when the registrar is offline”When a share link’s registrar is unreachable, both the hosted verifier and the self-hosted verify page fall back to the directory:
- Read the employer identifier and the attester key from the bundle.
- Fetch the Employer Record, the Head Checkpoint, and the Attester Record from the directory.
- Run the same pure predicate for chain integrity, and anchor freshness on the directory’s head checkpoint — whose embedded registrar signature proves it is the registrar’s authentic head — instead of a live registrar call.
- The verdict states that the credential was verified against a directory checkpoint at a given time, with the registrar offline.
Discovery across registrar switches
Section titled “Discovery across registrar switches”The Employer Record is owned by the employer key — the one identity that stays constant when an employer switches registrars. The record names the employer’s current registrar. On an epoch transition the employer republishes the record pointing at the new registrar; because the owner set is unchanged, the directory accepts the update.
Resolving an employer identifier to its current registrar’s address and key is a single directory read, available in both client implementations. A verifier or wallet with no cached registrar address uses it to find the registrar for an employer it has never seen before — and after a switch it resolves to the new registrar, without contacting either the old or the new registrar to discover it. See Misbehavior & switching.
Rehearsals
Section titled “Rehearsals”Two end-to-end exercises are run against the reference directory.
The offline-survival rehearsal proves the headline claim: a credential still verifies after the registrar and its mirrors are gone. It starts a reference directory, wires up a registrar, onboards an employer, runs a pay-run, builds a bundle, and verifies it live. It then drops the registrar, deletes the mirrors, and verifies the same bundle again — chain integrity intact, freshness anchored on the directory checkpoint — with no Tenure infrastructure running at all. Each step is reported pass or fail.
The registrar-transition rehearsal prints the directory’s view of an employer’s registrar at each step of a switch, and asserts that a fresh verifier discovers the incoming registrar through the directory alone once the transition completes.
Status
Section titled “Status”The directory is optional and disabled in the current pilot deployment, which runs registrar-only; the machinery described here is built and exercised but not yet switched on in production. The directory server used for demonstrations and rehearsals is a reference implementation with a single anchor key. Replacing that anchor with an external ledger’s light-client root — the step that converts equivocation detection into prevention — remains future work.