TornadoCash V2: Privacy-Pools and "Proof-of-Innocence"

Introduction

TornadoCash is the most renowned anonymous transaction service in the world of cryptocurrency. TornadoCash utilizes Zero-Knowledge Proof (ZKP) technology to conceal the source of funds. The mechanism behind TornadoCash was criticized by the United States government for facilitating illegal financial activities, leading to its enforced delisting by the U.S. Treasury Department in August 2022. Privacy protection and money laundering activities often seem closely intertwined in many cases. While pursuing privacy, malicious actors often exploit these privacy features for illicit money laundering. Is it possible to find a method that allows people to maintain their privacy while effectively curbing money laundering activities? A possible direction has been suggested by Privacy-Pools, developed by ameen.eth, one of the early developers of TornadoCash. (Regarding the delisting, only the frontend website and GitHub repository were affected, while the contract portion remains unaffected on the blockchain. Eventually, the GitHub repository was restored under the efforts of the Electronic Frontier Foundation. For more details, please refer to this source.)


Introduction to TornadoCash Mechanism

Before introducing Privacy-Pools, it is important to understand the design principles behind TornadoCash. For a detailed explanation, you can refer to my previous article titled "Breaking Down TornadoCash: A Beginner's Guide to Explaining its Functionality to Friends." Here, I will briefly review the design principles of TornadoCash.

TornadoCash utilizes receipts, known as commitments, to control access rights. A commitment is generated by hashing a secret value and a nullifier code together. Each commitment can only be used for one withdrawal. Deposit information is recorded using a Merkle Tree structure, with commitments serving as leaf nodes, and the Merkle Root is calculated. Users only need to provide the data path from the leaf to the root to prove that the data is one of the leaves in the Merkle Tree, thereby indirectly proving the previous deposit of funds into TornadoCash. Zero-Knowledge Proofs are used to hide the source of the deposit, while nullifiers are used to prevent Double Withdrawal attacks.

TornadoCash's commitments serve two purposes:

  1. Proving Previous Deposit

  2. Ensuring Single Withdrawal


“Proof-of-Innocence”

According to the design principles of TornadoCash, it is only possible to determine that the withdrawn funds come from a previous deposit, but the specific deposit cannot be identified. This anonymity feature is exploited by criminals for illicit money laundering activities, which is why the US government seeks to regulate TornadoCash. However, if we can provide an alternative proof, such as Zero-Knowledge Proof (ZKP), to demonstrate that the withdrawn funds do not originate from deposits on the blacklist, it could potentially prove that the withdrawal is not associated with illicit activities. This concept is known as "Proof-of-Innocence," which aims to establish the innocence of the individual involved.

The concept of "Proof-of-Innocence" can be divided into two directions:

  1. Proving that the withdrawn funds originate from the set of deposits listed on the whitelist (Allowed List).

  2. Proving that the withdrawn funds do not come from the set of deposits listed on the blacklist (Denied List).

These two directions aim to establish the legitimacy of the withdrawn funds by either demonstrating their association with authorized deposits or their dissociation from prohibited deposits.

source: https://medium.com/@chainway_xyz/introducing-proof-of-innocence-built-on-tornado-cash-7336d185cda6
source: https://medium.com/@chainway_xyz/introducing-proof-of-innocence-built-on-tornado-cash-7336d185cda6

The design principle of Privacy-Pools

The design principle of Privacy-Pools builds upon TornadoCash and adds the concept of "Proof-of-Innocence." In Privacy-Pools, the withdrawal receipt serves not only its original purpose of representing a TornadoCash receipt but also carries a third meaning: "proving that the withdrawn funds originate from deposits on the whitelist."

By incorporating this additional proof, Privacy-Pools aims to provide an enhanced level of assurance regarding the legitimacy of the withdrawn funds, ensuring that they can be traced back to authorized deposits listed on the whitelist.

The receipt from Privacy-Pools represents the following meanings:

  1. Proving Previous Deposit

  2. Ensuring Single Withdrawal

  3. Proof that the withdrawn funds originate from deposits on the whitelist

Here, we use the Allow Merkle Tree to explain how Privacy-Pools incorporates the concept of "Proof-of-Innocence" into the system (where the Allow Merkle Tree represents the whitelist concept). First, the Allow Merkle Tree has several characteristics.

  • As the name suggests, the Allow Merkle Tree is a Merkle Tree.

  • The height of the tree and the number of nodes are the same as the Deposit Merkle Tree in Privacy-Pools.

  • Each leaf of the Allow Merkle Tree corresponds to the position of a leaf in the Deposit Merkle Tree (representing a deposit).

The data in the leaf nodes of the Allow Merkle Tree can be categorized into the following two types:

  • allowed: This indicates that the deposit at that position is allowed. (Positions without any deposits are also considered allowed by default.)

  • blocked: This indicates that the deposit at that position is blocked or denied.

The image below illustrates that the positions at index 0 and 1 in the Deposit Merkle Tree represent legal funds, and their corresponding positions in the Allow Merkle Tree are also marked as allowed.

Let's assume that today a criminal wants to engage in money laundering activities and deposits illicit funds into Privacy-Pools at the position with Deposit Merkle Tree ndex: 2. We are aware that these funds are illicit, so we update the corresponding position in the Allow Merkle Tree, specifically index: 2, to blocked This action ensures that the blocked funds cannot be withdrawn as they are associated with illicit activities.

In the case of withdrawals from the allowed list

Suppose a user, whose deposit is listed on the US government's allowed list, wants to withdraw funds. In addition to providing proof of having a deposit in the Deposit Merkle Tree, they also need to provide proof of being allowed on the US allowed list. The corresponding proof of the US allowed list includes the Allow Merkle Root (provided by the user, referred to as subsetRoot in the code) and the intermediate node values encountered along the way.

During the ZKP verification stage in Privacy-Pools, the Merkle Root is constructed using the leaf value allowed (in the actual code, it is keccak256(allowed)) and the given intermediate node values. The system then checks whether this calculated Merkle Root matches the Allow Merkle Root provided by the user. If they match, the verification is successful, indicating that the withdrawn funds come from a deposit listed on the US government's allowed list.

In the case of withdrawals from the denied list

If a user, whose deposit is not listed on the US government's allowed list, attempts to withdraw funds and their corresponding deposit position in the US allowed list is marked as blocked it would prevent the user from using the Allow Merkle Root associated with the US government's allowed list to withdraw funds. This would result in a verification failure as the corresponding proof cannot be generated.

In Privacy-Pools, the calculations rely on the leaf value allowed (keccak256(allowed) in the code), but the US government's allowed list marks that position as blocked. This discrepancy leads to the inability to calculate the same Merkle Root, resulting in a verification failure. As a result, the user would not be able to withdraw funds using the Allow Merkle Root from the US government's allowed list.

Under this design, the user would indeed need to provide an alternative Allow Merkle Root to withdraw funds. This alternative Allow Merkle Tree must mark the corresponding deposit position as allowed in order to calculate the same Allow Merkle Root for successful verification. This alternative Allow Merkle Tree can come from another government or institution that maintains such a list or even be generated by the user themselves.

In this scenario, the US government could use the Allow Merkle Root used during the withdrawal process to determine whether the user's funds comply with US government regulations, enabling them to track the funds. If the user is using a self-generated or untrusted Allow Merkle Tree, it is highly likely that the withdrawn funds come from problematic deposits, as any reputable third-party Allow Merkle Tree would mark that deposit position as blocked.


FAQ:

Q: If the Allow Merkle Root is provided by the withdrawer, can they forge a fake Allow Merkle Root to claim that the leaf corresponds to an allowed deposit? Does this mean they can still withdraw the funds?

A: The answer is affirmative. It is indeed possible to withdraw the funds in such a scenario. The author specifically points out that the intention of this mechanism is not to prevent criminals from withdrawing the funds, but rather to ensure that even if they succeed in doing so, it becomes known that the funds originated from the denied list. When the withdrawer provides an unconvincing Allow Merkle Root, it can be assumed that they are withdrawing funds from a deposit on the denied list. The reason for allowing this behavior is speculated to be to maintain the decentralized nature of the service. Each Allow Merkle Tree requires certain permission management to update the status of each leaf. If a specific Allow Merkle Tree root were enforced, it would mean that someone has certain privileges to control the withdrawal of funds, which goes against the spirit of decentralization.

Q: Who decides whether this transaction comes from funds on the denied list?

A: The author does not specifically mention who decides whether a transaction comes from funds on the denied list. It is understood that this aspect is likely to be determined by the respective regulatory authorities. For example, if the US government intends to investigate illicit funds in Privacy-Pools, they could examine each transaction's Allow Merkle Root to determine if it is associated with illicit funds. The criteria for determining which Allow Merkle Roots are considered valid or allowed would be determined by the respective regulatory authorities themselves.


Privacy-Pools Code

Here, I have provided the main code along with the author's comments, hoping it will help everyone understand the main logic through the code.

// circuits/withdraw_from_subset.circom
template WithdrawFromSubset(levels, expectedValue) {
    // public
    signal input root;
    signal input subsetRoot;
    signal input nullifier;
    signal input assetMetadata; // abi.encode(token, amount).snarkHash();
    signal input withdrawMetadata; // abi.encode(recipient, refund, relayer, fee).snarkHash();

    // private
    signal input secret; 
    signal input path; // Indicate whether the data represents the left leaf or the right leaf.
    signal input mainProof[levels];  // Construct the data required for deposit root.
    signal input subsetProof[levels]; // Construct the data required for allow root.

    // Calculate the nullifier and commitment.
    component hasher = CommitmentNullifierHasher();
    hasher.secret <== secret;
    hasher.path <== path;
    hasher.assetMetadata <== assetMetadata;
    nullifier === hasher.nullifier;

    // expectedValue: keccak256("allowed") % p
    component doubleTree = DoubleMerkleProof(levels, expectedValue);
    doubleTree.leaf <== hasher.commitment;
  
    // Convert the path to bits to specify whether it is the left leaf or the right leaf. 
    // It can be observed that the deposit tree and allow tree share the same path.
    doubleTree.path <== path; 
    for (var i = 0; i < levels; i++) {
        doubleTree.mainProof[i] <== mainProof[i];
        doubleTree.subsetProof[i] <== subsetProof[i];
    }
    root === doubleTree.root; // Verify the deposit root.
    subsetRoot === doubleTree.subsetRoot; // Verify the allow root.

    signal withdrawMetadataSquare;
    withdrawMetadataSquare <== withdrawMetadata * withdrawMetadata;
}

TL;DR

  • "Proof-of-Innocence" is a concept that uses another proof to demonstrate that a withdrawal comes from a deposit listed on the allowed list. It can be constructed from both the perspective of the allowed list and the denied list.

  • Privacy-Pools builds upon TornadoCash and adds the concept of "Proof-of-Innocence." The receipt in Privacy-Pools represents an additional meaning: proving that the withdrawn funds come from a deposit listed on the allowed list.

  • The Allow Merkle Tree exists to provide proof that the withdrawn funds come from the allowed list. The leaf positions in the Allow Merkle Tree correspond to the deposit leaf positions in the Deposit Merkle Tree. The Allow Merkle Tree leaf data can be "allowed" or "blocked."

  • In addition to providing the necessary data to construct the Deposit Merkle Root, the withdrawer also needs to provide the Allow Merkle Root and the data required to construct it as proof that the withdrawn funds come from the allowed list.

  • Since the Allow Merkle Root is provided by the withdrawer, it is possible for malicious actors to forge a fake Allow Merkle Root to withdraw illicit funds. However, the presence of a forged Allow Merkle Root would still raise suspicions on the blockchain and enable tracking of the flow of illicit funds.

Developer ameen.eth combines the concept of "Proof-of-Innocence" with TornadoCash, offering another perspective that "privacy is not equal to criminality." The author finds it interesting to use another Zero-Knowledge Proof (ZKP) to prove an additional fact, akin to the addition of ZKPs. This approach is simpler and more efficient compared to constructing a larger and more complex ZKP. Regarding the choice of the Allow Merkle Tree, it seems that in the future, it may be constructed by a more impartial entity, which would provide greater credibility to others.

Lastly, the author expresses gratitude to Chih-Cheng Liang and Ping Chen for reviewing the article and providing valuable insights.


Reference

Subscribe to Albert.Lin
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.