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
2 changes: 1 addition & 1 deletion .github/workflows/test-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jobs:
env:
# The NethermindEth/nethermind commit whose native suite runs against the library. Bump it with any ABI or
# verification key change.
NETHERMIND_REVISION: 0260e692fcf8e6b8bcb41289d877e0d5e380b5cd
NETHERMIND_REVISION: 1e5d1fa8a071b0b329a243437d00026e1d4a72df
NATIVE_TEST_PROJECT: Nethermind.Crypto.LeanFfi.Test
LEANVM_NUM_THREADS: 1
steps:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Nethermind.Crypto.Lean.Tests;
public partial class NativeLibraryTests
{
private const string Library = "nethermind_lean";
private const uint ExpectedAbi = 9;
private const uint ExpectedAbi = 10;
private const string ExpectedAggregatedVk = "417152e8bd83e0dfb6f3e2bb8991e948f62c7f15d74b693b55979a40b239efa1";

// A project reference leaves the library under runtimes/<rid>/native; a package consumer gets it beside the binary.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<PropertyGroup>
<Description>Native EIP-8288 Lean backend (libnethermind_lean, ABI 9) for linux-x64 (x86-64-v3 + PCLMULQDQ) and linux-arm64 (AES/PMULL).</Description>
<Description>Native EIP-8288 Lean backend (libnethermind_lean, ABI 10) for linux-x64 (x86-64-v3 + PCLMULQDQ) and linux-arm64 (AES/PMULL).</Description>
<PackageId>Nethermind.Crypto.Lean</PackageId>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/nethermindeth/lean-bindings</PackageProjectUrl>
Expand Down
Git LFS file not shown
Git LFS file not shown
2 changes: 2 additions & 0 deletions src/ffi/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src/ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ lean_vm = { git = "https://github.com/Marchhill/leanVM", rev = "e2bc4212013087c0
lean_compiler = { git = "https://github.com/Marchhill/leanVM", rev = "e2bc4212013087c0823188e975b224ade286d878" }
primitives = { git = "https://github.com/Marchhill/leanVM", rev = "e2bc4212013087c0823188e975b224ade286d878" }
parallel = { git = "https://github.com/Marchhill/leanVM", rev = "e2bc4212013087c0823188e975b224ade286d878" }
zk_alloc = { git = "https://github.com/Marchhill/leanVM", rev = "e2bc4212013087c0823188e975b224ade286d878" }
bincode = "1.3"
tiny-keccak = { version = "2.0", features = ["keccak"] }

[target.'cfg(all(target_os = "linux", target_env = "gnu"))'.dependencies]
libc = "0.2"

[profile.release]
opt-level = 3

Expand Down
25 changes: 18 additions & 7 deletions src/ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ with an illegal instruction (SIGILL) on an older CPU: build on the oldest CPU th
set `RUSTFLAGS` to that CPU plus the carry-less multiply feature (for example
`-C target-cpu=x86-64-v3 -C target-feature=+pclmulqdq`). Proving uses leanVM's arena allocator, which recycles the prover's transient buffers
across proofs; it allows one proof per process at a time, which the backend's prover lock ensures.
No arena phase opens while a verification runs; a verification waits only for an opening in progress (including the prover's input preparation, which verifies any leanSTARK inputs), then runs
alongside the proof node on its own slab rather than for the node (1–3 s on a 12-core arm64 host, about 7 s on 2 cores).
The arena keeps its touched slabs resident between proofs. leanVM also switches glibc's heap trimming and
large-allocation mmap off process-wide when it enables the arena; at the first proof the backend restores the
operator's `GLIBC_TUNABLES`/`MALLOC_*_` values or glibc's defaults, so the host's own freed memory still returns to
the kernel. glibc's adaptive mmap threshold stays off.

`BuildLeanFfi=true` builds and copies the host native library into consumer build/publish
outputs and rejects a different target RID. Build on each target platform. The release Docker
Expand All @@ -43,12 +49,13 @@ The main solution compiles the test project without requiring Rust. Without the
the native suite is explicitly skipped. With it, the backend and fixtures are required and
missing libraries fail the run.

The C ABI is version 9, with Cdecl calls, 32-byte hashes/keys and `size_t` buffer lengths.
The C ABI is version 10, with Cdecl calls, 32-byte hashes/keys and `size_t` buffer lengths.
`nlean_limits` writes nine u32 values (proof bytes, dependencies, recursive children,
SPHINCS witness bytes, leanSTARK claims per list, instructions, operand offset, aggregation
input bytes, mixed guest proof bytes); startup checks these against the managed protocol
bounds before accepting work.
Verification/proving return 1 on success, 0 on failure and -1 for a contained panic. Callers initialize proof output
Verification/proving return 1 on success, 0 on failure and -1 for a contained panic. After -1, `nlean_last_error(out, len)` on the same
thread copies up to `len` bytes of the panic message and returns its full length. Callers initialize proof output
pointers to null; successful proof allocations must be released once with `nlean_free`
using the returned pointer and length. Verification contains upstream panics and never
accepts malformed inputs. Panic diagnostics on ABI callers and the pinned parallel worker
Expand Down Expand Up @@ -137,7 +144,7 @@ EIP, with the pinned guest's generic leanVM CPU proof as its leanSTARK profile:
statement over it to the prover, a received mode-1 wrapper over it is invalid and an
inclusion-list proof over it imposes no obligation, both without penalty or verification.

Startup checks ABI 9, the pinned key and the nine bounds together. New devnets require fresh
Startup checks ABI 10, the pinned key and the nine bounds together. New devnets require fresh
chain and database namespaces.

The latest companion specification has no block dependency quota: blocks are bounded by gas, mode-0 wrappers by `MAX_LEANSIG_DEPS_PER_WRAPPER`, `MAX_LEANSTARK_DEPS_PER_WRAPPER` and `MAX_WRAPPER_BYTES`, and mode-1 wrappers by `MAX_WRAPPER_BYTES` and the dependency-list limit of the circuit behind `AGGREGATED_VK`, which EIP-8288 fixes from benchmarks before activation. This prototype guest's limit is 256 dependencies, at most 16 of them leanSTARK; a received mode-1 wrapper over it is invalid and discarded before verification, without penalizing its sender. Blocks have no such limit in the draft, so this key cannot prove every block the draft permits and this prototype is not full-capacity conformance. Raising the bound changes the guest and so `AGGREGATED_VK`. Local inability to prove or retain a set is not an inclusion-list omission excuse. Full activation requires a verifier and proof format supporting every set the fork's gas rules permit, with the complete construction, including recursive merges and discards, benchmarked against the slot deadline.
Expand Down Expand Up @@ -183,9 +190,11 @@ with `UnsupportedFork` rather than losing their proofs.

Enable EIP-8141 and EIP-8288 in a development chainspec with `eip8288TransitionTimestamp`,
or the geth genesis key `eip8288PrototypeTime`. The named `Eip8288Prototype` / `eip8288PrototypeTime` also enables master's EIP-8250 keyed
nonces, EIP-8272 recent roots and EIP-7906 POST_TX frames. Frame transactions use explicit
`nonce_keys`; `[0]` retains account-nonce behavior. Individual chainspec transition fields
remain independently configurable. Recent roots follow master's older envelope-reference /
nonces and EIP-7906 POST_TX frames. It does not enable slot numbers or EIP-8272 recent roots: EIP-8272 requires
EIP-7843, so schedule it with `eip8272PrototypeTime` or `eip8272TransitionTimestamp` at or after EIP-7843 (for example
Amsterdam's `amsterdamTime`); loading refuses an EIP-8272 activation without or before EIP-7843, and an EIP-7843 later
than EIP-8288. Frame transactions use explicit `nonce_keys`; `[0]` retains account-nonce behavior. Other chainspec
transition fields remain independently configurable. Recent roots follow master's older envelope-reference /
`RECENTROOTREFLOAD` draft, with existing commitment and slot-age checks; the newer EIP-8272
canonical VERIFY contract remains TBD and is not implemented here.

Expand Down Expand Up @@ -324,7 +333,9 @@ circuit's dependency-list limit (the guest's 256 dependencies), and a bucket als
proving cost equal to folding 16 fresh signatures: already proven aggregates merge whole and may
carry many more dependencies. Mode-0 witnesses fold directly into the aggregate, and a set a held
proof already proves is not proven again; for partial coverage held proofs are merged and only
missing dependencies added, discarding those outside the retained transactions. A set an announced
missing dependencies added, discarding those outside the retained transactions. A dependency without a
held direct witness takes the held recursive proof covering the most still-needed dependencies, as each
recursive input costs about one recursive verification whatever its size. A set an announced
mode-1 wrapper claims (by its `deps-hash`) is left for up to two intervals while that wrapper is
fetched, then proven locally. Completed selections are checked against current pool membership
before publication. `eth_getProofWrapper` returns a copy without invoking the prover.
Expand Down
4 changes: 2 additions & 2 deletions src/ffi/examples/lean_startup_stub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
#[unsafe(no_mangle)]
pub extern "C" fn nlean_abi_version() -> u32 {
if std::env::var("NETHERMIND_LEAN_STARTUP_PROBE").as_deref() == Ok("abi") {
8
} else {
9
} else {
10
}
}

Expand Down
Loading
Loading