Trusted setup: one contributor. Try it; do not guard value with it yet.

Read the setup record

Privacy Developer SDK

The toolkit this site runs on

sdk/ in the repository is a small TypeScript package (@zksium/sdk). The pages of this site import it as is, and the Foundry tests use it to make the real proofs they verify. It runs in Node, in a page and in a Web Worker; the prover (snarkjs) is passed in.

Membership proof

import * as snarkjs from "snarkjs";
import {
  createIdentity, leafOf, MemberTree, scopeOf,
  proveEligibility, toBundle, proofCalldata,
} from "@zksium/sdk";

// 1. Member: make an identity, send only the leaf to the gate admin.
const me = createIdentity();             // keep me.secret private
const leaf = leafOf(me);

// 2. Rebuild the gate's tree from its MemberAdded logs (index order)
//    and compare tree.root with the contract's currentRoot(gateId).
const tree = new MemberTree(leaves);
const i = tree.indexOf(leaf);

// 3. Prove for a recipient. The scope binds the nullifier to this gate.
const scope = scopeOf(99901, GATE, gateId);
const files = { wasm: "eligibility.wasm", zkey: "eligibility.zkey" };
const p = await proveEligibility(snarkjs, files, me, tree.path(i), scope, recipient);

// 4. Send claimEligibility(gateId, recipient, p.root, p.nullifier, proofCalldata(p.proof))
//    from any address, or hand toBundle(p, 99901, GATE, gateId) to a checker.

Threshold proof

import { createAttribute, commitmentOf, exportAttribute,
  importAttribute, proveThreshold } from "@zksium/sdk";

// Attester: asks the holder for their leaf (never their secret)
const attr = createAttribute(250n, holderLeaf); // value + salt + holder
const c = commitmentOf(attr);            // publish: attest(c)
const handout = exportAttribute(attr);   // give privately to the holder

// Holder (only the identity behind holderLeaf can prove)
const a = importAttribute(handout);
const p = await proveThreshold(snarkjs, files, a, me, 100n, recipient);
// claimThreshold(gateId, recipient, p.commitment, proofCalldata(p.proof))

Check a bundle on Elysium

curl -s https://zksium.xyz/api/verify \
  -H 'content-type: application/json' \
  --data @zksium-proof.json
# {"valid":true,"block":5527811,"readAt":...}

Runs the generated verifier on Elysium's precompiles (eth_call + state override). 30 checks per 10 minutes per network.

Circuits

eligibility.circom · Eligibility(16)

4,326 constraints. Private: secret, 16 path elements, path index. Public: root, scope, recipient; output nullifier = Poseidon(secret, scope). leaf = Poseidon(secret). Up to 65,536 members per gate.

threshold.circom · Threshold()

667 constraints. Private: value, salt, holder secret. Public: commitment = Poseidon(value, salt, Poseidon(holder secret)), threshold, recipient. The attester knows value and salt but not the holder secret, so cannot prove in the holder's place. value and threshold are range-checked to 64 bits.

File served by this siteWhatsha256
/circuits/eligibility.wasmwitness generator76a0505f2f9038023e912304d8827219e20c6bae616b59870f4f0eb8994b0e4c
/circuits/eligibility.zkeyproving key (2.6 MB)4f8acedfeb197bef3990fe8aeef49a010ba41e19250de0c10f420b0587170ace
/circuits/eligibility.vkey.jsonverification key1dff35df87dfda715d6773dc274cc37898a262679f4bba8dd9def78d99bc8555
/circuits/threshold.wasmwitness generator36fe9664aa0d907edd27750b98d868c1bdab5480f950d1e0d18a9f8e7a54d429
/circuits/threshold.zkeyproving keyc5a15ebb98f7cfbc308cdd5414e196f3e4e1bbe00929c31c78f334e86bf55140
/circuits/threshold.vkey.jsonverification key23098bfaa05ad122f3bf97c93774bf131ab68e65134dd17bf581865610da6790

Contracts

ZksiumProofGate keeps gates, an on-chain Poseidon member tree per eligibility gate (depth 16, last 32 roots accepted), attestations, nullifiers and claims. No owner, no fee, no upgrade, no payable function, no token; it never holds funds. Verifiers are the snarkjs output for the two circuits; the Poseidon hasher is bytecode generated by circomlibjs. Deployed on Elysium on 14 Nov 2026 (gate created at block 6231853). npm run verify-deployment checks all four byte for byte against this build; the three Solidity contracts also have their source verified on the explorer. It is a new contract with no outside security review and a single-contributor setup: try it with nothing of value.

check* / ClaimRejected codeMeaning
0Valid: the contract would record this claim.
1No gate with this number.
2This proof is for the other kind of gate.
3The gate is closed to new claims.
4The root is not one of the gate's last 32 roots.
5This member already claimed in this gate (nullifier used).
6The commitment is not attested by the gate's attester, or the attestation was revoked.
7This commitment already claimed in this gate.
8This recipient already holds a claim in this gate.
9The proof does not verify against these public inputs.
10The recipient cannot be the zero address.

Measured with Foundry: a claim costs about 255,000 to 260,000 gas (Groth16 pairing check included); adding a member costs about 530,000 gas (16 Poseidon hashes on chain); deploying the gate about 2.9 million gas.