Skip to main content

ZK Identity System

The ZK Identity System provides a privacy-preserving way to attest to an identity (e.g., verifying you are a Github user) without revealing the specific identity or linking multiple actions to the same user. It uses Zero-Knowledge Proofs (ZK-SNARKs) to guarantee:
  1. Privacy: No one knows which user performed an action.
  2. Uniqueness: A user cannot double-spend an action in the same context (via Nullifiers).
  3. Soundness: Mathematical proof of validity.

Core Concepts

Commitment

Poseidon(provider_id, secret) A cryptographic commitment to an identity, stored on-chain in a Merkle Tree. It hides the user’s ID and secret.

Nullifier

Poseidon(provider_id, context) A unique hash generated for a specific action (context). Prevents double-spending while maintaining anonymity.

Merkle Tree

A valid commitment must exist in the global Merkle Tree. The ZK proof verifies inclusion in this tree.

ZK Proof

A Groth16 proof that asserts: β€œI know a secret corresponding to a commitment in the Merkle Tree, and here is my unique nullifier for this context.”

Architecture Overview

The system operates in a Two-Phase Flow:
1

Generate Secret

User generates a random secret locally. This never leaves their device.
2

Create Commitment

User calculates commitment: Hash(provider_id, secret).
3

Submit to Chain

User submits the commitment to the blockchain via an identity_commitment transaction.
4

Merkle Update

Validators verify the transaction and add the commitment to the global Merkle Tree.

Phase 2: Prove Ownership (Repeatable)

When a user wants to perform an action (e.g., vote, claim airdrop) anonymously:
1

Generate Proof

User uses their secret and the current Merkle path to generate a ZK proof locally.
2

Calculate Nullifier

User calculates a nullifier based on the action context: Hash(provider_id, context).
3

Submit Attestation

User submits identity_attestation transaction with the proof and nullifier.
4

Verification

Validators verify the proof against the current Merkle root and checking if the nullifier has been used before.

Privacy Model

ComponentVisibilityDescription
Provider IDπŸ”’ PrivateHidden inside commitment and ZK proof
User SecretπŸ”’ PrivateKnown only to user, never transmitted
Commitment🌍 PublicVisible on-chain, but opaque
Nullifier🌍 PublicVisible on-chain, used for uniqueness check
Context🌍 PublicThe specific action being performed

Security Guarantees

  • Anonymity Set: All users across all providers in the Merkle Tree.
  • Unlinkability: No link between the commitment (Phase 1) and the attestation (Phase 2).
  • Double-Spend Protection: The nullifier guarantees a user can only act once per context.