Work / Bharat-First / Bharat eVote
Capstone · Bharat-First · Civic Tech
A sealed ballot.
A public Merkle root.
Every vote auditable.
भारत eVote · for an Indian election
A remote, auditable, accessible voting system for Indian elections. The application, the cryptographic audit log, the project report and the pitch deck all run from a single Cloud Run container, sized for a 1 GB-RAM phone on 3G.
Act I · The Crisis
A vote you cannot verify
is a vote you cannot trust.
-
Pain · 01
Remote voting is not the same as online voting.
The migrant worker, the deployed soldier, the student on exam day. Indian elections still ask them to be in their constituency on a Tuesday. The country is overdue a remote primitive that an Election Commission could actually trust.
-
Pain · 02
"Trust me, I am the server" is the wrong answer.
An election cannot rest on the operator's good intentions. A ballot has to be sealed before it is cast, the audit log has to be append-only, and the public has to be able to verify the count without trusting the counter.
-
Pain · 03
The crypto has to survive the next twenty years.
A 2026 ballot system that ships only AES and X25519 will be reading harvested ciphertext through a quantum lens by 2040. The contract has to slot ML-KEM-768 in without rewriting the protocol.
-
Pain · 04
Accessibility is a constitutional question.
If the voting tool will not open on a 1 GB-RAM phone, on 3G, in two languages, with screen-reader support, a disenfranchisement is being built into the platform. WCAG 2.2 from the first commit, not the last.
Act II · The Promise
Seal the ballot. Hash the ciphertext. Publish the root.
Every cast vote becomes a leaf. Every leaf hashes upward into a tree. Every observer can fetch the public root from /audit.html and prove their ballot is in the count, without revealing their choice. The voter ↔ ballot link is blinded before storage.
Act III · The Trail
A public log every observer can replay.
The admin console exposes a SIEM-style log feed at /admin.html and a public audit page at /audit.html. PII never enters logs. Voter IDs are masked before any OTP-issuance line is written.
Act IV · The Flow
Six phases. Five gates. One container.
-
Phase 01
Voter identifies.
Voter ID + OTP at
/auth.html. Voter IDs are masked in every log line. In demo mode the OTP returns in the response so reviewers can complete the flow without an SMS gateway; production is gated behindNODE_ENV. -
Phase 02
Session starts.
Short-lived session, blinded link to the ballot box. Voter ↔ ballot mapping never leaves memory. Server holds the roll, the session table, and the ballot box in three separate compartments.
-
Phase 03
Ballot seals.
AES-256-GCM under HKDF-SHA-256 derived key. The symmetric leg is structured to slot a future ML-KEM-768 + X25519 hybrid in place without changing the protocol surface.
-
Phase 04
Leaf appends.
SHA-256 of the ciphertext appends to the Merkle log. The new root is computed, published, and pinned to the audit page. Append-only by construction.
-
Phase 05
Tally runs.
Live tally at
/results.html· by party, seats, constituency. Counted without unsealing individual ballots wherever the tally permits. -
Phase 06
Public audits.
/audit.htmlexposes the current root and a tail of leaf hashes. Observers can verify any ballot's inclusion without learning the choice it carries.
Act V · Proof
It already runs. One image. Free tier.
Live · Cloud Run · asia-east1
bharat-evote.dmj.one
Express bootstrap. Min instances 0, max 10. 512 MiB RAM. CNAME to ghs.googlehosted.com on Cloudflare DNS-only. scripts/deploy.sh wraps the same command and prints the URL.
Public Merkle root
/audit.html · GET /v1/audit/root
Append-only ballot tree. Root + ciphertext tail visible to any observer. The election is verifiable without unsealing the votes.
Pitch deck and report · in-container
/pitch · /report
25-slide web deck (←/→ keys) and the capstone report (DOCX + Markdown export) served from the same Express service as the app. One image, every artifact.
Zero client npm dependencies
public/js · vanilla
Static UI is hand-written HTML, CSS and vanilla JavaScript. Service worker and manifest ship a PWA-ready install. Slow phones load fast.
Hybrid PQ-ready crypto
src/crypto.js
AES-256-GCM today, structured for ML-KEM-768 + X25519 hybrid plus ML-DSA-65 Merkle-root signatures (report §11.2). The protocol surface does not change.
SIEM-style admin console
/admin.html
Phase control, structured JSON log, ring buffer, in-memory store you can swap for Cloud Spanner behind the same interface. Reviewers replay the entire election without setup.
The Stack
One container. Every artifact.
- Node.js 22
- Express
- AES-256-GCM
- HKDF-SHA-256
- SHA-256 Merkle
- ML-KEM-768 (planned)
- ML-DSA-65 (planned)
- Cloud Run
- Cloud Build
- Cloudflare DNS
- Service Worker · PWA
- Vanilla HTML / CSS / JS
- i18n EN / हिन्दी
Need a partner who can ship · or a mentor who can guide a team to ship the same way?
An election is the highest-stakes UX in the country. The same posture · sealed inputs, public audit, accessible from line one · works for any application where trust has to be earned in code.