掃碼下載
BTC $76,768.74 +2.67%
ETH $2,400.28 +2.44%
BNB $639.39 +2.76%
XRP $1.47 +3.94%
SOL $89.58 +4.66%
TRX $0.3242 -0.68%
DOGE $0.1011 +3.82%
ADA $0.2625 +4.43%
BCH $452.72 +2.75%
LINK $9.69 +3.36%
HYPE $44.39 -1.49%
AAVE $117.17 +8.99%
SUI $1.01 +3.27%
XLM $0.1717 +6.10%
ZEC $344.70 +0.11%
BTC $76,768.74 +2.67%
ETH $2,400.28 +2.44%
BNB $639.39 +2.76%
XRP $1.47 +3.94%
SOL $89.58 +4.66%
TRX $0.3242 -0.68%
DOGE $0.1011 +3.82%
ADA $0.2625 +4.43%
BCH $452.72 +2.75%
LINK $9.69 +3.36%
HYPE $44.39 -1.49%
AAVE $117.17 +8.99%
SUI $1.01 +3.27%
XLM $0.1717 +6.10%
ZEC $344.70 +0.11%

最精妙的 ZK 應用:回看 Tornado Cash 的原理與業務邏輯

Summary: Tornado 為代表的隱私項目才是真正用到了 ZK-SNARK 算法的零知識性,而大多數打著 ZK 旗號的 Rollup,用到的只是 ZK-SNARK 的簡潔性。
極客 Web3
2023-09-08 17:39:36
收藏
Tornado 為代表的隱私項目才是真正用到了 ZK-SNARK 算法的零知識性,而大多數打著 ZK 旗號的 Rollup,用到的只是 ZK-SNARK 的簡潔性。

撰文: Faust ,極客 web3

導語:近期 Vitalik 和一些學者聯名發表了新論文,其中提到了 Tornado Cash 如何實現反 xi 錢方案(其實就是讓取款人證明,自己的存款記錄屬於一個不包含黑錢的集合),但文中缺乏對 Tornado Cash 業務邏輯與原理的細緻解讀,讓人似懂非懂

此外值得一提的是,Tornado 為代表的隱私項目才是真正用到了 ZK-SNARK 算法的零知識性,而大多數打著 ZK 旗號的 Rollup,用到的只是 ZK-SNARK 的簡潔性。很多時候人們往往混淆了 Validity Proof 與 ZK 的區別,而 Tornado 恰好是理解 ZK 應用的極佳案例。

本文作者恰好在 2022 年於Web3 Caff Research寫過一篇關於 Tornado 原理的文章,今日將其部分段落節選並拓展,整理成文,以便大家系統的理解 Tornado Cash。

「龍捲風」的原理

Tornado Cash 是利用了零知識證明的混幣器協議,舊版本在 2019 年投入使用,新版本在 2021 年底啟動了 beta 版。 Tornado 舊版本基本實現了去中心化,鏈上合約開源且無多簽控制,前端代碼開源且備份在了 IPFS 網絡裡。由於舊版 Tornado 的整體結構更簡單易懂,所以本文將針對舊版本進行解讀。

Tornado 的主要思路是:把大量的存取款行為混雜在一起,存款者在 Tornado 存入 Token 後,出示 ZK Proof 證明自己存過款,再用一個新地址提款,以此切斷存取款地址之間的關聯性。

更具體的概括, Tornado 就像一個玻璃箱,混雜了很多人放進去的 Coin 硬幣。我們能看到放 Coin 的是哪些人,但這些 Coin 高度同質化,如果有生面孔的人從玻璃箱拿走一枚 Coin ,我們很難知道他拿走的 Coin 最初是誰放進去的。

(圖源: rareskills )

這種場景似乎屢見不鮮:當我們從 Uniswap 池子裡 SWAP 幾枚 ETH 時,根本無法知道劃走的 ETH 是誰提供的,因為曾給 Uniswap 提供流動性的人太多了。但不同之處是,每次用 Uniswap 劃走 Token ,我們需要用其他 Token 作為等價的成本,且不能把資金「私密的」轉讓給別人;而混幣器只需要提款者出示存款憑證就行。

為了讓存取款動作看起來有同質性,Tornado 池子的存款地址每次存入的資金、取款地址每次取出的資金都保持一致,比如某個池子的 100 個存款者和 100 名取款者,雖然公開可見,但看起來彼此沒有任何聯繫,而且每人存入的金額、取出的金額,都是一樣的。這時就可以混淆視聽,沒法按照存取款金額判斷關聯性,進而切斷資金轉移痕跡,顯而易見的是,這為 xi 錢行為提供了天然的便利。

但有一個關鍵問題:取款者在提款時,怎麼證明自己存過款?向混幣器發起取款的地址,與所有的存款地址都不關聯,那麼該如何判斷他的提款資格?看起來最直接的方法,是取款者直接披露自己的存款記錄是哪一筆,但這就直接洩露了身份。此時零知識證明就派上了用場。

提款者出具一個 ZK Proof ,證明自己在 Tornado 合約裡有存款記錄,且該筆存款尚未被提取,就能順利發起取款。零知識證明本身就實現了隱私保護,外界只知道:取款人的確往資金池裡存過款,但不知道他對應哪個存款者。

要證明「我在 Tornado 資金池裡存過款」可以被轉化為「我的存款記錄可以在 Tornado 合約裡找到」 x 。如果用 Cn 表示存款記錄,問題就歸納為:

已知 Tornado 的存款記錄集合為{ C1 , C2 ,… C1 00…},取款者 Bob 證明自己曾用手上的密鑰,生成了存款記錄裡的某個 Cn ,但通過 ZK 不洩露 Cn 具體是誰。

這裡要用到 Merkle Proof 的特殊性質。因為Tornado 的所有存款記錄,都存進了鏈上構造的一棵 Merkle Tree ,作為其最底層的葉子結點,而葉子總數約為 2 的 20 次幂>100 萬,大多數都處於空白狀態(賦予了初始值)。每當有新存款行為產生時,合約就會把其對應的特徵值 Commitment 寫入一個葉子裡,然後更新 Merkle Tree 的 root。

比如, Bob 的存款操作是 Tornado 有史以來第 1 萬筆,那麼與這筆存款有關聯的一個特徵值 Cn 會寫入 Merkle Tree 的第 1 萬個葉子結點,也即 C10000 = Cn 。然後合約會自動算出新的 Root , update 一下。( ps :為了節約計算量, Tornado 合約會緩存之前一批有變化的節點的數據,比如下圖中的 Fs1 和 Fs2 、 Fs0 )

(圖源: RareSkills )

Merkle Proof 本身很簡潔輕便,它利用了樹狀數據結構在檢索 / 溯源過程中的簡潔性。若想對外證明某筆交易 TD 存在於 MerkleTree 中,只要給出 Root 對應的 MerkleProof(如下圖中右邊的部分),它相當簡潔。如果 Merkle Tree 格外龐大,底層葉子有 2 的 20 次幂個,也就是包含 100 萬筆存款記錄,Merkle Proof 也只需要包含 21 個節點的數值,非常短。

如果要證明某筆交易 H3 的確包含在 Merkle Tree 中,設法證明用 H3 和 Merkle Tree 上其他的部分數據,可以生成 Root ,而生成 Root 所需要的那部分數據(包括 Td 在內)就構成了 Merkle Proof 。

而 Bob 在取款時,要證明自己擁有的憑證對應著 Merkle Tree 上有記錄的某筆存款哈希 Cn 。也就是說,他要證明兩件事:

  • Cn 存在於鏈上 Tornado 合約裡的 Merkle Tree 中,具體可以構造一個 Merkle Proof ,裡面包含 Cn ;
  • Cn 與 Bob 手上的存款憑證有關聯。

Tornado 業務邏輯詳解

Tornado 用戶界面的前端代碼中事先實現了很多功能,當一名存款者打開 Tornado Cash 網頁並點擊存款按鈕後,前端代碼附帶的程序會在本地生成 2 個隨機數 K 和 r ,隨後會計算出 Cn = Hash ( K , r ) 的值,再把 Cn (就是下圖中的 commitment )傳入 To r nado 合約,插入到後者記錄的 Merkle Tree 裡。說白了,K 和 r 相當於私鑰。它們很重要,系統會提示用戶妥善保存。後面提款時仍然要用到 K 和 r。

(此處的 enc r yptedNote 是可選項,允許用戶把憑證 K 和 r 用私鑰加密,存儲到鏈上,防止遺忘)

值得注意的是,以上工作皆發生於鏈下,也就是說:Tornado 合約和外界觀察者都不知曉 K 和 r。如果 K 和 r 被洩露了,就類似於錢包私鑰被盜。

To r nado 合約收到用戶存款,並收到用戶提交的 Cn = Hash ( K , r ) 後,便將 Cn 插入到 Me r kle 樹的最底層,作為新的葉子結點,同時會更新 Root 的數值。所以,Cn 和用戶的存款動作是一對一關聯的,外界可以知道每個 Cn 對應著哪個用戶,知道有哪些人往混幣器裡存入了 Token,並且知道每個存款者對應的存款記錄 Cn。

在取款步驟中,取款者在前端網頁裡輸入憑證 / 私鑰(存款時生成的隨機數 K 和 r),Tornado Cash 前端代碼中的程序會使用 K 和 r 、 Cn = Hash ( K , r )、 Cn 對應的 Merkle Proof 作為輸入參數,生成 Z K P r oof,證明 Cn 是存在於 Merkle Tree 上的某筆存款記錄,而 K 和 r 是對應 Cn 的憑證。

這一步就相當於證明:我知道某筆記錄於 Merkle Tree 上的存款記錄對應的密鑰。當 ZK Proof 被提交給 Tornado 合約時,上述 4 個參數均被隱藏,外界(包括 Tornado 合約)無法獲知,借此保障了隱私。

生成 ZKProof 涉及的其他參數還包括:取款時 Tornado 合約裡 Merkle Tree 的根 root、自定義的收款地址 A、防止重放攻擊的標識符 nf(後面會講)。這 3 個參數會公開發布到鏈上,外界可以獲知,但不影響隱私。

這裡面有個細節,就是存款操作生成 Cn 時,用了 2 個隨機數 K 和 r 來生成 Cn ,而不是單個隨機數。這是因為單個隨機數不夠安全,有一定概率發生碰撞,比如,採用單隨機數可能導致兩個不同的存款者恰巧採用 1 個同樣的隨機數,導致生成的 Cn 撞車。

至於上圖中的 A,代表接收提款的地址,由提款者自己填寫。nf 則是一個防止重放攻擊的標識符,其數值 nf=Hash(K),K 就是存款生成 Cn 那一步用到的 2 個隨機數之一(K 和 r)。這樣一來,nf 就與 Cn 關聯了起來,換言之,每個 Cn 都有對應的 nf,兩者一一關聯。

為什麼要防止重放攻擊呢?由於混幣器在設計上的特性,取款時不知道用戶提走的幣對應 Merkle 樹的哪個葉子 Cn,也就不知道提款人和哪些存款人關聯,就不知道提款人到底存過幾次款。提款者可以利用這一特性頻繁提款,發起重放攻擊,多次從混幣器池裡取走 Token,直到把資金池抽乾。

在這裡,nf 標識符的作用類似於每個以太坊地址都有的交易計數器 nonce ,都是為了防止某筆交易被重放而設置。當一筆取款發生時,取款者需要提交一個 nf,檢查這個 nf 是否已被使用過(記錄在案):如果有,此次取款無效。如果沒有,表示該 nf 尚未被使用,取款有效,對應的 nf 會被記錄下來。下次再有人提交這個 nf 時,對應的取款動作直接判定為無效。

如果有人胡亂生成一個合約沒記錄過的 nf 行不行?當然不行,因為取款者生成 ZK Proof 時,需要保證 nf=Hash(K),而隨機數 K 與存款記錄 Cn 關聯,也就是說,nf 與某筆有記錄的存款 Cn 關聯。如果隨便編造一個 nf,這個 nf 與存款記錄中的所有存款都對不上號,就不能順利生成有效的 ZK Proof,後續的工作就無法順利完成,取款操作就不會成功。

可能也有人會問:不用 nf 行不行?既然提款者在提款時需要提交 ZK 證明,證明自己和某個 Cn 有關聯,那麼每當提款動作發生時,查找對應的 ZK Proof 是否被提交到鏈上過,不就行了嗎?

但事實上,這樣做的成本很高,因為 Tornado cash 合約不會永久存儲過去提交的 ZK Proof ,因為這會嚴重浪費存儲空間。與其比較每個新交到鏈上的 ZK Proof 和既有的 Proof 是否一致,還不如設置個佔地很小的標識符 nf 並將其永久存儲來得更划算。

按照取款函數的代碼示例,其需要的參數和業務邏輯如下:

用戶提交 ZK Proof 、 nf ( Nullifier Hash )= Hash ( K ),自定義一個接收提款的地址 r ecipent , ZK P roof 隱藏了 Cn 和 K 、 r 的數值,讓外界無法獲取判斷用戶身份。 r ecipent 往往會填寫一個乾淨的新地址,也不會洩露個人信息。

但這裡面有個小問題,就是用戶在取款時,為了不可溯源,往往用新申請的地址發起取款交易,此時新地址沒有 ETH 來支付 gas 費。所以取款地址發起取款時,要顯式聲明一個中繼者 relayer ,由它代付 gas 費,之後混幣器合約會直接從用戶提款裡扣掉一部分交給 relayer,作為回報。

綜上所述,TornadoCash 可以隱瞞取款者與存款者的關聯,在用戶量很大的情況下,就如同一個鬧市區,犯人混進人群後警方就難以追蹤。取款過程中需要用到 ZK-SNARK,被隱藏起來的 witness 部分包含取款人關鍵信息,這是整個混幣器最關鍵的一點。目前看來,Tornado 可能是與 ZK 相關的最巧妙的應用層項目之一。

參考資料 1.https://etherscan.io/address/0xa160cdab225685da1d56aa342ad8841c3b53f291#codeTornado 合約源碼 2.https://mirror.xyz/mazemax.eth/BTbTOrEKzGkc-XoDcFtLPfJPtQ1Mt96BZYsW83m33IUTornado.cash 新舊版機制對比 3.https://www.youtube.com/watch?v=Z0s4W3UBxM8AnonymousPayments 4.https://medium.com/taipei-ethereum-meetup/zkp-study-group-tornado-cash-fdbb84d44b93[ZKP 讀書會]TornadoCash 5.https://medium.com/taipei-ethereum-meetup/tornado-cash-%E5%AF%A6%E4%BE%8B%E8%A7%A3%E6%9E%90-eb84db35de04TornadoCash 實例解析

warnning 風險提示
app_icon
ChainCatcher 與創新者共建Web3世界