ciphera-sdk
v0.1.2
Published
Zero-Knowledge KYC for Algorand — generate ZK proofs in the browser, verify KYC on-chain
Maintainers
Readme
Zero-Knowledge KYC for Algorand — TypeScript/JavaScript SDK
Generate ZK proofs in the browser. Verify KYC on-chain. Zero personal data exposed.
Install
npm install ciphera-sdkWhat is Ciphera?
Ciphera is a privacy-preserving zero-knowledge KYC system on Algorand. Users prove they are verified Indian adults without exposing any personal information. ZK proofs are generated entirely in the browser using snarkjs — private inputs (Aadhaar hash, wallet secret) are computed locally and then destroyed.
How it works
| Step | Actor | Action |
|---|---|---|
| 1 | User | Uploads Aadhaar XML → SDK generates Groth16 ZK proof in-browser |
| 2 | Issuer | Calls verifyProof() → registers nullifier on Algorand |
| 3 | dApp | Calls verifyKYC() → checks on-chain registry |
Quick Start
🌐 Browser — Generate ZK Proof
import { CipheraProver } from 'ciphera-sdk';
const prover = new CipheraProver({
wasmUrl: 'https://your-cdn.com/kyc.wasm',
zkeyUrl: 'https://your-cdn.com/kyc_final.zkey',
});
const result = await prover.generateProof({
aadhaarHash: '123456789012345...', // SHA-256 of Aadhaar XML as BN254 field element
walletSecret: '987654321098765...', // Random secret tied to user's wallet
appId: 756272073, // NullifierRegistry app ID
dobYear: 2000, // User's birth year (age >= 18 enforced by circuit)
});
console.log(result.nullifierHex); // '3b1f8a2c...' — 32-byte hex for on-chain use
console.log(result.proveTimeMs); // e.g. 4200ms
// → Send result.proof + result.publicSignals to your issuer backend🖥️ Issuer Backend — Verify Proof & Register On-Chain
import { verifyProof, CipheraClient } from 'ciphera-sdk';
import verificationKey from './verification_key.json' assert { type: 'json' };
// 1. Verify the ZK proof
const verification = await verifyProof(
verificationKey,
proof,
publicSignals,
756272073 // Expected appId (prevents cross-app replay attacks)
);
if (!verification.valid) throw new Error(verification.error);
// 2. Register nullifier on Algorand Testnet
const client = new CipheraClient();
const txId = await client.registerNullifier(
process.env.ISSUER_MNEMONIC!,
verification.nullifierHex!,
userWalletAddress
);
console.log('Registered:', CipheraClient.explorerTxUrl(txId));
// → https://allo.info/tx/<txid>🏗️ dApp — Gate Access by KYC Status
import { CipheraClient } from 'ciphera-sdk';
const client = new CipheraClient();
// Check registry-level KYC
const status = await client.verifyKYC(userWalletAddress);
if (status.isVerified) {
// Grant access
}
// Or check a specific nullifier directly
const registered = await client.isNullifierRegistered(nullifierHex);API Reference
CipheraProver
new CipheraProver({ wasmUrl, zkeyUrl, smtDepth? })| Method | Returns | Description |
|---|---|---|
| generateProof(inputs) | Promise<KYCProofResult> | Generate Groth16 ZK proof entirely in-browser |
ProveInputs parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| aadhaarHash | string \| bigint | ✅ | SHA-256 of Aadhaar XML as BN254 field element |
| walletSecret | string \| bigint | ✅ | Random secret binding proof to wallet |
| appId | number \| string \| bigint | ✅ | NullifierRegistry app ID |
| dobYear | number \| string | ✅ | Year of birth (circuit enforces age ≥ 18) |
| currentYear | number \| string | ❌ | Defaults to current year |
| merkleSiblings | string[] | ❌ | SMT proof path (20 elements, defaults to zeros) |
| merklePos | string[] | ❌ | SMT path bits (20 elements, defaults to zeros) |
CipheraClient
new CipheraClient(config?)| Method | Returns | Description |
|---|---|---|
| verifyKYC(walletAddress?) | Promise<KYCStatus> | Check registry KYC status |
| isNullifierRegistered(hex) | Promise<boolean> | Direct nullifier box check |
| registerNullifier(mnemonic, hex, wallet) | Promise<string> | Register on-chain (issuer only) |
| getCredentialAsaId() | number | KYCRED ASA ID |
| CipheraClient.explorerTxUrl(txId) | string | Allo.info TX explorer URL |
| CipheraClient.explorerAppUrl(appId) | string | Allo.info app explorer URL |
CipheraConfig options:
| Option | Type | Default | Description |
|---|---|---|---|
| algodServer | string | Algorand Testnet (AlgoNode) | Custom Algod endpoint |
| algodToken | string | "" | Algod API token |
| contractIds | Partial<ContractIds> | Testnet defaults | Override deployed contract IDs |
| wasmUrl | string | — | Path/URL to kyc.wasm |
| zkeyUrl | string | — | Path/URL to kyc_final.zkey |
verifyProof(vk, proof, signals, appId?)
Verify a Groth16 ZK proof off-chain.
| Parameter | Type | Description |
|---|---|---|
| verificationKey | VerificationKey | Groth16 verification key (from verification_key.json) |
| proof | Groth16Proof | Proof object from the browser SDK |
| publicSignals | string[] | Public signals array |
| expectedAppId | number \| string | (Optional) Guard against cross-app attacks |
Returns: { valid, nullifierHex?, publicSignals?, error? }
Crypto Utilities
import { mimcHash, computeNullifier, computeNullifierHex } from 'ciphera-sdk';
// Compute nullifier directly (without generating a full proof)
const hex = computeNullifierHex(aadhaarHash, appId, walletSecret);
// Low-level MiMC hash (Miyaguchi-Preneel, BN254 field)
const hash = mimcHash([field1, field2]);Types
interface KYCProofResult {
proof: Groth16Proof;
publicSignals: KYCPublicSignals;
nullifierHex: string; // 32-byte hex for on-chain use
proveTimeMs: number; // Proof generation time in milliseconds
}
interface KYCStatus {
isVerified: boolean;
totalRegistered?: number;
nullifier?: string;
appId: number;
}
interface KYCPublicSignals {
nullifier: string; // BN254 field element (decimal string)
merkleRoot: string; // SMT root
appId: string; // Algorand app ID
isIndian: "1"; // Circuit-enforced
isAdult: "1"; // Circuit-enforced (age >= 18)
isKYCVerified: "1"; // Circuit-enforced
}Deployed Contracts (Algorand Testnet)
| Contract | App ID | Explorer |
|---|---|---|
| NullifierRegistry | 756272073 | allo.info ↗ |
| SMTRegistry | 756272075 | allo.info ↗ |
| KYCBoxStorage | 756272299 | allo.info ↗ |
| CredentialManager | 756281076 | allo.info ↗ |
| KYCRED ASA | 756281102 | allo.info ↗ |
Links
License
MIT © Aditya Pandey
