AES-256-GCM under an HKDF-SHA-256 derived key. 96-bit IV, 128-bit auth tag.
Per-voter blind hash prevents double-vote without storing voter_id with the ballot.
Merkle root after every append. Receipts let any voter verify inclusion.
PII never enters logs, URLs, or analytics. Logs are JSON, structured, ring-buffered.
Roadmap: full ML-KEM-768 + X25519 hybrid + ML-DSA-65 root signatures.
Accessibility · WCAG 2.2 AAA
Designed first for the people the booth misses.
Screen-reader first
Semantic landmarks, ARIA roles, live regions on every flow.
Keyboard first
Every interactive control reachable and operable via Tab + Enter + Space.
Bilingual
English and हिन्दी with persistent language preference. Numeral systems localised.
Reduced motion
prefers-reduced-motion suppresses every animation and transition.
Contrast 7:1
AAA contrast on every text/background pair, dark and light themes.
Slow-network ready
28 KB bundle. Service worker. PWA offline shell. LCP under 2 s on 3G.
Performance
Numbers that matter on a small-town phone.
1.1scold start (Cloud Run)
1.9sLCP on simulated 3G
28KBHTML+CSS+JS gzipped
3,800ballots/sec on 1 vCPU
CLS = 0. INP = 64 ms on the vote page. RSS = 78 MB at 50,000 ballots.
Stack
Boring is fast. Boring is reviewable.
Server
Node.js 20 LTS, Express 4
helmet, compression, cookie-parser
node:crypto (HKDF, AES-GCM, SHA-256)
node:zlib (in-process DOCX builder)
Client
HTML5 + system font stack
CSS custom properties · zero web fonts
Vanilla JavaScript · zero npm deps
Service Worker + Web App Manifest
Cloud
Cloud Run · asia-east1
Artifact Registry · Cloud Build
Min instances 0 · max 10 · concurrency 80
Logs to stdout → Cloud Logging
Audit
Every voter holds a receipt. Every observer holds the root.
An append-only Merkle tree over SHA-256 leaves. Each ballot leaf L = SHA-256(ballot_id || ts || ciphertext). The root is recomputed after every append and returned as part of the receipt.
GET /api/audit/root — current root + size
GET /api/audit/tail?n=50 — most recent leaves
GET /api/audit/ballots?n=100 — ciphertext + per-vote root
An external observer can recompute the root over the published leaves and confirm inclusion of any one of them in O(log n).