Skip to content

lushdash-sh/fhe-hack-final

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CivicChain FHE — confidential crowd-verification of civic complaints

Anyone can see where problems are and whether they're fixed. What stays secret is the community's verdict: every verification vote is encrypted in the browser, tallied homomorphically on-chain (Fhenix CoFHE), and only a single verified / not-verified boolean is ever revealed. The reporter can't game the process by watching the count, and no server ever holds a raw vote.

What's encrypted, what's not

Data Where Encrypted?
Vote value (yes=1 / no=0) on-chain euint32, encrypted in the browser
Per-complaint tallies on-chain euint32, never decryptable by anyone
Verified status on-chain derived ebool; only this is ever revealed
Voter trust / reputation on-chain euint32, hidden even from the user; only a "trusted?" ebool reaches the authority
Complaint risk / urgency score NLP service (plaintext) ❌ public intelligence — orders the authority queue
Voter / reporter identity wallets pseudonymous, never surfaced as PII
Photo, category, zone, status, reviews off-chain + public metadata ❌ powers the map & analytics

One-line pitch: the NLP layer figures out which problems look urgent; Fhenix privately decides which reports are trustworthy and which verifiers to trust — computed on encrypted data no one can read or game.

Confidential trust (feature 2)

A voter who backs a complaint that the community later verifies earns +1 confidential trust (claimTrust). The award is vote * verified computed in ciphertext, so it only counts a YES vote — but the raw score is never FHE.allow'd to anyone, not even the earner. Only a derived trusted? boolean (trust >= 3) is shared, and only with the authority, which uses it to notify high-trust verifiers first about new issues in their area. See the Authority view's "Trusted verifiers — notification routing" panel.

NLP risk service (feature 5, plaintext)

risk_service/ is a small FastAPI app that scores each complaint's urgency (0..1) from its text + category and flags near-duplicates, ordering the authority queue highest-risk first. It is deliberately separate from the FHE layer — public intelligence, no encryption. Optional: if it's not running, the queue falls back to newest-first and nothing breaks. See risk_service/README.md.

Repo layout

  • contracts/ — Hardhat + @cofhe/hardhat-plugin. CivicComplaints.sol + full test suite (including tests that the tallies are undecryptable and that rigged ballots are clamped homomorphically).
  • frontend/ — Vite + React + Tailwind + wagmi + @cofhe/sdk (browser-side TFHE encryption). Five views: Feed (encrypted voting), Report, My complaints (private unseal of the verified flag), Authority, Analytics.

Quickstart (local, no external services)

# 1. contracts
cd contracts && npm install
npx hardhat test                     # 7 CivicComplaints + 12 Counter tests
npx hardhat node                     # terminal A — auto-deploys CoFHE mocks
npx hardhat run scripts/deploy.ts --network localhost   # terminal B
npx hardhat run scripts/seed.ts   --network localhost   # optional demo data

# 2. frontend
cd ../frontend && npm install
npm run dev                          # http://localhost:5173

The deploy script writes VITE_CONTRACT_ADDRESS into frontend/.env.local automatically. Users connect with MetaMask and are identified only by their wallet address. The authority is the dedicated wallet 0x953D3747B46001764de006dC638115a480C9Bc76 — import that account into MetaMask to use the Authority view (override with AUTHORITY=0x... when running the deploy script). Photos are stored in localStorage unless Supabase is configured (see below).

For wallet-less local testing only, set VITE_DEV_WALLETS=1 in frontend/.env.local to get a dropdown of hardhat dev accounts that the node signs for.

90-second demo

  1. A citizen files a geotagged pothole photo → complaint registered on-chain.
  2. Three other wallets each cast an encrypted yes — expand “Show what the chain stores” to display the ciphertext handles nobody can decrypt.
  3. The reporter → My complaintsCheck status (private)Verified ✓ (“computed from encrypted votes; the tally was never revealed”), then Finalize on-chain.
  4. The authority wallet resolves it with a fixed-area photo → complaint closed.
  5. Analytics: per-area, per-category, open vs resolved, timeline.

Deploy to Arbitrum Sepolia

cd contracts
echo PRIVATE_KEY=0x... > .env        # funded with Arbitrum Sepolia ETH
npx hardhat run scripts/deploy.ts --network arb-sepolia
# frontend/.env.local now has the new address; switch MetaMask to Arb Sepolia

Voting on testnet uses the real CoFHE coprocessor — the flow is identical, the mocks are simply replaced by the live threshold network.

Live deployment

CivicComplaints is deployed on Arbitrum Sepolia at 0x5F400d9C2A6A97AeDD9Ae69bcB37dc10271e1882 (authority 0x953D3747B46001764de006dC638115a480C9Bc76). Connect MetaMask on Arbitrum Sepolia and everything — registration, encrypted votes, trust claims, resolution — is real transactions using Fhenix's live CoFHE coprocessor.

Proof-gated verification

A YES vote requires evidence: the verifier must upload their own geotagged photo of the problem and write a short review. If the complaint has coordinates, the proof photo's EXIF GPS must be within 5 km of the reported spot or the vote is rejected client-side. The vote itself is still encrypted — the proof shows you were there; the ballot stays secret. A NO (dispute) vote needs no proof.

Supabase (shared storage + realtime)

  1. Create a project at supabase.com.
  2. Run supabase/schema.sql in the SQL editor (tables, open demo policies, realtime on reviews, storage policies).
  3. Create a public storage bucket named photos.
  4. Set in frontend/.env.local:
VITE_SUPABASE_URL=https://<project>.supabase.co
VITE_SUPABASE_ANON_KEY=<anon key>

Photos, geo metadata, risk scores, and reviews (with proof photos) then live in Supabase, and new reviews stream to all connected clients in real time. Without these env vars the app falls back to per-browser localStorage.

Contract guarantees (contracts/contracts/CivicComplaints.sol)

  • Votes are clamped to {0,1} with FHE.min — a “999 yes” ballot counts as 1.
  • FHE.allow is never called on yesVotes/totalVotes; the ACL makes them permanently undecryptable (covered by tests).
  • verified = FHE.gte(yesVotes, 3) — recomputed per vote; the reporter gets private view access to this boolean only.
  • The public status flip uses the threshold-network decrypt flow (allowPublic → decryptForTx → publishDecryptResult), so “verified” is provable on-chain without trusting the caller.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages