 Thank you for making it today. As the title says, I'll be presenting on our work on formally specifying and formally verifying the distributed validator technology protocol. And the way I'm going to do so is by answering to four key questions. Why do we need a distributed validator in the first place? Why do we need to formally specify and formally verify the distributed by data technology protocol. How does our formal specification look like, and finally, what we've actually achieved so far, and what is left to do. But before diving into answering to these questions, some due acknowledgments, this work has been carried out by consensus R&D, but as I received a grant co-funded by the theorem foundation, obol, and SSV network. Also, I'm here presenting the work, but this was done together with Tanaitran, who is one of my colleagues in the distributed system formal verification team at consensus. Everybody, I think so at least, I can start answering to the first quick questions. Why do we need distributed by data? Now, if you are here before the talk by Colin Oisin, you may already know why, but I'll briefly go over it. Actually, the way I go over it will be by answering to another question. What can go wrong with an ethereum validator? Well, there are two things, at least, that can go wrong with an ethereum validator. The first one is that your ethereum validator might fail, and let's see what this means. Now, you know you have your slots, in some of the slots you have the proposed, and now that you are a tester, and your ethereum validator is working, what this means is that it produces blocks, you get rewards, produces attestations, you get rewards. But now, suppose that your node fails, but what's going to happen is you start missing your duties. So if you miss a block, you don't receive rewards. If you miss an attestation, you don't receive rewards. You also get penalized. What this means basically with what can happen with a node failure is that you miss rewards and you also can incur penalties. The second thing that can go wrong is that the validator key might be compromised, and let's see what this means. Let's see if your ethereum validator with your validator sign in key. Now, in malicious node is somehow able to steal it. What this malicious node can do can actually produce, for example, two attestations, slashable attestations, sign with your validator sign in key, and package all of these into a slash improve, sign with a malicious node sign in key. And propose a block, submit it to the network. What's going to happen is that, of course, you're going to get slashed, and some of your funds get actually kind of transferred to the malicious node. So while the malicious node doesn't have the withdrawal key, they can still somehow get some of your funds. And this is very bad. It's bad for you as a staker. It's bad for the network because it means that malicious nodes can get more and more power, more and more stake, and we don't want this. The way to fix this is not to strive forward, as one might think. Just think about the first issue, which is, if you want, the simplest. One might think, well, let's just run more than one ethereum validator, and, well, we know from the early day of the big chain, this is the perfect recipe for getting yourself slashed. So, yeah, we know we can't do that. And this is why, while the theorem foundation, Deitcher, Duncan, and come up with the concept of distributed validator technology protocol, which is simplified here. So what you need, essentially, you need a coordination layer between the different nodes. You need this coordination layer because you need to ensure that whatever attestations are submitted potentially by more than one node, they are not slashebode. And this relies on a consensus protocol that basically have a middleware between the beacon nodes and the remote signer. And this middleware, which is called distributed validator client, runs underneath a consensus protocol, plus another layer on top, that ensures that, or must ensure that you never get slashed. This is a protocol that allows basically splitting the distributed validator signing key into different key shares, and it's a remote signer as its own key share. So none of the remote signer has the full key. This is what ensures protection against validator signing key stealing. Okay, now we know why it's important. Well, why do we need to formally specify and verify such a protocol? We have removed any single point of failure, and so we have higher resiliency. However, there is no such thing as a free lunch, we have increased the complexity of the system. Now we have a distributed system in place of a single piece of code. And so we have higher sciences of bugs. And this is where formal verification can really help us. And to give you an idea of how it can really help us, I want just to draw a comparison to testing. And the key concept here is that formal verification is exhaustive, and testing is not. To give you an idea, with formal verification we can consider networks of any size. You pick a number, we can deal with it. You can't do that with testing on small network sizes. And it's very important when it comes to Byzantine behavior, because with formal verification we can really consider any Byzantine behavior. With testing, even with fuzzing, you can only consider a limited set of Byzantine behaviors, perhaps. I know it doesn't respond, but you can't really exhaustively consider all of them. Also, if you want to make sure that a property is insured, well, and this property actually doesn't hold, so there is a bug in the protocol. Well, with formal verification it can be detected. With testing, maybe yes, maybe no, it depends. It's not exhaustive, so you might get lucky. Moreover, if a property is actually true, well, with formal verification we can prove that it's true. With testing we cannot do it, because, again, it's not exhaustive. So, this is the benefit. This is why formal verification is very well suited for this protocol. Now, I want to give you an idea of what formal verification consists of. You have a formal specification, which essentially is a mathematical definition of how the protocol is supposed to behave, which says, basically, when you receive message X, you need to send message Y. Then you have a property definition, which is a mathematical definition of the properties that the protocol is expecting to guarantee, something like never commit a slashable offense. Although this is kind of packaged together in a formal proof, which is a mathematical proof that the protocol specification ensures the properties. Now, what we do, we take this a step further, and we work with machine checkable proofs. It means that our proofs are checked by a computer, and this provides a higher guarantee that the proofs are actually correct. Okay, now we know why we need to do that, and now we can have a look how the specification actually looks like. Now, the specification is not a piece, it's not a single piece, it's modular. We need to specify the different things. We need to specify how the single node, the DVC, the middle layer behaves, but we also need to specify how the Byzantine node behaves. And actually what we need to do is specify what it cannot do. So there are things that Byzantine node cannot do, cannot force signature. Also it cannot change the state of another node. So all these things need to be coded in the specification. We also have a specification for the consensus protocol. This is because the DVT protocol is agnostic of the consensus protocol used. And so what we need to do, we need to specify the behavior that we expect from the consensus protocol. We also need to specify how the network is supposed to behave, for example, which sequencing of messages you might have. I'll go over on this one in more detail later. And all of this is put together, is linked together in the distributed validator specification. What we have, actually, we also have an executable reference implementation that implements the single node specification. And all of this is written for this project in Daphne, which is a programming language. It has a Python JavaScript-like syntax. And it's a formally verification-aware language. And so I'm going to go over the spec by starting from the bottom, as being a bit, say, vague, abstract, I want to give you some practical code to look at. So I start from the executable reference implementation. What I want to show here, this is the method that is called when the consensus protocol decides on a new attestation. What I want to show here is that the code is pretty easy, I would say, to understand. It's really, I think, that any developer would be able to read it. It's really a mix of JavaScript and Python. You have some statements that are required for formal verification. Those are the top. If you are just interested in, say, looking at the reference implementation and having your own implementation, you can just ignore them. There are also some specific syntax like this one at the bottom, which is kind of the equivalent in some sense of exception propagation in some of the common languages. But aside from this, it's pretty simple. And this is one of the reasons we've chosen Daphne for this project to basically make it as easy as possible for the developer community to really use this protocol. But now let's go up. How does the actual specification looks like? So what the specification does really defines how the system transition from one state to the next. And the system state includes the state of all the various nodes the state of the network, the state of the adversary, the state of the consensus. So all this is encapsulated in the different fields of the system state. Now the transition says, well, on a given event, which can be a new set of duties, time to execute the next duty, message received, you move from one state to the next, like from the yellow state to the green state. One very important characteristic of the way this specification is. Britain, which is also to our TLA plus way of writing specification TLA plus, we allow nondeterministic behavior. Now, what you have on the, and explain why this is important. What you have on the left hand side is not really nondeterministic, but close to it. So what can happen is that from one state, you might have more than one event that can move you to two different states. So for example, a node might receive a message from node two or perhaps from node three. And this is what allows to capture network at synchrony. So, and this is one of the important differences to testing. We can really reason on any possible sequences of messages. Any that you can imagine, this is coded in. The other point I want to make is really about the nondeterministic behavior. So from one state, the same event can get you to two different states. And now, why this can happen? Mainly because of the adversary. So if you have a given state, the adversary can behave in multiple ways on an event. And this is what allows us to capture this. When I speak about this, I want to draw a comparison to model checking, which is a different technique. And with model checking, you have the problem of state explosion. And it's very, it would take, it's very hard for model checker to really being able to check a property considered in bison time behavior, because it will take a lot of time. And with formal verification, it takes a lot of time to put together the proof, but once the proof is put together, it's quite quick to be run through. Now looking, I want to show a bit code again, how actually the formal specification is written in Daphne. Let's focus on the top of the slide. So let's assume you have this transition from the yellow state to the green and purple state, when the gray event is received. The way we code it, we essentially have a function that takes a so state, an event, and the destination state and returns a boolean. Now, the way that the transition is encoded is that the function, if the function returns true on a given source, event, and destination state, it means that the system can transition from source to destination given the event. If it returns false, there is no such transition. So in this example, it returns true for yellow, gray, green, and purple, but not false for any other combination. And this is, you can see at the bottom, it's coded in, this is how it's coded in. Daphne now, this is essentially simplification of this, but this is expressed using first of the logic, and now this is something we don't see often in standard programming languages, but it's not much of a stretch to say. What you can see here, this is essentially an end of different state transition. And here we have the state transition for the honest node, and you can see here, we say basically, this much true for whole honest nodes. That's what the for all does. And then we put this in end with the state transition for network, adversary, and consensus. And now what you can see here, if this exists, is what gives us the non-determinism. Because we're saying, this function returns true as long as there exists a set of messages received, messages sent, and decided value such that they satisfy all the various constraints and the end expression at the bottom. Now before going into what we actually achieved, I need to make sort of a disclosure. There are parts of this, say system that needs to be trusted. So these are the parts that need to be trusted. And these are the parts that actually we don't trust. Now, if you look at this, it seems the area, it's part of the trusted and non-trusted, but the area doesn't really represent the value of complexity. Also it's not really a problem of formal verification, it's sort of existential problem. You need to assume how the adversary will behave in your system, even if you just write software, you do, you write tests, whatever you do, in to assume how that you have a consensus that all a library that works correctly, you have a network, you assume how the network will behave, same things for properties. You assume that you have a set of properties that are those that you are really interested in to. So it's just something that, yes, formal verification doesn't solve, but it solves a good chunk of problems in ensuring that your single node, as it is specified with us, will guarantee those properties. Also, there are things one can do to increase the chances that the trusted part is correct. One is to keep the trusted specification as simple as possible. One is to have a peer review. Also for the tool, it's important to use formal verification tools that have good support. We use Daphne. Daphne is very active, bugs get fixed very quickly. Also, in this system usually you have two types of properties, safety properties, which say something bad will never happen, and you have liveness property, where they say something good will eventually happen. Now, if you formally prove that a specification guarantees both, it really increases the chances that the trusted part is correct. It's quite hard to put together a specification that guarantees both properties, and it isn't incorrect. So now we can go over what you actually achieved so far and what is left to do. So on the right-hand side you have what you've been able to prove, on the left-hand side you have the assumption. What you've been able to prove is that it's possible attestation signed by the distributed validator signing key, the one that is shared. They can never be created. In other words, the account associated with the distributed validator signing key can never get slashed because of attestation signing. And this is done under the assumptions you see on the left-hand side. And the assumption is, again, we allow for any message delay. We don't constrain this at all. We allow messages to be lost. We also allow the beacon nodes here to be actually out of sync for this proof. We don't require them to be in sync. They could be serving completely different duties and the proof is still old. And then we have some assumption on the number of nodes that are either Byzantine or have a compromised key to be less than one third. And this is theoretical bound on consensus protocols as well. We assume that signatures cannot be forged and they are unique. And also that you have a sound two-throw signature scheme. And under these assumptions, we've been able to prove the property. We've also been able to prove that the reference implementation adheres to the specification. Now, what this means is that if you deploy a system running the reference implementation of the distributed validator client node, what you get is a system that ensures the non-slashable attestation property. And so looking at what is left to do, so we put together this proof, we have the specification, we have the reference implementation and it's all open sourced on the GitHub repo that you can see here. What is left to do is to extend the specification and the reference implementation to distributed block proposing and block header signing to extend the formal proof of non-slashable attestation to non-slashable blocks and then to add the proof of liveness, as I mentioned before, so proving that a distributed validator will always eventually create valid attestation, valid blocks and valid header signatures. And this is all for me. Thank you for listening. What techniques were used to prove that reference implementation adheres to the specification? So, okay, so we have used the refinement technique, so we proved through refinement, basically showing that if there is a relationship between the rest implementation state and the specification state and on a transition that is maintained. How far away do you think we are from being able to use validator pools for either ETH2 or other protocols? I probably, this is a question I need to to defer to someone else, sorry. Yeah, it's only, this is about implementation, so yeah, I don't have that answer. How difficult is the learning curve to kind of become someone who can contribute to this, you know, formal verification things and be able to start working on that? It's reasonably steep, not too much, though. I mean, nowadays with tools like Daphne, I think it's much simpler than having to learn something like Coq, Isabel, or these theorem improves that there are a bit more, you say, abstract syntax and way of proving things, so things are improving, but there is a bit. In terms of contributing to the specification, say, or reference implementation, I think it's not my view, not as much harder as contributing to a Python specification, so it won't contribute just to the specification, necessarily to the proof. How big is your team and how long have you been working on this proof to get it to this point now? So, well, the theme consists of four people. On this one, I've been working just myself and Tanai, and we've been working on this... We've been working initially on the specification, so specifically on the proof, I say, since June roughly, just for the proof. There was a bit of fixing up of the specification before that. So, why Daphne and not other languages like Coq or Isabel, as you said? Yeah, one of the reasons is that is for the fact that we think it's easier for developers to understand Daphne compared to Coq or Isabel. That's one of the reasons also. When you can compile, still I think Coq or Isabel, but the way you write it is far more complex. I'm not pretty sure. Like, with Daphne, you can kind of use... As the concept of classes and state, which is very similar to programming, and you can have some... If some of the things are implemented and open for external implementation.