Zk Proof: Part 2- Verifier, Validator, and Hooks

zk-proof-part-2-verifier-validator-and-hooks
MayankSolanki

Mayank Solanki

24 Feb 2023

Others

Introduction  

A zero-knowledge proof (ZKP) verifier is a mechanism whereby one party—the prover—may show to another party—the verifier—that they have specific information without disclosing the actual data itself.  
 
The verifier makes sure the prover knows the information without disclosing it and that the proof she offers is legitimate, that is, fulfills set requirements.  
 
Usually developed using a method called zero-knowledge proof construction, the proof offered by the prover is a mathematical object dependent on the knowledge and the stated criteria. The ZKP verifier is found in hardware, software, or smart contract form. 

 

It can be used in various scenarios, such as in privacy-sensitive applications, where the verifier needs to confirm that a user has access to specific data without actually seeing the data, or in financial systems where a user wants to prove that they have the assets they claim to have without revealing the assets themselves. 

 

Related: Zk-Proofs: Part 1 - Claim Issuer 

What is the main difference between verifiers and validators? 

In a zero-knowledge proof (ZKP) system, the validator, and the verifier play slightly different roles. 

 

A validator is responsible for ensuring that the proof provided by the prover is valid, meaning that it conforms to specific predefined criteria. The validator is a set of rules or algorithms that checks the proof against these criteria. The validator can be a smart contract, a software library, or a hardware device. 

 

On the other hand, a verifier is a party that receives the proof from the prover and checks that it is valid. The verifier does this by sending the evidence to the validator, preventing the proof against the predefined criteria, and returning a result to the verifier. The verifier can be a smart contract, a software application, or a person. 

 

In summary, a validator is a mechanism that checks that a proof is valid according to specific predefined criteria. In contrast, a verifier is a party that receives and verifies the proof by sending it to the validator. 

Zero Knowledge Airdrop 

// SPDX-License-Identifier: MIT 

pragma solidity ^0.8.0; 

import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 

import "./lib/GenesisUtils.sol"; 

import "./interfaces/ICircuitValidator.sol"; 

import "./verifiers/ZKPVerifier.sol"; 

contract ERC20Verifier is ERC20, ZKPVerifier { 

uint64 public constant TRANSFER_REQUEST_ID = 1; 

 

Mapping to store the addresses of that already claimed the contract. 

 

mapping(uint256 => address) public idToAddress; 

mapping(address => uint256) public addressToId; 

uint256 public TOKEN_AMOUNT_FOR_AIRDROP_PER_ID = 

     5 * 10**uint256(decimals()); 

constructor(string memory name_, string memory symbol_) 

     ERC20(name_, symbol_) 

{} 

... 

 

This Solidity smart contract implements an ERC20 token and a zero-knowledge proof (ZKP) verifier. The agreement's purpose is to allow users to claim an airdrop of the token by providing a valid ZKP, which is verified by the contract. 

 

The contract includes several hooks that run specific checks before and after the ZKP is submitted. The statements involve verifying that the address submitted the proof is the same as the address calling the "Proof Submit" function, ensuring that each address can only claim the airdrop once, and verifying that the ZKP record is stored in the contract. The contract also restricts token transfers to addresses that have successfully claimed the airdrop. 

Libraries 

ZKPVerifier likely provides functions and variables necessary for verifying zero-knowledge proofs, such as storing a record of which users have submitted proofs and checking the validity of proofs before they are processed. 

 

We will discuss its functionalities in the next part of the blog. 

 

The ICircuitValidator interface is imported into the code to define the expected behavior and functions of the circuit validator. In the code, the circuit validator is used to verify zero-knowledge proofs submitted by users. 

 

Using an interface, the code can be abstracted from the specific implementation of the circuit validator, allowing for different implementations to be used in other contract deployments. The performance of the circuit validator must meet the requirements defined in the ICircuitValidator interface to be compatible with the contract. 

Hooks  

function _beforeProofSubmit( 

     uint64, /* requestId */ 

     uint256[] memory inputs, 

     ICircuitValidator validator 

) internal view override { 

     // check that the challenge input of the proof is equal to the msg.sender 

     address addr = GenesisUtils.int256ToAddress( 

         inputs[validator.getChallengeInputIndex()] 

     ); 

     require( 

         _msgSender() == addr, 

         "address in proof is not a sender address" 

     ); 

_beforeProofSubmit is a hook in the code that runs a check before the "Proof Submit" function is executed. It verifies that the address that submitted the proof on the validator is the same as the address calling the "Proof Submit" function on the contract. If the check fails, the process will stop execution and return an error message. This hook aims to ensure the integrity and security of the contract by ensuring that the address submitting the proof is indeed the address calling the function. 

 

function _afterProofSubmit( 

     uint64 requestId, 

     uint256[] memory inputs, 

     ICircuitValidator validator 

) internal override { 

     require( 

         requestId == TRANSFER_REQUEST_ID && addressToId[_msgSender()] == 0, 

         "proof can not be submitted more than once" 

     ); 

     uint256 id = inputs[validator.getChallengeInputIndex()]; 

     // execute the airdrop 

     if (idToAddress[id] == address(0)) { 

         super._mint(_msgSender(), TOKEN_AMOUNT_FOR_AIRDROP_PER_ID); 

         addressToId[_msgSender()] = id; 

         idToAddress[id] = _msgSender(); 

     } 

 

The afterProofSubmit hook in the code is executed after a zero-knowledge proof has been submitted to the ERC20Verifier contract. The hook performs checks and operations to determine if the submitted proof should be accepted and processed. 

 

The afterProofSubmit hook checks that: 

  • The requestId of the submitted proof is equal to TRANSFER_REQUEST_ID
  • The address that submitted the proof has not claimed the airdrop previously (by checking if the address is mapped to a unique ID in the addressToId mapping) 

If these checks pass, the hook performs the actual execution of the airdrop by calling the _mintfunction (inherited from the ERC20 contract) to transfer the TOKEN_AMOUNT_FOR_AIRDROP_PER_ID to the address that submitted the proof. Additionally, the hook updates the addressToId and idToAddress mappings to store the mapping between the address and the unique ID provided in the proof. 

Benefits of Zero-Knowledge Airdrops 

Zero-knowledge proof (ZKP)-based airdrops introduce a new level of security, privacy, and efficiency compared to traditional airdrops. Here’s why they are superior: 

 

1. Privacy-Preserving 

In traditional airdrops, users often need to verify their identity or meet specific criteria, which might involve sharing wallet details, transaction history, or even personal information. With ZKP-based airdrops: 

  • Users can prove eligibility without revealing their wallet balance or transaction history.
  • Sensitive data remains private while still allowing verification.
  • This enhances anonymity, making ZKP-based airdrops particularly useful for privacy-focused projects. 

2. Sybil Resistance (Fraud Prevention) 

A common issue with traditional airdrops is Sybil attacks, where users create multiple wallets to claim tokens multiple times. ZKP-based airdrops mitigate this by: 

  • Using unique cryptographic proofs that ensure each eligible user can claim only once.
  • Preventing double claims through verifiable, non-replayable proofs.
  • Reducing the risk of bots and fraudulent users exploiting the airdrop. 

3. Decentralization (No Centralized KYC or AML) 

Most airdrops require centralized Know Your Customer (KYC) or Anti-Money Laundering (AML) checks, which introduce: 

  • Privacy concerns (users must share ID documents).
  • Central points of failure (data breaches, hacks).
  • Regulatory hurdles. 

ZKP-based airdrops eliminate the need for centralized verification. Instead, users can prove eligibility (e.g., holding a certain NFT or participating in an event) without revealing any personal information, maintaining true decentralization. 

Security Risks & How to Prevent Them 

While ZKP-based airdrops offer many advantages, they also come with potential security risks. Here’s how they can be prevented: 

 

1. Replaying Proofs (Double Spending Risk) 

  • Issue: If a user submits the same proof multiple times, they might claim multiple airdrops.
  • Solution: Implement unique challenge inputs for each proof submission.
    • Use a timestamp or nonce so that each proof is valid only once.
    • Store used proofs on-chain to prevent reuse. 

2. Front-Running Attacks (Malicious Actors Stealing Airdrops) 

  • Issue: In blockchain transactions, attackers can see pending proof submissions and try to manipulate the system by submitting fraudulent proofs with higher gas fees.
  • Solution:
    • Use encrypted proof submissions so attackers cannot see the details before they are verified.
    • Implement commit-reveal schemes, where users first submit a hashed proof and reveal it in a second transaction.
    • Utilize Layer 2 scaling solutions like rollups to process proofs privately before submitting them on-chain. 

3. Smart Contract Vulnerabilities 

  • Issue: Poorly written smart contracts can have security loopholes, allowing attackers to bypass validation and claim unauthorized airdrops.
  • Solution:
    • Use formal verification methods to ensure the correctness of ZKP validation logic.
    • Conduct multiple security audits before deploying contracts.
    • Implement access controls and emergency stop functions to halt the contract in case of an exploit. 

How ZKPs Improve Gas Efficiency 

Gas fees are a major concern in blockchain-based applications, and ZKPs help optimize costs. 

 

1. Off-chain computation with zk-SNARKs and zk-STARKs 

  • Traditional airdrops require on-chain verification, which consumes gas for every claim.
  • zk-SNARKs (Zero-Knowledge Succinct Non-Interactive Arguments of Knowledge) and zk-STARKs (Scalable Transparent Arguments of Knowledge) allow proof generation off-chain, significantly reducing on-chain computation.
  • The verifier contract only checks a small proof instead of processing all the eligibility conditions on-chain. 

2. Gas Fee Comparison: Traditional Airdrop vs. ZKP-Based Airdrop 

Feature 

Traditional Airdrop 

ZKP-Based Airdrop 

Gas Cost per Claim 

High (due to on-chain validation of eligibility) 

Low (only verifying a small proof) 

Computation Location 

Fully on-chain 

Mostly off-chain 

Transaction Complexity 

Higher due to multiple validation steps 

Lower due to succinct proofs 

Scalability 

Limited (cost increases with number of users) 

High (same proof size regardless of users) 

 

 

 

contact bg image

Ready to Accelerate your Business?

Partner with Reveation Labs today and let’s turn your business goals into tangible success. Get in touch with us to discover how we can help you.

Schedule a call with us today!