Long-term L1 execution layer proposal: replace the EVM with RISC-V

Compilation is clearly beneficial for direct (CPU/GPU) execution.

For ZKP, it’s more tricky. SNARKs do not prove the program execution directly, but rather prove knowledge of the program execution trace (on some input).
Let’s assume f(x) is our program, x is some input to the program, w is the program execution trace (in some form). There is also some circuit C(x, w, y) to check the trace validity, i.e. C(x, w, f(x)) should output true for valid traces.
A SNARK prover typically proves satisfiability of such circuit (and that it knows the w witness), which is existentially quantified (due to the additional parameter w) and (in case of proving program execution) uniform (inputs/traces of different lengths are served by the same circuit).

So, it’s drastically different from the direct execution. The difference is critical for performance, as you can transform evaluation (sub)problems to circuit satisfiability (sub)problems, which might be much cheaper to prove (e.g. for proving 1 / a operation one has to provide some b and check that a * b == 1, while calculating the inverse directly will require proving much more intermediate steps).

Moreover, since the execution trace is available to prover it can select a cheaper implementation option, depending on the concrete trace content. E.g. a value can be u256 in general, but a particular occurrence can fit byte, so its properties/operations can be proved using less steps than the full u256 value.

So, the ability to inspect the trace can largely compensate absence of compilation. Static analyses/optimizations can still benefit ZKP (a call site can be recognized statically as monomorphic, so one can skip proving branch decisions). However, such optimizations are not that trivial to implement in practice:

  • one need to withstand “JIT bombs” attacks
  • one should prove somehow that such optimizations preserve semantics

With that said, I generally agree that compilation is the right direction. However, in the case of ZK proving of EVM code execution it’s not really clear whether compilation worth implementing given the associated costs. The EVM+EOF would definitely help here (e.g. static analysis, separate validation).

Compilation is of course useful in it’s own right. What I’m trying do here though is avoid the apparently high overheads of proving a program on an EVM interpreter written in RISC-V rather than proving a program written in RISV-V. Or even better, directly prove EVM programs.

2 Likes

This is the best option IMO.
It’s strange that Vitalik didn’t even consider it.

Makes sense. I take it that compiling from Rust you would see the same difficulties?

CPU-oriented code generation/optimization makes it more difficult to apply ZKP-oriented optimizations. So, with Rust → RISC-V approach to ZKP, one wants to rollback CPU-specific decisions, which can be difficult.

EVM bytecode retains more high-level info, so it’s better in that respect. EVM+EOF is even better here. YUL should be more or less the same. YUL with finer grained type info should be better.

One exception here is that RISC-V code operates with 32bit (64bit) values vs 256bit in case of EVM. So it retains stricter value bounds. It’s not a huge advantage since ZKP prover can inspec traces on the fly.

However, in case of (ZKP proving of) Rust smart-contracts one can start from IR like MLIR, or translate to LLZK.

OK. There is a trade-off - EOF’s structured functions - like Wasm’s, make linear-time interprocedural optimization difficult-to-impossible. I think the worst case is a quadratic, though one static analyst told me there are analyses that dynamic jumps render exponential or even undecidable.

1 Like

Thanks. We are getting pretty far past my understanding of ZK. But my overall take remains that RISC-V probably has some advantages, but they don’t begin to outweigh the cost of replacing the EVM (and its large and growing ecosystem) with a different one.

2 Likes

long live ethererum …

Well, we are discussing problems that users do not really have.

There is absolutely no need to “prove” blockchain using ZK. It is a solution in search of a problem.

Blockchain is proven by re-executing the same code on zillions of nodes.

Bitcoin has done it from the beginning. ZK is just inferior, slow and complex. There is no need to modify EVM to make slow and complex ZK run just a little faster.

2 Likes

Thank you for the proposal (and for the lovely talk at Protocol Berg, which made me aware of this ongoing discussion). I have a few thoughts which I wanted to share with the Ethereum community here.

Concerning the stated goal of ISA optimization

I can see that there may be a solid case for RISC-V as an ISA as compared to the EVM from the specific perspective of succinct cryptographic proving efficiency (although the term “zk-EVM” is used, as far as I can tell these constructions neither expect nor depend on an actual “zero knowledge” property, nor do they seek to provide privacy to applications – please correct me if I am wrong about this).

I am no expert in “zk”, or “succinct cryptographic proof-compatible”, virtual machine architecture, so I’ll leave those details to the folks working on such projects, but I would note that as far as I am aware all serious zkVMs in existence rely heavily on “precompiles” of their own for heavily-used primitives such as hash functions, elliptic curve cryptography, and recursive proof verification. Seriously optimizing for succinct proving speed is thus also likely to require upgrading and altering precompiles, not just switching to RISC-V. Furthermore, if part of the goal here is to “stabilize and ossify” the execution layer, there’s a straightforward theoretical argument that the goals of stability and efficiency will always be in tension: which precompiles will most improve execution efficiency depends on what code is actually run, which is simply not something that a protocol or VM designer can know in advance! If a protocol designer really wishes to harmonize the goals of stability and efficiency as best as possible, I think it would be necessary to instead design a protocol for measuring what code paths are most frequently run and periodically automatically updating the set of precompiles to optimize for those heavily-used code paths. This is far from trivial, but not impossible – one could examine, for example, how Urbit’s Nock uses jets. Still, only so much can be done in software – eventually you would need to dynamically reprogram FPGAs or even perform automatic hardware synthesis. I expect that this is beyond the scope of what the Ethereum community would want to consider right now, but I think it’s important to build a clear shared understanding of the fundamental tension and possibility space here, which is useful context to evaluate whether the time and engineering complexity costs of any particular upgrade are worth it. The idea that we could simply upgrade once to RISC-V and never need to change the execution layer again, without making substantial compromises in efficiency, is simply a fantasy.

Concerning the broader strategic context

@vbuterin – your opening post pitches a RISC-V upgrade as a “radical idea for the future of the Ethereum execution layer”. While I can agree with that from the perspective of the engineering efforts and social coordination needed to execute such an upgrade, from the strategic perspective my worry is that an upgrade to RISC-V would be nowhere near radical enough. An ISA upgrade to RISC-V is, at best, a straightforward optimization: it would make execution cheaper (and specifically cheaper to prove). As far as I can tell (admittedly from a rather ad-hoc dataset), execution costs are not the primary problem facing Ethereum users and developers right now. In fact, execution costs wouldn’t even make the top problems at all. In my experience (and recent canvassing at Protocol Berg), Ethereum users and developers are currently frustrated by (~ top five, unordered):

  • Protocol, user experience, and liquidity fragmentation across hundreds of L2s
  • Lack of native privacy on the L1, or any way to build privacy-preserving apps for the L1
  • Inconsistent commitments, direction, and progress of L1 data availability scalability w.r.t. calldata and blobs (not execution)
  • Loss of users, traders, liquidity, and general interest to other chains and ecosystems which iterate much faster than Ethereum does
  • A lack of strategic clarity on what exactly Ethereum should focus on as a product proposition (see e.g. this excellent essay)

Upgrading the execution layer to the RISC-V ISA would do absolutely nothing to address any of these frustrations and problems, and it would consume collective years of engineering and social coordination efforts which could be better spent on something else. If such bandwidth exists, why not instead consider, for example:

  • Upgrading the execution layer to support native privacy-preserving applications using a state model like that developed by Aztec, Aleo, or Anoma [disclosure: I work on Anoma]. This would open up new categories of applications that are currently impossible to build on Ethereum.
  • Upgrade the execution layer to support proper execution sharding. Near has already shipped a well-specified sharding protocol which could be adopted by Ethereum (probably including in a way that would maintain compatibility with existing EVM contracts). Anoma has also specified a sharding system which is architecturally compatible with the EVM – we have not implemented it for the EVM, but someone could, and we’d be happy to help.
  • Developing a new, “heterogeneous trust”, virtual machine which would encompass state on all (standardized) L2s, not just the L1, allow developers to write applications once and run them anywhere, and defragment the user experience. This is more of a green field research project – you can find the rough idea described here – but I don’t see any other way personally to really defragment the Ethereum experience (other than shipping execution sharding and killing all the L2s).

Perhaps these ideas are “too radical” – I’m not sure – but at least they stand a chance of actually helping Ethereum achieve the original mission. Swapping 256-bit integer operations for some RISC-V instructions does not.

3 Likes