DEV Community

Hamid Iqbal
Hamid Iqbal

Posted on

Show HN: ZKAuth – Zero-Knowledge identity on Android using Rust + Plonky2 (39ms proofs)

Built a ZK identity system that lets you prove
who you are without revealing any data.

Tech: Rust (Plonky2 v0.2.2) via JNI → Kotlin
Two tiers:

  • Tier 1: NFC passport (ICAO 9303)
  • Tier 3: Android KeyStore + biometric

Benchmarks on Realme RMX3830 (Android 14):

  • Proof: 39ms
  • Verify: 8ms
  • Memory: 78KB
  • Proof size: 20KB

Live demo: zkp-identity-production.up.railway.app

💬 Feedback & Chat:
discord.gg/rXmMh2q2k
Happy to answer questions about circuit
design or Rust-JNI implementation.

Top comments (2)

Collapse
 
arkforge-ceo profile image
ArkForge

The 8ms verify time is the number that matters most for relying parties at scale - at that latency you can verify inline per-request rather than caching session tokens, which eliminates a whole class of replay and session fixation attack surface.

One design question worth thinking through: how do you bind the proof to a specific transaction or session without leaking correlation data across uses? A blinded nonce committed inside the circuit would let the verifier confirm freshness while preserving zero-knowledge - otherwise the same 20KB proof could be replayed across relying parties if it ever leaks.

Also curious whether the Tier 1 (NFC passport) path handles the active authentication step in ICAO 9303, or only passive authentication - the distinction matters for proof binding since passive auth proofs don't prevent cloning from a captured NFC dump.

Collapse
 
hamid_iqbal_75c855b7c8375 profile image
Hamid Iqbal • Edited

Great questions — exactly the threat model
we thought about.

On replay prevention: the proof includes a
Poseidon nullifier scoped to domain +
challenge. Each session generates a fresh
64-byte hex challenge server-side, committed
inside the circuit. The server maintains a
nullifier registry — same nullifier = instant
reject. The 20KB proof is session-bound, not
reusable across relying parties.

On ICAO path: currently passive authentication
only — we verify the SOD signature (RSA/ECDSA)
and DG1 hash chain, but active authentication
(chip private key challenge-response) is on
the roadmap. You're right that passive auth
alone doesn't prevent replay from a captured
NFC dump. Our current mitigation is binding
the passport proof to the device KeyStore key
at generation time — so even a valid DG1 dump
needs the hardware-bound ECDSA sig to complete
the proof. Not a full substitute for active
auth, but raises the bar.

The 8ms verify observation is spot on — that's
exactly why we chose Plonky2's FRI backend over
Groth16. Sub-10ms inline verification was the
design target.

Repo: github.com/Hamid0004/zkp-identity