Privacy-Preserving Zero-Knowledge KYC for Algorand
Prove identity without revealing it. Zero-Knowledge KYC infrastructure built natively for the Algorand blockchain.
Ciphera solves the fundamental Web3 dilemma β How do protocols prevent Sybil attacks and comply with regulations while maintaining the absolute privacy of their users?
Using Groth16 zk-SNARKs, ECIES Encryption, and Shamir Secret Sharing, Ciphera creates a decentralized, privacy-first identity standard for Algorand. Users prove they hold a valid government-issued ID and meet specific criteria (e.g., age β₯ 18, Indian citizen) without ever revealing personal data, biometrics, or addresses β on-chain or off-chain.
Modern Web3 protocols (DeFi, RWAs, DAOs) face a regulatory trilemma:
| Challenge | Description |
|---|---|
| Compliance vs Privacy | KYC regulations require identity verification, but storing raw identity data on-chain risks breaches and doxxing |
| Sybil Attacks vs Anonymity | Airdrops and quadratic voting are constantly gamed by bot farms β identifying unique humans without stripping pseudonymity has been impossible |
| Data Minimization | DPDP (India), GDPR (EU) demand minimal PII collection β storing identity hashes on an immutable ledger violates this permanently |
| Step | What Happens | Privacy Guarantee |
|---|---|---|
| 1. Import XML | User loads their government-signed Aadhaar XML directly in the browser | Raw data never leaves the device |
| 2. Generate ZK Proof | Circom/Groth16 circuit proves the signature is valid and user meets criteria | Private inputs destroyed after proof |
| 3. Nullifier | Circuit outputs a unique hash tied to the user's ID + dApp | 1 Human = 1 Wallet per dApp (Sybil resistant) |
| 4. On-Chain Registry | Algorand smart contracts verify the proof and store the nullifier | No PII ever reaches the chain |
| 5. Soulbound ASA | User receives a non-transferable "KYC Verified" token | Cryptographically bound to their wallet |
| 6. Court-Order Safety Net | ECIES-encrypted backup only decryptable via 3-of-5 custodian multisig | Privacy preserved even against insider threats |
Ciphera is composed of four cleanly separated microservices:
| Component | Tech Stack | Purpose |
|---|---|---|
widget/ |
React + Vite + snarkjs | Drop-in UI for users to upload Aadhaar and generate ZK proofs |
dashboard/ |
React + Vite | Custodian management panel |
backend/ |
FastAPI + Python | Off-chain relayer, ECIES broker, Shamir SSS |
Ciphera-kyc/ |
PuyaPy + AlgoKit | Algorand smart contracts (NullifierRegistry, CredentialManager, SMT) |
sdk/ |
TypeScript | ciphera-sdk npm package for JS/TS developers |
python-sdk/ |
Python | ciphera PyPI package for Python developers |
projects/circuits/ |
Circom + snarkjs | ZK circuit β prove KYC validity with PLONK proofs |
sequenceDiagram
participant User as π€ User (Browser)
participant Widget as Ciphera Widget
participant Circuit as βοΈ ZK Circuit (WASM)
participant Backend as π₯οΈ FastAPI Relayer
participant Algo as βοΈ Algorand (PuyaPy)
User->>Widget: Upload Aadhaar XML & Wallet Secret
Widget->>Circuit: Generate Groth16 Proof (in-browser)
note over Circuit: Proves validity of ID & generates Nullifier
Circuit-->>Widget: Returns ZK Proof & Nullifier
Widget->>Widget: ECIES Encrypt raw ID data (for Custodian threshold)
Widget->>Backend: Submit Proof, Nullifier, Encrypted Blob
Backend->>Backend: Verify ZK Proof (snarkjs)
Backend->>Algo: Invoke NullifierRegistry.register()
note over Algo: Verifies uniqueness, stores Box
Backend->>Algo: Invoke CredentialManager.issue()
Algo-->>User: Mints "KYC Verified" Soulbound Token
All core contracts are live. View transactions and box storage on Lora Explorer:
| Contract | App ID | Explorer | Purpose |
|---|---|---|---|
| NullifierRegistry | 756272073 |
View β | Stores unique ZK nullifiers in Box storage β prevents Sybil attacks |
| SMT Registry | 756272075 |
View β | Sparse Merkle Tree root for revoked credentials |
| KYC Box Storage | 756272299 |
View β | ECIES-encrypted payloads gated by issuer logic |
| Credential Manager | 756281076 |
View β | Core controller interfacing with the ASA |
| KYCRED ASA | 756281102 |
View β | Soulbound, non-transferable KYC Verified token |
# JavaScript / TypeScript
npm install ciphera-sdk
# Python
pip install cipheraJavaScript Quick Start:
import { CipheraClient } from 'ciphera-sdk';
const client = new CipheraClient();
const status = await client.verifyKYC(userWalletAddress);
if (status.isVerified) { /* grant access */ }Python Quick Start:
from ciphera import CipheraClient
client = CipheraClient()
status = client.verify_kyc(wallet_address)
print(status.is_verified)Prerequisites: Docker, AlgoKit, Node.js 18+, Python 3.12+
# 1. Clone & bootstrap
git clone https://github.com/Aditya060806/Ciphera.git
cd Ciphera/Ciphera-kyc/projects/Ciphera-kyc
algokit bootstrap all
# 2. Start local Algorand network
algokit localnet start
# 3. Deploy smart contracts
algokit project run build
algokit project deploy localnetStart all services (3 terminals):
# Terminal 1 β Widget (User-facing)
cd widget && npm install && npm run dev
# Terminal 2 β Dashboard (Custodian)
cd dashboard && npm install && npm run dev
# Terminal 3 β Backend API
cd backend
pip install -r requirements.txt
uvicorn main:app --reload --port 8000One of the hardest engineering challenges is standardizing ECIES payloads between browser JavaScript and server Python:
| Challenge | Solution |
|---|---|
| Shared Point Derivation | eciesjs uses the full 65-byte uncompressed point; Python's cryptography library uses only the X coordinate. Ciphera manually intercepts and applies the full point in Python |
| AES-GCM IV Length | eciesjs uses a 16-byte nonce (standard is 12-byte). Ciphera explicitly pads the IV slice to 16 bytes on the Python side |
| MAC Tag Position | Python appends the GCM tag (ct β₯ tag); JS prepends it (tag β₯ ct). Ciphera parses the 109-byte payload mathematically to extract and shift chunks |
In the event of a severe legal mandate:
User's raw ID is ECIES-encrypted in the browser
β
Stored in KYC Box Storage (Algorand)
β
Custodian Multisig: 3-of-5 custodians must vote
β
3 Shamir Secret Shares β reconstruct ECIES private key
β
Decrypt payload β revoke SMT leaf β clawback ASA
No single custodian can access private data alone. Without the 3-of-5 threshold, the raw PII is mathematically inaccessible β even to the protocol deployers.
Built by Aditya Pandey for AlgoBharat Hack Series 3.0