See withdraw_from_subset.circom for the circom implementation of this scheme. I'm not the best with math notation so it might make more sense to read the actual circom file.
$$
\begin{aligned}
\psi &= \text{poseidon hash function}\
\kappa_q &= \text{keccak256 hash function, mod q if necessary}\
R_{C'} &= \text{Merkle root of all deposits}\
M_{C'} &= \text{array of elements that form a merkle proof in }R_{C'}\
R_a &= \text{merkle root of some subset of }R_{C'}\
M_a &= \text{array of elements that form a merkle proof in }R_a\
A &= \text{asset public metadata: }\kappa_q(\text{token, denomination})\
W &= \text{withdraw public metadata: }\kappa_q(\text{recipient, relayer, fee})\
E &= \text{expected value in the subset: }\kappa_q(\text{"allowed"})\
s&= \text{crytographically secure random value}\
C &= \text{raw commitment: }\psi(s)\
C' &= \text{stamped commitment: }\psi(C, A)\
C'i &= \text{$i$-th commitment in } R{C'}\
N_i &= \text{nullifier for
Private Inputs
$s$ $i$ $M_{C'}$ $M_a$
Public Inputs
$R_{C'}$ $R_a$ $N_i$ $A$ $W$
- Verify that this design does what it claims to do.
- Solidity implementation & unit tests
- Subset compression and decompression algorithms
- Contracts/library for posting/retrieving data on-chain
- Interface and testnet deployment