You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Anonymous identity and DAO voting — log in to sites and vote on proposals without revealing your identity. Built on U2SSO (User-issued Unlinkable Single Sign-On) from ePrint 2025/618.
The Core Idea
You create a secret only you know (Semaphore identity + r)
You derive public values that prove you know it, without revealing it
Commitments live on-chain (Solidity); backend verifies proofs and stores registrations
What Each Side Knows
Who
What they know
You (browser)
Semaphore identity and r — secrets only you have
IdR (blockchain)
Commitments only — no secrets
Backend
ZK proof, nullifier, pseudonym — never your identity
Step-by-Step Flow
Phase 1: Create identity (Home page)
You (browser): Create Semaphore Identity + bootstrap seed
You (browser): POST /registry/register for both commitments
Backend: Calls IdR contract addCommitment() — stores on-chain
You (browser): Store identity, r in localStorage
Phase 2: Register with a site (one-time per SP)
You (browser): GET /registry/group → fetches commitments from IdR contract
You (browser): Build Semaphore Group, generate ZK proof (membership + nullifier for sp_id)
You (browser): Derive cskl = HKDF(r, sp_id), ϕ = Ed25519 public key
You (browser): POST /verify/register (ϕ, nullifier_hash, proof, merkle_root)
Backend: Verifies ZK proof, stores (pseudonym, nullifier) in PostgreSQL
Phase 3: Login (subsequent visits)
You (browser): GET /verify/auth/challenge (sp_id, pseudonym)
You (browser): Sign challenge with cskl (Ed25519)
You (browser): POST /verify/auth (ϕ, challenge, signature)
Backend: Verifies Ed25519; no ZK proof needed
Phase 4: DAO Voting
You (browser): GET /dao/proposals → list proposals from DAOVoting contract
You (browser): Generate ZK proof (scope=proposalId, message=voteChoice)
You (browser): POST /dao/vote (proposal_id, vote_choice, proof, nullifier_hash, merkle_root)
Backend: Verifies proof, checks nullifier in dao_votes, relays to castVote()