Zero-knowledge KYC credential verification enforced via Solana Token-2022 transfer hooks.
Status: Proof of concept — devnet deployment target.
Token transfers are gated by KYC credentials verified with zero-knowledge proofs. A user proves they hold valid KYC data from an approved issuer without revealing any personal information. The transfer hook checks this credential on every token transfer — if the sender or recipient isn't verified, the transfer reverts.
User (offchain) Solana (onchain)
───────────── ─────────────────
Generate ZK proof → KYC Verifier Program
(snarkjs/circom) ├─ groth16_verify(proof)
└─ Store KycCredential PDA
↓
Token Transfer → Transfer Hook Program
├─ Read KycCredential PDA
├─ Check: exists + not expired
└─ Allow or revert transfer
Two Solana programs + one Circom circuit:
KYC Verifier (programs/kyc-verifier/) — Accepts Groth16 ZK proofs, verifies them onchain using groth16-solana (<200k compute units), and stores credential status in PDAs. Manages an issuer registry of approved KYC providers.
Transfer Hook (programs/transfer-hook/) — Token-2022 transfer hook that reads credential PDAs on every transfer. Both sender and recipient must have valid, non-expired credentials. Uses ExtraAccountMetaList for automatic PDA resolution.
Circom Circuit (circuits/kyc_proof.circom) — Proves knowledge of KYC credential data (secret + issuer + expiry) hashed with Poseidon, bound to a specific wallet, with an expiry check. ~100 constraints, proof generation <500ms.
| Component | Technology |
|---|---|
| ZK Circuit | Circom 2.1 + Poseidon hash |
| Proof Generation | snarkjs (Groth16) |
| Onchain Verification | groth16-solana (audited, BN254) |
| Programs | Anchor 0.30.0+ |
| Token Standard | Token-2022 (Token Extensions) |
# Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
# Solana CLI (v1.18+)
sh -c "$(curl -sSfL https://release.solana.com/v1.18.0/install)"
# Anchor (v0.30+)
cargo install --git https://github.com/coral-xyz/anchor anchor-cli --locked
# Circom
npm install -g circom
# Node.js 18+ (for snarkjs)# 1. Install dependencies
npm install
cd circuits && npm install && cd ..
# 2. Compile circuit + trusted setup
bash scripts/setup-circuit.sh
# 3. Generate Rust verification key constants
npx ts-node scripts/convert-vk.ts
# Copy the output into programs/kyc-verifier/src/lib.rs
# 4. Configure Solana for devnet
solana config set --url devnet
solana-keygen new # if needed
solana airdrop 2
# 5. Build and deploy
anchor build
# Update program IDs (see deploy script)
bash scripts/deploy.sh# Generate ZK proofs and run the transfer demo
cd client && npx ts-node src/client.ts| Scenario | Expected Result |
|---|---|
| Both parties have valid KYC credentials | Transfer succeeds |
| Recipient's credential is expired | Transfer blocked (CredentialExpired) |
| Recipient has no credential | Transfer blocked (RecipientNotVerified) |
| Tampered ZK proof submitted | Verification rejected (ProofVerificationFailed) |
zk-kyc-hook/
├── programs/
│ ├── kyc-verifier/ # Groth16 proof verification + credential PDAs
│ └── transfer-hook/ # Token-2022 transfer hook enforcement
├── circuits/
│ └── kyc_proof.circom # ZK circuit (Poseidon hash + expiry check)
├── client/
│ └── src/
│ ├── prover.ts # snarkjs proof generation
│ ├── setup.ts # Token + account setup
│ └── client.ts # End-to-end demo
├── tests/
│ └── integration.test.ts # 4 test scenarios
└── scripts/
├── setup-circuit.sh # Circuit compilation + trusted setup
├── convert-vk.ts # Verification key → Rust constants
└── deploy.sh # Build + deploy to devnet
- groth16-solana requires negating proof.A's y-coordinate — handled in
prover.ts - Verification key conversion from snarkjs JSON to Rust byte arrays —
scripts/convert-vk.ts - ExtraAccountMetaList seeds include KYC credential PDA derivation for automatic resolution
- Cannot combine ConfidentialTransfer + TransferHook (Solana limitation)
- Circuit uses Poseidon hash (BN254-native, efficient in circom)
- Solana Token Extensions: Transfer Hook
- groth16-solana — Audited Groth16 verifier
- Civic Transfer Hook — Reference implementation
- ERC-3643 — EVM compliance standard (architectural reference)
- circomlib — Poseidon hash circuit
MIT