This document describes the various methods to store an RLN membership set (sparse merkle tree).
The two broad categories are, off-chain, and on-chain storage.
This category involves storing the RLN membership set on-chain with various techniques.
This strategy involves using a smart contract to merely serve as a coordination layer for registrations and withdrawals.
This is made possible by the usage of events emitted by the contract to signal new insertions/removals to be made by users to their local copy of the tree.
Solidity pseudocode:
function register(uint256 commitment) external {
require(commitments[commitment] == 0, "double registration"); // there are other checks as well.
commitments[commitment] = idCommitmentIndex;
emit MemberRegistered(idCommitmentIndex, commitment);
idCommitmentIndex += 1;
}
This strategy involves using a smart contract with a full implementation of an incremental binary tree for registrations and withdrawals.
This is made possible by using @zk-kit/imt.sol/BinaryIMT.sol
, which provides a BinaryIMT library for insertions, removals and root updates.
Solidity pseudocode:
BinaryIMTStorage binStorage;
function register(uint256 commitment) external {
require(commitments[commitment] == 0, "double registration"); // there are other checks as well.
BinaryIMT.insert(binStorage, idCommitmentIndex, commitment);
emit MemberRegistered(idCommitmentIndex, commitment);
idCommitmentIndex += 1;
}
function root() public pure {
return BinaryIMT.root(binStorage);
}
This strategy involves using a smart contract which serves as a coordination layer for registrations, withdrawals and updates to the merkle root without having the whole tree on-chain.
This can be achieved by making use of "state transition proofs" of the merkle tree, which each user provides while registering to the membership set
Verifier private v;
uint256 public root;
function register(uint256 commitment, uint256[8] proof) external {
require(commitments[commitment] == 0, "double registration"); // there are other checks as well.
v.verifyProof(proof);
emit MemberRegistered(idCommitmentIndex, commitment);
// extract root from proof provided
root = extractRoot(proof);
idCommitmentIndex += 1;
}