evm2rv 將 EVM runtime 位元組碼(即 solc --bin-runtime 的輸出)轉換為 Rand 程式。它會輸出 C 程式碼,再由 rand-guest build 將該 C 程式碼編譯為 RV32IM 映像。該映像接受與 Rand 的 EVM 直譯器 guest(evm.bin)相同的輸入向量,並公布相同的八個輸出字。它以原生方式執行合約,而不是逐個操作碼進行直譯。本頁以一個 ERC-20 展示完整流程。
簡介
| 輸入 | EVM runtime 位元組碼,十六進位文字(.hex)或原始位元組 |
| 輸出 | 一個 C shim crate;rand-guest build 會將其製成映像容器 |
| 執行位置 | 鏈下,在開發者的機器上;鏈上只會看到映像 |
| 必須符合的項目 | evm.bin 的狀態、八個輸出字及 gas_used |
| 儲存庫 | circuits 儲存庫中的 evm2rv/ |
| 固定的工具鏈 | Rust 1.98.1、clang 23.1.1、cc crate 1.4.6 |
轉譯器處理的是 runtime 程式碼,而非建立合約的程式碼。一次證明涵蓋對已部署合約的一次呼叫,因此建構函式不會執行。建構函式本應寫入的狀態,改為作為儲存見證,成為前狀態的一部分。
轉譯分為兩個階段。兩者的結果與 gas 相同;各自是獨立的程式,有各自的 hc。
| 階段 | 旗標 | 作用 |
|---|---|---|
| 一 | --stage 1 | 每個操作碼均透過記憶體堆疊執行 |
| 二 | --stage 2,預設 | 每個區塊的堆疊字置於 C 區域變數,常數在轉譯時摺疊 |
輸入向量與直譯器的相同:程式碼、calldata、呼叫者及其他環境字、gas 上限、前狀態根,以及該次呼叫所觸及的每個儲存槽各一個儲存見證。輸出為 out[0],即狀態(1 表示成功,0 表示還原,2 表示異常中止),以及 out[1..8],即涵蓋程式碼雜湊、兩個狀態根、返回資料和日誌的 EVM_OUT 摘要。
信任模型
驗證者分兩步檢查已轉譯的合約。
hc == translate(bytecode)。 以相同的--stage和--chain-id對已公布的位元組碼重新執行evm2rv,以固定的工具鏈重新建構,再比對hc。所產生的 crate 會精確固定cc的版本,並自帶Cargo.lock。- 程式碼守衛將
hc與位元組碼綁定。 已轉譯的邏輯會被編譯進映像,但CODECOPY和CODESIZE讀取的是輸入向量中的程式碼。若無檢查,同一個hc可能以呼叫者自行選擇的程式碼位元組執行。因此contract.c帶有來源位元組碼(其長度與位元組)的 Poseidon2 摘要,而 shim 會在任何已轉譯的程式碼執行之前,以同樣方式對輸入向量中的程式碼進行雜湊。其他程式碼會被拒絕:狀態 2,gas_used為 0,中止原因為OutOfBounds。
EVM_OUT 摘要同樣綁定程式碼的 keccak256,與直譯器的做法一致。鏈上不會記錄來源位元組碼或其雜湊。若要讓他人核對 hc,請公布位元組碼,或公布 Solidity 原始碼及確切的 solc 建構版本。
守衛在 transfer 上耗費 1,008 個週期。與來源相差一個位元組的程式碼,在階段二以 30,418 個週期被拒絕(tier 16)。
涵蓋範圍與會觸發陷阱的情況
操作碼。 Shanghai 指令集。請以 --evm-version shanghai 編譯:較新的目標會輸出 MCOPY 及其他 Cancun 操作碼,而這些操作碼會觸發陷阱。
環境操作碼:
| 操作碼 | 轉譯方式 |
|---|---|
ADDRESS、CALLER、CALLVALUE、CALLDATASIZE、CODESIZE | 取自輸入向量,與直譯器的讀取方式相同 |
CHAINID | --chain-id 的值,於轉譯時寫入,故 hc 會與之綁定;程式碼含有 CHAINID 時必須提供 |
ORIGIN | 等於 CALLER(單次呼叫,無中繼者) |
GASPRICE、COINBASE、TIMESTAMP、NUMBER、PREVRANDAO、GASLIMIT、SELFBALANCE、BASEFEE、BLOCKHASH | 觸發陷阱(狀態 2),與直譯器相同 |
在有方法將這九個區塊情境操作碼綁定至區塊之前,它們都會觸發陷阱。私密輸入無法攜帶區塊事實,因為驗證者無法開啟 H_IN。在作出該決定之前,凡讀取時間或區塊編號的合約(例如許可的到期時間),都會觸發陷阱。
呼叫。 當目標為地址 1 至 9 時,CALL、CALLCODE、DELEGATECALL 和 STATICCALL 會執行預編譯合約。任何其他目標都會觸發陷阱。CALL 或 CALLCODE 帶有非零金額時會觸發陷阱:目前沒有餘額模型。
預編譯合約。 九個均以軟體執行。由於一次證明最多容納 2²⁰ 列,部分預編譯合約目前過慢,無法證明:
| 預編譯合約 | 向量 | 週期 | 是否容於 2²⁰ |
|---|---|---|---|
| 1 ecrecover | ValidKey | 14,510,525 | 否 |
| 2 sha256 | ”abc” / 200 bytes | 2,791 / 5,289 | 是 |
| 3 ripemd160 | ”abc” | 12,195 | 是 |
| 4 identity | 100 bytes | 4,498 | 是 |
| 5 modexp | nagydani-1-square / -1-pow0x10001 | 122,332 / 874,548 | 是 |
| 5 modexp | eip_example1 (256-bit) | 11,170,118 | 否 |
| 5 modexp | nagydani-5-pow0x10001 (1,024-byte) | 55,076,950 | 否 |
| 6 bn256 add | chfast1 | 978,262 | 是,剛好容納 |
| 7 bn256 mul | chfast1 | 3,060,669 | 否 |
| 8 bn256 pairing | 1 pair / 2 pairs | 1,853,656,212 / 2,019,000,469 | 否 |
| 9 blake2f | 12 rounds | 14,493 | 是,最多約 1,800 輪 |
modexp 的底數與模數各自上限為 1,024 位元組。
可接受的差異。 狀態、八個字及 gas_used 必須一致。有三項差異可予接受:中止的種類可能不同(靜態 gas 於每個區塊開頭收取,因此 OutOfGas 與另一種中止可能互換;兩者均為狀態 2 且耗盡所有 gas);轉譯實作了 CHAINID、ORIGIN 及預編譯合約呼叫,而直譯器對這些會觸發陷阱;以及程式碼守衛會拒絕來源以外的程式碼。
數據
含程式碼守衛的 ERC-20 呼叫。週期取自 rand-guest run;括號內為 tier。
| 呼叫 | 直譯器(evm.bin) | 階段一 | 階段二(預設) |
|---|---|---|---|
transfer(BOB, 250) | 121,638 (18) | 80,211 (18) | 66,235 (18) |
approve(BOB, 5) | 85,645 (18) | 56,261 (16) | 48,119 (16) |
transferFrom(ALICE, BOB, 100) | 161,434 (18) | 110,074 (18) | 88,824 (18) |
| 程式 | 字數 | hc |
|---|---|---|
evm.bin,直譯器 | 18,009 | 7e1aea2b…854c08 |
| ERC-20,階段一 | 15,804 | 9cdb79e7…2fd048c8 |
| ERC-20,階段二 | 11,686 | a0feae92a7311c9562495717100eb7aea71270a38ed435d06dc31387e0ea8ff6 |
階段二執行這三個呼叫,分別只用了直譯器週期的 54.5%、56.2% 和 55.0%。transfer 仍停留在 tier 18:其 66,235 個週期加上 3,155 列摘要,合共 69,390 列,比 tier 16 的 65,535 多出 3,855 列。
階段二 transfer 約 60%(約 39,928 個週期)是兩個映像共用的框架:解碼輸入、驗證儲存見證、ABI 的 keccak256 呼叫,以及輸出摘要。任何轉譯工作都無法降至這個下限以下。
逐步示範:由 Solidity 到輸出一致的 ERC-20
每條指令均自位於 7ef3220 的 circuits 簽出目錄根目錄執行,工具鏈取自 Deploy a Rust program,clang 23.1.1 取自 Deploy a RISC-V program。較長的輸出於標示 … 處截去。
0. 建構工具
(cd evm2rv && cargo +1.98.1 build --release)
(cd rand-guest && cargo +1.98.1 build --release)
1. 將 Solidity 編譯為 runtime 位元組碼
合約為已提交的 guests-compiled/evm/contracts/ERC20.sol:一個自足的 ERC-20,採用 OpenZeppelin v4 的儲存佈局,pragma solidity 0.8.37。請精確使用 solc 0.8.37;其他版本的最佳化方式不同,會產生不同的位元組碼。
| 發行版本 | github.com/ethereum/solidity/releases 的 v0.8.37 |
| macOS 資產 | solc-macos,sha256 a27396e7732aa52e80ff89ad7bd8a2e46fec2a6dcc4ef20cd16e5e0c502d6821 |
| Linux 資產 | solc-static-linux,取自同一發行版本 |
$ curl -sSL -o solc https://github.com/ethereum/solidity/releases/download/v0.8.37/solc-macos
$ shasum -a 256 solc
a27396e7732aa52e80ff89ad7bd8a2e46fec2a6dcc4ef20cd16e5e0c502d6821 solc
$ chmod +x solc && ./solc --version
solc, the solidity compiler commandline interface
Version: 0.8.37+commit.f401782d.Darwin.appleclang
$ (cd guests-compiled/evm && ../../solc --optimize --optimize-runs 200 --evm-version shanghai \
--bin-runtime contracts/ERC20.sol) | tee solc.out
======= contracts/ERC20.sol:ERC20 =======
Binary of the runtime part:
608060405234801561000f575f5ffd5b5060043610610060575f3560e01c8063095ea7b31461006457806318160ddd1461008c57806323b872dd1461…
$ tail -1 solc.out > evm2rv/target/mytoken.hex
最後一行是 runtime 位元組碼,共 1,296 位元組。它與已提交的 guests-compiled/evm/contracts/erc20.runtime.hex 逐位元組相同;SOLC=$PWD/solc bash guests-compiled/evm/contracts/build.sh 會檢查這一點,並輸出 contracts: erc20.runtime.hex reproduces。
這些旗標至關重要:
--bin-runtime:已部署的程式碼,而非建立合約的程式碼。--evm-version shanghai:0.8.37 的預設目標會輸出MCOPY,而它會觸發陷阱。--optimize --optimize-runs 200:適用於已部署合約的設定。
2. 轉譯
$ evm2rv/target/release/evm2rv evm2rv/target/mytoken.hex --out evm2rv/target/mytoken --chain-id 12
1296 code bytes: 74 blocks, 798 opcodes, 51 jumpdests (stage 2)
CHAINID is the constant 12
no trapping opcodes present
wrote evm2rv/target/mytoken (crate mytoken): contract.c, Cargo.toml, Cargo.lock, build.rs, src/main.rs, shim.ld
--out必須位於 circuits 簽出目錄之內。沒有它,evm2rv只會分析程式碼。- 任何會觸發陷阱的操作碼,都會連同其 pc 在此列為警告。
- 本次示範以
--chain-id 12擷取。此 ERC-20 不含CHAINID,因此--chain-id不會改變其hc。讀取CHAINID的合約必須提供此旗標;請將其設為你要部署的鏈(現行鏈為--chain-id 19)。
contract.c 以程式碼守衛的摘要作結:
const uint32_t *evm_code_digest(void) {
static const uint32_t d[8] = {0xf679280fu, 0x86c10e83u, 0x7e8f1f39u, 0xa2377de3u, 0x8a2e282fu, 0xc54cad42u, 0xddfaf009u, 0x7d28a8afu};
return d;
}
3. 建構映像
預設上限為 4,096 個字,因此請傳入 --max-words 65535。
$ rand-guest/target/release/rand-guest build evm2rv/target/mytoken --max-words 65535
…
11686 words against a cap of 65535 (fits); 0 ecall(s) with a non-static a7
OK
wrote evm2rv/target/mytoken/image.bin and its .sha256 (11686 words, hc a0feae92a7311c9562495717100eb7aea71270a38ed435d06dc31387e0ea8ff6, program id f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d)
$ rand-guest/target/release/rand-guest info evm2rv/target/mytoken/image.bin
form: image container
text 11147 words at 0x10000; data 408 words (205 non-zero) at 0x1ae2c; prologue 539 words; program 11686 words from base_pc 0xf794
hc a0feae92a7311c9562495717100eb7aea71270a38ed435d06dc31387e0ea8ff6
program id f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d
11686 words against a cap of 4096: does not fit
這就是已公布的階段二 hc。crate 名稱不會影響它。
4. 建立輸入向量並執行 transfer
erc20_vector 範例會將一致性測試的向量以輸入字的形式輸出:transfer(ALICE 向 BOB 轉 250,她持有 1,000)、approve(ALICE 允許 BOB 花費 5)及 transferFrom(BOB 在 300 的額度內,從 ALICE 的 1,000 中轉出 100)。對於你自己的合約,請在 Rust 中以同樣方式建立 EvmCall;該範例即為範本。
$ (cd evm2rv && cargo +1.98.1 run -q --release --example erc20_vector -- transfer > target/transfer.words)
921 input words
$ rand-guest/target/release/rand-guest run evm2rv/target/mytoken/image.bin --input $(cat evm2rv/target/transfer.words)
out[0] = 1
out[1] = 513227413
out[2] = 3087537901
out[3] = 995619457
out[4] = 4004100029
out[5] = 234390638
out[6] = 3262201797
out[7] = 3842361427
cycles 66235
tier 18
5. 與直譯器比較
同一輸入在直譯器 guest 上的結果:
$ rand-guest/target/release/rand-guest run guests-compiled/bin/evm.bin --input $(cat evm2rv/target/transfer.words)
out[0] = 1
out[1] = 513227413
out[2] = 3087537901
out[3] = 995619457
out[4] = 4004100029
out[5] = 234390638
out[6] = 3262201797
out[7] = 3842361427
cycles 121638
tier 18
其次是在主機上以原生方式運行的解譯器,即測試所用的基準(oracle):
$ (cd evm2rv && cargo +1.98.1 run -q --release --example erc20_vector -- transfer --expected)
out[0] = 1
out[1] = 513227413
…
out[7] = 3842361427
interpreter (native): status 1, Return, gas_used 29956
將檢查合併為一條命令:
$ diff <(rand-guest/target/release/rand-guest run evm2rv/target/mytoken/image.bin --input $(cat evm2rv/target/transfer.words) | grep '^out') \
<(rand-guest/target/release/rand-guest run guests-compiled/bin/evm.bin --input $(cat evm2rv/target/transfer.words) | grep '^out') \
&& echo "the eight words are identical"
the eight words are identical
對 approve 和 transferFrom 重複步驟 4 和 5;兩者得出的字相同。cd evm2rv && cargo +1.98.1 test --release 會在兩個階段下運行這些向量及另外五個向量,並同時檢查 gas_used(70 項測試,另有 2 項被忽略的證明)。
| 翻譯後(第二階段) | 解譯器(evm.bin) | |
|---|---|---|
| 八個輸出字 | 相同 | 相同 |
| 週期數,transfer | 66,235 | 121,638 |
| 層級 | 18 | 18 |
| 程式字數 | 11,686 | 18,009 |
6. 部署
rand program deploy evm2rv/target/mytoken/image.bin
錢包會先列印程式 id、字數及 hc,然後在生成任何證明之前檢查鏈的上限。該映像為 11,686 個字,因此需要創世區塊將 max_program_words 設為至少 11,686 的鏈。鏈 12 採用預設值 4,096,因此部署在該鏈上被拒絕。鏈 13,即 v0.4 鏈,將 max_program_words 設為 65,535,其後每條鏈均沿用此值。鏈 21 自 2026-10-12 起為運行中的鏈(fullnode v0.8.0,創世區塊 ca76c2766ed6090ac6ba5dad86b724dd5d2b80c0edfaed287cd8b129e663ca9a),同樣沿用鏈 13 的調用信封及公開輸入上限,將證明上限設為 6 MiB(6,291,456 位元組;鏈 17 至 20 設為 4 MiB,鏈 13 至 16 設為 8 MiB),並將區塊上限設為 19 MiB。字數上限不再是唯一的關卡。鏈 21 的創世區塊與鏈 20 及鏈 19 一樣,設有 hardening_v6,在此設定下,部署的程式字數若超過一次調用在第 14 層調用上限下所能容納的數量,即屬無效(ProgramUncallable):在沒有公開輸入的情況下,最多為 8,180 個字。此映像為 11,686 個字,因此鏈 21 會拒絕該部署,亦會拒絕相關調用:每次 ERC-20 調用均在第 16 或 18 層生成證明,高於第 14 層調用上限(步驟 7)。鏈 21 已關閉區塊聚合(其創世區塊沒有 aggregation 區段);其啟動節點列於運行驗證者。部署費用為 0.001 + 0.0001 × 11,686 = 1.1696 RAND,與下文鏈 13 部署所付的費用相同。
此次部署於 2026-09-19 在鏈 13 上進行,當時鏈 13 為運行中的鏈(正式 FRI 配置,創世區塊 8123ccac1883a45750e4df6964fb7cd3f0b321798cde4c0ef406a0293939ece3),使用創世錢包 shielded-1。其後的每條鏈(14 至 19)均以不含鏈 13 程式的全新鏈切換,該映像並未在其中任何一條鏈上重新部署,因此下列交易及高度屬於鏈 13,已無法在瀏覽器中查閱。程式 id 僅由 base_pc 與字的哈希值得出,故同一映像在任何接納該部署的鏈上均得到相同的 id。錢包的輸出如下,進度行已省略(…):
$ rand program deploy <image.bin>
program id: f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d (11686 words, hc 92aefea0951c31a717574962aeb70e10a37012a7d035d48e8713c36df68feae0)
…
proved in 92.2s: tier 14, 1419655 bytes
submitted deploy c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0
…
| 程式 id | f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d |
| 映像 | 11,686 個字;rand-guest 寫法為 hc a0feae92…,錢包寫法為 92aefea0… |
| 費用捆綁包(鏈 13 的 2 入 2 出捆綁包) | 第 14 層,1,419,655 位元組,證明耗時 92.2 秒 |
| 部署交易(鏈 13) | c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0 |
| 提交高度(鏈 13) | 381 |
自鏈 14 起,支付用的捆綁包是每筆交易均附帶的一個 4 入 4 出隱藏資產捆綁包,並針對該交易的綁定值生成證明。它仍為第 14 層:在鏈 14 及 15 的正式配置下,約需 100 秒,約 1.42 MB。自鏈 17 起,捆綁包亦附帶一個第 10 層的授權證明(拆分授權),因此在鏈 18 及 19 上,一筆交易的費用捆綁包約含 1.49 MB 的捆綁包證明及約 1.37 MB 的授權證明。
7. 調用
一次 transfer 調用以 921 個字的向量作為私有輸入,低於任何鏈的輸入上限(預設為 4,295 個字,鏈 20 及 21 為 16,071 個字),且沒有公開字。**此調用無法提交至鏈 21:**該程式無法在鏈 21 上部署(步驟 6),transfer 在第 18 層生成證明,而自 fullnode v0.5.6(2026-09-25)起,節點會在建立驗證密鑰之前,以 CallTierTooHigh 拒絕任何高於第 14 層的調用證明。下列命令在本機生成證明,而鏈會拒絕其結果;所列量度屬鏈下證明。rand call 以重複的 --input 接收每個字:
rand call f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d \
$(for w in $(cat evm2rv/target/transfer.words); do printf -- '--input %s ' "$w"; done)
現已量度。第 18 層的證明在 48 GB 的手提電腦上於 24.7 GB 時被終止,但在 128 GB 的 droplet(m-16vcpu-128gb)上,翻譯後的 transfer 調用已成功生成證明:峰值 RSS 為 85.0 GB,耗時 3,230.5 秒(53.8 分鐘),證明大小為 811,600 位元組。在 droplet 上驗證耗時 101.4 秒,在 48 GB 的 Apple 晶片手提電腦上驗證耗時 50.2 秒,RSS 為 3.66 GB(證明記憶體)。在帳本的固定層級收費表下(即沒有 gas 區段的鏈所採用的規則,至鏈 17 為止),第 18 層的調用費用為 0.0024 RAND。鏈 18 及 19 則改以調用所宣告的 gas 上限及其位元組數計價,按創世價格為每 gas 100 單位、每 KiB 800 單位,且不接納任何高於第 14 層的調用。
鏈 13 上的調用,2026-09-19
approve(BOB, 5) 調用(649 個私有字,第 16 層)於 2026-09-19 在鏈 13 上運行,當時該鏈為運行中的鏈,採用正式 FRI 配置,使用同一個錢包。其後的鏈均未進行調用,因為程式並未在其上部署;鏈 21 與鏈 20 一樣,會拒絕這個第 16 層的調用證明(CallTierTooHigh)。錢包的輸出如下,進度行已省略(…):
$ rand call f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d --input <w0> --input <w1> … # the 649 words of approve(BOB, 5)
…
proved in 388.7s: tier 16, 3412405 bytes, outputs [1, 942495465, 790002515, 1351749335, 1059083501, 2923046783, 2814575942, 696258848]
…
proved in 96.0s: tier 14, 1420423 bytes
submitted call 279e1f62abf3f177ca71b08c633e051c37bc4720118c79ddb00936f036c4bfa7
…
| 調用證明 | 第 16 層,3,412,405 位元組,證明耗時 388.7 秒 |
| 費用捆綁包(鏈 13 的 2 入 2 出捆綁包) | 第 14 層,1,420,423 位元組,證明耗時 96.0 秒 |
| 密封信封 | 2,700 位元組 |
| 調用交易(鏈 13) | 279e1f62abf3f177ca71b08c633e051c37bc4720118c79ddb00936f036c4bfa7 |
| 錨定高度/提交高度 | 高度 802/高度 919 |
| 費用 | 0.00357 RAND |
收據 h_pub | null |
| 收據輸出 | 與解譯器對同一向量得出的八個字相同 |
| 耗時、峰值 RSS | 622.8 秒,22.9 GB,於 48 GB 的 M 系列手提電腦上 |
- 正式證明為 3,412,405 位元組,超過鏈 12 的 2 MiB 證明上限。鏈 12 無法接納此調用;鏈 13 的 8 MiB 上限則可。鏈 14 至 16 沿用相同上限,鏈 17 至 20 設為 4 MiB(4,194,304 位元組),鏈 21 設為 6 MiB,此大小的證明均在這些上限之內。自 v0.5.6 起,節點在檢視調用的大小之前,會先按其層級拒絕該調用。
- 費用包含鏈 13 收費表的位元組項:3.41 MB 的證明超出 2 MiB + 18,432 位元組的免費額度。自鏈 18 起,每次調用由第 0 個位元組起按每 KiB 收費。
收據的八個字即步驟 4 中所列者。鏈不保存任何 EVM 狀態:調用者提供前狀態根及儲存見證,後狀態根則包含在 EVM_OUT 摘要之內。
限制
- 無區塊上下文。 九個區塊上下文操作碼會觸發陷阱(trap),直至區塊綁定設計落實為止。
- 不支援價值轉移。 附帶非零價值的
CALL會觸發陷阱。對預編譯合約以外的合約發出的呼叫亦會觸發陷阱。 - ecrecover、bn256 mul、配對運算及大型 modexp 目前無法證明。 它們各自超出 2²⁰ 行的層級上限,需要協處理器表格。
- 鏈上沒有 EVM 狀態。 一次呼叫即是對單次運行的一份證明,狀態由呼叫方自行攜帶。
- 在 chain 21 上,部署與任何 ERC-20 呼叫均不獲接納。 在 chain 21 的
hardening_v6下,字數超過第 14 層呼叫所能容納的部署屬無效(ProgramUncallable;至多 8,180 字),而映像為 11,686 字。自 fullnode v0.5.6 起,呼叫證明必須為第 14 層或以下(CallTierTooHigh);approve在第 16 層證明,transfer與transferFrom在第 18 層證明。同一項檢查亦限制呼叫可聲明的雜湊表:2¹² 行 Keccak(128 次置換)及 2¹³ 行 SHA-256(128 次壓縮)。如下文所述,這些呼叫仍可在鏈下證明。 - 儲存索引只有 32 位元深。
evm-core按keccak256(slot)的前 32 位元安置合約儲存葉節點,因此與選定槽位碰撞的槽位,需約 2³² 次 Keccak 雜湊才能找到;而只要該槽位持有非零值,選定的槽位即遭凍結(既無法偽造,亦不會損失價值)。此問題目前處於休眠狀態:evm.bin為 18,009 字,處於第 14 層上限的呼叫至多容納 8,184 字,故任何鏈上均無可呼叫的 EVM 運行時。fullnode 的docs/confidential.md在呼叫上限旁記錄了此前提條件(審計 v6,ZKV-6;自 2026-09-30 起於main,在 v0.6.7 標籤之後):在鏈取消第 14 層呼叫上限,或接納小至可供呼叫的 EVM 運行時之前,必須加深儲存索引並重新釘選evm.bin。 - 已證明。 第一階段的 transfer 證明(第 18 層)在一部 48 GB 的手提電腦上,運行 1,016 秒、佔用 24.7 GB 後被 SIGKILL 終止;但第二階段的
transfer呼叫已在一部 128 GB 的 droplet(m-16vcpu-128gb)上完成證明:峰值 RSS 為 85.0 GB,歷時 3,230.5 秒(53.8 分鐘),證明為 811,600 位元組,驗證耗時 101.4 秒(droplet)及 50.2 秒、佔用 3.66 GB RSS(48 GB 手提電腦)。直譯器的evm.bintransfer 證明結果相當接近:85.5 GB、3,143.3 秒(52.4 分鐘)、證明為 805,108 位元組;兩份證明帶有相同的公開輸出字,確認了在真實證明器上的一致性。approve(第 16 層,經轉譯)的成本低得多:21.7 GB、786.7 秒(13.1 分鐘)、證明為 798,930 位元組。轉譯只有在把呼叫降至較小層級時,才會降低證明成本。 - 鏈上不記錄位元組碼。 請公開發佈,讓其他人可重建
hc。