詳解Tornado Cash V2 設計原理

> 開發者ameen.eth 將「Proof-of-Innocence」概念和Tornado Cash 結合,提供另一個「隱私不等同於犯罪」的方向。

撰文:林瑋宸Albert Lin

前言

TornadoCash 是加密貨幣世界中著名的匿名交易服務。 TornadoCash 利用ZKP(Zero-Knowledge Proof)技術來隱藏資金來源。美國政府主張這樣的機制助長了非法金流活動,最終在2022 年8 月被美國財政部製裁而被迫下架。隱私保護和洗錢活動在很多情況下似乎總是緊密相連。在追求隱私的同時,不法分子往往利用這些隱私特性進行非法資金清洗。是否能找到一種方法,既能讓人們擁有隱私,又能有效遏制洗錢活動? TornadoCash 早期開發者ameen.eth 的Privacy-Pools 或許給出了一個方向。 (關於下架的部分只有前端網站和GitHub Repository 受到影響,合約部份因在區塊鏈上則不受影響。最後在電子前哨基金會的爭取之下GitHub 有恢復Repository,詳情可以參考這)

簡介TornadoCash 原理

在介绍 Privacy-Pools 之前,需要先理解 TornadoCash 相关的设计原理。详细介绍可以参考我之前的文章「Breaking Down TornadoCash: A Beginner’s Guide to Explaining its Functionality to Friends」。这边简单複习一下 TornadoCash 的设计原理。

TornadoCash 使用收據( commitment)來控制訪問權限。收據是由secret(秘密值)和nullifier (註銷碼)一起Hash 產生,每個收據只能提款一次。使用Merkle Tree (雜湊樹)記錄存款信息,將收據作為leaf 節點併計算出Merkle Root (雜湊樹根)。使用者只需提供leaf 到root 中間經過的數據,即可證明該數據是否Merkle Tree 的leaves 之一,也間接證明之前有存款資金到TornadoCash。使用Zero-Knowledge Proof 來隱藏存款來源,另外使用nullifier 防止Double Withdrawal 攻擊。

TornadoCash 的收據有兩個含義

  • 證明之前發送者有存入資金
  • 確保每個接收者只能領取一次資金

「無罪證明」

根据 TornadoCash 设计的原理,只能知道领款的资金一定是来自之前的某笔存款的资金,但却不知道是来自哪一笔存款。这是不法份子使用 TornadoCash 进行不法的洗钱活动的主要目的,也是美国政府为什麽要监管 TornadoCash 原因。若我们可以提出另外的 Proof(ZKP),来证明领款时的资金不是来自拒绝清单的存款,是否就能证明这笔领款并非来自于不法份子,这就是「Proof-of-Innocence」(「无罪证明」)核心概念。

「Proof-of-Innocence」概念可以分成兩個方向

  • 證明領款的資金是來自允許清單中存款的資金集合(允許清單)
  • 證明領款的資金並沒有來自拒絕清單的存款資金集合(拒絕清單)

这两种做法都是可以证明领款资金都不是来自于拒绝清单裡的存款。下图的做法是採用拒绝清单的方式,证明领款的资金并非来自于拒绝清单的存款(红色)。

來源:

Privacy-Pools 設計原理

Privacy-Pools 在TornadoCash 基礎上多加上了「Proof-of-Innocence」的概念。 Privacy-Pools 領款收據除了TorandoCash 收據原本代表的意義之外,還有第三個意思:「證明領款的資金來自於允許清單中的存款」。

Privacy-Pools 收據代表意義:

  • 證明之前發送者有存入資金
  • 確保每個接收者只能領取一次資金
  • 證明領款的資金來自於允許清單中的存款

這邊我們使用Allow Merkle Tree 來解釋Privacy-Pools 是如何把「Proof-of-Innocence」運用在這個系統中(Allow Merkle Tree 是運用允許清單的概念)。首先Allow Merkle Tree 有幾個特點

  • Allow Merkle Tree 顧名思義是一個Merkle Tree
  • 樹高和節點數都跟Privacy-Pools 的Deposit Merkle Tree 相同。
  • Allow Merkle Tree 的leaf 皆對應Deposit Merkle Tree leaf(存款) 位置。

Allow Merkle Tree leaf 資料可以分成下面二類:

  • allowed:表示該位置的存款是允許。 (尚未有存款的位置也是預設allowed )
  • blocked:表示該位置的存款是拒絕。

下圖可以看到index 0 和1 的位置在Deposit Merkle Tree 皆為legal funds,對應的Allow Merkle Tree leaf 位置也是allowed。

假設今天有一名不法份子想要進行洗錢活動,他把攻擊後所得不法資金存進Privacy-Pools ,存款位置是Deposit Merkle Tree index:2 的位置。我們知道那是不法的資金,所以在對應的Allow Merkle Tree index:2 位置我們更新為blocked。

允許清單領款情形

假設今天有一名在美國政府允許清單存款的用戶想要提領資金,需要提供「有存款在Dposit Merkle Tree 中的證明」之外,還需要提供「在美國允許清單的是Allowed 的證明」。對應美國允許清單的證明包含了Allow Merkle Root (由用戶自行提供,在程式碼中為subetRoot)和中途會經過的node 值。 Privacy-Pools 在驗證ZKP 階段時,會以leaf 值為allowed (實際程式碼中是keccak256(allowed))和給定中途會經過的node 值去建構出Merkle Root。驗證此Merkle Root 與用戶提供的Allow Merkle Root 是否相同。若相同代表驗證通過,表示該領款的資金是來存在於美國政府允許清單中的存款。

拒絕清單領款情形

今天有一名不在美國政府允許清單存款的用戶想要提領資金,而對應的存款的位置在美國政府允許清單中被標記成blocked。這樣會導致用戶無法使用美國政府允許清單的Allow Merkle Root 去領出資金,因為產生不出對應的證明而導致驗證失敗(因為Privacy-Pools 使用leaf 是值allowed 去做計算,而美國政府允許清單將該位置標記成blocked,導致計算不出相同的Merkle Root )。

这样的设计被迫这名用户需要提供其他的 Allow Merkle Root 才能提领资金(其他的 Allow Merkle Tree 需将该存款位置标记成 allowed,才能计算出相同的 Allow Merkle Root 来通过验证)。这个其他的 Allow Merkle Tree 可能来自于其他政府或机构所维护,甚至是这名用户自行产生。今天美国政府就可以藉由提领时所用的 Allow Merkle Root, 来判断用户的资金是否符合美国政府的法律规范,藉此来达到追踪的目的。若用户是使用自己产生或不具公信力的的 Allow Merkle Tree ,基本上该笔领款资金极有可能来自有问题的存款(每个具公信力的第三方 Allow Merkle Tree 都将该存款位置标记成 blocked)。

常見的問題

**Q: 如果Allowroot 是由提領人提供,是不是可以假造一個假Allow Merkle Root 來證明該leaf 是允許清單中的存款,是不是代表還是可以把錢領走呢? **

A: 答案是肯定的,確實是可以把錢領走。這一點作者有特別提出說,這樣的機制並不是要禁止不法份子把錢領走,而是就算可以領走也會被知道說這筆資金是拒絕清單的資金。當提領人提供了一個沒有說服力的Allow Merkle Root,基本上可以視為他是從拒絕清單存款提領。筆者這邊猜測允許這樣做的原因是想要保持這個服務的去中心化性質。因為每個Allow Merkle Tree 都需要有一定的權限管理去更新每個leaf 的status。若強制指定某個allow tree root 的話,代表有人有一定權限控制資金的提領,這一點並不符合去中心化的精神。

**Q: 會是由誰來決定這筆交易是來自於拒絕清單資金呢? **

A: 笔者看到的部分并没有特别提,理解是这部分应该由各监管单位自己去做。假设今天美国政府要查 Privacy-Pools 的髒钱,他可以透过去检查每笔的 Allow Merkle Root 来判断他是不是髒钱。至于怎样的 Allow Merkle Root 是允许,那就是各监管单位他们自己去判断。

Privacy-Pools 程式碼

这裡附上主要的程式码和笔者自己的注解,希望可以帮助大家可以透过程式码理解主要逻辑。

// circuits/withdraw_from_subset.circom

模板 WithdrawFromSubset(級別,預期值){

// 民眾

信號輸入根;

信號輸入subsetRoot;

信號輸入消除器;

信號輸入資產元數據; // abi.encode(token, amount).snarkHash();

信號輸入withdrawMetadata; // abi.encode(recipient, refund, relayer, fee).snarkHash();

// 私人的

信號輸入秘密;

信號輸入路徑; // 表示數據代表的是左葉還是右葉。

信號輸入 mainProof [levels] ; // 構造存款根所需的數據。

信號輸入子集證明 [levels] ; //構造允許root所需的數據。

// 計算 nullifier 和 commitment。

組件散列器 = CommitmentNullifierHasher();

hasher.secret <== 秘密;

hash.path <== 路徑;

hasher.assetMetadata <== assetMetadata;

nullifier === hasher.nullifier;

// expectedValue: keccak256("允許") % p

組件 doubleTree = DoubleMerkleProof(levels, expectedValue);

doubleTree.leaf <== hasher.commitment;

// 將路徑轉換成bits,指定是左葉還是右葉。

// 可以觀察到deposit tree和allow tree共享同一條路徑。

doubleTree.path <== 路徑;

for ( i = 0; i < levels; i++) {

doubleTree.mainProof [i] <== 主證明 [i] ;

doubleTree.subsetProof [i] <== 子集證明 [i] ;

}

root === doubleTree.root; // 驗證存款根。

subsetRoot === doubleTree.subsetRoot; // 驗證允許根。

信號 withdrawMetadataSquare;

withdrawMetadataSquare <== withdrawMetadata * withdrawMetadata;

}

長篇大論

  • 「Proof-of-Innocence」是用另一個Proof 來證明該筆領款是來自於允許清單中的存款。 「Proof-of-Innocence」可以從允許清單和拒絕清單兩個角度來建構。
  • Privacy-Pools 在TornadoCash 基礎上疊加了「Proof-of-Innocence」的概念,原本的收據代表意義多了第三個意思:「證明領款的資金來自於允許清單中的存款」。
  • Allow Merkle Tree 存在可以證明提領資金是存在允許清單中。 Allow Merkle Tree 的leaf 位置相對應於Deposit Merkle Tree 的存款leaf 位置。 Allow Merkle Tree leaf 資料為allowed 和blocked。
  • 領款者除了需要提供建構Deposit Merkle Root 所需資料之外,還需要另外提供Allow Merkle Root 和建構Allow Merkle Root 的資料來證明提領資金的是存在允許清單中。
  • 由于 Allow Merkle Root 是由领款者提供,不法份子仍有办法透过假造的 Allow Merkle Root 来把不法资金领走。假造的 Allow Merkle Root 依然会呈现在链上并被其他人视为这笔领款仍有存有疑虑,藉此来达到追踪不法资金的流向。

开发者 ameen.eth 将「Proof-of-Innocence」概念和 TornadoCash 结合,提供另一个「隐私不等同于犯罪」的方向。笔者觉得有趣的角度是利用另一个 ZKP 来证明另一件事实,有点像是 ZKP 的加法。这样的使用方式会比建构一个更大行更複杂的 ZKP 更来为简单,效率也更高。关于 Allow Merkle Tree 的选择,感觉之后会是由一个比较公正的单位来建构,这样对于其他人也有比较高的说服性。

最後感謝Chih-Cheng Liang 以及Ping Chen 幫忙Review 文章和給出寶貴的意見!

> 參考:

> 隱身地址

> Tornado Cash實例解析

> ZKP 與智能合約的開發入門

> [ZKP 讀書會] TornadoCash

> Tornado Cash — 運作方式 | DeFi + 零知識證明

> 深入理解TornadoCash 技術細節

> 0xhhh Thread 介紹新功能和其原理

> 演示視頻

> Vitalik’s 講如何改進 Tornadov2

> 隱私池 v0tweet

> 引入基於 TornadoCash 的無罪證明

查看原文
本頁面內容僅供參考,非招攬或要約,也不提供投資、稅務或法律諮詢。詳見聲明了解更多風險披露。
  • 讚賞
  • 留言
  • 分享
留言
0/400
暫無留言
交易,隨時隨地
qrCode
掃碼下載 Gate.io APP
社群列表
繁體中文
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)