作者: Lin Oshitani ( Nethermind Research )。感謝Matteo 、 Ahmad 、 Michal 、 Conor 、 Gustavo 、 Daniel 、 David 、Yuewang 和Ignacio的討論和/或審閱,感謝Musa的討論以及協助運行基準測試。
這項工作由Taiko資助,是Taiko<>Nethermind 戰略合作伙伴關係的一部分。
太長不看
每個操作碼的獨立證明成本是多少?為了回答這個問題,我們基於 EF 的 zkEVM 基準測試工具和 imapp 團隊的 Gas Cost Estimator 邊際方法,在多 GPU 設置下對各個 EVM 操作碼和預編譯程序的每 gas 證明時間進行了基準測試。我們還使用實際證明時間測量結果,評估了 zk 週期是否能有效代表實際證明時間。
介紹
隨著零知識共享 (ZK) 彙總進一步去中心化,無論是Rollup階段還是序列器和證明器的去中心化程度都日益提高,緩解“證明器殺手”區塊對其安全性和經濟可持續性至關重要。這些惡意區塊旨在最大化證明時間,同時保持在以太坊虛擬機 (EVM) 的 gas 限制內,從而可能引發拒絕服務攻擊,或使證明過程在經濟上不可行。此外,隨著以太坊 L1 本身向基於 ZK 的擴容轉型,它也將面臨同樣的挑戰。
傳統的EVM gas計量僅考慮執行成本,例如CPU時間、存儲訪問和狀態增長,但無法完全捕捉證明成本。因此,零知識彙總需要額外的安全措施。一種主流方法是顯式計量證明成本,並基於此指標強制執行區塊限制。然而,構建此類機制需要精確的模型來描述各個操作對整體證明時間的貢獻,該模型既要足夠精確以防止惡意區塊,又不能過度損害可用性。
為了對證明時間進行建模,我們重點關注以下核心問題:每個 EVM 操作碼或預編譯程序對總證明時間的貢獻是多少?具體來說,如果我們添加一個消耗額外 X 個 gas 的操作碼或預編譯程序,在其他條件不變的情況下,它會增加多少額外的證明時間?由此,我們估算出每個操作碼或預編譯程序每單位 gas 的邊際證明時間。
以太坊基金會之前的zkEVM 基準測試工作通過構建密集填充特定操作碼或預編譯代碼的區塊(通過循環)提供了有價值的端到端測量結果。這種方法非常適用於識別和分析證明成本極高的操作,因為目標操作的成本在整體證明時間中佔據主導地位。然而,由於這些基準測試沒有明確區分每次操作的成本和周圍的開銷(例如,將參數壓入棧、彈出返回值和控制流),因此對於成本較低的操作,它們的信息量較少,因為周圍的代碼可能會顯著影響測量結果。因此,這些基準測試不足以構建一個涵蓋所有操作碼和預編譯代碼的全面證明時間模型。
為了克服這一侷限性,我們採用了imapp團隊Gas Cost Estimator項目中的邊際測量方法。該方法通過創建僅改變目標操作數而保持其他執行上下文不變的測試用例,將每個操作碼或預編譯的貢獻與周圍開銷隔離開來。然後,我們擬合線性迴歸模型並取斜率來估算每單位gas的驗證時間。
我們的基準測試實現基於以太坊基金會的zkEVM 基準測試工作負載工具,並由其提供支持。我們根據 gas 成本估算器的邊際方法創建了一套自定義執行規範測試,並進行了擴展以更好地適應零知識證明環境(例如,一種放大方法,以防止固定零知識證明設置開銷主導測量結果)。然後,我們使用 EF 基準測試工具的自定義分支執行這些測試,該分支為 SP1 添加了多 GPU 支持。
此外,我們利用基準測試結果,通過直接測量證明時間來評估 zk 週期是否能有效代表實際證明時間。我們發現,證明時間和 zk 週期之間的關係在不同的指令集和預編譯版本中差異很大,這限制了基於 zk 週期的估計的準確性。
主要結果
我們首先介紹結果;對假設和實驗設置感興趣的讀者可以在方法論部分找到詳細信息。
在本節中,我們將介紹基準測試的主要結果,這些測試是在以下環境下運行的(有關設置的更多詳細信息,請參見下面的方法論部分):
證明器:sp1-v5.2.3(帶 sp1-cluster)和 risc0-v3.0.4(帶
RISC0_KECCAK_PO2=15標誌以防止證明器崩潰)GPU :4 x NVIDIA GeForce RTX 4090
執行客戶端: reth-v1.9.3
注意:證明時間很大程度上取決於運行配置(例如,證明器標誌和配置、硬件/運行時設置、證明時 GPU 的狀態ETC)。因此,這些結果應解釋為特定配置下的測量結果。
注:這些基準測試未進行塊頭驗證。本地測試表明,驗證對大多數操作碼的影響很小;與 LOG 相關的操作碼的性能提升了 4-5 倍,但它們的驗證成本仍然相對較低。
每單位氣體的驗證時間
下方列出了 SP1 和 RISC0 架構中每個操作碼/預編譯程序的“每 gas 驗證時間”。該指標表示使用額外一個 gas 單位對特定操作碼或預編譯程序產生的額外驗證時間。R² 值表示線性迴歸的擬合優度。
更詳細的數據(例如,每個操作碼的迴歸圖)託管在此處: SP1 , RISC0
一些初步觀察:
密碼學預編譯(例如
modexp、point_evaluation)通常每個 gas 的證明時間都很長。與取模/除法相關的操作碼(
mulmod、mod、div、sdiv)具有相對較高的證明時間和selfbalance。圍繞 log/create(
log1、log2、log3、create、create2)的操作碼在 SP1 和 RISC0 上都具有最快的每 gas 證明時間,這可能是因為它們的 gas 成本主要由數據和存儲而非計算構成。總體而言,RISC0 和 SP1 中各操作碼的證明時間排名大致相同,但也存在一些顯著的例外(例如,
keccak256在 RISC0 中速度慢約 12 倍,而sha256在 RISC0 中速度快約 10 倍)。這可能是由於某些操作碼的 zkvm 預編譯版本在一個架構中存在而在另一個架構中不存在(有關證明器之間的更多比較,請參見附錄中的圖表:SP1/RISC0 比較)。
每個 ZK 週期的驗證時間
ZKVM 引入了ZK 週期這一概念,它代表 ZKVM 執行程序驗證所需的計算步驟數,類似於傳統計算中的 CPU 週期。一個自然而然的問題是:ZK 週期能否很好地代表實際的驗證時間?如果 ZK 週期與所有操作的驗證時間呈線性相關,那麼它們可以作為 ZK gas 計量的一個更簡單的指標。然而,如果這種關係是非線性的,或者在不同操作類型之間存在顯著差異,那麼為了實現精確的 DoS 防護,必須直接測量驗證時間。
為了回答這個問題,我們對每個操作碼/預編譯程序,以證明時間為因變量,zk週期數為自變量,擬合了線性迴歸模型。以下是研究結果。
在特定操作中,循環次數與證明時間的關係呈強線性(R² 值較高):循環次數翻倍,證明時間也大致翻倍。但循環次數到時間的轉換率並非普遍適用,它很大程度上取決於具體操作。
下圖的柱狀圖顯示了每個操作的“每個 zk 週期的耗時”。如果週期數是一個好的指標,那麼所有柱狀圖應該基本對齊;但實際上,它們分佈很廣——這可能是因為某些操作是在不同的電路中實現的(例如,自定義 zkVM 預編譯)。例如,在 SP1 中, bn128_add操作每個 zk 週期耗時約 930 納秒,而pop操作僅需約 63 納秒,兩者相差約 15 倍。這表明僅憑 zk 週期數不足以準確計量驗證時間。緩解措施包括:
使用測量驗證時間進行計量(如本文所述)
改進週期核算,以更好地反映驗證時間(例如,改進不同電路之間的 zk 週期轉換)
使用 ZK 週期作為證明時間的代理,但要保守一些,即使用每個 ZK 週期操作的最慢時間。
方法論
我們採用邊際成本法,該方法最初由 imapp 團隊開發,用於 L1 天然氣重新定價,作為天然氣成本估算器項目的一部分,以分離單個操作的驗證成本。
首先,我們為每個操作碼/預編譯創建 4-7 個塊,每個塊的操作次數各不相同(0、N、2N、3NETC),同時通過保持所有其他因素在變體之間相同(堆棧設置、內存初始化、控制流和清理操作)來保持恆定的開銷。
下表是 ADD 操作碼的一個字節碼結構示例。請注意,每個變體都恰好包含 20 個 PUSHE 和 10 個 POP——只有 ADD 操作碼的數量不同。
| 操作數 | 設置 | 主要的 | 清理 |
|---|---|---|---|
| 0 | 推×20 | — | POP×10 |
| 3 | 推×20 | 加法 + (彈出 + 加法)×2 | POP×8 |
| 5 | 推×20 | 加法 + (彈出 + 加法)×4 | POP×6 |
| 10 | 推×20 | 加法 + (彈出 + 加法)×9 | POP×1 |
接下來,我們執行每個區塊變體,並記錄整個區塊的總證明時間和消耗的 gas 量。然後,我們對所有變體擬合proving_time = α × gas_used + β 。以下是 SP1 中 ADD 操作碼的示例:
斜率α表示所考慮的操作碼或預編譯代碼每單位 gas 的邊際證明時間。由於只有目標操作次數會變化,而所有其他執行上下文保持不變,因此α可以單獨衡量該操作的貢獻。在上面的示例中, α = 3.78µs ,這意味著在 SP1 模式下,使用 4 個 GPU 的 ADD 操作的每 gas 證明時間為3.78µs 。
操作碼/預編譯參數
對於操作碼/預編譯參數,我們使用固定的輸入,這些輸入經過精心挑選,力求具有代表性,並在適用情況下儘可能地涵蓋“最壞情況”。我們的選擇參考了現有基準測試套件中已知的最壞情況模式。使用最壞情況輸入有助於避免無意中測量僅在特殊輸入(例如,全零緩衝區)下才會出現的優化快速路徑。
我們的工作假設是,對於給定的操作,證明時間與 gas 消耗呈線性關係,這不僅體現在不同的操作次數上,也體現在同一操作的不同論證選擇上(即,gas 翻倍,證明時間也翻倍)。這基於以下兩個假設:(1)gas 能準確反映計算複雜度;(2)證明時間與計算複雜度成正比。
在實踐中,這一假設可能不成立,例如,因為 gas 值並不能準確反映計算複雜度,或者 ZKVM 對某些論證會表現出不同的行為。因此,我們的測量結果應解釋為針對特定測試輸入的結果,而對於其他輸入,則僅作為近似值。對論證相關的證明成本進行更細緻的分析,考察每個操作的證明時間如何隨整個論證空間變化,將留待未來工作。
最後,對於像 LOG 和 CREATE 這樣的操作,其 gas 消耗主要受數據大小和內存擴展而非計算量驅動,我們使用標準參數(例如,32 字節有效載荷),而不是基於 gas 消耗的最壞情況參數。使用較大的有效載荷會增加 gas 成本,但不會顯著增加證明工作量,從而低估了每單位 gas 的計算證明開銷。
與 EF 基準測試工具集成
我們的基準測試流程基於以太坊基金會的zkEVM 基準測試工作負載,並引入了兩個關鍵擴展:
自定義 EEST 邊緣測試/夾具:我們添加了遵循邊緣方法的自定義執行規範測試(EEST)。
多 GPU SP1 支持:我們擴展了EF 的 ZKEVM 基準測試工具,以支持 SP1 集群執行,從而可以使用 4 個 GPU 來驗證相同的工作負載。
通過這些新增功能,我們生成 EEST 夾具,使用 EF 工具將其轉換為 zkEVM 見證輸入,通過 EF 主機運行器(4 個 GPU 上的 SP1 或 RISC0)運行證明,然後對生成的指標(證明時間、gas、zk 週期)進行後處理,以擬合迴歸並提取每個 gas(或每個 zk 週期)的邊際證明時間。
申請及後續步驟
以下是這些測量結果的一些潛在實際應用:
面向零知識庫 (ZK) 的區塊計量:基於每 Gas 的證明時間測量值可用於直接計量和限制區塊的證明成本。具體而言,可以通過對每個操作碼/預編譯消耗的 Gas 進行加權,並乘以一個由其每 Gas 證明時間計算得出的係數,來定義一個“ZK Gas”指標。通過限制每個區塊的總 ZK Gas 消耗,該協議可以限制最壞情況下的證明時間,並緩解證明器殺手區塊的出現。
對 zkVM 實現者的指導:逐操作細分突出了哪些操作碼/預編譯需要改進,幫助 zkVM 團隊確定優化優先級(例如,專用電路)。它還為改進 ZK 週期統計提供了一個具體信號,使 ZK 週期數在不同的電路路徑上更一致地跟蹤驗證時間。
對客戶端實施者的指導:客戶端團隊可以使用這些測量結果來識別 ZK 不友好的熱點,並優化特定的操作碼/預編譯實現或執行模式,以減少證明開銷。
項目後續步驟:
論證依賴型基準測試:擴展該方法以涵蓋所有輸入。
持續性能監控:實現流水線端到端自動化(測試夾具生成→見證生成→驗證→迴歸→報告),以便跟蹤每個操作碼/預編譯 zkVM/客戶端的性能隨時間的變化。
多維計量:研究如何將這些測量結果納入多維氣體計量中。
鏈接
我們的基準測試詳細數據(例如,每個操作碼/預編譯的迴歸圖):
用於基準測試的自定義執行規範測試: https://github.com/linoscope/execution-specs/pull/1/changes
EF 工具中 SP1 集群支持的 PR:
Ignacio 關於 EF ZK 基準測試工具的精彩演講: https://youtu.be/D2TpmD62tjQ?si =D4mzEagb2MXX1QXy&t=1510
Jacek關於邊際方法的演講很精彩: https://www.youtube.com/watch?v =KmaFpyV9jvM
附錄:SP1/RISC0 比較
下圖顯示了(RISC0 proving_time_per_gas) / (SP1 proving_time_per_gas)的關係,其中每proving_time_per_gas是每個驗證器對應操作碼的迴歸斜率。參考線 1.0 倍表示性能相同。大於 1.0 倍的值表示 RISC0 較慢(對於該操作碼/預編譯,RISC0 的每 Gas 驗證時間比 SP1 長),小於 1.0 倍的值表示 SP1 較慢。









