--- Title: How to Build a Private DAO on Ethereum breaks: false --- $$\def\Zq{\mathbb{Z}_q} \def\EE{\mathbb{E}} \def\deq{\mathrel{\mathop:}=} \def\range#1{[{#1}]} \def\PK{\textit{pk}} \def\SK{\textit{sk}} \def\ct{\textit{ct}}$$ # How to Build a Private DAO on Ethereum ### Griffin Dunaif and Dan Boneh --- A [DAO is a form of partnership](https://en.wikipedia.org/wiki/Decentralized_autonomous_organization) where a group of people come together to achieve a shared goal. Recently, a DAO called [ConstitutionDAO](https://en.wikipedia.org/wiki/ConstitutionDAO) formed with the mission of purchasing one of the last remaining physical copies of the Constitution. The DAO raised an astonishing $40 million in under a week to place a bid. However, the DAO was promptly outbid by an individual investor who placed a bid at$43.17 million, just slightly above the assets of ConsutitutionDAO, thereby ensuring that the investor won the auction. Herein lies the problem with the current state of DAOs: their treasuries are public. When ConstitutionDAO was raising money, its entire balance sheet was visible to the public. This property can be detrimental to DAOs and impairs their ability to participate in certain types of auctions. In particular, DAOs cannot participate in sealed bid auctions precisely because their treasuries are public. In the case of ConstitutionDAO, having a public treasury enabled other bidders to know its maximal bid and outbid it. If DAOs are to become widely adopted, particularly by businesses, it is essential that the assets of the DAOs remain private. In particular, only the DAO managers should know the total assets managed by the DAO. There are ample use cases where a private treasury is necessary: an investment DAO may want the size of the fund to remain private, a business may want to keep its current sales numbers private, and of course, a fund participating in auctions needs its treasury to remain private. To solve this issue, we propose a simple treasury design that enables DAOs to utilize private treasuries. This short post explains the inner workings of a private DAO that runs on the Ethereum network. Our protocol is somewhat related to a protocol used by an anonymity mixer called [Tornado.cash Classic](https://tornado.cash/), however the privacy properties of the two protocols are quite different. Most notably, in Tornado.cash the sender and receiver are the same person: a client deposits funds into the Tornado contract and that same client later withdraws the funds. In our settings the sender and receiver are different: anyone can send funds to the DAO, but only the DAO manager can withdraw the funds. We note that a more advanced version of Tornado.cash, called Nova, provides all the features we need. However, Nova is designed to solve a much harder problem. Our Private DAO protocol is much simpler than Nova, but offers a different privacy properties. ## Privacy Goals and high level design The plan is to deploy a single *master contract* on the Ethereum chain, and this one contract will manage many DAOs, similar to the design of [juicebox](https://juicebox.money/#/). This single contract acts as a platform that makes it easy to create and manage DAOs. Every DAO created on this platform has a designated *DAO manager*, or a designated group of managers. Anyone can send funds to a DAO on the platform. However, only the DAO manager can withdraw funds from the DAO it is managing. We aim to provide the following privacy properties: * **Balanace privacy**: When someone sends funds to a DAO managed by the master contract, an observer cannot tell which DAO the funds are for. Clearly, an observer can tell the aggregate amount submitted to all DAOs on the platform by reading the master contract's balance. However, an observer learns nothing about the balance of each DAO, other than this upper bound. * **The DAO manager**: The DAO manager can calculate the current balance of funds sent to its DAO. Moreover, the DAO manager should be able to prove to a 3rd party that the DAO's balance is greater than a certain amount. * **Withdrawal privacy**: When the DAO manager withdraws funds from its DAO, the amount withdrawn is public, but the remaining balance of the DAO remains hidden. * **Non goal:** We stress that we do not aim to provide privacy for end users who contributed funds to the DAO. In particular, an observer may eventually learn the Ethereum addresses who sent funds to the DAO. While we do not aim to provide privacy for contributors, our protocol does provide some privacy. We will come back to this when describing the withdrawal protocol. The last bullet needs more discussion. There are protocols that provide privacy for contributors, such as Tornado.cash Nova, where even the DAO manager does not know the source of the funds to its DAO. However, these designs may be difficult to use in the context of a DAO platform. First, privacy for contributors may complicate KYC requirements. Second, privacy for contributors may complicate the process of issuing refunds to contributors, in case the DAO needs to refund all or some of the contributions. Both issues are solvable, but they complicate the user experience. As such, we believe that our set of privacy goals outlined above is an interesting point in the design space, and one that enables a simple and efficient protocol. <!-- **Privacy for contributors**: The system should not reveal the source of the funds. An observer can see that a specific Ethereum address sent funds to the master contract. However, the observer should not know which DAO received the funds. Moreover, privacy for contributors should be maintained even after that DAO manager withdraws funds from the DAO. --> If the master contract manages sufficiently many DAOs of comparable size, then our privacy goals make it possible for DAOs on the platform to participate in a sealed bid auction. While an observer knows an upper bound on the assets of a particular DAO, it does not know the amount that belongs to that DAO. Moreover, the DAO manager can prove to the auction house that it has sufficient funds to participate in the auction, and can withdraw the funds when it comes time to bid. ## PDAO: A Private DAO Protocol The life cycle of a DAO managed on the platform has three key steps: * **DAO creation**: the DAO manager creates the DAO. This step require no on-chain transations. * **Deposit**: used by an end-user who wants to contrbute funds to the DAO. * **Withdrawal**: used by the DAO manager to withdraw funds from the DAO. We describe these steps in detail in the next three subsections. **Contract initialization**: When the master contract is first deployed it is initialized with an empty Merkle tree $T$ of depth $d$ (say $d = 32$). An empty tree is a tree where all the leaves are zero. The contract stores (i) the root hash of this Merkle tree, and (ii) a counter called *next* that is initially set to zero. This counter indicates the location of the next empty leaf in the tree, counting from left to right. When *next* reaches to $2^{d}-1$, the tree is full and a new contract must be initialized. ### Step 1: Creating a DAO Our protocol uses a finite cyclic group $\EE$ of prime order $q$ with generator $G \in \EE$. For efficiency, we take $\EE$ to be the group of points on the [Grumpkin elliptic curve](https://hackmd.io/@aztec-network/ByzgNxBfd#2-Grumpkin---A-curve-on-top-of-BN-254-for-SNARK-efficient-group-operations) that are defined over the base field. This curve is designed for efficient SNARK proof generation on the Ethereum network. The curve is defined over a prime field $\mathbb{F}_r$, where $r$ is the size of the curve *alt_bn128* used by the [Ethereum pairing precompile](https://eips.ethereum.org/EIPS/eip-197). As such, arithmetic over $\mathbb{F}_r$ can be efficiently implemented by a SNARK prover. Now, to create a DAO, the DAO manager posts a Schnorr public key to the DAO web site. In more detail, the DAO manager samples a random $\alpha$ from $\Zq$, computes $\PK \gets \alpha \cdot G \in \EE$, and posts $\PK$ to the DAO’s website. The manager keeps the secret key $\alpha$ to itself. That’s it. There is no on-chain activity and no gas fees. ### Step 2: A member sends funds to the DAO A client wants to send ETH to the DAO, say a total of $v$ ETH. The client obtains the DAO’s public key $\PK \in \EE$ from the DAO's web site and does the following: 1. Sample a random $\rho$ in $\Zq$; 1. Compute what we call a leaf, which is a pair: $\ \ L = \bigl( \rho \cdot G,\ \ \rho \cdot \PK \bigr) \in \EE^2$; 1. Call the master contract’s *deposit()* function with the argument $L$, sending $v$ ether in the transaction; 1. The master contract accepts the funds and records the expanded leaf $$L’ = \bigl( \rho \cdot G,\ \ \rho \cdot \PK,\ \ v, \ \ n \bigr)$$ in the next unoccupied leaf, from left to right, of the Merkle tree $T$. Here $n$ is the leaf number that is designated for $L'$ in $T$. Specifically, the contract sets $n \gets \textit{next}$ and inserts $L'$ into leaf number *next*. The contract increments the value of *next* by one, and computes the Merkle root of the tree $T$ obtained by adding this new leaf $L'$ to the existing tree $T$ at position $n$. If the tree has depth $d$, then computing the updated Merkle root can be done by storing only $d$ hash values in the contract's storage. Since the leaf $L$ is posted on-chain, and is public for the entire world to see, it is imperative that $L$ reveal nothing about the identity of the DAO that received the funds. In particular, nothing about $\PK$ should be revealed. This easily follows from the hardness of the Decision Diffie-Hellman assumption in the group $\EE$. ### Step 3: the DAO manager withdraws funds When the DAO manager wants to withdraw $w$ ETH from the DAO, it must do so by proving that the DAO was the intended recipient of at least that much ETH. Moreover, those funds should only be withdrawn once. All this must be done without revealing the balance of the DAO to the contract. We will accomplish this by utilizing a SNARK. First, how does the DAO manager even know the balance of the funds sent to the DAO? To do so, the DAO manager will monitor all the deposits sent to the master contract. For every observed leaf $L' = \bigl(P,\ Q,\ v,\ n \bigr)$ the DAO manager uses its secret key $\alpha$ to test if $$\alpha \cdot P = Q.$$ If so, the DAO manager learns that this deposit is intended for its DAO and records that $v$ ETH were added to the DAO balance. Otherwise, this deposit is meant for some other DAO. *A word of caution:* When the DAO manager finds a deposit meant for its DAO it will do a little more work to add the balance to the DAO balanace. It is important that this does not introduce a timing side channel on the DAO manager's machine, otherwise an observer will learn that the current deposit is meant for this DAO. [This paper](https://floriantramer.com/publications/sidechannels20/) discusses this problem in detail. **The withdrawal protocol.** Next, suppose the DAO manager wants to withdraw $w$ ETH from the DAO. We require that there is a subset of leaves $\bigl\{L_i' = (P_i, Q_i, v_i, n_i) \bigr\}_{i=1}^\ell$ that belong to the DAO such that $v_1 + \cdots + v_\ell = w$. A simple withdrawal protocol is for the DAO manager to call the *withdraw()* function on the master contract giving it the argument \begin{align} \label{eq:one} (L_1', \ldots, L_\ell',\ \pi_m,\ \pi_s), \tag{1} \end{align} where * $\pi_m$ is a batch-Merkle proof that proves that $L_1', \ldots, L_\ell'$ are leaves in the Merkle tree $T$ (recall that the master contract stores the Merkle root for $T$), * $\pi_s$ is a batch-Schnorr proof that proves that the DAO manager knows $\alpha \in \Zq$ such that $Q_i = \alpha P_i$ for all $i=1,\ldots,\ell$. Note that batch-Merkle and batch-Schnorr proofs are more efficient than simply repeating a single-instance Merkle or Schnorr proof $\ell$ times. The master contract verifies that 1. the proofs $\pi_m$ and $\pi_s$ are valid with respect to its stored Merkle root, 2. $v_1 + \cdots + v_\ell = w$, and 3. the leaves $n_1, \ldots, n_\ell \in [2^d]$ have not yet been spent. If so, the master contract sends $w$ ETH to the DAO manager, which is the originator of the withdrawal request. It also adds $n_1, \ldots, n_\ell$ to its list of spent leaves so that these leaves cannot be spent again. Note that by revealing which leaves are spent on withdrawal, an observer learns the Ethereum address of the contributor who sent the funds to the DAO. As such, a contributor Alice is anonymous until the point in time when the DAO manager withdraws Alice's contribution from the master contract. Prior to that moment, an observer will know that Alice contributed to the platform, but will not know which DAO received the contribution. **A more efficient withdrawal protocol.** The difficulty with the simple withdrawal protocol above is that the call data $(L_1', \ldots, L_\ell', \pi_m, \pi_s)$ in $\eqref{eq:one}$ can be quite large. Moreover, verifying the Merkle and Schnorr multi-proofs on chain can be quite costly. Both these factors can result in high transaction fees for withdrawing funds from the master contract. We can reduce the withdrawal transaction fees by using a SNARK. Here the DAO manager calls the *withdraw()* function on the master contract giving it the much shorter argument $$(n_1, \ldots, n_\ell, \pi),$$ where $\pi$ is a SNARK proof that the DAO manager knows a witness $$(\alpha, P_1, Q_1, v_1, \ldots, P_\ell, Q_\ell, v_\ell)$$ such that 1. for $i=1,\ldots,\ell$ the leaf $(P_i, Q_i, v_i, n_i)$ is in the merkle tree $T$, 2. for $i=1,\ldots,\ell$ we have $Q_i = \alpha \cdot P_i$, and 3. $v_1 + \cdots + v_\ell = w$. The master contract verifies the SNARK proof $\pi$ and checks that the leaves $n_1, \ldots, n_\ell \in [2^d]$ have not yet been spent. If so, the master contract sends $w$ ETH to the DAO manager, the originator of the withdrawal request. It then adds $n_1, \ldots, n_\ell$ to its list of spent leaves so that these leaves cannot be spent again. Since a SNARK requires a fixed size input, we can set $\ell = 100$, so that the DAO manager can withdraw a batch of up to a hundred leaves at a time. ## Implementation <!-- Our implementation of the system is available here: https://github.com/securitylab/privDAO --> The current implementation features a JavaScript CLI and package, which can be plugged into a graphical user interface. The JavaScript module consists of two functions: *deposit()* and *withdraw()*. The *withdraw()* function runs on the DAO manager's machine and computes a SNARK proof. This is done using the Groth16 SNARK system implemented in *snarkjs*. The PrivateTreasury smart contract is 145 lines of Solidity. It includes a SNARK verifier. In addition, it features the MerkleTreeWithHistory contract from TornadoCash, and the MiMC hash from circomlib.