Skip to main content

Overview

The ZK Proofs SDK enables you to generate zero-knowledge proofs that verify user reputation without revealing sensitive data. Prove score thresholds, achievements, attestations, and more while maintaining user privacy.

Generate Proof

Create a zero-knowledge proof for various verification types:
const proof = await sdk.zkProofs.generate({
  address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1',
  type: 'score-threshold',
  threshold: 700,
  hideExactScore: true,
});

console.log(proof);
// {
//   proofId: "zkp_abc123",
//   type: "score-threshold",
//   proof: "0x1234567890abcdef...", // ZK proof data
//   publicInputs: {
//     threshold: 700,
//     timestamp: "2024-10-23T14:30:00Z"
//   },
//   expiresAt: "2024-10-23T15:30:00Z", // 1 hour validity
//   metadata: {
//     circuit: "score-threshold-v1",
//     protocol: "groth16"
//   }
// }

Proof Types

Prove score is above/below a threshold without revealing exact value
const proof = await sdk.zkProofs.generate({
  address: '0x742d35...',
  type: 'score-threshold',
  threshold: 700,
  operator: 'gte', // 'gte' | 'lte' | 'eq'
  hideExactScore: true,
});

Parameters

params
object
required
Proof generation parameters

Verify Proof

Verify a zero-knowledge proof’s validity:
const isValid = await sdk.zkProofs.verify(proof);

console.log(isValid);
// {
//   valid: true,
//   proofId: "zkp_abc123",
//   type: "score-threshold",
//   verified: true,
//   timestamp: "2024-10-23T14:30:00Z",
//   publicInputs: {
//     threshold: 700
//   }
// }

Parameters

proof
object | string
required
Proof object or proof ID to verify

Returns

valid
boolean
Whether the proof is valid
verified
boolean
Whether the underlying claim is verified
expired
boolean
Whether the proof has expired

Advanced Examples

Score-Gated Access with Privacy

async function checkAccessWithPrivacy(userAddress: string, minScore: number) {
  try {
    // User generates proof
    const proof = await sdk.zkProofs.generate({
      address: userAddress,
      type: 'score-threshold',
      threshold: minScore,
      operator: 'gte',
      hideExactScore: true,
    });

    // Application verifies proof without seeing exact score
    const verification = await sdk.zkProofs.verify(proof);

    if (verification.valid && verification.verified) {
      console.log('✅ Access granted (score meets threshold)');
      return true;
    } else {
      console.log('❌ Access denied');
      return false;
    }
  } catch (error) {
    console.error('Error checking access:', error);
    return false;
  }
}

// Usage
const hasAccess = await checkAccessWithPrivacy('0x742d35...', 700);

Multi-Condition Proof

async function generateComplexProof(address: string) {
  // Generate multiple proofs in parallel
  const [scoreProof, ageProof, kycProof] = await Promise.all([
    sdk.zkProofs.generate({
      address,
      type: 'score-threshold',
      threshold: 700,
      hideExactScore: true,
    }),
    sdk.zkProofs.generate({
      address,
      type: 'wallet-age',
      minDays: 365,
      hideExactAge: true,
    }),
    sdk.zkProofs.generate({
      address,
      type: 'attestation',
      schema: 'kyc-verification',
      conditions: {
        'data.verified': true,
      },
      hideAttester: true,
    }),
  ]);

  // Verify all proofs
  const verifications = await Promise.all([
    sdk.zkProofs.verify(scoreProof),
    sdk.zkProofs.verify(ageProof),
    sdk.zkProofs.verify(kycProof),
  ]);

  const allValid = verifications.every((v) => v.valid && v.verified);

  return {
    valid: allValid,
    proofs: {
      score: scoreProof,
      age: ageProof,
      kyc: kycProof,
    },
    verifications,
  };
}

Selective Disclosure

async function selectiveDisclosure(address: string, fieldsToDisclose: string[]) {
  const score = await sdk.scores.getScore(address);

  // Create proof with selective disclosure
  const proof = await sdk.zkProofs.generate({
    address,
    type: 'selective-disclosure',
    disclose: fieldsToDisclose,
    hide: Object.keys(score.breakdown).filter(
      (key) => !fieldsToDisclose.includes(key)
    ),
  });

  return proof;
}

// Example: Only disclose DeFi score
const proof = await selectiveDisclosure('0x742d35...', ['defi']);

Proof Caching

class ProofCache {
  private cache = new Map<string, { proof: any; expiresAt: number }>();

  async getOrGenerateProof(
    address: string,
    type: string,
    params: any
  ): Promise<any> {
    const cacheKey = `${address}-${type}-${JSON.stringify(params)}`;
    const cached = this.cache.get(cacheKey);

    // Return cached proof if still valid
    if (cached && Date.now() < cached.expiresAt) {
      return cached.proof;
    }

    // Generate new proof
    const proof = await sdk.zkProofs.generate({
      address,
      type,
      ...params,
    });

    // Cache with expiry
    this.cache.set(cacheKey, {
      proof,
      expiresAt: new Date(proof.expiresAt).getTime(),
    });

    return proof;
  }

  clearExpired() {
    const now = Date.now();
    for (const [key, value] of this.cache.entries()) {
      if (now >= value.expiresAt) {
        this.cache.delete(key);
      }
    }
  }
}

const proofCache = new ProofCache();

// Usage
const proof = await proofCache.getOrGenerateProof('0x742d35...', 'score-threshold', {
  threshold: 700,
});

Batch Verification

async function verifyMultipleProofs(proofs: any[]) {
  const verifications = await Promise.all(
    proofs.map((proof) => sdk.zkProofs.verify(proof))
  );

  const results = verifications.map((v, i) => ({
    proofId: proofs[i].proofId,
    valid: v.valid,
    verified: v.verified,
  }));

  const allValid = results.every((r) => r.valid && r.verified);

  return {
    allValid,
    results,
    validCount: results.filter((r) => r.valid && r.verified).length,
    invalidCount: results.filter((r) => !r.valid || !r.verified).length,
  };
}

Time-Bound Proofs

async function generateTimeBoundProof(address: string, validityMinutes: number) {
  const proof = await sdk.zkProofs.generate({
    address,
    type: 'score-threshold',
    threshold: 700,
    ttl: validityMinutes * 60, // Convert to seconds
  });

  console.log(`Proof valid until: ${proof.expiresAt}`);

  return proof;
}

// Generate proof valid for 30 minutes
const shortLivedProof = await generateTimeBoundProof('0x742d35...', 30);

NFT Mint Proof

async function generateMintEligibilityProof(address: string) {
  // Combine multiple proofs for NFT mint eligibility
  const [scoreProof, tradingProof, achievementProof] = await Promise.all([
    sdk.zkProofs.generate({
      address,
      type: 'score-threshold',
      threshold: 800,
      hideExactScore: true,
    }),
    sdk.zkProofs.generate({
      address,
      type: 'trading-volume',
      minVolume: '10000',
      timeRange: '90d',
      hideExactVolume: true,
    }),
    sdk.zkProofs.generate({
      address,
      type: 'achievement',
      achievementId: 'nft-collector',
      hideOtherAchievements: true,
    }),
  ]);

  // Verify all proofs
  const [scoreValid, tradingValid, achievementValid] = await Promise.all([
    sdk.zkProofs.verify(scoreProof),
    sdk.zkProofs.verify(tradingProof),
    sdk.zkProofs.verify(achievementProof),
  ]);

  const eligible =
    scoreValid.valid &&
    tradingValid.valid &&
    achievementValid.valid;

  return {
    eligible,
    proofs: {
      score: scoreProof,
      trading: tradingProof,
      achievement: achievementProof,
    },
  };
}

Recursive Proofs

async function generateRecursiveProof(address: string) {
  // Generate base proof
  const baseProof = await sdk.zkProofs.generate({
    address,
    type: 'score-threshold',
    threshold: 700,
  });

  // Generate proof that proves the first proof is valid
  const metaProof = await sdk.zkProofs.generate({
    address,
    type: 'proof-verification',
    proofToVerify: baseProof.proofId,
  });

  return {
    baseProof,
    metaProof,
  };
}

Anonymous Voting

async function generateVotingProof(voterAddress: string, minReputation: number) {
  // Generate proof of voting eligibility without revealing identity
  const proof = await sdk.zkProofs.generate({
    address: voterAddress,
    type: 'score-threshold',
    threshold: minReputation,
    hideExactScore: true,
    anonymize: true, // Don't include address in public inputs
  });

  // Generate nullifier to prevent double voting
  const nullifier = await sdk.zkProofs.generateNullifier({
    address: voterAddress,
    context: 'proposal-123',
  });

  return {
    proof,
    nullifier,
  };
}

On-Chain Verification

For on-chain verification, you can export proofs compatible with Solidity verifiers:
// Generate proof with on-chain format
const proof = await sdk.zkProofs.generate({
  address: '0x742d35...',
  type: 'score-threshold',
  threshold: 700,
  format: 'solidity',
});

console.log(proof.solidityCalldata);
// "0x1234567890abcdef..." - Ready for smart contract call

Smart Contract Integration

// Example Solidity verifier
contract ZKScoreVerifier {
    function verifyScoreProof(
        uint[2] memory a,
        uint[2][2] memory b,
        uint[2] memory c,
        uint[1] memory input
    ) public view returns (bool) {
        // Verification logic
        return zkVerifier.verifyProof(a, b, c, input);
    }
    
    function mintWithProof(
        uint[2] memory a,
        uint[2][2] memory b,
        uint[2] memory c,
        uint[1] memory input
    ) public {
        require(verifyScoreProof(a, b, c, input), "Invalid proof");
        // Mint logic
    }
}

Privacy Guarantees

ZK proofs guarantee:
  • Zero Knowledge: No information leaked beyond the claim
  • Soundness: Invalid proofs cannot be generated
  • Completeness: Valid claims always produce valid proofs
  • Privacy: Original data remains confidential

Performance Considerations

// Proof generation times (approximate)
const perfMetrics = {
  'score-threshold': '~2s',
  'achievement': '~1.5s',
  'attestation': '~2.5s',
  'wallet-age': '~1s',
  'trading-volume': '~3s',
};

// Optimization: Generate proofs in advance
async function preGenerateProofs(address: string) {
  const proofs = await Promise.all([
    sdk.zkProofs.generate({ address, type: 'score-threshold', threshold: 700 }),
    sdk.zkProofs.generate({ address, type: 'wallet-age', minDays: 365 }),
    // ... more proofs
  ]);
  
  // Cache for instant access
  return proofs;
}

Error Handling

try {
  const proof = await sdk.zkProofs.generate({
    address: '0x742d35...',
    type: 'score-threshold',
    threshold: 700,
  });
} catch (error) {
  if (error.code === 'INSUFFICIENT_DATA') {
    console.log('Not enough data to generate proof');
  } else if (error.code === 'BELOW_THRESHOLD') {
    console.log('User does not meet threshold requirements');
  } else if (error.code === 'PROOF_GENERATION_FAILED') {
    console.log('ZK proof generation failed');
  } else {
    console.error('Error generating proof:', error);
  }
}

TypeScript Types

interface ZKProof {
  proofId: string;
  type: string;
  proof: string;
  publicInputs: Record<string, any>;
  expiresAt: string;
  metadata: {
    circuit: string;
    protocol: string;
  };
  solidityCalldata?: string;
}

interface ProofVerification {
  valid: boolean;
  verified: boolean;
  expired: boolean;
  proofId: string;
  timestamp: string;
}

Best Practices

  1. Cache Proofs: Proof generation is computationally expensive
  2. Set Appropriate TTL: Balance security and user experience
  3. Verify Before Use: Always verify proofs on the server side
  4. Handle Expiry: Check proof expiration before verification
  5. Use Appropriate Type: Choose the right proof type for your use case

Next Steps