Privacy-preserving calendar matching app -allows users to identify mutual events in a private manner
MeetPoint is a conference scheduling app allowing users to identify overlapping events with others without disclosing their full calendar or other information.
In the world of conferences, networking events, and community gatherings, attendees often want to connect with specific people but face a coordination problem: how do you find out which events you'll both be at without sharing your entire schedule? MeetPoint solves this privacy-versus-coordination dilemma using cryptographic techniques that reveal only mutual attendance while keeping everything else private.
The Problem
Traditional calendar sharing is all-or-nothing. If you want to coordinate with someone, you typically have to:
For conference attendees, this creates a real barrier to spontaneous meetups and networking. You might want to grab coffee with someone between talks or quickly pitch your project, but you don't want to reveal that you're skipping certain sessions or attending competitor events.
The Solution
MeetPoint uses Private Set Intersection (PSI) - a cryptographic protocol that allows two parties to discover which items they have in common without revealing their non-matching items. When you and a peer want to find mutual events:
The entire process happens in your browser. No calendar data is ever sent to a server. The matching is peer-to-peer through a lightweight signaling mechanism.
Key Features:
Privacy-Preserving Matching The core innovation is the ECDH-based PSI protocol. Each event UID is "blinded" using elliptic curve cryptography (secp256k1, the same curve used in Bitcoin and Ethereum). Through a three-step handshake: a) Alice blinds her events with her secret key b) Bob double-blinds Alice's events and sends his own blinded events c) Alice double-blinds Bob's events d) Both parties compare the double-blinded values to find matches Because of the commutative property of elliptic curve multiplication, matching items produce identical blinded values, while non-matching items remain indistinguishable random points on the curve.
Web3 Identity with ENS Instead of traditional usernames and passwords, MeetPoint uses Ethereum wallets for identity. Users connect with MetaMask, Brave Wallet, or any Web3 wallet, and their ENS name (if they have one) is automatically resolved and displayed. This provides:
Every sensitive operation happens in your browser:
The only server-side components are:
Built with Next.js 15 and Tailwind CSS, MeetPoint features:
Use Cases
Privacy Guarantees
MeetPoint provides strong privacy guarantees based on well-established cryptographic assumptions:
The security relies on the hardness of the Discrete Logarithm Problem on the secp256k1 elliptic curve - the same assumption that secures billions of dollars in cryptocurrency.
What Makes This Special
Unlike existing calendar tools that require full access to your calendar or centralized coordination platforms that store your data, MeetPoint achieves the seemingly impossible: letting you coordinate with others while keeping your schedule private. It's calendar sharing without the sharing.
The combination of cryptographic privacy, Web3 identity, and a polished user experience makes MeetPoint uniquely positioned at the intersection of privacy tech and practical utility. It's not just a proof-of-concept - it's a fully functional app deployed at https://meetpoint-zeta.vercel.app/ that you can use today.
I have used Antigravity to kick off the project, which helped me rapidly iterate on both the cryptographic implementation and the UI/UX early on. This left me with more time to work on the solution design as well.
Tech Stack Next.js 15 powers the frontend with the App Router. All sensitive operations stay strictly client-side while leveraging server components for the public-facing parts.
Wagmi + Viem + RainbowKit handle Web3 integration. Wagmi provides React hooks for wallet interactions, Viem handles Ethereum operations with TypeScript-first design, and RainbowKit delivers the wallet connection modal. ENS integration was straightforward using Wagmi's built-in hooks. Testing with the use of the faucet was smooth as well.
@noble/curves + Web Crypto API power the cryptography. The PSI protocol uses @noble/curves for secp256k1 elliptic curve operations. For encrypted notes, I used the browser's native Web Crypto API with AES-GCM for authenticated encryption.
ical.js parses Lu.ma's ICS calendar feeds, converting them into JavaScript objects to extract event UIDs and metadata.
Tailwind CSS creates the dark mode glassmorphism aesthetic with minimal effort.
Architecture The PSI Protocol is the heart of the app. Event UIDs are hashed to curve points, then blinded with each user's private key. Through a three-step handshake (initiator sends blinded events -> joiner double-blinds and sends their own -> initiator double-blinds joiner's set), both parties end up with matching double-blinded values for shared events. The commutative property of elliptic curve multiplication makes this work.
Signaling API uses Next.js API routes with in-memory storage. It's intentionally ephemeral - sessions exist only in RAM and disappear on restart. This is a feature, not a bug: no persistent storage means no data retention concerns.
Client-Side State Management handles a complex state machine (IDLE -> CREATED -> EXCHANGING -> COMPUTING -> RESULTS) with message polling every 2 seconds. React's useCallback prevents unnecessary re-renders while keeping state fresh.
Notable Hacks CORS Proxy: Lu.ma's ICS feeds lack CORS headers, so I built a Next.js API route that proxies requests server-side and forwards them to the client.
Hash-to-Curve Simplification: Proper hash-to-curve for secp256k1 is complex. For this MVP, I treat the SHA-256 hash as a private key and generate the corresponding public key point. Not textbook-perfect, but works great for high-entropy UIDs.
Hydration Fixes: Next.js 15's SSR caused hydration mismatches with wallet state. Solution: a mounted state flag that ensures wallet-dependent UI only renders client-side.
TypeScript Type Wrangling: Web Crypto API expects BufferSource, but @noble/hashes returns Uint8Array. Had to add type assertions to satisfy both.
Past Event Filtering: Last-minute addition to filter out past events so only upcoming events are matched. Simple but impactful for UX.
Deployment Deployed on Vercel with automatic deployments from GitHub. Zero configuration - it auto-detects Next.js and handles build, deploy, and CDN distribution.
Trade-offs For production, I'd implement proper hash-to-curve (RFC 9380), add a solution for persistent sessions, implement message deduplication, add rate limiting, support more calendar providers, and get a formal security audit.
But for a hackathon MVP, this stack hit the sweet spot of "cryptographically sound enough" and "ships fast enough." With the app in its current state I'll be able to test the usability and the product-market fit.
It's live at https://meetpoint-zeta.vercel.app/ and is already being tested.

