No description
  • TypeScript 87.2%
  • Solidity 9.1%
  • CSS 1.9%
  • JavaScript 1.4%
  • Dockerfile 0.2%
  • Other 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
tim 89d2edf251
All checks were successful
ci / docker (push) Successful in 6s
ci / e2e (push) Successful in 5m36s
ci / check (push) Successful in 10m56s
docs(world): a stray period after item 12's title
- Fixed Bug in docs/selfie-check-feedback.md: "two apps?." reads "two apps?"
2026-09-13 17:57:38 +02:00
.github/workflows fix(ci): the contracts tests run without the runner's REGISTRY variable, on stable forge 2026-09-13 08:29:05 +02:00
.issues/closed feat(graph): the reference graph, read from chain, with its shape and a sybil rank 2026-09-12 04:01:31 +02:00
apps fix(api): the audit's findings on today's changes: withdrawals, org vouches, the unlink's reach and its error path 2026-09-13 16:25:41 +02:00
docs docs(world): a stray period after item 12's title 2026-09-13 17:57:38 +02:00
packages docs: the Chainlink Confidential Workflow is laid out criterion by criterion for the judges 2026-09-13 15:51:17 +02:00
scripts fix(ci): a suite that exists is a suite that runs 2026-09-11 23:44:06 +02:00
.env.example feat(humanity): verify World ID proofs and write them into the humanity domain 2026-09-10 11:31:56 +02:00
.gitignore fix(humanity): the voucher step claims what a proof shows, not a guarantee it may not carry 2026-09-10 11:44:56 +02:00
.gitmodules feat: scaffold attestation registrar, ENSv2 instance contracts, monorepo 2026-09-08 10:39:54 +02:00
AGENTS.md Created initial scaffold 2026-09-06 20:45:26 +08:00
CONTRIBUTING.md feat(references): read what references say via the Noolog fast council; invite the pageless to pass a policy 2026-09-12 05:51:28 +02:00
package.json feat(repo): one command runs what CI runs 2026-09-10 22:45:04 +02:00
pnpm-lock.yaml feat(humanity): verify World ID proofs and write them into the humanity domain 2026-09-10 11:31:56 +02:00
pnpm-workspace.yaml feat: web app after the noolog template, nonce endpoint, Coolify deploy corrections 2026-09-08 11:46:10 +02:00
README.md feat(api): SybilScore conserves trust, weighs each vouch by its reading, and stops after log n hops 2026-09-13 16:01:08 +02:00
TODO.md feat(web): every employer message is the invitation; each reference carries its reading; unsolicited can be set aside 2026-09-12 09:48:32 +02:00
tsconfig.base.json feat: scaffold attestation registrar, ENSv2 instance contracts, monorepo 2026-09-08 10:39:54 +02:00

ShibbolETH

A reference letter that cannot be deleted, and that a reader can check without asking us. Somebody who has proved they are one real person writes a letter for you; it becomes an ENS name under shibboleth.eth, and whoever is considering you reads it against their own policy.

Key features

  • Non-permissioned. Anyone writes a letter for anyone; an uninvited one is published and marked solicited: false. architecture.md
  • Policy driven. Questions are domains, answers are names; an employer's bar travels in the invite link. employers.md
  • Sybil protected. World ID Selfie Check seeds a SybilScore over the vouch graph, trust conserved after SybilRank: a farm behind one proved human holds what one account would. architecture.md
  • Privacy and tamper-proof. The attester is a Chainlink CRE Confidential Workflow: identity token and keys stay in the enclave, a registrar-signed record leaves it. Below
  • View codes. A private account is a masked name plus a commitment; the holder decides who can open it. disclosure.md
  • Permanent names. Records are on chain, expiry is enforced at resolution, a withdrawn letter stays readable as withdrawn.

The registrar of every record is a CRE workflow running in a Nitro enclave. What the prize track asks for, and where it is:

Criterion Here Where
A meaningful part of the app runs as a Confidential Workflow Every record is signed inside the enclave: it verifies the Privy identity token and the wallet's intent, derives the masked name and view code, signs as registrar workflow.ts onAttest
A registered TEE handler Two: onAttest and onDisclose, registered with cre.handlerInTee(http.trigger(), …, [{ tee: "nitro" }]) workflow.ts initWorkflow
Sensitive inputs processed inside the enclave The identity token (never leaves), the registrar key and the view-code key (runtime.getSecret), the view-code preimage; only a chain read and the signed record cross to the DON (runtime.usingTheDons()) same file, onAttest / onDisclose
Evidence of execution Simulated with cre workflow simulate --broadcast: the DON write went through the MockKeystoneForwarder to AttestationReporterAttestationBridge → Multipass on Sepolia. Public record 0x71b7edd5…, masked record 0x6af38a23… packages/cre/README.md

Why it matters here: the relay never holds the registrar key or sees an identity token, and a reader can check every record against the registrar's signature on chain. Where the enclave is not deployed (the CRE account has no deploy access yet) the same code signs on this deployment's own node, and the portal says which of the two it is doing. Full walk-through, the 30 handler tests against a fake TEE runtime, and the deploy order: packages/cre/README.md.

Stack

flowchart LR
  subgraph People
    WEB[portal]
    ENS[any ENS client]
  end
  subgraph Identity
    PRIVY[Privy]
    WORLD[World ID]
  end
  subgraph Attestation
    CRE[Chainlink CRE<br/>confidential]
    RELAY[relay API]
  end
  subgraph ENSv2
    UR[Universal Resolver]
    RAR[RootAttestationResolver]
  end
  MP[(Multipass)]
  PRIVY & WORLD -.-> WEB
  WEB ==>|signed intent| CRE ==>|signed record| RELAY ==> MP
  ENS ==>|read| UR ==> RAR ==> MP

Write: the person signs an intent, the enclave signs the record as registrar, the relay pays gas and registers it in Multipass. Read: any ENS client asks the Universal Resolver, which reaches RootAttestationResolver through shibboleth.eth. Full diagram: architecture.md.

What it adds to ENSv2

One wildcard resolver answers the whole tree, so a person, a letter, an answer and a platform account are all paths under shibboleth.eth with no per-name registration. Accounts are findable at their own DNS name (iampeersky.com.x.www.shibboleth.eth), and a private one resolves as the holder's label only until a view code opens it. namespace.md

Run it locally

pnpm install
pnpm --filter "./packages/**" run build      # needs foundry
cp .env.example .env
cp apps/web/.env.example apps/web/.env.local
pnpm --filter @ketsuban/api dev              # http://127.0.0.1:8787
pnpm --filter @ketsuban/web dev              # http://localhost:3000
pnpm verify                                  # what CI runs

Docs

Sepolia

Address
RootAttestationResolver 0x542012eCb66De81CBd5De2E2952254c0e84a9447
Multipass 0x418F82fd0014a4CA402F145978bfaF0555a9cA06
AttestationBridge 0xE5e985B5f152EbD07aF9922d564AA8A7ccB77c62
ENSv2 UniversalResolver 0x4A1817d13E9cF196f471725176355C1234b63C70

License

MIT