IFT Research Call, June 18th 2025 - Zerokit v0.8 and its applications

Minutes

YouTube recording TBD

Concerns about the performance of RLN

Q: Particularly for high-throughput, low-latency applications like gaming on L2, considering the cost of proof generation and verification, is the performance an obstacle, so RLN can’t be used?

A: Clarification: the latest version has significantly improved performance, with proving now taking milliseconds (previously it was 1 second, now it is 200ms while the verification takes 6ms), making it suitable for many applications. Also verification is highly parallelizable, which reduces the limits to practically nothing, meaning no bottlenecks in verification or proving. The sequencer in an L2 would likely be a more significant bottleneck than RLN performance. It is also highly dependent on the specific application.

Stateless Merkle Tree Implementation

Q: How stateless Merkle trees work without being stored by Zerokit?

A: This is related to Groth16. In that setup, we generate a message that includes private user parameters — it’s a classical ZK (zero-knowledge) proof structure. This proof allows us to verify whether a user belongs to a specific group — one where we want to implement spam protection, for example. In addition to that, we perform some other checks, like validating timestamps or message ID limits. But those aren’t part of the ZK proof; they’re just simple number checks. Now, regarding the Merkle tree proof and the Groth16 proof — these are independent. They can be verified separately. That’s a key reason why we can decouple the identity layer and Merkle tree handling. In older versions of Zerokit, we had full support for all proof generation and verification, and the entity (our server) stored the Merkle tree. But this created a challenge: if you wanted to validate how many users there are or what identities they have, you’d need to store a full copy of the Merkle tree somewhere else — maybe on another server. That added complexity and inefficiency.

So, we introduced a stateless feature. Here’s how it works: for proof generation, we can now separate responsibilities. Private data remains on the user’s device (e.g., the Rocket side), and public data — such as the Merkle tree of identities — is stored on your side (for example, on-chain). When a user wants to generate a proof using non-stateless Zerokit, they simply request: “Generate a proof for this message.” They provide the message, their identity, and we look up the Merkle tree on our side, generate the Merkle proof, and include it with the rest of the ZK proof. During verification, the same applies: the verifier sends the proof, message, and identity to our Merkle tree instance, and we verify the Merkle proof, the ZK proof, and any other checks — then respond whether it’s valid or not. Now, in the stateless version, we no longer have access to the Merkle tree — it could be stored on-chain or off-chain, doesn’t matter. But we still need to be able to generate and verify proofs. So now, the user also needs to provide the Merkle path (the sibling hashes) and corresponding nodes. For example, with a Merkle tree of depth 20 (21 layers if counting the root), the user provides the 20 sibling nodes needed for the Merkle path. This way, we can independently verify the Merkle proof. In fact, this verification can happen entirely on the client side without giving us anything — but we support both options.

In summary, your group holds all user identities and knows how the Merkle tree is constructed. If you store that tree on-chain, you can use the stateless feature — ZeroKit doesn’t care how the tree is built or stored. You just delegate Merkle proof handling and ZK proof generation to ZeroKit. I hope that now it makes more sense.