ZKEVM是一個具有可編程性,以ZK技術為基礎的虛擬機,它可以為虛擬機執行的所有操作生成一個零知識證明(zk proof),用來證明虛擬機執行操作的正確性。有關ZKEVM的幾種實現方案介紹及優劣對比,可以參考V神的文章: The different types of ZK-EVMs ;如果你想了解更多的設計細節,你也可以閱讀PSE的ZKEVM方案(native-level ): privacy-scaling-explorations/zkevm-specs Polygon的ZKEVM設計(bytecode-level): Polygon zkEVM Documentation ; Sin7y的ZKEVM設計(language-level): OlaVM: An Ethereum compatible ZKVM 。無論是哪種方案,都需要用zk去約束VM的所有的行為,這些行為包括:

• 執行合約計算邏輯

• 執行內存訪問

• 執行哈希計算

• 執行世界狀態更新

• ...

眾所周知,zk在計算壓縮領域,具有極大的應用的前景;無論原始的計算多麼複雜,其驗證過程都十分高效,這是所有zk算法的基本技能。因此,對於VM執行過程中的計算部分(比如合約邏輯,哈希計算等),zk可以很好的發揮作用;而在VM執行的過程中,除了計算本身外,還存在一些內存訪問操作,我們需要把一些數據提前放在內存裡,然後在執行計算的時候取出來。

而由於大部分的VM都是讀寫內存,因此不得不約束這些內存訪問操作的正確性(比如,從某個地址讀出的數據和上一次寫入的數據相同的一致性校驗);對於內存訪問的約束本身並不復雜(case比較少),但是由於內存訪問的次數很高,所以導致多項式的階數很高,使得內存相關的約束證明耗時比較可觀。

在ZK(E)VM的方案中,我們更應該把zk主要應用在對於計算本身的證明,對於EVM的其他行為(比如內存訪問),我們可以在VM層面去優化(比如使用write-once內存) ,以減少zk約束的規模(避免了內存訪問的一致性校驗約束)。

Memory的設計

EVM為例, EVM的內存是一塊很簡單的字節數組,可以存儲32字節或者1字節的數據,也可以讀取32字節的數據。

關於在 ZKEVM 中移除內存限制的一些想法

圖片來源:ethereum_evm_illustrated, page 51

在EVM中,和Memory相關的指令有:

• MLOAD(x): 從地址x處加載32字節的數據到調用棧(stack)

• MSTORE(x,y): 從地址x開始,寫入32字節的y

• MSTORE8(x,y): 從地址x開始,寫入8字節的y(低位開始) 有興趣的讀者可以在EVM Playground上感受下,上述內存操作帶來的內存和棧的變化。

Memory的約束

OlaVM的5.3.5節,你可以看到關於Memory約束的設計原則(OlaVM內存相關的指令和EVM類似)。

關於在 ZKEVM 中移除內存限制的一些想法

在OlaVM中,RAM的所有操作組成一個獨立的table,table裡的內容由memory和storage兩種類型組成。在這裡,我們只關注對於memory的約束。內存的操作類型大體可以分為三類:

• Init操作

• write操作

• read操作

觸發Init的場景有三種,分別是ctx的變換,type的變化,addr的變化;當任何一個場景觸發時,需要約束,操作類型為w(write),v(value)為0

當上述三種場景沒有觸發時,則需要根據當前的操作類型來約束;

• 如果是w(write)操作,需要約束clk是遞增的(調用rangecheck模塊),寫入的值v是對的(調用copy constraints,OlaVM裡,內存指令所有的值都來源於寄存器)。

• 如果是r(read)操作,需要約束clk是遞增的(調用rangecheck模塊),讀取的值和上次寫入的值是相同的

一些可能性提升(更加zk友好)

• 對於Init操作,需要約束一個內存地址的初始化的值為0麼?

我認為沒有必要對初始化的操作進行約束;實際上,對於任何地址,你可以約束它的第一次訪問必須是write操作,而不是read操作;而如果是write-once內存模型,這個限制將天然存在,因此,如果虛擬機的內存模型改為write-once模型,將減少對內存的訪問約束。

• 對於read操作,能否避免對應的約束,即避免校驗讀取的值和上次寫入的值一致?

由於VM本身定義的memory類型的讀寫內存,無法保證,VM在讀取這個內存地址的值之前,這個地址的值沒有被修改,因此需要增加一個相等性校驗,如下圖所示:

關於在 ZKEVM 中移除內存限制的一些想法

由此可以看出,產生這個約束的核心原因,內存模型是讀寫內存,地址的值存在被改寫的可能,因此,如果嘗試使用只讀內存(只寫一次),那麼就不需要在memory的約束去實現上述的一致性約束。

關於在 ZKEVM 中移除內存限制的一些想法

注意:這可能會增加虛擬機的實現難度,因為這是一個不常用的內存模型;並且,我們應該不會首先在這個虛擬機上面去定義一個高級DSL,因為這個語言對Dapp開發者會有些不友好,需要在編譯器層面去消除,使得這些不友好,對開發者不可見。所以,如果採用上述內存模型,內存模塊的約束,將只剩下針對write操作的約束,即使用copy constraints來保證寫入的值是對的即可。無須約束

讀取的值等於寫入的值,因為內存只能被寫一次

讀的clk大於寫的clk,因為只能先寫再讀

內存的初始化值為0(兩種內存都沒必要)

參考

ethereum_evm_illustrated, page 51

關於我們

Sin7Y成立於2021年,由頂尖的區塊鏈開發者和密碼學工程師組成。我們既是項目孵化器也是區塊鏈技術研究團隊,探索EVM、Layer2、跨鏈、隱私計算、自主支付解決方案等最重要和最前沿的技術。

微信公眾號:Sin7y

GitHub:Sin7y

Twitter:@Sin7Y_Labs

Medium:Sin7y

Mirror:Sin7y

HackMD:Sin7y

HackerNoon:Sin7y

Email:contact@sin7y.org