Skip to content

Start typing to search the documentation.

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 completes a supported document flow in the mobile app (passport, ID, Aadhaar, or KYC)
  • 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 data
  • Hub 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
} else if (attestationId == AttestationId.AADHAAR) {
    // Route to Aadhaar verification logic
} else if (attestationId == AttestationId.KYC) {
    // Route to KYC 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 or EuIdOutput with raw field data
  • Data 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, ID card, Aadhaar, or KYC-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 contract
  • Passes 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, EU_ID_CARD, AADHAAR, or KYC
    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 number, name+dob, name+yob]
}

Key V2 Improvements

Multi-Document Support

  • Automatic routing for attestation types: E_PASSPORT, EU_ID_CARD, AADHAAR and KYC
  • Document-specific verification pipelines
  • Unified interface for different document types

Structured Output

  • Rich GenericDiscloseOutputV2 with pre-extracted attributes
  • No more manual parsing of raw field elements
  • Type-safe access to identity data

Flexible Configuration Management

  • Reusable VerificationConfigV2 stored in Hub
  • Create 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