Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed
- Benchmark comparison refreshed against current alloy crates (alloy-primitives 1.6.0, alloy-sol-types 1.6.0, alloy-dyn-abi 1.6.0, alloy-consensus 2.0.5, alloy-signer 2.0.5, alloy-rlp 0.3.15); bench/alloy-bench migrated from alloy-primitives 0.8 / alloy 0.6. New score: eth.zig wins 18/26 (alloy improved Keccak on larger inputs, hex encoding, RLP u256 decoding, and UniswapV4-style swap math)

### Added
- `mev_share` module: MEV-Share client mirroring `mev-share-client-ts` -- `sendTransaction` (eth_sendPrivateTransaction via `flashbots.Relay`), `simulateBundle` (mev_simBundle with `SimBundleOpts`/`SimBundleResult`), blocking SSE event stream subscription (`MevShareClient.on` with `PendingEvent`/`PendingTransaction`/`PendingBundle` and pure `parseEventData`), and `getEventHistory` (GET /api/v1/history) (#34)
- `eth_sendPrivateTransaction` (MEV-Share private transactions) on `flashbots.Relay`: submit a single private transaction with hint preferences (calldata, contract_address, logs, function_selector), builder selection, fast mode, and max inclusion block (#40)
Expand Down
51 changes: 26 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,43 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Zig](https://img.shields.io/badge/Zig-%E2%89%A5%200.16.0-orange)](https://ziglang.org/)

**The fastest Ethereum library.** Beats Rust's alloy.rs on 23 out of 26 benchmarks.
**The fastest Ethereum library.** Beats Rust's alloy.rs on 18 out of 26 benchmarks.

A complete Ethereum client library written in Zig -- ABI encoding, RLP serialization, secp256k1 signing, Keccak-256 hashing, HD wallets, ERC-20/721 tokens, JSON-RPC, ENS, and more.

**[Read the docs at ethzig.org](https://ethzig.org)**

## Why eth.zig?

**Fastest Ethereum library** -- eth.zig [beats alloy.rs](bench/RESULTS.md) (Rust's leading Ethereum library, backed by Paradigm) on **23 out of 26 benchmarks**. ECDSA signing 2.09x faster, ABI decoding up to 7.65x, secp256k1 recovery 3.23x, mulDiv 1.76x, u256 division 5.57x, Keccak hashing up to 1.26x. See the [full results](bench/RESULTS.md).
**Fastest Ethereum library** -- eth.zig [beats alloy.rs](bench/RESULTS.md) (Rust's leading Ethereum library, backed by Paradigm) on **18 out of 26 benchmarks**, measured 2026-06-10 against current alloy 1.6/2.0. RLP transaction encoding 24.33x faster, ABI decoding up to 8.41x, secp256k1 recovery 4.23x, ECDSA signing 2.34x, u256 division 3.43x, mulDiv 1.82x. See the [full results](bench/RESULTS.md).

**Comptime-first** -- Function selectors and event topics are computed at compile time with zero runtime cost. The compiler does the hashing so your program doesn't have to.

**Complete** -- ABI, RLP, secp256k1, Keccak-256, BIP-32/39/44 HD wallets, EIP-712, JSON-RPC, WebSocket, ENS, ERC-20/721 -- everything you need for Ethereum in one package.

## Performance vs alloy.rs

eth.zig wins **23/26 benchmarks** against [alloy.rs](https://alloy.rs). Measured on Apple Silicon, `ReleaseFast` (Zig) vs `--release` (Rust). Criterion-style harness with 0.5s warmup and 2s measurement.
eth.zig wins **18/26 benchmarks** against [alloy.rs](https://alloy.rs) (alloy-primitives 1.6.0, alloy-consensus 2.0.5; run 2026-06-10). Measured on Apple Silicon, `ReleaseFast` (Zig) vs `--release` (Rust). Criterion-style harness with 0.5s warmup and 2s measurement.

| Operation | eth.zig | alloy.rs | Winner |
|-----------|---------|----------|--------|
| secp256k1 sign | 24,481 ns | 51,286 ns | **zig 2.09x** |
| secp256k1 sign+recover | 67,816 ns | 218,720 ns | **zig 3.23x** |
| Keccak-256 (32B) | 268 ns | 337 ns | **zig 1.26x** |
| Keccak-256 (4KB) | 7,886 ns | 9,238 ns | **zig 1.17x** |
| ABI encode (static) | 24 ns | 100 ns | **zig 4.17x** |
| ABI encode (dynamic) | 176 ns | 325 ns | **zig 1.85x** |
| ABI decode (uint256) | 16 ns | 51 ns | **zig 3.19x** |
| ABI decode (dynamic) | 34 ns | 260 ns | **zig 7.65x** |
| u256 mulDiv (512-bit) | 17 ns | 30 ns | **zig 1.76x** |
| u256 division | 7 ns | 39 ns | **zig 5.57x** |
| u256 multiply | 4 ns | 9 ns | **zig 2.25x** |
| UniswapV2 getAmountOut | 21 ns | 27 ns | **zig 1.29x** |
| UniswapV4 swap | 42 ns | 47 ns | **zig 1.12x** |
| TX hash (EIP-1559) | 333 ns | 407 ns | **zig 1.22x** |

alloy.rs wins on address hex parsing (1.36x -- SIMD) and RLP u256 decoding (1.40x). See [full results](bench/RESULTS.md).
| secp256k1 sign | 22,033 ns | 51,490 ns | **zig 2.34x** |
| secp256k1 sign+recover | 52,095 ns | 220,150 ns | **zig 4.23x** |
| Keccak-256 (32B) | 263 ns | 319 ns | **zig 1.21x** |
| Keccak-256 (4KB) | 7,732 ns | 7,838 ns | **zig 1.01x** |
| ABI encode (static) | 25 ns | 97 ns | **zig 3.88x** |
| ABI encode (dynamic) | 171 ns | 337 ns | **zig 1.97x** |
| ABI decode (uint256) | 14 ns | 51 ns | **zig 3.64x** |
| ABI decode (dynamic) | 32 ns | 269 ns | **zig 8.41x** |
| RLP encode (EIP-1559 tx) | 3 ns | 73 ns | **zig 24.33x** |
| u256 mulDiv (512-bit) | 17 ns | 31 ns | **zig 1.82x** |
| u256 division | 7 ns | 24 ns | **zig 3.43x** |
| u256 multiply | 5 ns | 10 ns | **zig 2.00x** |
| UniswapV2 getAmountOut | 24 ns | 24 ns | tie |
| UniswapV4 swap | 45 ns | 42 ns | rs 1.07x |
| TX hash (EIP-1559) | 271 ns | 361 ns | **zig 1.33x** |

alloy.rs wins on address hex parsing (1.55x -- SIMD), hex encoding (1.08x), UniswapV4 swap (1.07x), and Keccak at 256B/1KB inputs (within ~2%, measurement noise). See [full results](bench/RESULTS.md).

## Quick Start

Expand Down Expand Up @@ -311,12 +312,12 @@ cd examples && zig build && ./zig-out/bin/01_derive_address

| Category | eth.zig | alloy.rs |
|----------|---------|----------|
| Benchmarks won | **23/26** | 2/26 |
| secp256k1 signing | Faster (2.09-3.23x) | -- |
| ABI encoding/decoding | Faster (1.85-7.65x) | -- |
| Hashing (Keccak) | Faster (1.17-1.26x) | -- |
| u256 arithmetic | Faster on all ops (1.12-5.57x) | -- |
| Hex operations | Faster (1.05-1.22x) | Faster on hex parsing (1.36x, SIMD) |
| Benchmarks won | **18/26** | 5/26 |
| secp256k1 signing | Faster (2.34-4.23x) | -- |
| ABI encoding/decoding | Faster (1.96-8.41x) | -- |
| Hashing (Keccak) | Faster on small inputs (1.19-1.21x) | Within ~2% on 256B-1KB |
| u256 arithmetic | Faster on mul/div/mulDiv (1.82-3.43x) | UniswapV4 swap (1.07x) |
| Hex operations | Faster decoding (1.17x) | Faster encoding (1.08x) and parsing (1.55x, SIMD) |

### Features vs Zabi (Zig)

Expand Down
78 changes: 41 additions & 37 deletions bench/RESULTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,59 @@

Zig vs Rust -- a head-to-head performance comparison of [eth.zig](https://github.com/StrobeLabs/eth.zig) and [alloy.rs](https://alloy.rs) across 26 core Ethereum operations: Keccak-256 hashing, ABI encoding/decoding, RLP serialization, secp256k1 ECDSA signing, u256 arithmetic (including UniswapV4 mulDiv with true 512-bit intermediate), hex operations, address derivation, and EIP-1559 transaction hashing.

**Score: eth.zig wins 23/26 | alloy.rs wins 2/26 | tied 1/26**
**Score: eth.zig wins 18/26 | alloy.rs wins 5/26 | tied 3/26**

Benchmarks run on Apple Silicon with `ReleaseFast` (Zig) vs `--release` (Cargo). Custom criterion-style harness with 0.5s warmup, calibrated batch sizes, and 2s measurement window. Both mulDiv benchmarks use true 512-bit intermediate arithmetic (eth.zig's `mulDiv`, alloy's `U512` from ruint).
Run date: 2026-06-10 on Apple Silicon (aarch64-macos), Zig 0.16.0 `ReleaseFast` vs Rust 1.94.0 `--release`. alloy crate versions: alloy-primitives 1.6.0, alloy-sol-types 1.6.0, alloy-dyn-abi 1.6.0, alloy-consensus 2.0.5, alloy-signer 2.0.5, alloy-rlp 0.3.15, k256 0.13. Custom criterion-style harness with 0.5s warmup, calibrated batch sizes, and 2s measurement window. Both mulDiv benchmarks use true 512-bit intermediate arithmetic (eth.zig's `mulDiv`, alloy's `U512` from ruint).

> Historical note: an earlier comparison (March 2026, against alloy-primitives 0.8 / alloy 0.6) scored eth.zig 23/26. alloy has since improved several hot paths (Keccak on larger inputs, RLP u256 decoding, hex encoding, UniswapV4-style swap math), and the table below is the current head-to-head against alloy 1.6/2.0.

## Full Comparison

| Benchmark | eth-zig | alloy.rs | Winner |
|---|---|---|---|
| keccak256_empty | 275 ns | 333 ns | **zig 1.21x** |
| keccak256_32b | 268 ns | 337 ns | **zig 1.26x** |
| keccak256_256b | 536 ns | 640 ns | **zig 1.19x** |
| keccak256_1kb | 2,052 ns | 2,432 ns | **zig 1.19x** |
| keccak256_4kb | 7,886 ns | 9,238 ns | **zig 1.17x** |
| secp256k1_sign | 24,481 ns | 51,286 ns | **zig 2.09x** |
| secp256k1_sign_recover | 67,816 ns | 218,720 ns | **zig 3.23x** |
| address_derivation | 262 ns | 370 ns | **zig 1.41x** |
| address_from_hex | 15 ns | 11 ns | rs 1.36x |
| checksum_address | 312 ns | 450 ns | **zig 1.44x** |
| abi_encode_transfer | 25 ns | 61 ns | **zig 2.44x** |
| abi_encode_static | 24 ns | 100 ns | **zig 4.17x** |
| abi_encode_dynamic | 176 ns | 325 ns | **zig 1.85x** |
| abi_decode_uint256 | 16 ns | 51 ns | **zig 3.19x** |
| abi_decode_dynamic | 34 ns | 260 ns | **zig 7.65x** |
| rlp_encode_eip1559_tx | 57 ns | 72 ns | **zig 1.26x** |
| rlp_decode_u256 | 14 ns | 10 ns | rs 1.40x |
| keccak256_empty | 261 ns | 310 ns | **zig 1.19x** |
| keccak256_32b | 263 ns | 319 ns | **zig 1.21x** |
| keccak256_256b | 534 ns | 532 ns | rs 1.00x |
| keccak256_1kb | 2,073 ns | 2,039 ns | rs 1.02x |
| keccak256_4kb | 7,732 ns | 7,838 ns | **zig 1.01x** |
| secp256k1_sign | 22,033 ns | 51,490 ns | **zig 2.34x** |
| secp256k1_sign_recover | 52,095 ns | 220,150 ns | **zig 4.23x** |
| address_derivation | 265 ns | 328 ns | **zig 1.24x** |
| address_from_hex | 17 ns | 11 ns | rs 1.55x |
| checksum_address | 304 ns | 341 ns | **zig 1.12x** |
| abi_encode_transfer | 24 ns | 47 ns | **zig 1.96x** |
| abi_encode_static | 25 ns | 97 ns | **zig 3.88x** |
| abi_encode_dynamic | 171 ns | 337 ns | **zig 1.97x** |
| abi_decode_uint256 | 14 ns | 51 ns | **zig 3.64x** |
| abi_decode_dynamic | 32 ns | 269 ns | **zig 8.41x** |
| rlp_encode_eip1559_tx | 3 ns | 73 ns | **zig 24.33x** |
| rlp_decode_u256 | 7 ns | 7 ns | tie |
| u256_add | 4 ns | 4 ns | tie |
| u256_mul | 4 ns | 9 ns | **zig 2.25x** |
| u256_div | 7 ns | 39 ns | **zig 5.57x** |
| u256_uniswapv2_amount_out | 21 ns | 27 ns | **zig 1.29x** |
| u256_mulDiv | 17 ns | 30 ns | **zig 1.76x** |
| u256_uniswapv4_swap | 42 ns | 47 ns | **zig 1.12x** |
| hex_encode_32b | 22 ns | 23 ns | **zig 1.05x** |
| hex_decode_32b | 23 ns | 28 ns | **zig 1.22x** |
| tx_hash_eip1559 | 333 ns | 407 ns | **zig 1.22x** |
| u256_mul | 5 ns | 10 ns | **zig 2.00x** |
| u256_div | 7 ns | 24 ns | **zig 3.43x** |
| u256_uniswapv2_amount_out | 24 ns | 24 ns | tie |
| u256_mulDiv | 17 ns | 31 ns | **zig 1.82x** |
| u256_uniswapv4_swap | 45 ns | 42 ns | rs 1.07x |
| hex_encode_32b | 26 ns | 24 ns | rs 1.08x |
| hex_decode_32b | 24 ns | 28 ns | **zig 1.17x** |
| tx_hash_eip1559 | 271 ns | 361 ns | **zig 1.33x** |

## Score Summary

| | Count |
|---|---|
| eth-zig wins | 23 |
| alloy.rs wins | 2 |
| Tied | 1 |
| eth-zig wins | 18 |
| alloy.rs wins | 5 |
| Tied | 3 |

## Key Optimizations

| Optimization | Impact |
|---|---|
| bitcoin-core/secp256k1 C backend (vendored) | secp256k1_sign: 2.09x faster than alloy; sign_recover: 3.23x faster |
| Lane-complementing Keccak-f[1600] (XKCP opt64) | keccak256_4kb: 1.17x faster than alloy |
| Streamlined mulDiv with native u128 division | mulDiv: 1.76x faster than alloy (17ns vs 30ns) |
| U256Limb limb-native arithmetic | uniswapv2: beats alloy 1.29x |
| Half-word division (`div128by64`) | u256_div: 7ns, 5.57x faster than alloy |
| bitcoin-core/secp256k1 C backend (vendored) | secp256k1_sign: 2.34x faster than alloy; sign_recover: 4.23x faster |
| Lane-complementing Keccak-f[1600] (XKCP opt64) | keccak256_32b: 1.21x faster than alloy (larger inputs are now within ~2% of alloy 1.6) |
| Streamlined mulDiv with native u128 division | mulDiv: 1.82x faster than alloy (17ns vs 31ns) |
| Half-word division (`div128by64`) | u256_div: 7ns, 3.43x faster than alloy |
| mulWide + divWide (Knuth D for 512-bit) | Replaces 256-iteration binary long division with ~4-iteration Knuth D |
| FixedBufferAllocator in benchmarks | Eliminates allocator overhead for ABI/RLP/TX benchmarks |
| Vendored bitcoin-core/secp256k1 + XKCP keccak | Best-in-class C backends compiled by `zig build` |
Expand All @@ -63,8 +64,11 @@ Benchmarks run on Apple Silicon with `ReleaseFast` (Zig) vs `--release` (Cargo).

| Benchmark | Gap | Root Cause |
|---|---|---|
| address_from_hex | 1.36x | alloy uses SIMD hex parsing; eth.zig uses scalar loop |
| rlp_decode_u256 | 1.40x | alloy's ruint has optimized small-integer RLP decoding |
| address_from_hex | 1.55x | alloy uses SIMD hex parsing; eth.zig uses scalar loop |
| hex_encode_32b | 1.08x | alloy's const-hex crate uses vectorized encoding |
| u256_uniswapv4_swap | 1.07x | ruint's U512 widening mul/div edges out eth.zig on this path |
| keccak256_256b | 1.00x | within measurement noise (~0.4%) |
| keccak256_1kb | 1.02x | within measurement noise (~2%) |

## Reproducing

Expand Down
14 changes: 7 additions & 7 deletions bench/alloy-bench/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ version = "0.1.0"
edition = "2021"

[dependencies]
alloy-primitives = { version = "0.8", features = ["rlp"] }
alloy-primitives = { version = "1.6", features = ["rlp"] }
alloy-rlp = "0.3"
alloy-rlp-derive = "0.3"
alloy-sol-types = "0.8"
alloy-dyn-abi = "0.8"
alloy-consensus = "0.6"
alloy-signer = "0.6"
alloy-signer-local = "0.6"
alloy-network = "0.6"
alloy-sol-types = "1.6"
alloy-dyn-abi = "1.6"
alloy-consensus = "2.0"
alloy-signer = "2.0"
alloy-signer-local = "2.0"
alloy-network = "2.0"
k256 = { version = "0.13", features = ["ecdsa"] }
criterion = { version = "0.5", features = ["html_reports"] }

Expand Down
71 changes: 37 additions & 34 deletions docs/content/docs/benchmarks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,57 @@ description: eth.zig vs alloy.rs -- head-to-head performance comparison across 2

eth.zig vs Rust -- a head-to-head performance comparison of eth.zig and [alloy.rs](https://alloy.rs) across 26 core Ethereum operations.

**Score: eth.zig wins 23/26 | alloy.rs wins 1/26 | tied 2/26**
**Score: eth.zig wins 18/26 | alloy.rs wins 5/26 | tied 3/26**

Benchmarks run on Apple Silicon with `ReleaseFast` (Zig) vs `--release` (Cargo). Custom criterion-style harness with 0.5s warmup, calibrated batch sizes, and 2s measurement window. Both mulDiv benchmarks use true 512-bit intermediate arithmetic.
Run date: 2026-06-10 on Apple Silicon (aarch64-macos) with `ReleaseFast` (Zig) vs `--release` (Cargo). alloy crate versions: alloy-primitives 1.6.0, alloy-sol-types 1.6.0, alloy-dyn-abi 1.6.0, alloy-consensus 2.0.5, alloy-signer 2.0.5, alloy-rlp 0.3.15. Custom criterion-style harness with 0.5s warmup, calibrated batch sizes, and 2s measurement window. Both mulDiv benchmarks use true 512-bit intermediate arithmetic.

## Full Results

| Benchmark | eth.zig | alloy.rs | Winner |
|-----------|---------|----------|--------|
| keccak256_empty | 257 ns | 334 ns | **zig 1.30x** |
| keccak256_32b | 259 ns | 336 ns | **zig 1.30x** |
| keccak256_256b | 519 ns | 639 ns | **zig 1.23x** |
| keccak256_1kb | 2,000 ns | 2,494 ns | **zig 1.25x** |
| keccak256_4kb | 7,673 ns | 9,292 ns | **zig 1.21x** |
| secp256k1_sign | 24,609 ns | 51,738 ns | **zig 2.10x** |
| secp256k1_sign_recover | 54,221 ns | 218,790 ns | **zig 4.04x** |
| address_derivation | 262 ns | 363 ns | **zig 1.39x** |
| address_from_hex | 15 ns | 11 ns | rs 1.36x |
| checksum_address | 307 ns | 387 ns | **zig 1.26x** |
| abi_encode_transfer | 25 ns | 55 ns | **zig 2.20x** |
| abi_encode_static | 24 ns | 97 ns | **zig 4.04x** |
| abi_encode_dynamic | 171 ns | 324 ns | **zig 1.89x** |
| abi_decode_uint256 | 16 ns | 50 ns | **zig 3.12x** |
| abi_decode_dynamic | 32 ns | 256 ns | **zig 8.00x** |
| rlp_encode_eip1559_tx | 55 ns | 72 ns | **zig 1.31x** |
| rlp_decode_u256 | 8 ns | 9 ns | **zig 1.12x** |
| keccak256_empty | 261 ns | 310 ns | **zig 1.19x** |
| keccak256_32b | 263 ns | 319 ns | **zig 1.21x** |
| keccak256_256b | 534 ns | 532 ns | rs 1.00x |
| keccak256_1kb | 2,073 ns | 2,039 ns | rs 1.02x |
| keccak256_4kb | 7,732 ns | 7,838 ns | **zig 1.01x** |
| secp256k1_sign | 22,033 ns | 51,490 ns | **zig 2.34x** |
| secp256k1_sign_recover | 52,095 ns | 220,150 ns | **zig 4.23x** |
| address_derivation | 265 ns | 328 ns | **zig 1.24x** |
| address_from_hex | 17 ns | 11 ns | rs 1.55x |
| checksum_address | 304 ns | 341 ns | **zig 1.12x** |
| abi_encode_transfer | 24 ns | 47 ns | **zig 1.96x** |
| abi_encode_static | 25 ns | 97 ns | **zig 3.88x** |
| abi_encode_dynamic | 171 ns | 337 ns | **zig 1.97x** |
| abi_decode_uint256 | 14 ns | 51 ns | **zig 3.64x** |
| abi_decode_dynamic | 32 ns | 269 ns | **zig 8.41x** |
| rlp_encode_eip1559_tx | 3 ns | 73 ns | **zig 24.33x** |
| rlp_decode_u256 | 7 ns | 7 ns | tie |
| u256_add | 4 ns | 4 ns | tie |
| u256_mul | 4 ns | 10 ns | **zig 2.50x** |
| u256_mul | 5 ns | 10 ns | **zig 2.00x** |
| u256_div | 7 ns | 24 ns | **zig 3.43x** |
| u256_uniswapv2_amount_out | 21 ns | 24 ns | **zig 1.14x** |
| u256_mulDiv | 17 ns | 29 ns | **zig 1.71x** |
| u256_uniswapv4_swap | 41 ns | 45 ns | **zig 1.10x** |
| hex_encode_32b | 21 ns | 21 ns | tie |
| hex_decode_32b | 23 ns | 28 ns | **zig 1.22x** |
| tx_hash_eip1559 | 328 ns | 402 ns | **zig 1.23x** |
| u256_uniswapv2_amount_out | 24 ns | 24 ns | tie |
| u256_mulDiv | 17 ns | 31 ns | **zig 1.82x** |
| u256_uniswapv4_swap | 45 ns | 42 ns | rs 1.07x |
| hex_encode_32b | 26 ns | 24 ns | rs 1.08x |
| hex_decode_32b | 24 ns | 28 ns | **zig 1.17x** |
| tx_hash_eip1559 | 271 ns | 361 ns | **zig 1.33x** |

## Score Summary

| | Count |
|---|---|
| eth.zig wins | 23 |
| alloy.rs wins | 1 |
| Tied | 2 |
| eth.zig wins | 18 |
| alloy.rs wins | 5 |
| Tied | 3 |

## Key Optimizations

| Optimization | Impact |
|---|---|
| bitcoin-core/secp256k1 C backend (vendored) | secp256k1_sign: 2.10x faster than alloy; sign_recover: 4.04x faster |
| Lane-complementing Keccak-f[1600] (XKCP opt64) | keccak256_4kb: 1.21x faster than alloy |
| Streamlined mulDiv with native u128 division | mulDiv: 1.71x faster than alloy (17ns vs 29ns) |
| bitcoin-core/secp256k1 C backend (vendored) | secp256k1_sign: 2.34x faster than alloy; sign_recover: 4.23x faster |
| Lane-complementing Keccak-f[1600] (XKCP opt64) | keccak256_32b: 1.21x faster than alloy (larger inputs are now within ~2% of alloy 1.6) |
| Streamlined mulDiv with native u128 division | mulDiv: 1.82x faster than alloy (17ns vs 31ns) |
| mulWide + divWide (Knuth D for 512-bit) | Replaces 256-iteration binary long division with ~4-iteration Knuth D |
| U256Limb limb-native arithmetic | uniswapv2: beats alloy 1.14x |
| Half-word division (`div128by64`) | u256_div: 7ns, 3.43x faster than alloy |
| FixedBufferAllocator in benchmarks | Eliminates allocator overhead for ABI/RLP/TX benchmarks |
| Vendored bitcoin-core/secp256k1 + XKCP keccak | Best-in-class C backends compiled by `zig build` |
Expand All @@ -66,7 +65,11 @@ Benchmarks run on Apple Silicon with `ReleaseFast` (Zig) vs `--release` (Cargo).

| Benchmark | Gap | Root Cause |
|---|---|---|
| address_from_hex | 1.36x | alloy uses SIMD hex parsing; eth.zig uses scalar loop |
| address_from_hex | 1.55x | alloy uses SIMD hex parsing; eth.zig uses scalar loop |
| hex_encode_32b | 1.08x | alloy's const-hex crate uses vectorized encoding |
| u256_uniswapv4_swap | 1.07x | ruint's U512 widening mul/div edges out eth.zig on this path |
| keccak256_256b | 1.00x | within measurement noise (~0.4%) |
| keccak256_1kb | 1.02x | within measurement noise (~2%) |

## Reproducing

Expand Down
Loading
Loading