{"id":40818953,"url":"https://github.com/eth-act/wasrisc","last_synced_at":"2026-01-21T21:44:43.167Z","repository":{"id":323652268,"uuid":"1091196135","full_name":"eth-act/wasrisc","owner":"eth-act","description":null,"archived":false,"fork":false,"pushed_at":"2026-01-13T12:48:58.000Z","size":16084,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-13T15:41:31.624Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eth-act.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-06T17:25:30.000Z","updated_at":"2026-01-13T12:49:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/eth-act/wasrisc","commit_stats":null,"previous_names":["eth-act/wasrisc"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/eth-act/wasrisc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eth-act%2Fwasrisc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eth-act%2Fwasrisc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eth-act%2Fwasrisc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eth-act%2Fwasrisc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eth-act","download_url":"https://codeload.github.com/eth-act/wasrisc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eth-act%2Fwasrisc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28644149,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T21:29:11.980Z","status":"ssl_error","status_checked_at":"2026-01-21T21:24:31.872Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-21T21:44:43.066Z","updated_at":"2026-01-21T21:44:43.159Z","avatar_url":"https://github.com/eth-act.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WASRISC\n\nThis repository demonstrates and benchmarks different compilation methods for translating high-level languages to RISCV64IM (the target architecture for RISCV zkVMs) using WASM-WASI as an intermediate representation.\n\nThis experiment measures the performance impact of using WASM-WASI as an intermediate step compared to direct compilation from high-level languages to RISCV64IM.\n\n**Note:** While any language that compiles to WASM with WASI support (0.1) can use these pipelines, this project focuses primarily on Go and Rust.\n\n## Pipeline Overview\n\nAll pipelines share a common first step: compiling high-level source code to WASM-WASI. Most modern language compilers support WASM as a target.\n\nThe transition from WASM to the zkVM target can be achieved through multiple approaches. This experiment explores three compilation methods:\n\n1. **w2c2 + GCC**: Transpile WASM to C source code using the `w2c2` compiler, then compile the C code to the final target using `gcc` or a platform-specific compiler\n2. **WAMR (LLVM)**: Compile WASM directly to the final target using WAMR's LLVM backend\n3. **wasmtime/wasmer (Cranelift)**: Compile WASM to Linux (either host or RISCV64) using `wasmtime` or `wasmer`, both of which use Cranelift for code generation\n\nFor the third approach, we targeted Linux because it's supported out of the box—porting to bare-metal would require significant additional effort. For benchmarking the Ethereum state transition function, this difference shouldn't significantly affect results due to minimal OS interaction and the absence of floating-point operations in the benchmark code.\n\n```mermaid\ngraph TD;\n\nsource_code[\"Source Code\u003cbr/\u003eGo, Rust, C, Zig, etc.\"]\nwasm[\"WebAssembly\u003cbr/\u003ewith WASI (wasip1)\"]\nc_source_code[\"C Source Code\"]\n\nsubgraph targets[\" \"]\n    zkvm_target_binary[\"Target Binary\u003cbr/\u003eRISCV zkVM\"]\n    linux_target_binary[\"Target Binary\u003cbr/\u003eRISC-V/AMD64 Linux\"]\nend\n\nsource_code --\u003e|\"Language-specific\u003cbr/\u003eWASM compiler\"| wasm\nwasm --\u003e|\"w2c2 transpiler\"| c_source_code\nc_source_code --\u003e|\"GCC/platform-specific\u003cbr/\u003ecompiler\"| zkvm_target_binary\nwasm --\u003e|\"WAMR\u003cbr/\u003ellvm backend\"| zkvm_target_binary\nwasm --\u003e|\"wasmtime\u003cbr/\u003ecranelift backend\"| linux_target_binary\nwasm --\u003e|\"wasmer\u003cbr/\u003ecranelift backend\"| linux_target_binary\n\nclassDef subgraphStyle fill:none,stroke:none;\n```\n\n## Prerequisites\n\nThe benchmark environment is dockerized and includes:\n- RISC-V GNU Toolchain with newlib (rv64ima)\n- w2c2 WebAssembly-to-C transpiler\n- QEMU with `libinsn` plugin\n- WAMR\n- wasmtime\n- wasmer\n\n\u003e **Note:** The first time you run the Docker script, it will take some time as it rebuilds the RISC-V GNU toolchain from source.\n\nIn addition to Docker, install the following on your host system:\n- Rust\n- Rust wasip1 target:\n  ```bash\n  rustup target add wasm32-wasip1\n  ```\n- Rust RISC-V target:\n  ```bash\n  rustup target add riscv64gc-unknown-linux-gnu\n  ```\n\n## Quick Start\n\nRun the `go_benchmark.sh` and `rust_benchmark.sh` scripts to compare different compilation methods for the Ethereum state transition function. These scripts will:\n\n1. Compile Rust and Go implementations using various methods\n2. Execute the compiled binaries under QEMU with the `libinsn` plugin to count instructions\n3. Save instruction counts for each compilation method to `go_benchmark_results.txt` and `rust_benchmark_results.txt` (see \"total insns\" in those files)\n\nSee the scripts for implementation details.\n\n## Benchmark Configurations\n\nThe following benchmarks were performed:\n\n- **w2c2 -O0**: WASM transpiled to C with `w2c2`, then compiled with GCC using `-O0` optimization for Linux `rv64imad`\n- **w2c2 optimized**: WASM transpiled to C with `w2c2`, then compiled with GCC using higher optimization levels for Linux `rv64imad`\n- **directly**:\n  - Rust: `cargo build --target riscv64gc-unknown-linux-gnu --release`\n  - Go: `GOOS=linux GOARCH=riscv64 go build`\n- **wasmtime**: WASM compiled with `wasmtime` using Cranelift backend to a `riscv64gc` precompiled \".cwasm\" file, then executed using the `wasmtime` runtime on Linux\n- **wasmer (cranelift)**: WASM compiled with `wasmer` using Cranelift backend to a `riscv64gc` precompiled \".wasmu\" file, then executed using the `wasmer` runtime on Linux\n- **wamr -O0**: WASM compiled with `wamr` using LLVM backend with `-O0` optimization for bare-metal `riscv64ima`\n\nThe following critical benchmarks could not yet be performed due to issues in `wasmer` and `wamr`:\n\n- **wasmer (llvm)**: WASM compiled with `wasmer` using LLVM backend to a `riscv64gc` precompiled \".wasmu\" file, then executed using the `wasmer` runtime on Linux\n- **wamr -O3**: WASM compiled with `wamr` using LLVM backend with `-O3` optimization for bare-metal `riscv64ima`\n\nSince these critical benchmarks could not be performed on RISC-V, they were performed on AArch64 with the expectation that those results would allow us to extrapolate potential RISC-V performance.\n\nSee the \"Known Issues\" section for details.\n\n## Benchmark Results on RISCV\n\n| Program | w2c2\u003cbr\u003e-O0 | w2c2\u003cbr\u003eoptimized | wasmtime | wasmer\u003cbr\u003e(cranelift) | wasmer\u003cbr\u003e(llvm) | WAMR\u003cbr\u003e-O0 | WAMR\u003cbr\u003e-O3 | directly |\n|---|---|---|---|---|---|---|---|---|\n| `reva-client-eth` (Rust) | 7,887,190,279 | 1,419,050,123\u003cbr\u003e(-O1) | 1,074,488,397 | doesn't work | ? | didn't check | ? | 388,564,723 |\n| `stateless` (Go) | 12,866,052,519 | 2,118,257,727\u003cbr\u003e(-O3) | 874,758,419 | 953,874,491 | ? | 5,427,433,654 | ? | 236,265,327 |\n\n## Analysis\n\n**Important:** The `reva-client-eth` and `stateless` numbers should not be compared directly against each other, as these implementations execute against different blocks using different block serialization frameworks.\n\nUnfortunately, we were unable to benchmark the most promising approaches (`wasmer (llvm)` and `wamr -O3`) on RISCV due to outstanding issues. The following analysis is based on available results for RISCV only.\n\n### Key Findings\n\n- **Direct compilation is fastest**: As expected, compiling directly to the target architecture provides the best performance\n- **Optimization level is critical for w2c2**: Using GCC optimization flags provides a 6x speedup compared to unoptimized `-O0` builds\n- **Cranelift-based pipelines perform best**: Among the WASM-based approaches, pipelines using Cranelift for code generation show the best performance\n- **Performance overhead of WASM intermediate step**: The ratio of instructions required when compiling via `wasmtime` versus direct compilation is:\n  - 2.8x for `reva-client-eth` (Rust)\n  - 3.7x for `stateless` (Go)\n- **WASM quality comparison**: The relatively similar overhead ratios suggest that Go's WASM compiler generates code quality comparable to Rust's WASM compiler\n- **WAMR -O0 performance**: Currently falls between `w2c2` and `wasmtime` in terms of instruction count\n\n### Binary Sizes\n\n```\n$ ls -lah build/bin/\n827K fibonacci.riscv.O0.elf\n686K fibonacci.riscv.O3.elf\n823K hello_world.riscv.O0.elf\n682K hello_world.riscv.O3.elf\n23M  reva-client-eth.riscv.O0.elf\n19M  reva-client-eth.riscv.O1.elf\n74M  stateless.amd64.O0.elf\n28M  stateless.amd64.O1.elf\n29M  stateless.amd64.O3.elf\n67M  stateless.riscv.O0.elf\n58M  stateless.riscv.O1.elf\n64M  stateless.riscv.O3.elf\n```\n\n## Supplementary Benchmark Results on AARCH64\n\nThe benchmark was performed for stateless (Go) only. `WAMR -O3` targets dynamically-linked AArch64 Linux MUSL. To reduce the impact of dynamic linker overhead and WAMR runtime setup, multiple runs of the business logic were performed. In the following tables, all WAMR rows without a `--b-c=0` annotation used the `--bounds-checks=0` option during WAMR compilation. All other rows used the `--bounds-checks=1` option during WAMR compilation.\n\n|pipeline\u003cbr\u003e/\u003cbr\u003enumber of runs|wasmtime|wasmer\u003cbr\u003e(cranelift)|wasmer\u003cbr\u003e(llvm)|WAMR\u003cbr\u003e-O3|directy|\n|---|---|---|---|---|---|\n|1x|659,241,636|663,867,152|626,137,758|990,892,303|166,611,730|\n|1x|(same)|(same)|(same)|699,810,538\u003cbr\u003e\u003csup\u003e--b-c=0\u003csup/\u003e|(same)|\n|10x|2,533,334,795|2,268,562,071|2,002,956,919|3,100,038,538|660,390,007|\n|25x|5,686,210,736|4,978,224,909|4,338,984,157|6,674,027,814|1,477,959,349|\n|50x|10,929,448,352|-|-|12,581,544,465|2,830,756,855|\n|50x|(same)|-|-|8,338,818,655\u003cbr\u003e\u003csup\u003e--b-c=0\u003csup/\u003e|(same)|\n\nThe following table presents the ratio between the number of steps executed for a given compilation pipeline and the number of steps executed for a directly compiled program.\n\n|pipeline\u003cbr\u003e/\u003cbr\u003enumber of runs|wasmtime|wasmer\u003cbr\u003e(cranelift)|wasmer\u003cbr\u003e(llvm)|WAMR\u003cbr\u003e-O3|directy|\n|---|---|---|---|---|---|\n|1x|3.95|3.98|3.75|5.94|1.0|\n|1x|(same)|(same)|(same)|4.19\u003cbr\u003e\u003csup\u003e--b-c=0\u003csup/\u003e|(same)|\n|10x|3.83|3.43|3.03|4.69|1.0|\n|25x|3.84|3.36|2.93|4.51|1.0|\n|50x|3.86|-|-|4.44|1.0|\n|50x|(same)|-|-|2.94\u003cbr\u003e\u003csup\u003e--b-c=0\u003csup/\u003e|(same)|\n\nThe `--bounds-checks=0` option appears to be critical for WAMR performance. Only with this option can WAMR outperform Cranelift-based frameworks in some scenarios. For a single run, `wasmtime`, `wasmer (cranelift)`, `and wasmer (llvm)` show similar performance. Single-run results for WAMR are difficult to interpret due to overhead from dynamic linking and Linux WAMR runtime setup, which would not be present on a zkVM bare-metal platform. For compute-intensive programs (50x), WAMR appears to have an edge over other compilation pipelines. The best-performing WebAssembly approaches appear to be 3-4 times slower than direct compilation of the stateless Go program.\n\nThese results have not been taken into account in the \"Analysis\" section.\n\n## Known Issues\n\n### WAMR -O3 Bug\n\nRunning WAMR with non-zero optimization levels on RISC-V currently fails with a relocation error.\nIssue: https://github.com/bytecodealliance/wasm-micro-runtime/issues/4765\n\n### Wasmer (LLVM) Bug\n\nThe wasmer team is actively working on fixing RISC-V target support.\nIssues:\n- https://github.com/wasmerio/wasmer/issues/5954\n- https://github.com/wasmerio/wasmer/issues/5951\n\n### GCC Bug\n\nThe `w2c2 optimized` pipeline for `reva-client-eth` uses the `-O1` optimization level. Higher optimization levels cause GCC to hang during compilation. This has been confirmed as a GCC bug based on the following observations:\n- Clang successfully compiles the same sources\n- When w2c2 is invoked with the `-f 100` option (which splits output into many source files), GCC hangs while compiling a single ~1000 LOC file\n\nFor reference, `reva-client-eth` compiled with Clang using `-O3` requires 1.2×10⁹ instructions to execute—not significantly fewer than when compiled with GCC using `-O1` (1.4×10⁹ instructions).\n\n### Linking Problem\n\nThe `w2c2 optimized` pipeline for the `stateless` program fails to link when using non-zero optimization levels, producing the error:\n\n```\nguest.c:(.text.guestInitMemories+0x50): relocation truncated to fit: R_RISCV_JAL against `.L214'\ncollect2: error: ld returned 1 exit status\n```\n\nThe issue stems from a single massive function `guestInitMemories` spanning over 100,000 lines of C code generated by w2c2 for `stateless`. GCC emits `R_RISCV_JAL` relocation for intra-function branches, which support only ±1MB PC-relative jumps. GCC lacks a fallback mechanism to automatically use AUIPC+JALR for out-of-range intra-function jumps when optimization creates this problem.\n\n**Workaround:** Use the `-fno-reorder-blocks` flag to disable the optimization that creates large jumps. With this flag, `stateless` can be built with `-O3` optimization.\n\n**Note:** This issue doesn't occur on x86 because that platform supports 32-bit relative jumps.\n\n### Compilation Times\n\nFor higher optimization levels (e.g., `-O3`), expect compilation times of up to 60 minutes for `reva-client-eth` and `stateless`.\n\n## Advanced Usage\n\n### Custom WASM Imports\n\nYou can call platform-specific functions from your WASM code using custom imports.\n\nIn Go, use `//go:wasmimport`:\n\n```go\n// examples/go/with_import/example.go\npackage main\n\nimport \"fmt\"\n\n//go:wasmimport testmodule testfunc\n//go:noescape\nfunc testfunc(a, b uint32) uint32\n\nfunc main() {\n    result := testfunc(1, 2)\n    fmt.Printf(\"testfunc(1, 2) = %d\\n\", result)\n}\n```\n\nImplement the import in `platform/*/custom_imports.c`:\n\n```c\n// platform/amd64/custom_imports.c\nU32 testmodule__testfunc(void* p, U32 a, U32 b) {\n    printf(\"testfunc called with %u, %u\\n\", a, b);\n    return a + b;\n}\n```\n\n### Memory Limits\n\nFor embedded targets with limited memory, use `debug.SetMemoryLimit()`:\n\n```go\nimport \"runtime/debug\"\n\nfunc main() {\n    debug.SetMemoryLimit(400 * (1 \u003c\u003c 20)) // 400MB limit\n    // ...\n}\n```\n\n## License\n\nMIT + Apache","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feth-act%2Fwasrisc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feth-act%2Fwasrisc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feth-act%2Fwasrisc/lists"}