
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
ciphera-sdk
Advanced tools
Zero-Knowledge KYC for Algorand — generate ZK proofs in the browser, verify KYC on-chain
Zero-Knowledge KYC for Algorand — TypeScript/JavaScript SDK
Generate ZK proofs in the browser. Verify KYC on-chain. Zero personal data exposed.
npm install ciphera-sdk
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.
| 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 |
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
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>
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);
CipheraProvernew 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) |
CipheraClientnew 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? }
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]);
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
}
| 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 ↗ |
MIT © Aditya Pandey
FAQs
Zero-Knowledge KYC for Algorand — generate ZK proofs in the browser, verify KYC on-chain
We found that ciphera-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.