介紹
隨著 zkevms 的商品化,出現了一些有趣的機會,可以在保持 EVM 兼容性的同時提供隱私智能合約基礎設施。開發人員可以編寫 Solidity 代碼,並使用 Solidity 編譯器或一些後處理工具進行編譯。從而創建隱私智能合約。
私有全局狀態和隱私之間存在重要的權衡,這源於這樣一種觀念:為了能夠證明,你需要知道你在證明什麼。因此,你不可能擁有一個包含你不知道的全局公開狀態的私有智能合約。由此可見,你不可能擁有一個包含全局私有狀態的私有智能合約。例如, Uniswap就無法實現,因為證明者需要知道兩個池子的餘額才能證明交換已正確完成。更多內容: 為什麼你無法使用零知識證明 (ZKP) 構建私有Uniswap - #24 by bowaggoner
所以,在IO出現之前,我們所熟知和喜愛的一些事物都無法以隱私的方式實現,這就是IO如此重要的原因。它讓我們能夠基於完全相同的信任假設,構建一個完全隱私的以太坊。
無論如何,這篇文章是關於如何向 reth pstore 和 pload 添加兩個操作碼,將其編譯成 zkevm 並擁有具有私有用戶狀態但不具有私有全局狀態的私有智能合約。
如何
某些合約調用是私有的。我們利用現有的 zkevm 代碼來證明這些調用已正確執行,但不會洩露任何有關合約實際執行內容的信息。除了滿足某些要求外,例如,需要從另一個合約中批准使用一定數量的代幣,但不能透露代幣持有者的身份。我們實現了兩個新的OP碼 pstore 和 pload,它們與 sload 和 sstore 類似,只是值是私有的。
工具箱
我們將 zkevm 作為我們的工具鏈。我們不會對 zkevm 本身進行任何更改。我們將其視為一個黑盒。相反,我們將對 reth 進行更改。我們為 reth 添加兩棵新樹:私有存儲樹 (PST) 和私有無效樹 (PNT)。
PST 和 PNT 中的每個葉子節點都會在每次更新時發佈。因此,任何人都可以證明自己是任何葉子節點的成員。但這些葉子節點包含的值只有創建它們的用戶知道。
上傳
pload 是我們添加的 evm 操作碼。它類似於 sload。當 sload 在 zkevm 中執行時,zkzkevm 會生成一個 Merkle 證明,證明某個值位於樹中的某個位置。
類似地,對於 pload,我們對樹中該葉子的成員資格進行了證明,但我們也證明了該葉子尚未被無效。
假設我們要上傳一個值 x。那麼我們基本上要做兩個 Merkle 證明
- 在 PST 中證明 x
- 證明 x.nullifier 不在 PNT 中
只有知道該葉子秘密值的用戶才能計算其無效器,並且只有這樣的用戶才能證明它沒有被無效。
注意:sload 隱含了非包含證明,因為它使用的是有序默克爾樹。我們不能對 pload 和 pstore 使用有序默克爾樹,因此我們需要某種編碼來確保指定的葉子節點未被創建。這種編碼可以是 hash (合約,槽位,值,無效符)
注意:我認為,如果你加載一個沒有任何內容的地址,得到的也是 0x0,這也需要考慮。可能需要想辦法在 zkzkevm 中處理這個問題,以便相同的 devex 存在。但很難證明存儲槽未被填滿。
存儲
pstore 的作用與 sstore 相同,但工作原理略有不同。
在 zkevm 中,每次執行 sstore 操作時,實際上都會執行兩個 Merkle 證明。第一個證明證明葉子節點的當前值為 x,第二個 Merkle 證明計算 Merkle 根,並將 x 的值替換為 y。因此,你可以將第一個證明視為獲取樹中所有葉子節點的彙總證明,而第二個證明則視為僅將單個葉子節點 (x) 替換為 y。
所以 sstore
- 證明值 x 在樹中
- 用 y 替換它
pstore 可以做同樣的事情,但略有不同
- 它通過獲取 x.nullifier 並將其添加到 nullifier 樹來刪除 x。
- 它通過將 y 添加到 PST 來用 x 替換 x。
Solidity
Solidity 編譯為 evm 操作碼。
假設我們有以下智能合約
def transfer(sender, reciver, amount) private:bal[sender]= bal[sender] - amountbal[reciver] = bal[reciver] + amount# this is not adding to the users balance directly. Instead it is kind of input out put thing where the user needs to get the received funds to add to their total balance. This nuance is encapsulated in a receiver address abstraction for now. But needs more work to figure out what is needed on zkzkevm side.return(1)Solidity 編譯器(某些後處理器的編譯器)會發現這一點,並將字節碼中的所有 sloads/sstore 替換為 ploads/pstores。它只會對帶有 private 修飾符或標籤的函數執行此操作。
具有一些私有分支和一些公共分支的呼叫鏈
可以將其視為 aztec connect 的更可編程版本。假設我們有一個私人錢包,也可以讓該錢包調用Uniswap。這可以實現,但我們必須小心處理 message.sender、tx.origin、nonce、gas_price、gas_limit 和其他元數據洩漏。我們可以通過幾種方法來實現這一點。
- 為每個調用創建代理合約,然後在另一個 tx 中或在當前 tx 調用堆棧的末尾重新平衡。
- 使用全局代理合約
注意:tx.origin 可能需要在 reth 變更中進行清理。不過它可能只是一個打包工具,所以我覺得還好。
權衡
這一切似乎有點複雜,只是為了實現 aztec 連接。但其強大之處在於能夠重用我們目前擁有的大部分基礎設施,從而支持更強大的應用程序。
卡特爾合同
我們討論了一下私有全局狀態,以及為什麼無法實現Uniswap 之類的功能。但是假設我想為我和我的朋友們創建一個智能合約。我希望將源代碼公開,但允許我和我的朋友們執行。所以這也是可能的,我們只需要放寬智能合約的數據可用性保證,這樣智能合約代碼就不需要公開了。
卡特爾內部在數據可用性保障方面存在一些細微差別。我想我們可以實施某種強制日誌記錄,將所有數據更新加密併發布,以便只有卡特爾成員才能看到。
結論
這個想法似乎會在兩個方面立即發揮作用
- 創建一個私有Rollup ,其中有一個巨型服務器,用於生成所有用戶向該服務器提供的數據證明,但其他所有人的數據不予提供
- 私人Rollup,用戶可以提供一些證明,以便他們的存儲訪問權限對怪物服務器隱藏。
看起來很有用,而且很容易實現。不需要 zk 知識,以 zk 作為商品。
待辦事項
我們需要更多地思考
- 如果我們要默認將 EOA 設為私有,似乎可以通過一些無效器技巧來實現,比如讓它們簽署“nullifier”,然後隨機字符串成為它們的無效器,或者像 nullifier_0 = hash (sign(“nullifier”) , 0 ) nullifier_1 = hash(sign(“nullifier”,1)) 等等。但要做到這一點,我們必須編譯所有 erc20 合約以使用 erc20 的 pstore 和 pload。這似乎可能會破壞其他功能。但手動 EOA 隱私似乎不包括狀態變化,因為大多數人關心的是 erc20 而不是ETH。
- 在移動設備上對一些寬鬆的事物進行 zkevm 證明是否可行?一些 ploads
- 如果您要存儲的值是動態生成的,那麼最好有一個無效器,怪物服務器可以使用它來為您存儲該葉子,而不是由於競爭條件而製作完整的葉子。
- 如何提供我的地址,以便我可以私下接收資金,而無需將所有收據連接在一起
- 我該如何使用日誌或其他機制來了解我是否收到了款項?可能很簡單,比如返回一個包含某種加密“標記”的日誌。




