Formal description of the circuits
Utils
utils.circom is a set of templates/gadgets that the RLN circuits uses.
These are:
- MerkleTreeInclusionProof - Merkle Tree inclusion check, used like set membership check;
- IsInInterval - used for range check.
Their description is given below.
MerkleTreeInclusionProof
MerkleTreeInclusionProof(DEPTH) template used for verification of inclusion in full binary incremental merkle tree. The implementation is a fork of https://github.com/privacy-scaling-explorations/incrementalquintree, and changed to binary tree and refactored to Circom 2.1.0.
Parameters:
DEPTH- depth of the Merkle Tree.
Inputs:
leaf-Poseidon(elem), whereelemis the element that's checked for inclusion;pathIndex[DEPTH]- array of length =DEPTH, consists of0 | 1, represents Merkle proof path. Basically, it says how to calculate Poseidon hash, e.g. for two inputsinput1,input2, if thepathIndex[i] = 0it shoud be calculated asPoseidon(input1, input2), otherwisePoseidon(input2, input1);pathElements[DEPTH]- array of length =DEPTH, represents elements of the Merkle proof.
Outputs:
root- Root of the merkle tree.
Templates used:
- mux1.circom from circomlib;
- poseidon.circom from circomlib.
IsInInterval
IsInInterval(LIMIT_BIT_SIZE) template used for range check, e.g. (x <= y <= z).
Parameters:
LIMIT_BIT_SIZE- maximum bit size of numbers that are used in range check, f.e. for theLIMIT_BIT_SIZE= 16, input numbers allowed to be in the interval[0, 65536).
Inputs:
in[3]- array of 3 elements.
Outputs:
out- bool value (0 | 1). Outputs 1 when the circuit is satisfied, otherwise - 0.
Templates used:
LessEqThan(n)from circomlib.
Logic/Constraints:
Checked that in[0] <= in[1] <= in[2]. That's done by combining two LessEqThan checks.
out value is calculated as a multiplication of two LessEqThan outputs.
RLN-same
rln-same.circom is a template that's used for RLN-same protocol.
Parameters:
DEPTH- depth of a Merkle Tree. Described here;LIMIT_BIT_SIZE- maximum bit size of numbers that are used in range check. Described here.
Private inputs:
identitySecret- randomly generated number inF_p, used as private key;messageId- id of the message;pathElements[DEPTH]- pathElements[DEPTH], described here;identityPathIndex[DEPTH]- pathIndex[DEPTH], described here.
Public inputs:
x-Hash(signal), wheresignalis for example message, that was sent by user;externalNullifier-Hash(epoch, rln_identifier);messageLimit- message limit of an RLN app.
Outputs:
y- calculated first-degree linear polynomial (y = kx + b);root- root of the Merkle Tree;nullifier- internal nullifier/pseudonym of the user in anonyomus environment.
Logic/Constraints:
- Merkle tree membership check:
identityCommitment=Poseidon(identitySecret)calculation;- Merkle tree inclusion check for the
identityCommitment.
- Range check:
- Range check that
1 <= messageId <= messageLimit.
- Range check that
- Polynomial share calculation:
a1=Poseidon(identitySecret, externalNullifier, messageId);y=identitySecret + a1 * x.
- Output of calculated
root,shareandnullifier=Poseidon(a_1)values.
RLN-diff
rln-diff.circom is a template that's used for RLN-diff protocol.
Parameters:
DEPTH- depth of a Merkle Tree. Described here;LIMIT_BIT_SIZE- maximum bit size of numbers that are used in range check. Described here.
Private inputs:
identitySecret- randomly generated number inF_p, used as a private key;userMessageLimit- message limit of the user;messageId- id of the message;pathElements[DEPTH]- pathElements[DEPTH], described here;identityPathIndex[DEPTH]- pathIndex[DEPTH], described here.
Public inputs:
x-Hash(signal), wheresignalis for example message, that was sent by user;externalNullifier-Hash(epoch, rln_identifier).
Outputs:
y- calculated first-degree linear polynomial (y = kx + b);root- root of the Merkle Tree;nullifier- internal nullifier/pseudonym of the user in anonyomus environment.
Logic/Constraints:
- Merkle tree membership check:
identityCommitment=Poseidon(identitySecret, )calculation;rateCommitment=Poseidon(identityCommitment, userMessageLimit)calculation;- Merkle tree inclusion check for the
rateCommitment.
- Range check:
- Range check that
1 <= messageId <= userMessageLimit.
- Range check that
- Polynomial share calculation:
a1=Poseidon(identitySecret, externalNullifier, messageId);y=identitySecret + a1 * x.
- Output of calculated
root,shareandnullifier=Poseidon(a_1)values.
Withdrawal
withdraw.circom is a template that's used for the withdrawal/slashing and is needed to prevent front run while withdrawing the stake from the smart-contract/registry.
Private inputs:
identitySecret- randomly generated number inF_p, used as private key.
Public inputs:
addressHash-F_pscalar field element.addressHash=Hash(address), whereaddressis ETH address that'll receive stake.
Outputs:
identityCommitment=Poseidon(identitySecret).