L1 zkEVM Breakout #9
L1 zkEVM Breakout · 14 Oct 2026 · 1:30:56
L1 zkEVM Breakout #9, held on 14 October 2026. These breakout calls cover how Ethereum's own execution layer could be proven with zero-knowledge proofs, including the standards and infrastructure that involves. A zkVM test release based on the official Sepolia tests was published, and an R2 bucket went live for Sepolia stateless inputs covering more than 50,000 blocks.
Speakers
Topics
From L1 zkEVM Breakout, hosted by Ethereum Foundation.
Transcript
Maxim Menshikov: Hi.
Ignacio Hagiopan: Hello, everyone.
Maxim Menshikov: Hi.
Ignacio Hagiopan: Let's wait for one or two more minutes for people… Let's wait for one or two minutes for people to join. I will… I'm coming from another call, so I have to prepare a bit the slides, so… Hold for a second.
Okay, so I think we can start. Let me share my screen for a second. Too many things open here. Okay. Can you see my screen?
Maxim Menshikov: Yeah.
Ignacio Hagiopan: Cool. Okay, welcome everyone, this is L1 zkEVM breakout call number 9. We will be sharing some updates. From the last, since the last call. So the agenda today is, we have some highlights on some topics that are quite important that will happen in the next days. We'll have some project updates, a bit partial, because, Cody and Han are out of office, so they might fold their updates in the next call. We will have some updates from the Zilkworm team. And we will have some updates from CL clients, and some plans that we have for Sepolia. So, one of the main highlights for you to be aware is, that in the next ACDC call, which is tomorrow, there are, like, high chances that we will
potentially decide on CFI EIP-8025 in Hegota. So it will be really useful if you have some strong opinions on doing this, to join our call and support our proposal to see if I need. We will make some, small presentation, maybe a… One, two, or three slides to highlight the main reasons why we want to do this, so that people really understand our argument. But at the end of the day it's up to the EL and potential EL clients to speak up and And… decide this. As another highlight update, I updated the EIP-8025 with the latest progress and arguments. I'm not sure how many people are really reading these things, because people are usually too busy on working on stuff, but I think it's…
Pretty important to have this kind of information in written form, so… There are… They have, like, the factual information about progress and… And similar, and not thinking that we are simply proposing some EIP that was, like, one-shotted in the last week, or something like that. I think the EIP-8025 effort has been… ongoing for, like, a pretty long time already. I'm pretty mature with a lot of releases, a lot of refinements. And I think the readiness is, like, probably our strongest argument to to highlight in the… in ACDC tomorrow. So yeah, if you're interested, or simply are working in EIP-8025, and you just want to have, like, a single document with a lot of links, and
Things that are going on, probably these are the best, Places. The best documents to use. As another, thing to highlight is that in the last ACDE call, EIP7709 was CFI. This is really nice for… Our interests, because it simplifies the stateless inputs for the guest program. Hasotldr. Today, the execution witness in the execution specs Has these headers filled? Which is a chain of… Up to 256 HeaderBlocks That we need to prove that potential block hash of code executions within the block use the correct data.
And what EIP-7709 is trying to do is to say, okay, now BlockHash, needs to use, EIP2935 system contract. To really access the hashes. So basically, this means that this execution witness container can really remove these headers, and this information is indirectly in this state field, right? Because BlockHash will be simply accessing the state tree. And this is indirectly captured by state. So we can remove this, this simplifies the execution with next generation, this simplifies A lot of test cases that we have today, the 8025. regarding, like. Receiving an invalid list of headers with a gap in the middle, with the chain. the… the… the… Parent. Hash, not really matching the… Correctly, and a lot of things that can go wrong.
So yeah, this will simplify this field, and hopefully in the future, whenever PVT comes, and bytecode is chunkified, this code still will also go away. Because code will be part of the state. And the execution with this would be mainly. just… state, like, tree nodes. So that's kind of the long-term direction that we are going, and 7709 is just a step in that direction, where it's taking care of this Headers field. So, CFI doesn't mean SFI, it just means that it's considered, but it's a really nice step forward. Okay, I will go through some updates, general updates. As I said, Cody and Han are not really here. But yeah, I will try to cover a bit of a lot of things, and for the EL part, I think Tao is in the call, and he will cover that part.
On the specs and tests, we have these tests, ZKVM release, version 21, which is basically based on the Sepolia official tests. And on top of that, we already simplified a couple things, like remove public keys field from stateless inputs, because apparently this is not really relevant anymore for Performance implications, and this simplifies also, like, execution with stateless input creation and verification. And cross-checking that the public case hints is really coherent with the transaction signatures and a lot of stuff, so this was a nice simplification. I've been working a lot of refactoring the branch in the execution specs. So, upstreaming this work is as easy as possible. This was more like to justify more 8025 in CFI.
Here on the right, I built a table where I showed that EIP-8025 actually might seem a big PR, it's like a 17,000 lines of code in total. But I want you to de-aggregate where these lines were coming from, and mostly to highlight that only 56 lines are actually in the STF spec of the branch, which is the most sensitive part that I think our developers care about. EIP-8025 is not really changing much of the STF, as one would expect. And a lot of these lines are basically comments and things like that, to be honest. Not really, like, a relevant change. Most of the lines are on the testing framework changes, because we have to add this new safely input bytes field and output fields.
We have a lot of new tests. For EIP-8025, so this is just, like, new tests for the EIP. And we have some other, like, yeah, more testing framework changes, like CI workflows, or filling benchmarks for CTEVM and things like that, so… Most of these 17K lines are really, like, high-risk changes for execution specs. regarding the STF. Which I think is the the most sensitive part. So that's kind of the I think I want you to highlight with this table, that is part of the… of the 8025 PR that is a draft in the repo. Yeah, we did a couple of other changes, like adding more tests and things like that. And now the Hive consumer also supports the REST and SSZ.
variant of the Engine API, So, this is pretty nice, because we can already start testing. Engine API running of tests using REST SSZ instead of JSON RPC. We made another release for test ZKVM benchmarks, based on the same branch. I'm now targeting these gas limits, which is pretty nice, because this is, like, an official release. Some people can run it through benchmark, their guest programs, and… And similar, it will be useful for us, too, whenever we start running these things in the EF proving cluster to make real proofs. And I'm coming soon, I will be rebasing, on the latest release of tests, which is… has some extra coverage for for Glamsterdam stuff. Plus, in the last two days, we have merged, like, 13 PRs.
With even more test coverage. I want to thank Gabriel and Omer for this. A couple of these PRs were coming from them. And this is really nice because, yeah, A lot of these PRs are, were created because of real bugs being found in In… in real guest programs, so this is looking really nice. As usual, we now have a new R2 bucket for, stateless inputs for real chains. Up to now, we only run this for, DevNets, but now that Sepolia has switched to… have activated Glamsterdam, we have this R2 bucket for Sepolia. It's already quite big. It has more than 50k blocks that you can run. To replay guest programs on Sepolia. Actually, this was the main source from which, I think, yeah.
CVM and CESU have found bugs and I think Nethermind too. Which motivated us creating more tests to avoid regressions. So, this is something that is live, and you can plug into your CI as you did before with previous testnets. Probably this R2 bucket will be long-lived. Right? Because the testnet is, like, a long-lived chain compared to previous devnets, which are shut down after a while. So this will continue to run, and eventually when Hoodi activates Glamsterdam, we will have our R2 bucket for Hoodi, and yeah, eventually when Glamsterdam gets activated on Mainnet, we will have the Mainnet R2 bucket. And the three of them will be long. Living, so we will have more and more and more,
I like bigger data sets for these problems to run. And we have also intentions to potentially backfill mainnets. For pre-Glamsterdam forks, this might require some changes in an EL to really be able to generate the execution witness. because many of the ELs kind of assume that BALs exists for… for it, so… I know, but this is more like a long-term intention, so we have, like, a… growing data set of of logs to to use as tests. We have also the updated EEST dashboard, which tests the compliance of stateful ELs on execution witness construction. Which is this, group here. And the guest programs, combined with supported ZKVMs, here in the bottom group.
So this is going pretty well. I mean, there are some tests that are failing, but we haven't really dived into them. This is more like keeping up to date the dashboard with the latest release. And here's the link if you want to look it for yourself. On the execution API side of the spec, there are two main things I wanted to highlight. The first one is the EIP, where We define the rest version. of, engine, new payload with Witness. Nimbus already implemented this and merged it, has merged it. So this is why, in this dashboard, you see Nimbus here as a box with REST SSZ, and also see it as Nimbus with the usual JSON RPC.
This is… we can do this, like, both fronts, in both modes, because, yeah. As I mentioned here, we… the Hive Consumer now supports running both styles. Umm. But I know that all our ELs have, yeah, draft PRs to support this, and as soon as they get merged, they will appear in the dashboard automatically. So that will be nice, to test that everything is working fine regarding execution with this generation in the new Engine API variant. iridum: And I created recently this other EIP on top of this one. For the block building side. This is, like, the same idea of, get payload, but with witness, such that we can avoid, like, the re-execution of the block to…
to generate it. This is not, like, strictly needed for EIP-8025. This is more, like, on the long-term arc of mandatory proofs. But it's just nice to have it, there, so we have, like, a complete picture of, how block building would work, for proving. Yeah, and if you are on EL, and you think at least this, new payload with Witness API for REST and SSZ makes sense, please, put some thumbs up to the PR. This is quite important for the maintainers of the report to consider it. being merged. I'm waiting for some extra ELs to actually implement it, and I think with that, we will be fine to… to get this… this… this one merged. On the zkVM standards, I actually created this slide, but yesterday I got a message from Cody that he prepared a video with his updates, so I will, instead of explaining this myself.
I will, switch to the video. Hopefully, you will hear the audio. If that's not the case, please… Someone speak, so yeah, I will play it here.
Audio shared by ignacio: Okay, so here are my updates given asynchronously. Here's a link to the slides. There's a QR for the… For the slides, if anyone wants to follow along. Here, first we have additional testing, so we've had testing of RISC-V compliance for a while. at this link zkEVM test monitor That repo, and then a live monitor is at this link. So what I've done is to add additional coverage for more of the standards, not just the ISA standard. And I've started with the accelerators. We have many accelerators covered by one standard, memory acceleration covered by another, and then an IO standard. And so I've added… Testing of those, using the… Act 4, ACT 4… framework from the RISC-V community for running these tests. They've recently added support for writing the test with C, so that's how you do it. You, you make a little C program.
I've also… there are a lot of generated tests, they're not all handwritten with C. We've generated tests from Geth and from the execution specs to not just cover the existence of the interface, but also to check whether the accelerators are implemented correctly. We propose that this become the norm. So when you propose a new standard you write a set of tests. At the very least, as the standard is progressing, Umm. And by the time it's accepted, we should have some tests written, and we should be able to check whether it's been… Implemented correctly. You can see here we have good progress, but definitely a lot of compliance gaps, and we encourage the teams we've tested here to have a look at those and fill them in.
Next up… We have Lukasz from Nethermind described an attack. That could happen now, where… You find… A collision in the internal hash map used by a guest program. And, Because these are not seeded on a per process basis, you could attack all provers for a given ZK EVM. At once. And so I've… there's a discussion here, if you're interested in a bit in the background. There's a standard here that I've put together to make a formal what Lukas proposed. To provide a facility on the host to, to allow the guest program to sample some randomness with a fresh seed. Eddie's execution. You don't have to prove anything about this randomness, I just need to start with a random value there.
And I also have some accompanying tests. Here, following what I proposed on the previous slide. And I've also put together a demo implementation for OpenVM here, if anyone wants to take a look. It'd be great if somebody could share a link to these slides in the, In the chat, since I'm not present. So people could easily access this stuff. Next up, we have more compliance, verification for Zisk, so I've been working on this for a while, and recently I've been hardening it, so I did some stress testing to see if the lean build would fail If you change some constraints, in many cases it does. In some cases, all of which were known, there are GitHub issues, but there were some missing links.
Which we refer to as welds in the context of this work. And, so, yeah, I removed some assumptions. that were inputs to the main soundness theorem and also tied together some of these. Missing links. Provided those missing links. And I also had a handoff meeting with Zisk to talk about the long-term future of this work as part of a broader formal verification initiative. that they're undertaking. So I'm not ready to say that this is… Rock solid verification, but I think it's pretty good, and there are many issues. recording gaps so we have a clear path to something we could really endorse as being a very reliable guarantee for Zisk For speaking here, not of the… Umm.
you know, recursion layers and so on, just the RISC-V circuits. And finally, SoundCalc… Haven't talked about that in a while, but that's something the cryptography team uses to calculate the… the number of bits of security that the zkVMs provide We had STIR support land since my last update, and we also have progress on the Lean version of this from Symbolic Software for anyone who wants to take a look. So that's all for me, and thank you very much.
Ignacio Hagiopan: Okay, that were the updates from Cody. Thanks, Cody, for this. I know he's not in the call, but anyway. I will share the links to his slides in the chat soon, and also the links to the… to my slides, which have some extra links here, so I will skip this slide, but I'm kind of repeating here what he said. Moving forward on the proving infrastructure, this is some, updates, most… mostly from Hans' work, which is out of office. He has been doing a lot of work in ere and Prover. Prover is, for people that maybe haven't heard before, is. Terraform extension to BenchmarkCore, which is a… use prove… used, benchmark infrastructure, that we use today for Ethereum. It was mainly used for Glamsterdam.
Repricing, some benchmarking, the idea here is that Extending BenchmarkCore to also allow to generate proofs. improving clusters, which are pretty complex, like, say that you have, like, 4 machines, each of them with GPUs. That… or the orchestration is much more complex than simply having a single machine. So Prover is trying to abstract that, so you can have an easy way to create proofs in proving clusters. He has been working also in adding, profiling support in ere. And this is really nice, because it would mean that the prover front end, will have Also, information about where the cost of proving is going. So, guest programs will have a more clear view of Where, maybe… Worth put the effort optimizing their code.
It will also have peak memory usage for each benchmark case. This will be pretty important to be sure that the guest program is not using too much memory, because zkVMs have a limited cap on how much memory can be used before running out of memory and crashing. And the main goal here is to have a single dashboard, that would show proving time. Proving costs, and some more detailed de-aggregation of where the proving cost is coming from, from the guest program. So we can have in a single place everything to, to, to help, both zkVMs and guest programs on. On… on benchmarking stuff. We will also be running, so you can run this in emulation mode. I have the proving cost estimation, but we are also planning to run the benchmarks on the real EF proving cluster with 16 GPUs.
So we get the actual, like, real proof proving time, numbers. Just in case the cost estimation diverges too much from the real proving cost. So yeah, all this front end is faking. We have some previews from hand, but I would prefer him to show them in the next call. The UI is… Pretty cool and awesome. I'm very excited about this. Being like… So, I will stop here, I don't know if there's any question, and if not, I think we can continue with Tom.
Francesco Risitano: I'll just share my screen. Okay, yeah, keep this quite concise, and then, you know, hand over and give an opportunity for, CL teams to give updates if they're here. But there's. Two main developments and then one future plan. So, in terms of developments on the consensus-spec side of things, we've essentially tried to be as kind of reductionist and minimal as possible. Which has meant that we've been able to purge a lot of the code in the consensus specs, primarily over to PRs, the first of which was, The way in which we kind of structured, the proof data type. And the gossip validation, so the gossip handler. There was actually an iteration in the framework for gossip handlers in the consensus specs, which allowed you to define the handler as, code, whereas previously it was just, prose, following some, you know, kind of human language.
standards, let's say. So that was the, the initial refactor, and then the second one, which is arguably more significant in terms of logical complexity, was reducing the. reducing the scope of the proof engine. So previously, the proof engine was responsible for, obviously verifying proofs, but also requesting the generation of proofs, and then, fetching those requests. So, now we've reduced the scope of the proof engine to be exclusively, proof verification. Client teams have, kind of optionality in regards to how they want to implement this. Ultimately, the proof engine is defined as, like an abstract interface, so, you know, one option is to take the, to take the proof, verifiers and embed those directly into the client.
Alternatively, you can have, like, an external sidecar, which you kind of invoke and engage with over HTTP, so… You know, that's essentially, unspecified in the specs, and, client teams are more than welcome to kind of choose whichever Pattern they believe is most, most reasonable for their their architectures and design. The second EIP that we've created, and this is in, this is a very initial draft, so, it's just surfacing the idea. I… we need to get review, even internally, from the team. I believe Ignacio's, taking a look at this, but, you know, there's a lot going on, so… and this is more of a future ambition and vision, as opposed to something that we expect to ship, you know, in the near term.
But the core idea, essentially, is to, Extend the scope of a single proof to be able to attest to the validity of some chain subset. So, just to give some context of why we would want this, when you join a chain. Essentially, you need to verify that payloads are valid from the weak subjectivity checkpoint until the head, that you're targeting. Traditionally, you know, using re-execution, this is done by fetching every payload, re-executing, and you just do that sequentially. the execution proofs it kind of… analogous construction would be to fetch, proofs for each payload, and then verify the proofs. But proofs are kind of large, you know, they're on the order of 300 megabyte, kilobytes, let's say, and, you know, we currently have this rule of K of N, so 2 or 3, or there's some, you know, threshold-based, validity condition, so…
Ultimately, this, kind of bloats the, the bandwidth requirements, and, you know, in an ideal construction, we can reduce that. And, you know, with recursive proofs, we can. So the idea is that The… the… the… each proof will take as input, one new payload which extends the head of the chain. And in addition to that, the ancestor proof, so the parent proof, which, you know, subsequently proofs the, the parent. And, you know, it's just a recursive chain all the way back to the origin. So, for this to be, safe, the origin would need to extend, to prior Or before the… at or before the weak subjectivity checkpoint when you're joining a chain, but… There are some, you know, some question marks here around, kind of, completeness. What happens if a proof is not… if a proof system is not complete, so a proof cannot be generated?
Et cetera, et cetera. So there's still some, you know, some kind of edge cases that we need to, we need to iron out, but, ultimately, if we are able to build a construction that we're, we're confident in, then. ultimately, this would result in the ability to sync, from the weak subjectivity checkpoint to the head in, using a single proof or, you know, K of N proofs, so you reduce the. The bandwidth requirements and the execution requirements, you know, by… orders of magnitude. So, it's an interesting idea, and I encourage people to, you know, to review to review the, the EIP and give some feedback. And then, just in terms of our future ambitions, we've had some progress from… on, kind of support and rebasing of, EIP-8025 on the Gloas specs. We're now in a position to.
kind of deploy onto Sepolia and run some test networks. So, at the EF, we're hoping… we're intending to deploy a prover on Sepolia, and we're inviting client teams to join the network and, you know. Essentially test out this feature on the test network. And, that's all from me. But I want to hand over. Let me just check the. Okay. Manu is here, so maybe I can hand over to Manu if you're willing to give a status update on the progress of the, of EIP-8025 implementation in Prysm.
Emmanuel Nalepa: Hi. So, yes, At Prysm, we implemented, so this EIP as a proof of concept. I just passed the link of the request in the chat. Yeah, basically, so it works well on, on kurtosis, running only Prysm, prover node and Prysm verification node. As Francesco said, regarding how we do choose to verify the proofs, so here we choose to implement a LIP based on array, which I called go-ere, which is directly imported, included in the PrysmBeaconNode binary. So it's just a function call to verify the proof, so no need to call another sidecar. Right now, I'm running a node on Sepolia, a verifier node on Sepolia.
We… I'm able to briefly, very briefly, appear with the lighthouse peers, which normally, send proofs. However, there is an incompatibility issue here. I have to see why with Lighthouse. I just know that Lighthouse sends us proofs of type 0. And it turns out proofs of type 0 are not defined. And so we check the message and eventually we disconnect the peer. That's our most… All I had to say. Let's continue to see how does it work. On, Sepolia. And yes, let's continue to work on this. Thank you.
Francesco Risitano: Awesome. Awesome. Thank you, Manu. I wonder if Lighthouse is here on the call. Don't believe so. I'm So, so, so maybe I can just, kind of raise a few. Sorry, is somebody here? Okay, so maybe I can just raise a few points, on the… on the next, on the next step. So, there's… there's a few open questions that we have to, we have to resolve. One of which is around the Beacon API, so the integration with Dora. the DORA Explorer, so DORA has a feature to display execution proofs, and, the PandaOps team have informed me that, they… there's some optimization and… on their side in regards to indexing and query patterns. But… It's our responsibility to decide on the Beacon API format.
So currently, I believe, most clients have only implemented the method for proofs to be submitted to the Beacon node. But to support the Explorer use case. We'll also need a method to fetch. from the… from the Beacon node. Now, this is somewhat You know, in contrast to the design that we've made, because we've said that ultimately there's no, there's no storage, requirements. On the… on the Beacon node in regards to execution proofs in the… in the fork that I implemented, I was serving, execution proofs from the gossip cache. Whether that's a reasonable design or not, I'm not sure. But that's, you know, ultimately a client detail that needs to be designed. But something that we need to kind of collaborate on is ultimately the.
the the Api. And secondly is around the, the container types for SSZ. So I, I, did actually bump some of the contain… well, I opened some PRs in the consensus specs to change some of the… well, one of the container types around the new payload request. And the, maybe we, we, we, we… we basically just need a bit more discussion to determine if that's reasonable or not. So, so that's one open question. But in any case, I'm in the pro… in the process of, integrating, Prysm. Lighthouse and our fork of Lighthouse on a local dev net, just to, kind of iron out any. Incompatibilities, let's say, and then the next stage will obviously be the deployment to, to Sepolia.
And we'll have some proofs there. And when we do that, we'll, you know, we'll be generating some proofs, and at this point in time, we haven't decided which guest programs we'll be using, etc, and which proofs we'll be using, so… Once again, maybe that can be a collaborative effort. I'll, I'll invite everybody to kind of contribute to the discussion on Discord. Maybe we can do some sort of pattern where we Rotate the proof stack and rotate the guest program so that we get good coverage of you know a number of guests and provers, and that that helps the the proving effort. So yeah, sorry, I know I spoke a lot, but that's all from me.
Ignacio Hagiopan: Yeah, amazing. Thanks, Francesco and Manu for the updates. I think… I agree with all these steps. So, we de-risk, as much as possible, testing things out before we go, kind of, live into proving SepoliaBlocks I think it would be awesome to really find, like, the unknown unknowns from our proving stack, and how everything fits together. So I think this would be pretty awesome. So yeah, thanks for the effort. Maybe Francesco, if you can share your slides. Link in the chat later? That would be nice.
Francesco Risitano: Yep.
Ignacio Hagiopan: Cool. Okay, so the… We go out of order in agenda, but I'm sorry, Sam. We have the… Our last point in agenda is on giving us an update on some work that Zilkworm has been doing on their guest client, and some experimentations. So, whatever you're ready, Son, feel free to start. Okay. I can't see…
Somnath Banerjee: I hope. I'm audible. Right, so I'm going to pass it over to… Tullio to start talking about the ere work. And then, to Pawel, and eventually I'll talk about Some of the tunings in Zilkworm itself, at the end. So over to you, Tullio.
Tullio Canepa: Thank you. Hi, guys. So, first of all, a quick update on Zilkworm in the ere benchmark. We first integrated Zilkworm into the benchmark in June, using the legacy fixture format. And our guest was downloaded from our own, release. And on the Osaka benchmark set. We needed roughly half, half. Recycle? Then in… later in July, the benchmark moved to The canonical EEST fixture only. And so our integration was removed, and the way back in was through the ere guests. And that's what we've done now. You can go to the next slide, please. And, Now we have two draft PRs. one registering our Alpha 4 release.
into ere guests, and another one re-adding the Zilkworm client to the benchmark. the relevant difference from the other guests, is that ours Our guest still reads our own input format, which is called MFBD, and I think some later will Talk about it. So, as a temporary… so… We have a temporary off-size adapter, which translates each fixture. In terms of result, we passed the whole Test zkEVM suite, except two fixtures. In the same family where Reth also has a couple of known failures. And we… we match every Sepolia block. And in terms of cost, we are about half of Reth's estimated proving cost, and cheaper on every block.
And also, our CI release pipeline, rechecks All this on every release. So, in terms of future plans. In… in the next release. Next slide, please. In the next release, which is going to be Alpha 5. Our guest will be able to read the canonical stateless input bytes. format, natively. And so the… The adapter goes away, the… the two PRs will… Come out of draft, and… and also Zilkworm. Plugs in like every other guest. And we also plan to To fix the two failing. Tests. And then, yeah, of course, more bug fixing, and… Even more performance improvement.
Yeah. And… So that's about it for the ere benchmark. I will hand over to Pawel.
Paweł Bylica: Yeah, hello everyone. So, on my side, I wanted to, give some overview of the performance gains we reached with, Zilkworm. Between, last two releases? And there's mostly, like, some… fun example of what this RISC-V target is for, like, for the software we try to run on. But overall, between Alpha 2 and Alpha 4. We got, like, we cut a third of the… of the executed cycles. And this is also with the fact that Alpha 4 is actually doing more work. There's more pre-validation enabled there, because we've been updating the… The implementation to match the current spec even more. And, yeah, so, this is, like, basic overview, and we used…
Mostly SP1 Hypercube, as the, VM. It is… It is basically nice, because, It gives you the direct information about estimated proving costs and execution cycles. And that has been enabled on CI, so we use the… collect this information. Okay, next slide, please. So, one of the aspects of the implementation was the realization that, compilers are not really very clever about handling this specific target, and the main issue is that the zkEVM Instruction set doesn't allow unaligned memory access. Compilers will mostly yeah, obey… obey this… this requirement. Not all the cases, sometimes it can happen, you can enable some… some options that will actually
Yeah, generate some unaligned accesses, and the execution will fail. But in the end, we ended up with, with… with shipping our own version of Memcopy, the instruction that copies bytes, and also our own copy of Memmove. Which is kind of similar, but has different requirements on the inputs. That gave us a lot of performance from there, and similarly, you can go into. Some specific implementation paths. Like, for example, the Keccak function, which also I don't mean the kernel of the Keccak function, I mean the… The part which loads bytes from somewhere to the… to the internal state, and then… hashes this. So that's also, like, this is a big improvement that we got here. It's over 10% on overall execution cycles.
Next slide. Second interesting part is… is the byte swap. So EVM, as you know, is big endian, and it's heavily… By swapping different, different, different bytes internally. to accommodate… little-endian architecture, which is common everywhere. Including RISC-V. I am. This is not so much visible on native architectures when there is dedicated byte swap instruction, usually. Or some, better emulations. However, for the instructions that we have, this is quite a big deal. this… and in the toolchain we use, which is GCC for now. This, this is emulated by… A dedicated procedure that compiler will call to on every byte swap-like Code pattern?
And the amount of this time spending in this procedure exceeded the actual EVM execution. It was, like, the top hot function, and… So we did some tricks to work around it, but the workaround is not fully complete. I think we're still using a lot of performance on this part. But what we did is we forced the compiler to at least inline. The, the procedure and. honorable mentions, I think Zisk added, the extension to, to instruction set to actually enable the, the byte swap instruction. Next one, please. And, third… third topic I wanted to briefly discuss is JUMPDEST analysis, the famous kind of EVM design flow that we need to Linear procedure, process the code before we can execute it.
So we cannot avoid it, and it's pretty bad on the stateless execution. Because caching doesn't work, so you need to prove. That the JUMPDEST analysis has been done, so we basically need to execute it. And We notice it's… that, the JUMPDEST analysis takes… Around 11% of all execution cycles. That includes pre-validation and post-validation. If you consider EVM itself, it's it's up to 30%. So up to 30%, your like bytecode execution is actually wasted of JUMPDEST analysis. We've been able to fine-tune the implementation, but There's not so much we can do. In this three arms, because there's no any vector instructions available.
I think I'm aware, if I'm aware correctly, the zisk… Add some precompile that probably does this outside of the instruction set. Okay, and next slide. And finally, we did some experiments with, compiler options, and… but basically, the learnings from here are that. The code size, at least in SP1, is basically free, so you can… Just create more code, and inline more stuff, unroll more stuff, and you will get better performance out of this. I also mentioned here some, like, dead ends that we tried, but actually were very unbeneficial, and Considering the number of options you can select from, this is pretty good work, probably, for experimentation.
Yeah, but you can… you can gain some… some performance by changing the way you build your software. And I wanted to mention that some are kind of. external initiatives here. One is LLVM Like, scheduling and tuning designed for similar use case. Where you specify that. you're going to execute your RISC-V code in interpreter-like VM, so it changes the trade-offs it makes. during, compilation. Yeah, so that's all from my side. I'm not sure we have… we have time for questions now, or we can leave it until the end. But yeah.
Somnath Banerjee: Thanks, Paweł. I'll take it from here. So, I'm going to go over a few things. Not everything is ready and published, but… Most of the things are, I'm going to start with, z6m node, which is, A version of Zilkworm execution client which partially executes lock. And we've been able to achieve, 300 millisecond Payload to witness timing, that includes all the indexing, All the disk reads and everything, so it gives us an overall 2.2 seconds block timestamp to Witness generation, on average. when this comes out, it'll, probably solve this, problem that we have had, we've been having with EL clients that usually takes, somewhere around 5, 6, even more, maybe 9 seconds to eventually get to the witness before the provers actually start proving the block.
It varies, and also there are cases in which, you are relying on the VM part of another client. This one would be re-executing Zilkworm in Native, and then passing over the witness back. So there is just one proving pipeline going smoothly and all you need is your consensus client. It would also include an Erigon integration for the transaction pool blobs. There are, like, some architectural things that we have to do, and overall, it's currently grossing at a terabyte of Storage that includes every possible optimization applied to. Make it fetch records faster. This in no way is optimized for disk, but only for Witness generation.
And, you know, there are, there's some breakdown of the numbers and, some recent. Catching up numbers from today morning that I was doing. More importantly, witness delivery is something to be solved, and it can be argued whether or not you need the full suite of EL if all you need EL is for generating the witnesses as a proofs. And on the other side, when this zkEVM thing becomes alive. You only need the proofs for. the re-execution. These are some numbers from the latest, releases. These are Possible to execute, but we're not running provers right now. Notable mention, we've been able to get the Airbender V3 after their release of zkSync OS.
We've been able to rebase Zilkworm with Airbender V3, which is Already, quite fast, thanks to their team and coordination. And, almost around 3.8 seconds with two 5090s. This is, currently live, I… Sort of. Made a quick and dirty, API registration today afternoon, just for, you know, people to go check out the numbers, and it's not a fad. It's slightly trailing, probably, behind zkSync OS, maybe 20%-ish. I'm sure this can be improved. But Zisk integration is another thing that is going to come in soon, and we have seen Not so good numbers, probably because we have not been able to optimize it. SP1 Currently also continues to be in the neighborhood of.
35 seconds with a single GPU. That is on Alpha 4. And this unfortunately includes the recent optimizations as well. To, to Alpha, to Alpha 4. So that sort of puts us with 2 GPUs at the 3rd place, On the currently grossing ethproofs provers, but that is, that is a game that, keeps changing. One important announcement again, like from source available to fully open SDLC pipeline. Zilkworm is now fully open source. Since about 2 weeks or 3 weeks ago. And, all of the pipelines, CIs, releases… Pull requests, reviews, comments are every… are all public now, and it's for everyone to
contribute to, and maybe we can gain more insights from ideas from different places. have The flat witness MFBD format that was mentioned before. I did publish a blog article, 2, actually, one about the design thinking. And the other one about the actual. format. So basically, the idea is that you have your witness bytes. When you try to serialize it in any form, SSZ, RLP, whatever. The decode actually takes quite a lot and there is also cost for memory allocation. Currently SP1 and most other VMs allow you to write to the memory, even the memory that the input bytes are. Passed on to from. So what you take is, just your bundle bytes. I'm calling it bundle bytes as
They bundle in, the whole witness in a slightly indexed mapped format that I'm going to talk about. You just reinterpret, cast them from C++ into pointers to objects. These objects are basically flat objects, and you just directly execute, With this, data. without having to, again, allocate, decode all of those. So, most of your memory-related operations coming from Witness or bundle is, just gone. small Walk through about what kind of hashing we're doing, so basically it's a simple mixer. We have got, like, around 25 instructions or so that compiles to. It is A couple of shifts and XORs and a multiply. And the basic idea is that When you have keys, you sort of put them into some buckets.
Over a loop, you calculate some displacement, Over those buckets and eventually place them. To certain, slots. This is an idea for a minimally perfect hash function. You can go check out the blog article about. What that is, but we're not exactly doing 100% minimal. We are actually assuming that there is going to be collisions. After the lookup is done, when you have found everything and your slot matches, what you basically do is, look at a collision sidebar as well. Which is, like, if your hash function was To miss some slot or, you know, collide with something else, then you can just consult an array. Where you would have all of your index indices mentioned as 0.
Basically, when you have a key, where is that? We're also using a shortened key version, which is You don't use 32 bytes of hash. As a key to the map and we're already using a different map. From anything that is available currently, as I mentioned before, I'd say. A simple mixer. The key source, key addresses and hashes are already randomized on an honest block. So, there is already… You know, collisions are, like, kind of rare, and you're already indexing it before. So, it is fine to use a shortened key. And eventually, you derive your slot index. Basically, you put this entire file in which you have a header and an array of different data slots, and every flat
Object is occupying a certain. Amount, or certain length of bytes. And you just kind of. Cast those bytes, as an individual pointer to your data. On RV, RV, that is just 26 key dependent and some. Constant construction… Instructions and, all of this is like, kind of. Optimized for RISC-V, the mixer is kind of simplistic, again. Because we have to stop at a position where things just work. So we divide the state into different kinds of MPHF. functions, we call it MPHF, MPHF, these are the prefixes that we'll be using. These are very simple maps address to plain state. Hash to code, and… Getapp of RLP to the Node RLP for the Node Store itself.
And once you have all of these, you sort of bundle them all together. Mind you, these are all flat bytes. We'll just create a container around the flat bytes and we just call it direct state. So this direct state has, No… Prior allocation required during the decode phase, but for all the accounts created. After the execution, there is an overlay, and it uses the overlay to eventually execute on new data that comes in. This is a representation. This information is present in the spec sheet, also present in the code base. And finally a lot of these things are optimized for our grid MPT loop, which Kind of combines the pre-state and post-state. Trie validation. Most of the other clients, what they might be doing, or the naive way of doing trie validation is to
Look through the node store, or the set of Nodes that you have and derive, all the state. Which is kind of repetitive. What we do is we take the state. And, during the final pass we just remember. All the read-only keys we have had to deal with. We put the root on a single stack. Unfold, the children from that stack. And for the pre-state. If it is read-only, we just verify that the state that we have come from the MFBD bundle actually matches the one That is also there, derived from the ketchup part of the tri. For this, some additional Elements like, like a set of address hashes is also mandated in the spec for MFBD.
And at the end of it, this is what it looks like. There's an overall MFBD bundle with some MFBD bundle. some magic versions and eventually every container has genesis the blocks ancestors And a whole section for the pre-state. That contains the accounts, address hashes, and the code. You also have the node store, of course, and some network selector. All of this is extensible, we frequently do keep updating the versions. And all you need to do is just cast a pointer, and for future optimizations, we can swap in or out the sections as required. We do several rounds of checks. Of course, when you cast bytes, you can't just trust that the source of the bytes is correct, so we have some structural, we have some functional sanitizations that include alignment checks, bound checks.
Matching HEAD-AC checks, and we check various other things that may be A lot of these checks are missing, for example, there are, there is a known issue of missing, Absence proofs in witnesses. And that can easily, make your Node. I actually think that the read value is 0, but… We sort of record those, and at the end of the… Trie validation loop, we also checked that. There were no, unsolicited zero reads, and, like, there are some, you know, ton of other checks, but these checks are actually kind of… Weighing this down, we have to also find a balance between how to optimize these checks, because doing them serially sort of beats the point, but why bother about all of this, you know?
I also started on with an alternative implementation with everything that we learned about reduced keys and using a simple mixer as a hasher as opposed to something else. And a very optimized hash data implementation that would eventually directly consume the stateless input bytes. And like with our best efforts, we are at 1.11x the cycles of the DirectState. So in a way you can say that given everything else to be the same, DirectState would be running Around 11% faster. Compared to a full state reconstruction from. The stateless input bytes. But of course, this number can go up or down a little bit with optimizations. There's also some work being done to improve this mixer with, some
Formal analysis and avalanche data and A different kind of constant, Just to give the mixer a better mixing characteristics. Wow. There are some structural changes to the hash state, but it is, Kind of straightforward, just take the blob. and construct most of these stores. These stores are going to be referenced with hashes instead of plain. And you have a similar overlay. Eventually the hash state is, An alternate code path, so at compile time, you either use the hash state or The direct state and the direct state would require the MFBD bundle, which is our custom format. But with the stateless input bytes as it is. You can just use the hash state from this construction.
And this is kind of the pipeline. I wouldn't want to be talking about this more unless there is a question. So I would say that's all from Zilkworm, and thank you for Giving us the opportunity to speak.
Ignacio Hagiopan: Oh, amazing. Thanks, everyone from the Zilkworm team, to sharing this… presentation, there's a lot of things to unpack here. And I think we have a lot of time for questions, but… There's… yeah, there's a lot of things here, from… I think Zilkworm supporting the EEST specs is going to be a good start, so we can benchmark all the guest programs using the specs, and then we can maybe start experimenting with many of these extra optimizations, and see how much this can justify, probably, a spec change, if we think it is worth the speedup versus complexity. I'm really glad that someone is taking a look at all these details. Because, someone has to do it to really get… so we can get the numbers and really start thinking about all these things, at least for the mandatory proofs, work direction, right?
So I think this is great. And thank everyone for sharing all this. I don't know if it's any, like, short… questions for… for them. If not, we can also schedule another, Q&A, in a future call, too. Oh. If there isn't, I know we are a bit over time. I know that Lion joined the call from Lighthouse. I don't know if you want to share any quick updates.
Lion Dapplion: Yeah, I'll give… I'll be very quick. So, in Lighthouse, we have merged into Unstable the capacity to run with a proof engine as a sidecar. We will maintain… we have implemented and we will maintain a sidecar, so we don't have to depend on Lighthouse development cycle, but the plan would be to eventually Integrate the verifiers on the codebase, but… later, when everything stabilizes. We can also run now Unstable Lighthouse without an EL. I know this is controversial, but that's what's on the code right now. And… and what else? Yeah, I'm also working, helping Tao on the recursive part. There's a PR. To pass the block route. And ZK Boost consume… the state. I also added the new… route.
to get the leaves. So we optimize state hashing on ZK Boost. And I think that's it. That's it.
Ignacio Hagiopan: Cool, great. Thanks for the updates. Well, I mean, this has been a pretty lengthy call. A lot of really cool stuff is going on. As a last reminder, please, everyone that is interested in all this topic, join ACDC tomorrow. I think will be a pretty important milestone for L1 block proving. In the protocol history, so hopefully we can… Settle a lot of the work that we have done in the last… year or more. And keep iterating on all this effort for mandatory proofs, which you all know that we have a lot to do regarding recursive proving, optimizations, potential spec changes, EFAR justify, and things like that. So hopefully we can figure out what is, like, a good plan and the right steps.
And which is the right order to… to do the things, and… and yeah, hopefully be ready to… have a solid and resilient one-proof brewery. So, yeah, with that, I… We'll thank you all for this and see you in the next call. We will be discussing maybe if we will skip the next call because it has some overlap with DEF CON. But I will share more on this on the Discord channel if we are going to skip it. But yeah, thanks everyone, and see you next time.
Francesco Risitano: Thank you.
Lion Dapplion: Thank you, bye.
Tullio Canepa: Thank you, bye.
Somnath Banerjee: you.
Transcript adapted from ethereum/pm, CC BY-SA 3.0.