Inspiration
Every deal starts with a signal — "I'd trade with you," "I'd hire you," "I'd acquire you." But that first signal is dangerous: the moment your intent leaks, the market front-runs you (MEV), or a one-sided approach becomes public and awkward. Today you either broadcast intent and eat the leak, or trust a middleman. We wanted to remove that trade-off entirely with cryptography.
What it does
- Register an identity: your public key goes on-chain; your intent never does.
- Express interest in a counterparty with a private reveal (terms/contact), encrypted on your device. Only an opaque tag, a nullifier, and ciphertext hit the chain — nothing about who-wants-whom.
- Match: because two parties who point at each other derive the same tag with no communication, their submissions land in the same slot. When both have posted, it unlocks — and only they can decrypt each other's reveal.
- "What the chain saw": a live ledger inspector proving the chain only ever held opaque tags — no identities, no intent.
How we built it
The core is non-interactive ECDH matching tags on Midnight's Jubjub curve. To
signal interest in PK_T, you compute the shared secret s = sk·PK_T inside a
zero-knowledge circuit and disclose only hash(s) (the slot "link"), a
per-direction nullifier, and a client-side-encrypted payload. Diffie–Hellman
(sk_A·PK_B = sk_B·PK_A) guarantees both sides derive the same link with zero
coordination. A Compact smart contract holds the ledger (registry, match slots,
nullifier set); TypeScript witnesses keep the secret key off-chain; the browser and
CLI encrypt payloads with WebCrypto AES-GCM using the same runtime EC primitives
the circuit uses, so off-chain and in-circuit math agree bit-for-bit.
Challenges we ran into
- Compact has no in-circuit encryption — we moved encryption client-side and store a fixed-size opaque blob, keeping the circuit tiny.
- The naive design leaked the target via an on-chain registry check; we removed it after realizing the nullifier alone prevents fake/self matches.
- Midnight's embedded Jubjub scalar field is smaller than the base field — a subtle source of "EmbeddedFr" decode errors until we sized secrets correctly.
Accomplishments we're proud of
A genuinely novel primitive — no prior Midnight project builds a matching/ threshold-reveal escrow — with a full test suite (mutual match, one-sided secrecy, replay + self-match rejection, ECDH cross-decrypt) and a working end-to-end match on a real Midnight node.
What's next
Atomic shielded-swap settlement on match (private intent → private settlement), and the generalization to k-of-n threshold escrow (e.g. multi-accuser whistleblowing: a report surfaces only when several people independently name the same target).
Built With
- compact
- crypto
- docker
- midnight
- react
- typescript
- vite
- zero-knowledge


Log in or sign up for Devpost to join the conversation.