Inspiration

Every time someone opens a bank account, exchanges crypto, or rents an apartment, they submit their passport again, to yet another company that will store it indefinitely. KYC compliance is necessary, but its current implementation is wasteful, privacy-invasive, and exclusionary.

We asked: what if identity verification was shared infrastructure? Verify once, prove anything, share nothing.

What it does

Sauron is a privacy-preserving identity layer. Users complete KYC once, submitting an ID document and a selfie, and receive a cryptographic identity they fully control. They can then prove identity attributes (age, nationality, document validity) to any connected service, without re-submitting documents and without revealing more than strictly necessary.

Two modes for service providers:

  • Full KYC: regulated services (banks, exchanges) query verified user data on demand, consuming a token
  • ZKP-only: services that only need attribute proofs (e.g. age ≥ 18, nationality = FRA) get exactly that. The raw data never leaves the system.

Anti-double-spending is enforced cryptographically: every token is burned on use, and the key image mechanism prevents the same identity from being registered twice.

How we built it

Sauron is a 4-service stack:

  • Rust (Axum 0.8.8, Tokio 1.49): core API and all cryptographic logic
  • Python (FastAPI + Gemini 2.5 Flash): KYC pipeline; document scanning, structured field extraction, and face matching
  • Next.js / React: admin dashboard, site partner interface, user onboarding flow
  • Docker Compose: full local orchestration

The cryptographic layer is implemented from scratch on Ristretto255 (curve25519-dalek 4.1.3):

  • OPRF (Oblivious Pseudo-Random Function): derives a deterministic identity from email + password without the server ever seeing either
  • Ring signatures: proves a user belongs to a group without revealing which member they are
  • Key image: secret × H(public_point) ; enables server-side lookup while preserving anonymity

The KYC pipeline uses Gemini 2.5 Flash for two multimodal tasks: extracting structured fields from identity documents (name, DOB, nationality, document number, expiry) and matching the document portrait against a live selfie, returning a confidence score and pass/review/fail decision.

Challenges we ran into

Crypto from scratch under time pressure. Implementing production-grade ring signatures and OPRF on Ristretto255 in Rust during a hackathon is unforgiving every bug in the cryptographic layer fails silently or produces subtly wrong outputs. Getting sign/verify to close correctly took multiple rounds of debugging.

Bridging server-side crypto and the browser. Ristretto255 is not natively available in JavaScript, so we built server-side /dev endpoints as scaffolding to let the frontend participate in the protocol without shipping a full crypto library to the client.

Making infrastructure feel like a product. We're building middleware, the value is invisible by nature. Designing the demo flow to make anonymous proofs visible and understandable required deliberate UX choices.

Accomplishments that we're proud of

  • A complete, working ring signature implementation in Rust, with unit tests that cover the full sign → verify loop
  • A functional end-to-end flow: document scan → OPRF key derivation → ring membership → anonymous attribute proof, all running live
  • Gemini 2.0 Flash doing real multimodal KYC in under 2 seconds per check

What we learned

Cryptographic protocols are notoriously hard to debug because incorrect implementations don't always produce obvious errors, they produce plausible-looking wrong answers. We learned to write unit tests for each primitive in isolation (OPRF determinism, key image consistency, ring closure) before composing them.

We also learned that the hardest part of building privacy-preserving systems is not the math, it's making the guarantees legible to non-cryptographers.

What's next for Sauron

  • Client-side crypto: ship a WASM Ristretto255 library so the browser participates directly in the OPRF and ring signing without server-side scaffolding
  • Real blind signatures: replace the current token scheme with a proper blind signature protocol
  • Regulatory alignment: map the ZKP-only mode to eIDAS 2.0 / EU Digital Identity Wallet requirements
  • SDK for financial services: let any regulated institution integrate Sauron with 3 API calls

Built With

Share this project:

Updates