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

Privacy

Privacy in Tenure is structural, not policy. The two load-bearing mechanisms: after mint, no plaintext claim values exist registrar-side (derive-then-purge), and worker keys are per-employer so cross-employer correlation is impossible by construction. This page describes the data split and the honest limits of each promise.

The data split

VisibilityData
PublicSigned log heads, checkpoints, the epoch chain, delegation existence (type-level only), revocation commitments (BLAKE3(attestation_id)), and KYB attestations. Employer identity is public; workers never are.
Authorized-onlyClaim payloads, the subject↔employer mapping, and share contents — visible to the employer, the subject, grant audiences, and authorized auditors
Holder-heldInclusion receipts — witnessing without publishing the employment graph

A revocation commitment is BLAKE3(attestation_id): a grant holder who knows the attestation_id can check whether it is revoked, but the commitment is unlinkable to anyone who doesn’t.

Derive-then-purge

The registrar must see exact values at mint — it derives the band and threshold variants of a claim family from the exact figure. The moment that is done, it purges the plaintext, retaining only:

  1. subject-encrypted blobs — the claim payloads sealed to the worker’s key,
  2. a recovery escrow exactly as strong as the descriptor’s recovery policy (no stronger), and
  3. commitments.

“Encrypted at rest with registrar-held keys” was the earlier posture and is explicitly rejected: it protects against disk theft, not against compromise or legal compulsion. Derive-then-purge means a compromised or compelled registrar has no plaintext to give up. The further hardening — the employer encrypts before submission, so the registrar never sees plaintext at all, and recovery becomes employer re-furnish — is a later commit-only storage path.

Per-employer keys

A worker has a fresh Ed25519 keypair per employer, generated silently when they claim a wallet. This is the privacy spine:

  • there is no key that links a worker’s records across two employers;
  • bundles are sealed to their audience;
  • nothing about a worker is publicly enumerable.

Because correlation is impossible at the key layer, the product never aggregates, scores, or hints that two employers’ statements corroborate each other — triangulation is impossible by design, and the design leans into that.

Disclosure is consented, logged, and decaying

  • Consented. A disclosure happens only when the worker signs a ShareGrant. The wallet shows a preview of exactly what the verifier will see before the grant is signed.
  • Logged. Every fetch the registrar serves — link opens, bundle downloads, portal verifications — lands in the worker-visible access log. This is fetch-scoped: what happens after the bytes leave (screenshots, a saved bundle, the self-hosted page) is governed by grant terms and verifier policy — contract, not cryptography, and labeled as such in the UI. The self-hosted verify page structurally cannot feed the access log, and the protocol names which promise covers which event class rather than pretending both are absolute.
  • Decaying. Revoking a grant stops future access through Tenure and makes already-saved copies fail re-verification: past the freshness window a saved bundle reads StaleHead, not Verified. It does not delete copies already viewed or downloaded, and the copy says exactly that.

Monitoring carries no values

A scope = monitor grant lets a verifier receive event classes onlyemployment_status_changed, attestation_superseded, grant_revoked — never new claim values. This is enforced at the type level: the monitoring event enum has no fields, so a push cannot carry a value. Learning what changed requires a fresh share the worker consents to. Consent duration lives inside the grant, and the consent copy is verbatim and explicit, including that revoking “may affect your application.”