Docs
How it works.
Zekro helps a person prove one requirement with cryptography, without handing over all the information behind it. The first requirement it covers: I belong to this group.
Overview
Picture a community with a list of members who may use an app. The usual way to check is to ask a person who they are and look them up. That tells the checker who is asking, every time. With Zekro, the list holds commitments instead of names, and a member proves that one commitment is theirs without saying which.
The technology is a zero-knowledge proof over a Merkle tree of commitments. Zekro is the studio around it: create a group, add commitments, publish the root, generate a proof in your browser, and let anyone check it.
What it does not do
It does not make your activity anonymous. A zero-knowledge proof proves only the statement designed into the circuit. Your wallet address, IP, network metadata and transaction activity can stay visible through other layers.
- If you send a proof from your everyday wallet, that wallet is on the transaction, with its whole history.
- If you add your own commitment from that wallet, the two are linked in public. Ask a curator to add it, or use open enrollment knowing what it shows.
- The RPC, this site's server and your network can see your requests.
- In a small group, being a member may already say a lot. A proof from a list of three hides you among three.
- It does not say a member is trustworthy, human or unique. It says what the list's curator put on the list.
- A valid proof alone proves nothing about a real group: anyone can prove against a tree of their own. The verify page says "checks out" only for a proof tied to a root still standing in the book, and shows anything else as a warning.
The review page shows all of this next to a real proof.
Identity and commitment
Your browser draws two random values and keeps them: a secret and a salt. The commitment is their Poseidon hash, and it is the only thing you share to join.
commitment = Poseidon(secret, salt)
nullifier = Poseidon(secret, scope)
signal = keccak256(message) >> 8The identity is kept in this browser's storage. Clear the storage or lose the device without a backup and that membership is gone: nobody can restore it. The studio shows a backup line you can copy; anyone who has that line can prove as you.
Groups, roots, scopes
A group has one admin and a list of up to 65,536 commitments. The admin hands out two roles per group: a curator adds or clears commitments and publishes roots, a scope keeper opens and closes scopes. A group moves from Forming to Active on its first root, can be Paused and resumed, and can be Retired for good.
A root is the Merkle root of the list. The contract cannot compute Poseidon, so the curator publishes the root next to the digest of the list it came from. A root for an older list is refused. Anyone can read the list from the contract, rebuild the tree and compare; the review page does this for you. The newest 32 roots stay usable so members who were mid-proof are not cut off, and the admin can revoke one.
A scope is one round: a vote, a gate, a claim on a seat. Each member can prove once per scope, because one secret gives one nullifier there. The contract ties each scope to this chain, this contract, this group and this scope number, so a proof made for one is worthless in any other.
Removing a member means clearing their leaf, publishing a new root and revoking the old ones. Until the old roots are revoked or age out, that member can still prove against them. That is a real limit: the admin has to act.
The circuit
The source is one short Noir file, circuits/membership/src/main.nr. Compiled size: 19,734 gates, proved with UltraHonk (Barretenberg). The whole statement:
fn main(root: pub Field, scope: pub Field, nullifier: pub Field, signal: pub Field,
secret: Field, salt: Field, path_elements: [Field; 16], path_indices: [Field; 16]) {
scope.assert_max_bit_size::<248>();
signal.assert_max_bit_size::<248>();
assert(secret != 0);
assert(nullifier == Poseidon(secret, scope));
assert(root_of(Poseidon(secret, salt), path_elements, path_indices) == root);
}Four public values, and that is all a verifier learns. The setup uses the universal parameters of Barretenberg (the public Ignition ceremony), so this circuit needed no ceremony of its own. Your browser fetches the circuit, about 7 MB of WASM and 4 MB of public parameters from this site, once.
Rebuild it from source and compare with bash circuits/build.sh --check, using nargo 1.0.0-beta.22 and bb 5.0.0-nightly.20260522.
The contracts
ZekroGroupBook keeps the groups: admin and roles per group, the status machine, commitments, root history, scopes and one nullifier per scope. It has no global owner, no fee and no upgrade path, and it takes no ETH.
ZekroMemberCheck is the verifier generated from the circuit, plus its two libraries ZekroFiatShamirTape and ZekroGateRelations. The runtime is 17,987 bytes, inside the 24 KB contract limit, so nothing had to be reduced. Generated verifiers put their heaviest code in those libraries, which is why there are four deployments and not two. Each part is under the limit on its own.
Accepting one proof on a local test chain took about 2.64 million gas for the whole transaction, verifier included. On Robinhood Chain you pay that in ETH at the current gas price; nothing else is charged.
Book: 0x3efe3bf22abfead607c75fba4b3086026fc66dae. Verifier: 0xd1cb32482ff03b79251e4fc4b7eedc493555dd3e.
Check any deployment against this source with npm run verify-deployment -- <address> --tx <creation tx>.
A proof, end to end
- A member makes an identity in the studio and sends the admin the commitment.
- A curator adds it, publishes the root, and a scope keeper opens a scope.
- The member reads the list, picks the scope, types a message and proves. The worker returns the proof and the four public values, and never the secret.
- The member hands out the bundle, or submits it to the contract from any wallet. Choose that wallet with care: it stays visible.
- Anyone checks it on the verify page, from the bundle or the transaction hash.
Status
| Membership circuit (Noir, depth 16) | Live on this site |
| Browser proving in a worker | Live on this site |
| Local check with the verification key | Live on this site |
| Studio in practice mode, kept in your browser | Live on this site |
| ZekroGroupBook + verifier on chain | Live |
| Hosted proving | Planned |
| Developer API | Planned |
| $ZEKRO utility | Planned |
Risks
- New code. The circuit and contracts have tests, listed in the repository, and no outside firm has examined them. A flaw in them could let someone prove what they should not.
- Generated verifier. It comes from a nightly build of the proving toolchain and could carry a flaw of its own.
- Group admins. An admin picks who is listed, can pause the group and can revoke roots. There is no appeal inside the contract.
- A dishonest root. A curator could publish a root that does not match the list. Rebuilding the tree shows this, but only if someone looks.
- Lost identity. There is no recovery. A leaked backup lets someone else prove as you.
- Slow devices. Proving runs on your machine; a low-end phone may take a long time or run out of memory.
$ZEKRO
$ZEKRO is the project's token, launching on Pons on Robinhood Chain. It has no promised value. The circuit, prover and contracts do not read it and do not need it. See the token page for the only address.
Planned
None of this is live, and we will not say it is until it is.
- Hosted proving, for devices that cannot prove on their own.
- A developer API for groups and proofs.
- $ZEKRO utility inside the studio.