acceso-zk-sdk
v1.0.0
Published
TypeScript SDK for Zero-Knowledge Proofs via Acceso API - Privacy-preserving verification
Maintainers
Readme
Acceso ZK SDK
Privacy-Preserving Zero-Knowledge Proofs via Acceso API
Documentation • API Reference • Get API Key
🔐 Overview
The Acceso ZK SDK enables you to generate and verify Zero-Knowledge Proofs without revealing sensitive data. Prove statements like "my balance is at least X" without disclosing your actual balance.
Key Features
- 🛡️ Privacy First - Prove facts without revealing underlying data
- ⚡ Fast Proofs - Groth16 proofs in 2-5 seconds
- 🔗 On-Chain Ready - Export to Solidity calldata
- 🌐 Universal - Works in Node.js and browsers
- 📦 Zero Dependencies - Just fetch and TypeScript types
Available Circuits
| Circuit | Use Case | Proving Time |
|---------|----------|--------------|
| balance | Prove balance ≥ threshold | ~2-3s |
| threshold | Prove any value ≥ threshold | ~2-3s |
| holder | Prove token ownership | ~3-5s |
📦 Installation
# npm
npm install acceso-zk-sdk
# yarn
yarn add acceso-zk-sdk
# pnpm
pnpm add acceso-zk-sdk⚡ Quick Start
import { Zk } from "acceso-zk-sdk";
// Initialize with your API key
const zk = new Zk({
apiKey: "acceso_ent_xxx", // Get your key at acceso.dev
});
// Prove you have at least 1 SOL without revealing actual balance
const proof = await zk.proveBalance(
5_000_000_000, // Actual balance: 5 SOL (private - never shared)
1_000_000_000 // Threshold: 1 SOL (public)
);
console.log("Proof generated!");
console.log("Public signals:", proof.public_signals);
// Output: ["1", "1000000000"] - shows valid=true and threshold, NOT actual balance!
// Verify the proof
const isValid = await zk.verify("balance", proof.proof, proof.public_signals);
console.log("Proof valid:", isValid); // true📖 API Reference
Zk Class
The main client for ZK proof operations.
const zk = new Zk(config);Configuration
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| apiKey | string | Required | Your Acceso API key |
| baseUrl | string | https://api.acceso.dev | API base URL |
| timeout | number | 60000 | Request timeout (ms) |
| debug | boolean | false | Enable debug logging |
Balance Proofs
Prove wallet balance meets a minimum without revealing actual amount.
proveBalance(balance, threshold)
// Prove you have at least 1 SOL
const proof = await zk.proveBalance(
5_000_000_000, // Actual: 5 SOL (lamports) - PRIVATE
1_000_000_000 // Threshold: 1 SOL - PUBLIC
);
// The proof object contains:
// - proof.proof: Groth16 proof (shareable)
// - proof.public_signals: ["1", "1000000000"]
// - proof.verification_info: Human-readable descriptionWhat's revealed: Only that balance ≥ threshold What's hidden: The actual balance (5 SOL)
Threshold Proofs
Generic proof for any numeric value meeting a minimum.
proveThreshold(value, threshold)
// Prove age is at least 18 without revealing actual age
const ageProof = await zk.proveThreshold(25, 18);
// Prove credit score is at least 700
const creditProof = await zk.proveThreshold(750, 700);
// Prove years of experience is at least 5
const expProof = await zk.proveThreshold(8, 5);Token Holder Proofs
Prove you hold a specific token without revealing balance.
hashToken(tokenAddress)
First, hash the token address (required for holder proofs):
const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
const { token_hash } = await zk.hashToken(USDC_MINT);proveHolder(balance, tokenAddress, tokenHash)
// Prove you hold USDC without revealing how much
const proof = await zk.proveHolder(
1_000_000, // Balance: 1 USDC (private)
USDC_MINT, // Token address
token_hash // From hashToken()
);Verification
verify(circuitId, proof, publicSignals)
const isValid = await zk.verify(
"balance",
proof.proof,
proof.public_signals
);
console.log("Proof valid:", isValid); // true or falseverifyFull(circuitId, proof, publicSignals)
Get full verification response:
const result = await zk.verifyFull("balance", proof.proof, proof.public_signals);
console.log(result);
// {
// valid: true,
// circuit_id: "balance",
// verified_at: "2025-12-10T..."
// }On-Chain Integration
toCalldata(proof, publicSignals)
Convert proof to Solidity calldata for smart contract verification:
const { calldata } = await zk.toCalldata(proof.proof, proof.public_signals);
// Use calldata in your contract call:
// contract.verifyProof(calldata);Circuit Information
getCircuits()
const circuits = await zk.getCircuits();
for (const circuit of circuits) {
console.log(`${circuit.name}:`);
console.log(` ID: ${circuit.id}`);
console.log(` Description: ${circuit.description}`);
console.log(` Constraints: ${circuit.constraints}`);
console.log(` Est. time: ${circuit.proving_time_estimate}`);
}Convenience Methods
Complete proof + verify flows in one call:
// Balance proof with automatic verification
const { proof, isValid } = await zk.proveAndVerifyBalance(5e9, 1e9);
// Threshold proof with automatic verification
const { proof, isValid } = await zk.proveAndVerifyThreshold(25, 18);
// Holder proof with automatic hashing and verification
const { proof, isValid, tokenHash } = await zk.proveAndVerifyHolder(
1_000_000,
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
);🛠️ Utilities
import {
lamportsToSol,
solToLamports,
usdcToAtomic,
atomicToUsdc,
formatBalance,
isValidSignal,
TOKENS,
THRESHOLDS,
} from "acceso-zk-sdk";
// Convert between units
lamportsToSol(5_000_000_000); // 5
solToLamports(5); // 5000000000n
usdcToAtomic(100); // 100000000n
atomicToUsdc(100_000_000); // 100
// Format for display
formatBalance(5_000_000_000n, "SOL", 9); // "5 SOL"
// Check proof validity signal
isValidSignal(["1", "1000000000"]); // true
// Common token addresses
TOKENS.SOL_USDC; // USDC on Solana
// Common thresholds
THRESHOLDS.ONE_SOL; // 1_000_000_000n
THRESHOLDS.ONE_USDC; // 1_000_000n💡 Use Cases
1. KYC-less Age Verification
// User proves they're 18+ without revealing exact age
const { proof, isValid } = await zk.proveAndVerifyThreshold(userAge, 18);
if (isValid) {
// Grant access to age-restricted content
grantAccess(proof);
}2. Private DeFi Eligibility
// Prove user has enough collateral for a loan
const MIN_COLLATERAL = 10_000_000_000n; // 10 SOL
const proof = await zk.proveBalance(userBalance, MIN_COLLATERAL);
// Send proof to protocol - they verify without seeing actual balance
await defiProtocol.submitCollateralProof(proof);3. Token-Gated Access
// Prove NFT/token ownership for Discord role
const { proof, isValid } = await zk.proveAndVerifyHolder(
tokenBalance,
NFT_COLLECTION_MINT
);
if (isValid) {
assignDiscordRole(userId, "Holder");
}4. Private Credit Check
// Prove creditworthiness without revealing score
const proof = await zk.proveThreshold(creditScore, 700);
// Lender verifies proof - never sees actual score
const { valid } = await zk.verifyFull("threshold", proof.proof, proof.public_signals);🔧 Error Handling
import { Zk, ZkError } from "acceso-zk-sdk";
try {
const proof = await zk.proveBalance(100, 1000); // Will fail: 100 < 1000
} catch (error) {
if (error instanceof ZkError) {
console.error(`ZK Error [${error.code}]: ${error.message}`);
// ZK Error [PROOF_GENERATION_FAILED]: Value is less than threshold
}
}🔒 Security Notes
- Private inputs stay private - Only public signals are shared
- Cryptographic soundness - Mathematically impossible to fake proofs
- Trusted setup - Uses Powers of Tau ceremony
- No replay attacks - Each proof is unique
📋 TypeScript Support
Full type definitions included:
import type {
Groth16Proof,
BalanceProofResponse,
ThresholdProofResponse,
HolderProofResponse,
VerifyProofResponse,
Circuit,
CircuitId,
} from "acceso-zk-sdk";📄 License
MIT © Acceso
Built with ❤️ by the Acceso Team
