Skip to main content

Overview

Implement zero-knowledge proof verification to prove score thresholds or achievements without revealing exact values.

Basic ZK Verification

Score Threshold Proof

import { ZKScoreClient } from '@zkscore/sdk';

const client = new ZKScoreClient({
  apiKey: process.env.ZKSCORE_API_KEY
});

class ZKVerification {
  constructor() {
    this.client = client;
  }
  
  async generateScoreProof(userAddress, threshold) {
    try {
      const score = await this.client.getScore(userAddress);
      
      if (score.total < threshold) {
        throw new Error('Score below threshold');
      }
      
      // Generate ZK proof that score >= threshold without revealing exact score
      const proof = await this.client.generateZKProof({
        type: 'score_threshold',
        user: userAddress,
        threshold: threshold,
        actualScore: score.total
      });
      
      return {
        proof,
        threshold,
        isValid: true
      };
    } catch (error) {
      console.error('Error generating proof:', error);
      return { isValid: false, error: error.message };
    }
  }
  
  async verifyScoreProof(proof, threshold) {
    try {
      const isValid = await this.client.verifyZKProof(proof, {
        type: 'score_threshold',
        threshold: threshold
      });
      
      return { isValid, threshold };
    } catch (error) {
      console.error('Error verifying proof:', error);
      return { isValid: false, error: error.message };
    }
  }
}

Achievement Proof

class AchievementProof {
  constructor(client) {
    this.client = client;
  }
  
  async generateAchievementProof(userAddress, achievementId) {
    try {
      const achievements = await this.client.getAchievements(userAddress);
      const hasAchievement = achievements.some(a => a.id === achievementId);
      
      if (!hasAchievement) {
        throw new Error('User does not have this achievement');
      }
      
      const proof = await this.client.generateZKProof({
        type: 'achievement',
        user: userAddress,
        achievementId: achievementId
      });
      
      return {
        proof,
        achievementId,
        isValid: true
      };
    } catch (error) {
      console.error('Error generating achievement proof:', error);
      return { isValid: false, error: error.message };
    }
  }
  
  async verifyAchievementProof(proof, achievementId) {
    try {
      const isValid = await this.client.verifyZKProof(proof, {
        type: 'achievement',
        achievementId: achievementId
      });
      
      return { isValid, achievementId };
    } catch (error) {
      console.error('Error verifying achievement proof:', error);
      return { isValid: false, error: error.message };
    }
  }
}

React ZK Verification Component

Proof Generation Component

import React, { useState } from 'react';
import { ZKScoreClient } from '@zkscore/sdk';

const ZKProofGenerator = ({ userAddress }) => {
  const [threshold, setThreshold] = useState(500);
  const [proof, setProof] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  
  const client = new ZKScoreClient({
    apiKey: process.env.REACT_APP_ZKSCORE_API_KEY
  });
  
  const generateProof = async () => {
    try {
      setLoading(true);
      setError(null);
      
      const result = await client.generateZKProof({
        type: 'score_threshold',
        user: userAddress,
        threshold: threshold
      });
      
      setProof(result);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };
  
  return (
    <div className="zk-proof-generator">
      <h2>Generate ZK Proof</h2>
      
      <div className="form-group">
        <label>Score Threshold:</label>
        <input
          type="number"
          value={threshold}
          onChange={(e) => setThreshold(parseInt(e.target.value))}
          min="0"
          max="1000"
        />
      </div>
      
      <button 
        onClick={generateProof} 
        disabled={loading}
        className="generate-button"
      >
        {loading ? 'Generating...' : 'Generate Proof'}
      </button>
      
      {error && <div className="error">{error}</div>}
      
      {proof && (
        <div className="proof-result">
          <h3>Generated Proof</h3>
          <div className="proof-details">
            <p><strong>Threshold:</strong> {proof.threshold}</p>
            <p><strong>Valid:</strong> {proof.isValid ? 'Yes' : 'No'}</p>
          </div>
          <div className="proof-data">
            <textarea 
              value={JSON.stringify(proof.proof, null, 2)} 
              readOnly 
              rows="10"
            />
          </div>
        </div>
      )}
    </div>
  );
};

Proof Verification Component

const ZKProofVerifier = () => {
  const [proofData, setProofData] = useState('');
  const [threshold, setThreshold] = useState(500);
  const [verificationResult, setVerificationResult] = useState(null);
  const [loading, setLoading] = useState(false);
  
  const client = new ZKScoreClient({
    apiKey: process.env.REACT_APP_ZKSCORE_API_KEY
  });
  
  const verifyProof = async () => {
    try {
      setLoading(true);
      
      const proof = JSON.parse(proofData);
      const result = await client.verifyZKProof(proof, {
        type: 'score_threshold',
        threshold: threshold
      });
      
      setVerificationResult(result);
    } catch (error) {
      setVerificationResult({
        isValid: false,
        error: error.message
      });
    } finally {
      setLoading(false);
    }
  };
  
  return (
    <div className="zk-proof-verifier">
      <h2>Verify ZK Proof</h2>
      
      <div className="form-group">
        <label>Proof Data:</label>
        <textarea
          value={proofData}
          onChange={(e) => setProofData(e.target.value)}
          placeholder="Paste proof JSON here..."
          rows="8"
        />
      </div>
      
      <div className="form-group">
        <label>Expected Threshold:</label>
        <input
          type="number"
          value={threshold}
          onChange={(e) => setThreshold(parseInt(e.target.value))}
          min="0"
          max="1000"
        />
      </div>
      
      <button 
        onClick={verifyProof} 
        disabled={loading || !proofData}
        className="verify-button"
      >
        {loading ? 'Verifying...' : 'Verify Proof'}
      </button>
      
      {verificationResult && (
        <div className={`verification-result ${verificationResult.isValid ? 'valid' : 'invalid'}`}>
          <h3>Verification Result</h3>
          <p><strong>Valid:</strong> {verificationResult.isValid ? 'Yes' : 'No'}</p>
          {verificationResult.error && (
            <p><strong>Error:</strong> {verificationResult.error}</p>
          )}
        </div>
      )}
    </div>
  );
};

Privacy-Preserving Access Control

ZK Gating System

class ZKGatingSystem {
  constructor(client) {
    this.client = client;
  }
  
  async checkZKAccess(userAddress, requirements) {
    try {
      const proofs = [];
      
      // Generate proofs for each requirement
      for (const requirement of requirements) {
        if (requirement.type === 'score_threshold') {
          const proof = await this.client.generateZKProof({
            type: 'score_threshold',
            user: userAddress,
            threshold: requirement.threshold
          });
          proofs.push(proof);
        } else if (requirement.type === 'achievement') {
          const proof = await this.client.generateZKProof({
            type: 'achievement',
            user: userAddress,
            achievementId: requirement.achievementId
          });
          proofs.push(proof);
        }
      }
      
      return {
        hasAccess: true,
        proofs: proofs
      };
    } catch (error) {
      return {
        hasAccess: false,
        error: error.message
      };
    }
  }
  
  async verifyZKAccess(proofs, requirements) {
    try {
      for (let i = 0; i < proofs.length; i++) {
        const proof = proofs[i];
        const requirement = requirements[i];
        
        const isValid = await this.client.verifyZKProof(proof, requirement);
        if (!isValid) {
          return { hasAccess: false, reason: 'Invalid proof' };
        }
      }
      
      return { hasAccess: true };
    } catch (error) {
      return { hasAccess: false, error: error.message };
    }
  }
}

Advanced ZK Features

Batch Proof Generation

class BatchZKProofs {
  constructor(client) {
    this.client = client;
  }
  
  async generateBatchProofs(userAddress, requirements) {
    try {
      const proofPromises = requirements.map(async (requirement) => {
        const proof = await this.client.generateZKProof({
          type: requirement.type,
          user: userAddress,
          ...requirement.params
        });
        return { requirement, proof };
      });
      
      const results = await Promise.all(proofPromises);
      return results;
    } catch (error) {
      console.error('Error generating batch proofs:', error);
      return [];
    }
  }
  
  async verifyBatchProofs(proofs, requirements) {
    try {
      const verificationPromises = proofs.map(async (proofData, index) => {
        const requirement = requirements[index];
        const isValid = await this.client.verifyZKProof(
          proofData.proof, 
          requirement
        );
        return { requirement, isValid };
      });
      
      const results = await Promise.all(verificationPromises);
      return results;
    } catch (error) {
      console.error('Error verifying batch proofs:', error);
      return [];
    }
  }
}

Best Practices

  1. Privacy First: Never reveal exact scores or sensitive data
  2. Proof Validation: Always verify proofs before granting access
  3. Error Handling: Handle proof generation failures gracefully
  4. Performance: Consider proof generation time for UX
  5. Security: Use secure proof generation and verification