Privacy-Preserving KYC for Autonomous Agents via zk-SNARKs
Architecting zero-knowledge KYC verification for institutional tokenized assets using Circom circuits, Groth16 proofs, and on-chain EVM verifiers.
Executive Summary
How zero-knowledge proofs (zk-SNARKs) allow autonomous AI agents and institutional investors to verify accredited KYC status on-chain without revealing sensitive personal identity documents.
When financial institutions tokenize **Real World Assets (RWAs)**—such as private credit funds, commercial real estate, and government debt—global regulatory frameworks mandate rigorous **Know Your Customer (KYC)**, **Anti-Money Laundering (AML)**, and **Accredited Investor** verification.
However, traditional identity verification models suffer from a dangerous architectural flaw on public blockchains: **The Public PII Exposure Trap**.
If an asset manager writes investor identity data directly to an Ethereum or Base smart contract, sensitive Personally Identifiable Information (such as passports, corporate tax identifiers, and investor net worth figures) is permanently exposed to the entire public Internet.
Conversely, if identity verification is managed entirely in centralized off-chain databases, tokenized asset transfers become slow, custodial, and completely unusable by **Autonomous AI Agents**.
┌────────────────────────────────────────────────────────────────────────┐
│ THE IDENTITY PRIVACY DILEMMA ON-CHAIN │
│ │
│ Naive On-Chain KYC: │
│ Passport & Tax ID ──► Written to Smart Contract ──► PII Leaked ❌ │
│ │
│ Centralized Off-Chain KYC: │
│ Manual Broker Approval ──► 5-Day Wire Delay ──► AI Agents Blocked ❌ │
│ │
│ Privacy-Preserving zk-SNARK KYC: │
│ Private Identity Vault ──► Circom ZK Proof (π) ──► On-Chain Verifier │
│ Result: 100% Cryptographic Compliance • Zero PII Exposed ✅ │
└────────────────────────────────────────────────────────────────────────┘**Zero-Knowledge Succinct Non-Interactive Arguments of Knowledge (zk-SNARKs)** resolve this paradox completely.
By leveraging cryptographic zero-knowledge circuits, an autonomous agent or institutional investor can mathematically prove to a smart contract:
- "I am a verified accredited investor residing in an authorized jurisdiction."
- "I am not on any international sanctions watchlists."
- "...all without revealing my name, passport number, net worth, or physical address."
1. The Zero-Knowledge KYC Verification Architecture
The privacy-preserving identity lifecycle operates across three distinct computational tiers:
┌────────────────────────────────────────────────────────────────────────┐
│ zk-SNARK IDENTITY PIPELINE ARCHITECTURE │
│ │
│ 1. Off-Chain Private Vault (Investor / AI Agent Secure Enclave): │
│ - Passport: X9482910 | Net Worth: $14.2M | Country Code: 840 (US) │
│ - Cryptographic Signature from Qualified Attestation Issuer │
│ │
│ 2. Client-Side Witness & Proof Generation (SnarkJS / Circom): │
│ - Evaluates arithmetic constraints inside local browser/agent │
│ - Generates Groth16 Proof (π_A, π_B, π_C) │
│ - Public Signal: isAccredited = 1, isSanctioned = 0 │
│ │
│ 3. On-Chain Smart Contract Verifier (Solidity / EVM): │
│ - verifyProof(proof, publicSignals) == true │
│ - Issues ephemeral permissioned transfer token (valid for 24 hours)│
└────────────────────────────────────────────────────────────────────────┘2. Production Circom Circuit Implementation
To verify accredited investor status without revealing the underlying financial figures, we compile arithmetic constraints using **Circom 2.1**:
pragma circom 2.1.6;
include "../node_modules/circomlib/circuits/poseidon.circom";
include "../node_modules/circomlib/circuits/comparators.circom";
template AccreditedKYCVerifier() {
// ── PRIVATE SIGNALS (Hidden from Blockchain) ──
signal input investorNetWorthUSD; // e.g. $14,200,000
signal input investorCountryCode; // e.g. 840 (United States)
signal input identitySalt; // Secret cryptographic nonce
signal input issuerSignature; // Signature from KYC provider
// ── PUBLIC SIGNALS (Exposed On-Chain) ──
signal input minRequiredNetWorth; // e.g. $1,000,000 (SEC Reg D threshold)
signal input sanctionedCountryCode; // e.g. 0 (Restricted jurisdiction flag)
signal output identityNullifier; // Cryptographic commitment hash
signal output isComplianceValid; // Boolean confirmation (1 = Valid)
// 1. Enforce Net Worth Threshold Invariant (netWorth >= minRequired)
component netWorthCheck = GreaterEqThan(64);
netWorthCheck.in[0] <== investorNetWorthUSD;
netWorthCheck.in[1] <== minRequiredNetWorth;
// 2. Enforce Sanctioned Jurisdiction Check (country != sanctioned)
component countryCheck = IsEqual();
countryCheck.in[0] <== investorCountryCode;
countryCheck.in[1] <== sanctionedCountryCode;
// 3. Compute Deterministic Poseidon Nullifier Hash
component hasher = Poseidon(3);
hasher.inputs[0] <== investorNetWorthUSD;
hasher.inputs[1] <== investorCountryCode;
hasher.inputs[2] <== identitySalt;
identityNullifier <== hasher.out;
// Invariant: netWorth passes AND country is NOT sanctioned
isComplianceValid <== netWorthCheck.out * (1 - countryCheck.out);
}
component main { public [ minRequiredNetWorth, sanctionedCountryCode ] } = AccreditedKYCVerifier();3. On-Chain Solidity Groth16 Verifier Contract
Once the zero-knowledge proof is generated client-side, the autonomous trading agent submits the cryptographic parameters $(\pi_A, \pi_B, \pi_C)$ to an **EVM Verifier Contract**:
// contracts/identity/ZKIdentityRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IGroth16Verifier {
function verifyProof(
uint256[2] calldata a,
uint256[2][2] calldata b,
uint256[2] calldata c,
uint256[2] calldata input
) external view returns (bool r);
}
contract ZKIdentityRegistry {
IGroth16Verifier public immutable groth16Verifier;
// Mapping of identity nullifiers to expiration timestamps
mapping(bytes32 => uint256) public verifiedAttestations;
event ZKIdentityVerified(address indexed agentWallet, bytes32 indexed nullifierHash, uint256 expiresAt);
constructor(address _verifierAddress) {
groth16Verifier = IGroth16Verifier(_verifierAddress);
}
/// @notice Submits zk-SNARK proof to gain permissioned asset transfer authorization
function registerVerifiedIdentity(
uint256[2] calldata a,
uint256[2][2] calldata b,
uint256[2] calldata c,
uint256[2] calldata publicInputs, // [identityNullifier, isComplianceValid]
uint256 validityDuration
) external {
// Enforce compliance assertion from zero-knowledge proof output
require(publicInputs[1] == 1, "ZK KYC: Compliance constraints not satisfied");
// Execute cryptographic elliptic curve pairing check on EVM
require(
groth16Verifier.verifyProof(a, b, c, publicInputs),
"ZK KYC: Invalid cryptographic proof signature"
);
bytes32 nullifier = bytes32(publicInputs[0]);
uint256 expiration = block.timestamp + validityDuration;
verifiedAttestations[nullifier] = expiration;
emit ZKIdentityVerified(msg.sender, nullifier, expiration);
}
/// @notice Returns true if identity nullifier holds active compliance status
function isCompliant(bytes32 nullifier) external view returns (bool) {
return verifiedAttestations[nullifier] > block.timestamp;
}
}4. Automated Testing Suite in Foundry
To guarantee that invalid zero-knowledge proofs or expired identity nullifiers deterministically revert, we test the verifier with Foundry:
// test/ZKIdentityRegistry.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "forge-std/Test.sol";
import "../contracts/ZKIdentityRegistry.sol";
contract MockGroth16Verifier is IGroth16Verifier {
bool public shouldPass = true;
function setProofResult(bool _pass) external {
shouldPass = _pass;
}
function verifyProof(
uint256[2] calldata,
uint256[2][2] calldata,
uint256[2] calldata,
uint256[2] calldata input
) external view returns (bool) {
return shouldPass && (input[1] == 1);
}
}
contract ZKIdentityTest is Test {
ZKIdentityRegistry public registry;
MockGroth16Verifier public verifier;
address public agentWallet = address(0xAA1);
function setUp() public {
verifier = new MockGroth16Verifier();
registry = new ZKIdentityRegistry(address(verifier));
}
function test_ValidZKProofRegistersNullifier() public {
uint256[2] memory a = [uint256(1), uint256(2)];
uint256[2][2] memory b = [[uint256(3), uint256(4)], [uint256(5), uint256(6)]];
uint256[2] memory c = [uint256(7), uint256(8)];
uint256[2] memory pubInputs = [uint256(0x999), uint256(1)]; // isComplianceValid == 1
vm.prank(agentWallet);
registry.registerVerifiedIdentity(a, b, c, pubInputs, 24 hours);
assertTrue(registry.isCompliant(bytes32(pubInputs[0])));
}
function testFail_InvalidProofReverts() public {
verifier.setProofResult(false);
uint256[2] memory a;
uint256[2][2] memory b;
uint256[2] memory c;
uint256[2] memory pubInputs = [uint256(0x999), uint256(1)];
vm.prank(agentWallet);
registry.registerVerifiedIdentity(a, b, c, pubInputs, 24 hours);
}
}5. Comparing Identity Architectures for Institutional Assets
6. Architectural Checklist for Deploying Zero-Knowledge Identity
To deploy privacy-preserving KYC systems safely:
- **Perform Trusted Setup Ceremonies via Perpetual Powers of Tau:** Always use audited Phase 2 ceremony artifacts to prevent toxic waste parameter generation.
- **Implement Rotating Nullifiers:** Generate time-bound session nullifiers so observers cannot correlate multiple on-chain transactions to the same underlying entity.
- **Deploy On Layer-2 Networks (Base / Arbitrum):** Elliptic curve pairing operations cost ~210,000 gas on Ethereum L1 ($12.00) but less than $0.02 on Layer-2 rollups.
- **Integrate Decentralized Claim Revocation:** Maintain an on-chain Merkle accumulator tree allowing identity issuers to revoke compromised investor credentials dynamically.
- **Conduct Formal Verification on Circom Constraints:** Verify that no under-constrained signals exist in the circuit that would allow malicious actors to forge proof witness vectors.
- **Automate Continuous Sanction Watchlist Sync:** Update circuit Merkle roots dynamically when international regulatory bodies update OFAC sanction lists.
- **Implement Ephemeral Attestation Expirations:** Require autonomous agents to refresh cryptographic proofs every 30 to 90 days to verify ongoing compliance status.
To learn how cryptographic identity integrates into complete institutional tokenization pipelines, explore our [Master Pillar Guide on Institutional RWA Tokenization](/guides/institutional-rwa-tokenization-architecture) or schedule an [Institutional Cryptography Architecture Consultation](/services/architecture).
Also in this series
Automated Dividend Distribution: Pro-Rata Yield Engines on Layer-2
How to architect automated, gas-optimized dividend and yield distribution smart contracts for tokenized debt and RWA funds on Base and Arbitrum.
ERC-3643 Permissioned Tokens: ONCHAINID Registries for AI Agents
How the ERC-3643 permissioned token standard leverages ONCHAINID identity registries and compliance modules to enable regulated institutional asset transfers.