Verification in the IdentityVerificationHub
The IdentityVerificationHub V2 is the core verification engine that processes zero-knowledge proofs and executes identity verification workflows.
How the Hub Works
The Hub operates as a central verification coordinator that:
Receives Verification Requests from contracts implementing
ISelfVerificationRoot
Processes ZK Proofs using specialized circuit verifiers
Applies Verification Rules based on stored configurations
Returns Structured Results to the calling contract
Complete Verification Flow
1. Request Initiation
// User contract calls Hub with proof data
function verifySelfProof(bytes calldata proofPayload, bytes calldata userContextData) external;
What happens:
TEE Proof Generation (Gas-Free for Users)
User Input: User scans passport/ID with mobile app
TEE Processing: Trusted Execution Environment securely processes identity data
ZK Proof Creation: TEE generates zero-knowledge proof without revealing raw identity data
Relayer (Sponsored Transactions)
Proof Relay: Relayer receives ZK proof from TEE
Gas Sponsorship: Relayer pays all transaction gas fees on behalf of user
Onchain Submission: Relayer submits proof to user's contract via blockchain transaction
User Experience: User gets verified identity without any crypto/gas requirements
Contract Processing
Contract receives ZK proof from TEE/Relayer
Calls Hub's
verifySelfProof
with proof + user context dataHub begins processing the verification request
2. Input Decoding & Context Processing
// Hub internal: _decodeInput() and _decodeUserContextData()
(HubInputHeader memory header, bytes calldata proofData) = _decodeInput(baseVerificationInput);
(configId, destChainId, userIdentifier, remainingData) = _decodeUserContextData(userContextData);
What happens:
Header Extraction: Gets contract version, scope, attestation ID
Context Parsing: Extracts config ID, destination chain, user identifier
Data Preparation: Prepares proof data for verification
3. Configuration Retrieval
// Hub loads verification configuration by configId
VerificationConfigV2 memory config = $v2._v2VerificationConfigs[configId];
What happens:
Hub looks up stored verification configuration using configId
Configuration contains all verification rules (age, countries, OFAC, etc.)
If config doesn't exist, verification fails
4. Document Type Detection & Routing
// Based on attestationId in header
if (attestationId == AttestationId.E_PASSPORT) {
// Route to passport verification logic
} else if (attestationId == AttestationId.EU_ID_CARD) {
// Route to EU ID card verification logic
}
What happens:
Hub identifies document type from attestation ID
Routes to appropriate verification pipeline
Uses document-specific circuit verifiers
5. Basic Verification (_basicVerification)
Purpose: Validates the cryptographic correctness and security of the ZK proof itself.
// Hub performs 4 core verification steps
bytes memory proofOutput = _basicVerification(
header,
vcAndDiscloseProof,
userContextData,
userIdentifier
);
What happens (4 verification scopes):
Scope 1: Contract Validation
Scope Check: Ensures proof was generated for the correct contract
User Identifier Check: Validates user identity consistency
Scope 2: Registry & Timestamp Validation
Root Check: Validates against Merkle tree in identity registry
Current Date Check: Ensures proof is within valid time window
Scope 3: Cryptographic Proof Verification
Groth16 Proof Verification: Validates ZK proof using circuit verifier
Public Signals Validation: Verifies proof inputs/outputs match expectations
Scope 4: Raw Data Extraction
Output Generation: Creates
PassportOutput
orEuIdOutput
with raw field dataData Preparation: Prepares extracted data for business logic verification
Output: Raw identity data (PassportOutput
/EuIdOutput
) ready for custom verification.
6. Custom Verification (CustomVerifier.customVerify)
Purpose: Applies business logic rules and validates identity attributes against configuration requirements.
// Hub applies custom verification logic
GenericDiscloseOutputV2 memory output = CustomVerifier.customVerify(
header.attestationId,
config,
proofOutput
);
What happens:
Document Type Routing: Routes to passport vs ID card specific verification
Business Rule Application: Applies age, geographic, and sanctions requirements
Identity Data Extraction: Converts raw data to structured, human-readable format
Final Validation: Ensures all configuration requirements are met
Output: Structured identity data (GenericDiscloseOutputV2
) with verification results.
Age Verification (olderThanEnabled)
if (verificationConfig.olderThanEnabled) {
if (!CircuitAttributeHandlerV2.compareOlderThan(
attestationId,
passportOutput.revealedDataPacked,
verificationConfig.olderThan
)) {
revert InvalidOlderThan();
}
}
Validates user meets minimum age requirement
Uses circuit-extracted age data for verification
Example: config requires 18+, user is 20 → ✅ passes
Example: config requires 21+, user is 18 → ❌ fails
Geographic Restrictions (forbiddenCountriesEnabled)
if (verificationConfig.forbiddenCountriesEnabled) {
for (uint256 i = 0; i < 4; i++) {
if (passportOutput.forbiddenCountriesListPacked[i] !=
verificationConfig.forbiddenCountriesListPacked[i]) {
revert InvalidForbiddenCountries();
}
}
}
Validates forbidden countries list matches exactly
Uses packed representation for gas efficiency (4 uint256 array)
Order in config must match proof's forbidden countries list
OFAC Sanctions Verification
if (verificationConfig.ofacEnabled[0] ||
verificationConfig.ofacEnabled[1] ||
verificationConfig.ofacEnabled[2]) {
if (!CircuitAttributeHandlerV2.compareOfac(
attestationId,
passportOutput.revealedDataPacked,
verificationConfig.ofacEnabled[0], // passport number
verificationConfig.ofacEnabled[1], // name + DOB
verificationConfig.ofacEnabled[2] // name + YOB
)) {
revert InvalidOfacCheck();
}
}
Mode 0: OFAC check using passport number
Mode 1: OFAC check using name + date of birth
Mode 2: OFAC check using name + year of birth
Each mode can be independently enabled/disabled
Uses circuit-provided OFAC verification results
7. Output Formatting & Generation
// Hub formats verification results into structured output
output = _formatVerificationOutput(header.contractVersion, genericDiscloseOutput);
What happens:
Raw proof signals converted to human-readable data
Structured identity information extracted
Verification results (age, OFAC, etc.) included
8. Result Delivery
// Hub calls back to the original contract
ISelfVerificationRoot(callingContract).onVerificationSuccess(
abi.encode(output),
userData
);
What happens:
Hub calls
onVerificationSuccess
on the requesting contractPasses structured output + user-defined data
Contract can then execute its custom business logic
Data Structures
VerificationConfigV2
struct VerificationConfigV2 {
bool olderThanEnabled; // Enable age verification
uint256 olderThan; // Minimum age requirement
bool forbiddenCountriesEnabled; // Enable country restrictions
uint256[4] forbiddenCountriesListPacked; // Packed forbidden countries
bool[3] ofacEnabled; // OFAC verification modes
}
GenericDiscloseOutputV2 (Verification Result)
struct GenericDiscloseOutputV2 {
bytes32 attestationId; // E_PASSPORT or EU_ID_CARD
uint256 userIdentifier; // User's unique identifier
uint256 nullifier; // Anti-replay nullifier
uint256[4] forbiddenCountriesListPacked; // Forbidden countries used
// Disclosed identity information
string issuingState; // Document issuing country
string[] name; // [first, middle, last] names
string idNumber; // Passport/ID number
string nationality; // User's nationality
string dateOfBirth; // Birth date (DD-MM-YY)
string gender; // User's gender
string expiryDate; // Document expiry date
// Verification results
uint256 olderThan; // Verified minimum age
bool[3] ofac; // OFAC results [passport, name+dob, name+yob]
}
Key V2 Improvements
Multi-Document Support
Automatic routing for E_PASSPORT vs EU_ID_CARD
Document-specific verification pipelines
Unified interface for different document types
Structured Output
Rich
GenericDiscloseOutputV2
with pre-extracted attributesNo more manual parsing of raw field elements
Type-safe access to identity data
Flexible Configuration Management
Reusable
VerificationConfigV2
stored in HubCreate configurations without contract redeployment
Use Self Configuration Tools to register configs
Enhanced Security
Separate verification logic for each document type
Improved timestamp and replay protection
Gas-optimized verification checks
Last updated